View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.buffer;
17  
18  import io.netty.util.internal.CleanableDirectBuffer;
19  import io.netty.util.internal.ObjectUtil;
20  import io.netty.util.internal.PlatformDependent;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.nio.ByteBuffer;
26  import java.nio.ByteOrder;
27  import java.nio.channels.ClosedChannelException;
28  import java.nio.channels.FileChannel;
29  import java.nio.channels.GatheringByteChannel;
30  import java.nio.channels.ScatteringByteChannel;
31  
32  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
33  
34  /**
35   * A NIO {@link ByteBuffer} based buffer. It is recommended to use
36   * {@link UnpooledByteBufAllocator#directBuffer(int, int)}, {@link Unpooled#directBuffer(int)} and
37   * {@link Unpooled#wrappedBuffer(ByteBuffer)} instead of calling the constructor explicitly.
38   */
39  public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
40  
41      private final ByteBufAllocator alloc;
42  
43      CleanableDirectBuffer cleanable;
44      ByteBuffer buffer; // accessed by UnpooledUnsafeNoCleanerDirectByteBuf.reallocateDirect()
45      private ByteBuffer tmpNioBuf;
46      private int capacity;
47      private boolean doNotFree;
48  
49      /**
50       * Creates a new direct buffer.
51       *
52       * @param initialCapacity the initial capacity of the underlying direct buffer
53       * @param maxCapacity     the maximum capacity of the underlying direct buffer
54       */
55      public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
56          this(alloc, initialCapacity, maxCapacity, false);
57      }
58  
59      UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity, boolean permitExpensiveClean) {
60          super(maxCapacity);
61          ObjectUtil.checkNotNull(alloc, "alloc");
62          checkPositiveOrZero(initialCapacity, "initialCapacity");
63          checkPositiveOrZero(maxCapacity, "maxCapacity");
64          if (initialCapacity > maxCapacity) {
65              throw new IllegalArgumentException(String.format(
66                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
67          }
68  
69          this.alloc = alloc;
70          setByteBuffer(allocateDirectBuffer(initialCapacity, permitExpensiveClean), false);
71      }
72  
73      /**
74       * Creates a new direct buffer by wrapping the specified initial buffer.
75       *
76       * @param maxCapacity the maximum capacity of the underlying direct buffer
77       */
78      protected UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer, int maxCapacity) {
79          this(alloc, initialBuffer, maxCapacity, false, true);
80      }
81  
82      UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer,
83              int maxCapacity, boolean doFree, boolean slice) {
84          super(maxCapacity);
85          ObjectUtil.checkNotNull(alloc, "alloc");
86          ObjectUtil.checkNotNull(initialBuffer, "initialBuffer");
87          if (!initialBuffer.isDirect()) {
88              throw new IllegalArgumentException("initialBuffer is not a direct buffer.");
89          }
90          if (initialBuffer.isReadOnly()) {
91              throw new IllegalArgumentException("initialBuffer is a read-only buffer.");
92          }
93  
94          int initialCapacity = initialBuffer.remaining();
95          if (initialCapacity > maxCapacity) {
96              throw new IllegalArgumentException(String.format(
97                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
98          }
99  
100         this.alloc = alloc;
101         doNotFree = !doFree;
102         setByteBuffer((slice ? initialBuffer.slice() : initialBuffer).order(ByteOrder.BIG_ENDIAN), false);
103         writerIndex(initialCapacity);
104     }
105 
106     /**
107      * Allocate a new direct {@link ByteBuffer} with the given initialCapacity.
108      * @deprecated Use {@link #allocateDirectBuffer(int)} instead.
109      */
110     @Deprecated
111     protected ByteBuffer allocateDirect(int initialCapacity) {
112         return ByteBuffer.allocateDirect(initialCapacity);
113     }
114 
115     /**
116      * Free a direct {@link ByteBuffer}
117      * @deprecated Use {@link #allocateDirectBuffer(int)} instead.
118      */
119     @Deprecated
120     protected void freeDirect(ByteBuffer buffer) {
121         PlatformDependent.freeDirectBuffer(buffer);
122     }
123 
124     protected CleanableDirectBuffer allocateDirectBuffer(int capacity) {
125         return PlatformDependent.allocateDirect(capacity, false);
126     }
127 
128     CleanableDirectBuffer allocateDirectBuffer(int capacity, boolean permitExpensiveClean) {
129         return PlatformDependent.allocateDirect(capacity, permitExpensiveClean);
130     }
131 
132     void setByteBuffer(CleanableDirectBuffer cleanableDirectBuffer, boolean tryFree) {
133         if (tryFree) {
134             CleanableDirectBuffer oldCleanable = cleanable;
135             ByteBuffer oldBuffer = buffer;
136             if (oldBuffer != null) {
137                 if (doNotFree) {
138                     doNotFree = false;
139                 } else {
140                     if (oldCleanable != null) {
141                         oldCleanable.clean();
142                     } else {
143                         freeDirect(oldBuffer);
144                     }
145                 }
146             }
147         }
148 
149         cleanable = cleanableDirectBuffer;
150         buffer = cleanableDirectBuffer.buffer();
151         tmpNioBuf = null;
152         capacity = buffer.remaining();
153     }
154 
155     void setByteBuffer(ByteBuffer buffer, boolean tryFree) {
156         if (tryFree) {
157             ByteBuffer oldBuffer = this.buffer;
158             if (oldBuffer != null) {
159                 if (doNotFree) {
160                     doNotFree = false;
161                 } else {
162                     freeDirect(oldBuffer);
163                 }
164             }
165         }
166 
167         this.buffer = buffer;
168         tmpNioBuf = null;
169         capacity = buffer.remaining();
170     }
171 
172     @Override
173     public boolean isDirect() {
174         return true;
175     }
176 
177     @Override
178     public int capacity() {
179         return capacity;
180     }
181 
182     @Override
183     public ByteBuf capacity(int newCapacity) {
184         checkNewCapacity(newCapacity);
185         int oldCapacity = capacity;
186         if (newCapacity == oldCapacity) {
187             return this;
188         }
189         int bytesToCopy;
190         if (newCapacity > oldCapacity) {
191             bytesToCopy = oldCapacity;
192         } else {
193             trimIndicesToCapacity(newCapacity);
194             bytesToCopy = newCapacity;
195         }
196         ByteBuffer oldBuffer = buffer;
197         CleanableDirectBuffer newBuffer = allocateDirectBuffer(newCapacity);
198         oldBuffer.position(0).limit(bytesToCopy);
199         newBuffer.buffer().position(0).limit(bytesToCopy);
200         newBuffer.buffer().put(oldBuffer).clear();
201         setByteBuffer(newBuffer, true);
202         return this;
203     }
204 
205     @Override
206     public ByteBufAllocator alloc() {
207         return alloc;
208     }
209 
210     @Override
211     public ByteOrder order() {
212         return ByteOrder.BIG_ENDIAN;
213     }
214 
215     @Override
216     public boolean hasArray() {
217         return false;
218     }
219 
220     @Override
221     public byte[] array() {
222         throw new UnsupportedOperationException("direct buffer");
223     }
224 
225     @Override
226     public int arrayOffset() {
227         throw new UnsupportedOperationException("direct buffer");
228     }
229 
230     @Override
231     public boolean hasMemoryAddress() {
232         CleanableDirectBuffer cleanable = this.cleanable;
233         if (cleanable != null) {
234             return cleanable.hasMemoryAddress();
235         }
236         ByteBuffer buffer = this.buffer;
237         return buffer != null && PlatformDependent.hasDirectByteBufferAddress(buffer);
238     }
239 
240     @Override
241     public long memoryAddress() {
242         ensureAccessible();
243         CleanableDirectBuffer cleanable = this.cleanable;
244         if (cleanable != null) {
245             if (cleanable.hasMemoryAddress()) {
246                 return cleanable.memoryAddress();
247             }
248         } else {
249             ByteBuffer buffer = this.buffer;
250             if (PlatformDependent.hasDirectByteBufferAddress(buffer)) {
251                 return PlatformDependent.directBufferAddress(buffer);
252             }
253         }
254         throw new UnsupportedOperationException();
255     }
256 
257     @Override
258     public byte getByte(int index) {
259         ensureAccessible();
260         return _getByte(index);
261     }
262 
263     @Override
264     protected byte _getByte(int index) {
265         return buffer.get(index);
266     }
267 
268     @Override
269     public short getShortLE(int index) {
270         ensureAccessible();
271         return _getShortLE(index);
272     }
273 
274     @Override
275     public short getShort(int index) {
276         ensureAccessible();
277         return _getShort(index);
278     }
279 
280     @Override
281     protected short _getShort(int index) {
282         if (PlatformDependent.hasVarHandle()) {
283             return VarHandleByteBufferAccess.getShortBE(buffer, index);
284         }
285         return buffer.getShort(index);
286     }
287 
288     @Override
289     protected short _getShortLE(int index) {
290         if (PlatformDependent.hasVarHandle()) {
291             return VarHandleByteBufferAccess.getShortLE(buffer, index);
292         }
293         return ByteBufUtil.swapShort(buffer.getShort(index));
294     }
295 
296     @Override
297     public int getUnsignedMedium(int index) {
298         ensureAccessible();
299         return _getUnsignedMedium(index);
300     }
301 
302     @Override
303     protected int _getUnsignedMedium(int index) {
304         return (getByte(index) & 0xff)     << 16 |
305                (getByte(index + 1) & 0xff) << 8  |
306                getByte(index + 2) & 0xff;
307     }
308 
309     @Override
310     protected int _getUnsignedMediumLE(int index) {
311         return getByte(index) & 0xff             |
312                (getByte(index + 1) & 0xff) << 8  |
313                (getByte(index + 2) & 0xff) << 16;
314     }
315 
316     @Override
317     public int getIntLE(int index) {
318         ensureAccessible();
319         return _getIntLE(index);
320     }
321 
322     @Override
323     public int getInt(int index) {
324         ensureAccessible();
325         return _getInt(index);
326     }
327 
328     @Override
329     protected int _getInt(int index) {
330         if (PlatformDependent.hasVarHandle()) {
331             return VarHandleByteBufferAccess.getIntBE(buffer, index);
332         }
333         return buffer.getInt(index);
334     }
335 
336     @Override
337     protected int _getIntLE(int index) {
338         if (PlatformDependent.hasVarHandle()) {
339             return VarHandleByteBufferAccess.getIntLE(buffer, index);
340         }
341         return ByteBufUtil.swapInt(buffer.getInt(index));
342     }
343 
344     @Override
345     public long getLongLE(int index) {
346         ensureAccessible();
347         return _getLongLE(index);
348     }
349 
350     @Override
351     public long getLong(int index) {
352         ensureAccessible();
353         return _getLong(index);
354     }
355 
356     @Override
357     protected long _getLong(int index) {
358         if (PlatformDependent.hasVarHandle()) {
359             return VarHandleByteBufferAccess.getLongBE(buffer, index);
360         }
361         return buffer.getLong(index);
362     }
363 
364     @Override
365     protected long _getLongLE(int index) {
366         if (PlatformDependent.hasVarHandle()) {
367             return VarHandleByteBufferAccess.getLongLE(buffer, index);
368         }
369         return ByteBufUtil.swapLong(buffer.getLong(index));
370     }
371 
372     @Override
373     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
374         checkDstIndex(index, length, dstIndex, dst.capacity());
375         if (dst.hasArray()) {
376             getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
377         } else {
378             ByteBuf unwrapped = dst instanceof WrappedByteBuf ? dst.unwrap() : dst;
379             if (unwrapped instanceof AbstractByteBuf) {
380                 ByteBuffer dstBuf = unwrapped.internalNioBuffer(dstIndex, length);
381                 PlatformDependent.absolutePut(dstBuf, dstBuf.position(), buffer, index, length);
382             } else if (dst.nioBufferCount() > 0) {
383                 for (ByteBuffer bb : dst.nioBuffers(dstIndex, length)) {
384                     int bbLen = bb.remaining();
385                     getBytes(index, bb);
386                     index += bbLen;
387                 }
388             } else {
389                 dst.setBytes(dstIndex, this, index, length);
390             }
391         }
392         return this;
393     }
394 
395     @Override
396     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
397         getBytes(index, dst, dstIndex, length, false);
398         return this;
399     }
400 
401     void getBytes(int index, byte[] dst, int dstIndex, int length, boolean internal) {
402         checkDstIndex(index, length, dstIndex, dst.length);
403 
404         ByteBuffer tmpBuf;
405         if (internal) {
406             tmpBuf = internalNioBuffer(index, length);
407         } else {
408             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
409         }
410         tmpBuf.get(dst, dstIndex, length);
411     }
412 
413     @Override
414     public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
415         checkReadableBytes(length);
416         getBytes(readerIndex, dst, dstIndex, length, true);
417         readerIndex += length;
418         return this;
419     }
420 
421     @Override
422     public ByteBuf getBytes(int index, ByteBuffer dst) {
423         getBytes(index, dst, false);
424         return this;
425     }
426 
427     void getBytes(int index, ByteBuffer dst, boolean internal) {
428         checkIndex(index, dst.remaining());
429 
430         ByteBuffer tmpBuf;
431         if (internal) {
432             tmpBuf = internalNioBuffer(index, dst.remaining());
433         } else {
434             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + dst.remaining());
435         }
436         dst.put(tmpBuf);
437     }
438 
439     @Override
440     public ByteBuf readBytes(ByteBuffer dst) {
441         int length = dst.remaining();
442         checkReadableBytes(length);
443         getBytes(readerIndex, dst, true);
444         readerIndex += length;
445         return this;
446     }
447 
448     @Override
449     public ByteBuf setByte(int index, int value) {
450         ensureAccessible();
451         _setByte(index, value);
452         return this;
453     }
454 
455     @Override
456     protected void _setByte(int index, int value) {
457         buffer.put(index, (byte) (value & 0xFF));
458     }
459 
460     @Override
461     public ByteBuf setShortLE(int index, int value) {
462         ensureAccessible();
463         _setShortLE(index, value);
464         return this;
465     }
466 
467     @Override
468     public ByteBuf setShort(int index, int value) {
469         ensureAccessible();
470         _setShort(index, value);
471         return this;
472     }
473 
474     @Override
475     protected void _setShort(int index, int value) {
476         if (PlatformDependent.hasVarHandle()) {
477             VarHandleByteBufferAccess.setShortBE(buffer, index, value);
478             return;
479         }
480         buffer.putShort(index, (short) (value & 0xFFFF));
481     }
482 
483     @Override
484     protected void _setShortLE(int index, int value) {
485         if (PlatformDependent.hasVarHandle()) {
486             VarHandleByteBufferAccess.setShortLE(buffer, index, value);
487             return;
488         }
489         buffer.putShort(index, ByteBufUtil.swapShort((short) value));
490     }
491 
492     @Override
493     public ByteBuf setMediumLE(int index, int value) {
494         ensureAccessible();
495         _setMediumLE(index, value);
496         return this;
497     }
498 
499     @Override
500     public ByteBuf setMedium(int index, int value) {
501         ensureAccessible();
502         _setMedium(index, value);
503         return this;
504     }
505 
506     @Override
507     protected void _setMedium(int index, int value) {
508         setByte(index, (byte) (value >>> 16));
509         setByte(index + 1, (byte) (value >>> 8));
510         setByte(index + 2, (byte) value);
511     }
512 
513     @Override
514     protected void _setMediumLE(int index, int value) {
515         setByte(index, (byte) value);
516         setByte(index + 1, (byte) (value >>> 8));
517         setByte(index + 2, (byte) (value >>> 16));
518     }
519 
520     @Override
521     public ByteBuf setIntLE(int index, int value) {
522         ensureAccessible();
523         _setIntLE(index, value);
524         return this;
525     }
526 
527     @Override
528     public ByteBuf setInt(int index, int value) {
529         ensureAccessible();
530         _setInt(index, value);
531         return this;
532     }
533 
534     @Override
535     protected void _setInt(int index, int value) {
536         if (PlatformDependent.hasVarHandle()) {
537             VarHandleByteBufferAccess.setIntBE(buffer, index, value);
538             return;
539         }
540         buffer.putInt(index, value);
541     }
542 
543     @Override
544     protected void _setIntLE(int index, int value) {
545         if (PlatformDependent.hasVarHandle()) {
546             VarHandleByteBufferAccess.setIntLE(buffer, index, value);
547             return;
548         }
549         buffer.putInt(index, ByteBufUtil.swapInt(value));
550     }
551 
552     @Override
553     public ByteBuf setLong(int index, long value) {
554         ensureAccessible();
555         _setLong(index, value);
556         return this;
557     }
558 
559     @Override
560     public ByteBuf setLongLE(int index, long value) {
561         ensureAccessible();
562         _setLongLE(index, value);
563         return this;
564     }
565 
566     @Override
567     protected void _setLong(int index, long value) {
568         if (PlatformDependent.hasVarHandle()) {
569             VarHandleByteBufferAccess.setLongBE(buffer, index, value);
570             return;
571         }
572         buffer.putLong(index, value);
573     }
574 
575     @Override
576     protected void _setLongLE(int index, long value) {
577         if (PlatformDependent.hasVarHandle()) {
578             VarHandleByteBufferAccess.setLongLE(buffer, index, value);
579             return;
580         }
581         buffer.putLong(index, ByteBufUtil.swapLong(value));
582     }
583 
584     @Override
585     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
586         checkSrcIndex(index, length, srcIndex, src.capacity());
587         if (src.nioBufferCount() > 0) {
588             for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) {
589                 int bbLen = bb.remaining();
590                 setBytes(index, bb);
591                 index += bbLen;
592             }
593         } else {
594             src.getBytes(srcIndex, this, index, length);
595         }
596         return this;
597     }
598 
599     @Override
600     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
601         checkSrcIndex(index, length, srcIndex, src.length);
602         ByteBuffer tmpBuf = internalNioBuffer(index, length);
603         tmpBuf.put(src, srcIndex, length);
604         return this;
605     }
606 
607     @Override
608     public ByteBuf setBytes(int index, ByteBuffer src) {
609         ensureAccessible();
610         if (src == tmpNioBuf) {
611             src = src.duplicate();
612         }
613         ByteBuffer tmpBuf = internalNioBuffer(index, src.remaining());
614         tmpBuf.put(src);
615         return this;
616     }
617 
618     @Override
619     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
620         getBytes(index, out, length, false);
621         return this;
622     }
623 
624     void getBytes(int index, OutputStream out, int length, boolean internal) throws IOException {
625         ensureAccessible();
626         if (length == 0) {
627             return;
628         }
629         ByteBufUtil.readBytes(alloc(), internal ? _internalNioBuffer() : buffer.duplicate(), index, length, out);
630     }
631 
632     @Override
633     public ByteBuf readBytes(OutputStream out, int length) throws IOException {
634         checkReadableBytes(length);
635         getBytes(readerIndex, out, length, true);
636         readerIndex += length;
637         return this;
638     }
639 
640     @Override
641     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
642         return getBytes(index, out, length, false);
643     }
644 
645     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
646         ensureAccessible();
647         if (length == 0) {
648             return 0;
649         }
650 
651         ByteBuffer tmpBuf;
652         if (internal) {
653             tmpBuf = internalNioBuffer(index, length);
654         } else {
655             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
656         }
657         return out.write(tmpBuf);
658     }
659 
660     @Override
661     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
662         return getBytes(index, out, position, length, false);
663     }
664 
665     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
666         ensureAccessible();
667         if (length == 0) {
668             return 0;
669         }
670 
671         ByteBuffer tmpBuf = internal ? internalNioBuffer(index, length) :
672                 (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
673         return out.write(tmpBuf, position);
674     }
675 
676     @Override
677     public int readBytes(GatheringByteChannel out, int length) throws IOException {
678         checkReadableBytes(length);
679         int readBytes = getBytes(readerIndex, out, length, true);
680         readerIndex += readBytes;
681         return readBytes;
682     }
683 
684     @Override
685     public int readBytes(FileChannel out, long position, int length) throws IOException {
686         checkReadableBytes(length);
687         int readBytes = getBytes(readerIndex, out, position, length, true);
688         readerIndex += readBytes;
689         return readBytes;
690     }
691 
692     @Override
693     public int setBytes(int index, InputStream in, int length) throws IOException {
694         ensureAccessible();
695         if (buffer.hasArray()) {
696             return in.read(buffer.array(), buffer.arrayOffset() + index, length);
697         } else {
698             byte[] tmp = ByteBufUtil.threadLocalTempArray(length);
699             int readBytes = in.read(tmp, 0, length);
700             if (readBytes <= 0) {
701                 return readBytes;
702             }
703             ByteBuffer tmpBuf = internalNioBuffer(index, readBytes);
704             tmpBuf.put(tmp, 0, readBytes);
705             return readBytes;
706         }
707     }
708 
709     @Override
710     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
711         ensureAccessible();
712         ByteBuffer tmpBuf = internalNioBuffer(index, length);
713         try {
714             return in.read(tmpBuf);
715         } catch (ClosedChannelException ignored) {
716             return -1;
717         }
718     }
719 
720     @Override
721     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
722         ensureAccessible();
723         ByteBuffer tmpBuf = internalNioBuffer(index, length);
724         try {
725             return in.read(tmpBuf, position);
726         } catch (ClosedChannelException ignored) {
727             return -1;
728         }
729     }
730 
731     @Override
732     public int nioBufferCount() {
733         return 1;
734     }
735 
736     @Override
737     public ByteBuffer[] nioBuffers(int index, int length) {
738         return new ByteBuffer[] { nioBuffer(index, length) };
739     }
740 
741     @Override
742     public final boolean isContiguous() {
743         return true;
744     }
745 
746     @Override
747     public ByteBuf copy(int index, int length) {
748         ensureAccessible();
749         ByteBuffer src;
750         try {
751             src = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
752         } catch (IllegalArgumentException ignored) {
753             throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
754         }
755 
756         return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
757     }
758 
759     @Override
760     public ByteBuffer internalNioBuffer(int index, int length) {
761         checkIndex(index, length);
762         return (ByteBuffer) _internalNioBuffer().clear().position(index).limit(index + length);
763     }
764 
765     @Override
766     ByteBuffer _internalNioBuffer() {
767         ByteBuffer tmpNioBuf = this.tmpNioBuf;
768         if (tmpNioBuf == null) {
769             this.tmpNioBuf = tmpNioBuf = buffer.duplicate();
770         }
771         return tmpNioBuf;
772     }
773 
774     @Override
775     public ByteBuffer nioBuffer(int index, int length) {
776         checkIndex(index, length);
777         return PlatformDependent.offsetSlice(buffer, index, length);
778     }
779 
780     @Override
781     protected void deallocate() {
782         ByteBuffer buffer = this.buffer;
783         if (buffer == null) {
784             return;
785         }
786 
787         this.buffer = null;
788 
789         if (!doNotFree) {
790             if (cleanable != null) {
791                 cleanable.clean();
792                 cleanable = null;
793             } else {
794                 freeDirect(buffer);
795             }
796         }
797     }
798 
799     @Override
800     public ByteBuf unwrap() {
801         return null;
802     }
803 }