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    *   http://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.IllegalReferenceCountException;
19  import io.netty.util.ResourceLeakDetector;
20  import io.netty.util.ResourceLeakDetectorFactory;
21  import io.netty.util.internal.PlatformDependent;
22  import io.netty.util.internal.StringUtil;
23  import io.netty.util.internal.SystemPropertyUtil;
24  import io.netty.util.internal.logging.InternalLogger;
25  import io.netty.util.internal.logging.InternalLoggerFactory;
26  
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.OutputStream;
30  import java.nio.ByteBuffer;
31  import java.nio.ByteOrder;
32  import java.nio.channels.GatheringByteChannel;
33  import java.nio.channels.ScatteringByteChannel;
34  import java.nio.charset.Charset;
35  
36  import static io.netty.util.internal.MathUtil.isOutOfBounds;
37  
38  /**
39   * A skeletal implementation of a buffer.
40   */
41  public abstract class AbstractByteBuf extends ByteBuf {
42      private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractByteBuf.class);
43      private static final String PROP_MODE = "io.netty.buffer.bytebuf.checkAccessible";
44      private static final boolean checkAccessible;
45  
46      static {
47          checkAccessible = SystemPropertyUtil.getBoolean(PROP_MODE, true);
48          if (logger.isDebugEnabled()) {
49              logger.debug("-D{}: {}", PROP_MODE, checkAccessible);
50          }
51      }
52  
53      static final ResourceLeakDetector<ByteBuf> leakDetector =
54              ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ByteBuf.class);
55  
56      int readerIndex;
57      int writerIndex;
58      private int markedReaderIndex;
59      private int markedWriterIndex;
60  
61      private int maxCapacity;
62  
63      private SwappedByteBuf swappedBuf;
64  
65      protected AbstractByteBuf(int maxCapacity) {
66          if (maxCapacity < 0) {
67              throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
68          }
69          this.maxCapacity = maxCapacity;
70      }
71  
72      @Override
73      public int maxCapacity() {
74          return maxCapacity;
75      }
76  
77      protected final void maxCapacity(int maxCapacity) {
78          this.maxCapacity = maxCapacity;
79      }
80  
81      @Override
82      public int readerIndex() {
83          return readerIndex;
84      }
85  
86      @Override
87      public ByteBuf readerIndex(int readerIndex) {
88          if (readerIndex < 0 || readerIndex > writerIndex) {
89              throw new IndexOutOfBoundsException(String.format(
90                      "readerIndex: %d (expected: 0 <= readerIndex <= writerIndex(%d))", readerIndex, writerIndex));
91          }
92          this.readerIndex = readerIndex;
93          return this;
94      }
95  
96      @Override
97      public int writerIndex() {
98          return writerIndex;
99      }
100 
101     @Override
102     public ByteBuf writerIndex(int writerIndex) {
103         if (writerIndex < readerIndex || writerIndex > capacity()) {
104             throw new IndexOutOfBoundsException(String.format(
105                     "writerIndex: %d (expected: readerIndex(%d) <= writerIndex <= capacity(%d))",
106                     writerIndex, readerIndex, capacity()));
107         }
108         this.writerIndex = writerIndex;
109         return this;
110     }
111 
112     @Override
113     public ByteBuf setIndex(int readerIndex, int writerIndex) {
114         if (readerIndex < 0 || readerIndex > writerIndex || writerIndex > capacity()) {
115             throw new IndexOutOfBoundsException(String.format(
116                     "readerIndex: %d, writerIndex: %d (expected: 0 <= readerIndex <= writerIndex <= capacity(%d))",
117                     readerIndex, writerIndex, capacity()));
118         }
119         setIndex0(readerIndex, writerIndex);
120         return this;
121     }
122 
123     @Override
124     public ByteBuf clear() {
125         readerIndex = writerIndex = 0;
126         return this;
127     }
128 
129     @Override
130     public boolean isReadable() {
131         return writerIndex > readerIndex;
132     }
133 
134     @Override
135     public boolean isReadable(int numBytes) {
136         return writerIndex - readerIndex >= numBytes;
137     }
138 
139     @Override
140     public boolean isWritable() {
141         return capacity() > writerIndex;
142     }
143 
144     @Override
145     public boolean isWritable(int numBytes) {
146         return capacity() - writerIndex >= numBytes;
147     }
148 
149     @Override
150     public int readableBytes() {
151         return writerIndex - readerIndex;
152     }
153 
154     @Override
155     public int writableBytes() {
156         return capacity() - writerIndex;
157     }
158 
159     @Override
160     public int maxWritableBytes() {
161         return maxCapacity() - writerIndex;
162     }
163 
164     @Override
165     public ByteBuf markReaderIndex() {
166         markedReaderIndex = readerIndex;
167         return this;
168     }
169 
170     @Override
171     public ByteBuf resetReaderIndex() {
172         readerIndex(markedReaderIndex);
173         return this;
174     }
175 
176     @Override
177     public ByteBuf markWriterIndex() {
178         markedWriterIndex = writerIndex;
179         return this;
180     }
181 
182     @Override
183     public ByteBuf resetWriterIndex() {
184         writerIndex = markedWriterIndex;
185         return this;
186     }
187 
188     @Override
189     public ByteBuf discardReadBytes() {
190         ensureAccessible();
191         if (readerIndex == 0) {
192             return this;
193         }
194 
195         if (readerIndex != writerIndex) {
196             setBytes(0, this, readerIndex, writerIndex - readerIndex);
197             writerIndex -= readerIndex;
198             adjustMarkers(readerIndex);
199             readerIndex = 0;
200         } else {
201             adjustMarkers(readerIndex);
202             writerIndex = readerIndex = 0;
203         }
204         return this;
205     }
206 
207     @Override
208     public ByteBuf discardSomeReadBytes() {
209         ensureAccessible();
210         if (readerIndex == 0) {
211             return this;
212         }
213 
214         if (readerIndex == writerIndex) {
215             adjustMarkers(readerIndex);
216             writerIndex = readerIndex = 0;
217             return this;
218         }
219 
220         if (readerIndex >= capacity() >>> 1) {
221             setBytes(0, this, readerIndex, writerIndex - readerIndex);
222             writerIndex -= readerIndex;
223             adjustMarkers(readerIndex);
224             readerIndex = 0;
225         }
226         return this;
227     }
228 
229     protected final void adjustMarkers(int decrement) {
230         int markedReaderIndex = this.markedReaderIndex;
231         if (markedReaderIndex <= decrement) {
232             this.markedReaderIndex = 0;
233             int markedWriterIndex = this.markedWriterIndex;
234             if (markedWriterIndex <= decrement) {
235                 this.markedWriterIndex = 0;
236             } else {
237                 this.markedWriterIndex = markedWriterIndex - decrement;
238             }
239         } else {
240             this.markedReaderIndex = markedReaderIndex - decrement;
241             markedWriterIndex -= decrement;
242         }
243     }
244 
245     @Override
246     public ByteBuf ensureWritable(int minWritableBytes) {
247         if (minWritableBytes < 0) {
248             throw new IllegalArgumentException(String.format(
249                     "minWritableBytes: %d (expected: >= 0)", minWritableBytes));
250         }
251         ensureWritable0(minWritableBytes);
252         return this;
253     }
254 
255     final void ensureWritable0(int minWritableBytes) {
256         ensureAccessible();
257         if (minWritableBytes <= writableBytes()) {
258             return;
259         }
260 
261         if (minWritableBytes > maxCapacity - writerIndex) {
262             throw new IndexOutOfBoundsException(String.format(
263                     "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
264                     writerIndex, minWritableBytes, maxCapacity, this));
265         }
266 
267         // Normalize the current capacity to the power of 2.
268         int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);
269 
270         // Adjust to the new capacity.
271         capacity(newCapacity);
272     }
273 
274     @Override
275     public int ensureWritable(int minWritableBytes, boolean force) {
276         ensureAccessible();
277         if (minWritableBytes < 0) {
278             throw new IllegalArgumentException(String.format(
279                     "minWritableBytes: %d (expected: >= 0)", minWritableBytes));
280         }
281 
282         if (minWritableBytes <= writableBytes()) {
283             return 0;
284         }
285 
286         final int maxCapacity = maxCapacity();
287         final int writerIndex = writerIndex();
288         if (minWritableBytes > maxCapacity - writerIndex) {
289             if (!force || capacity() == maxCapacity) {
290                 return 1;
291             }
292 
293             capacity(maxCapacity);
294             return 3;
295         }
296 
297         // Normalize the current capacity to the power of 2.
298         int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);
299 
300         // Adjust to the new capacity.
301         capacity(newCapacity);
302         return 2;
303     }
304 
305     private int calculateNewCapacity(int minNewCapacity) {
306         final int maxCapacity = this.maxCapacity;
307         final int threshold = 1048576 * 4; // 4 MiB page
308 
309         if (minNewCapacity == threshold) {
310             return threshold;
311         }
312 
313         // If over threshold, do not double but just increase by threshold.
314         if (minNewCapacity > threshold) {
315             int newCapacity = minNewCapacity / threshold * threshold;
316             if (newCapacity > maxCapacity - threshold) {
317                 newCapacity = maxCapacity;
318             } else {
319                 newCapacity += threshold;
320             }
321             return newCapacity;
322         }
323 
324         // Not over threshold. Double up to 4 MiB, starting from 64.
325         int newCapacity = 64;
326         while (newCapacity < minNewCapacity) {
327             newCapacity <<= 1;
328         }
329 
330         return Math.min(newCapacity, maxCapacity);
331     }
332 
333     @Override
334     public ByteBuf order(ByteOrder endianness) {
335         if (endianness == null) {
336             throw new NullPointerException("endianness");
337         }
338         if (endianness == order()) {
339             return this;
340         }
341 
342         SwappedByteBuf swappedBuf = this.swappedBuf;
343         if (swappedBuf == null) {
344             this.swappedBuf = swappedBuf = newSwappedByteBuf();
345         }
346         return swappedBuf;
347     }
348 
349     /**
350      * Creates a new {@link SwappedByteBuf} for this {@link ByteBuf} instance.
351      */
352     protected SwappedByteBuf newSwappedByteBuf() {
353         return new SwappedByteBuf(this);
354     }
355 
356     @Override
357     public byte getByte(int index) {
358         checkIndex(index);
359         return _getByte(index);
360     }
361 
362     protected abstract byte _getByte(int index);
363 
364     @Override
365     public boolean getBoolean(int index) {
366         return getByte(index) != 0;
367     }
368 
369     @Override
370     public short getUnsignedByte(int index) {
371         return (short) (getByte(index) & 0xFF);
372     }
373 
374     @Override
375     public short getShort(int index) {
376         checkIndex(index, 2);
377         return _getShort(index);
378     }
379 
380     protected abstract short _getShort(int index);
381 
382     @Override
383     public int getUnsignedShort(int index) {
384         return getShort(index) & 0xFFFF;
385     }
386 
387     @Override
388     public int getUnsignedMedium(int index) {
389         checkIndex(index, 3);
390         return _getUnsignedMedium(index);
391     }
392 
393     protected abstract int _getUnsignedMedium(int index);
394 
395     @Override
396     public int getMedium(int index) {
397         int value = getUnsignedMedium(index);
398         if ((value & 0x800000) != 0) {
399             value |= 0xff000000;
400         }
401         return value;
402     }
403 
404     @Override
405     public int getInt(int index) {
406         checkIndex(index, 4);
407         return _getInt(index);
408     }
409 
410     protected abstract int _getInt(int index);
411 
412     @Override
413     public long getUnsignedInt(int index) {
414         return getInt(index) & 0xFFFFFFFFL;
415     }
416 
417     @Override
418     public long getLong(int index) {
419         checkIndex(index, 8);
420         return _getLong(index);
421     }
422 
423     protected abstract long _getLong(int index);
424 
425     @Override
426     public char getChar(int index) {
427         return (char) getShort(index);
428     }
429 
430     @Override
431     public float getFloat(int index) {
432         return Float.intBitsToFloat(getInt(index));
433     }
434 
435     @Override
436     public double getDouble(int index) {
437         return Double.longBitsToDouble(getLong(index));
438     }
439 
440     @Override
441     public ByteBuf getBytes(int index, byte[] dst) {
442         getBytes(index, dst, 0, dst.length);
443         return this;
444     }
445 
446     @Override
447     public ByteBuf getBytes(int index, ByteBuf dst) {
448         getBytes(index, dst, dst.writableBytes());
449         return this;
450     }
451 
452     @Override
453     public ByteBuf getBytes(int index, ByteBuf dst, int length) {
454         getBytes(index, dst, dst.writerIndex(), length);
455         dst.writerIndex(dst.writerIndex() + length);
456         return this;
457     }
458 
459     @Override
460     public ByteBuf setByte(int index, int value) {
461         checkIndex(index);
462         _setByte(index, value);
463         return this;
464     }
465 
466     protected abstract void _setByte(int index, int value);
467 
468     @Override
469     public ByteBuf setBoolean(int index, boolean value) {
470         setByte(index, value? 1 : 0);
471         return this;
472     }
473 
474     @Override
475     public ByteBuf setShort(int index, int value) {
476         checkIndex(index, 2);
477         _setShort(index, value);
478         return this;
479     }
480 
481     protected abstract void _setShort(int index, int value);
482 
483     @Override
484     public ByteBuf setChar(int index, int value) {
485         setShort(index, value);
486         return this;
487     }
488 
489     @Override
490     public ByteBuf setMedium(int index, int value) {
491         checkIndex(index, 3);
492         _setMedium(index, value);
493         return this;
494     }
495 
496     protected abstract void _setMedium(int index, int value);
497 
498     @Override
499     public ByteBuf setInt(int index, int value) {
500         checkIndex(index, 4);
501         _setInt(index, value);
502         return this;
503     }
504 
505     protected abstract void _setInt(int index, int value);
506 
507     @Override
508     public ByteBuf setFloat(int index, float value) {
509         setInt(index, Float.floatToRawIntBits(value));
510         return this;
511     }
512 
513     @Override
514     public ByteBuf setLong(int index, long value) {
515         checkIndex(index, 8);
516         _setLong(index, value);
517         return this;
518     }
519 
520     protected abstract void _setLong(int index, long value);
521 
522     @Override
523     public ByteBuf setDouble(int index, double value) {
524         setLong(index, Double.doubleToRawLongBits(value));
525         return this;
526     }
527 
528     @Override
529     public ByteBuf setBytes(int index, byte[] src) {
530         setBytes(index, src, 0, src.length);
531         return this;
532     }
533 
534     @Override
535     public ByteBuf setBytes(int index, ByteBuf src) {
536         setBytes(index, src, src.readableBytes());
537         return this;
538     }
539 
540     @Override
541     public ByteBuf setBytes(int index, ByteBuf src, int length) {
542         checkIndex(index, length);
543         if (src == null) {
544             throw new NullPointerException("src");
545         }
546         if (length > src.readableBytes()) {
547             throw new IndexOutOfBoundsException(String.format(
548                     "length(%d) exceeds src.readableBytes(%d) where src is: %s", length, src.readableBytes(), src));
549         }
550 
551         setBytes(index, src, src.readerIndex(), length);
552         src.readerIndex(src.readerIndex() + length);
553         return this;
554     }
555 
556     @Override
557     public ByteBuf setZero(int index, int length) {
558         if (length == 0) {
559             return this;
560         }
561 
562         checkIndex(index, length);
563 
564         int nLong = length >>> 3;
565         int nBytes = length & 7;
566         for (int i = nLong; i > 0; i --) {
567             _setLong(index, 0);
568             index += 8;
569         }
570         if (nBytes == 4) {
571             _setInt(index, 0);
572             // Not need to update the index as we not will use it after this.
573         } else if (nBytes < 4) {
574             for (int i = nBytes; i > 0; i --) {
575                 _setByte(index, (byte) 0);
576                 index ++;
577             }
578         } else {
579             _setInt(index, 0);
580             index += 4;
581             for (int i = nBytes - 4; i > 0; i --) {
582                 _setByte(index, (byte) 0);
583                 index ++;
584             }
585         }
586         return this;
587     }
588 
589     @Override
590     public byte readByte() {
591         checkReadableBytes0(1);
592         int i = readerIndex;
593         byte b = _getByte(i);
594         readerIndex = i + 1;
595         return b;
596     }
597 
598     @Override
599     public boolean readBoolean() {
600         return readByte() != 0;
601     }
602 
603     @Override
604     public short readUnsignedByte() {
605         return (short) (readByte() & 0xFF);
606     }
607 
608     @Override
609     public short readShort() {
610         checkReadableBytes0(2);
611         short v = _getShort(readerIndex);
612         readerIndex += 2;
613         return v;
614     }
615 
616     @Override
617     public int readUnsignedShort() {
618         return readShort() & 0xFFFF;
619     }
620 
621     @Override
622     public int readMedium() {
623         int value = readUnsignedMedium();
624         if ((value & 0x800000) != 0) {
625             value |= 0xff000000;
626         }
627         return value;
628     }
629 
630     @Override
631     public int readUnsignedMedium() {
632         checkReadableBytes0(3);
633         int v = _getUnsignedMedium(readerIndex);
634         readerIndex += 3;
635         return v;
636     }
637 
638     @Override
639     public int readInt() {
640         checkReadableBytes0(4);
641         int v = _getInt(readerIndex);
642         readerIndex += 4;
643         return v;
644     }
645 
646     @Override
647     public long readUnsignedInt() {
648         return readInt() & 0xFFFFFFFFL;
649     }
650 
651     @Override
652     public long readLong() {
653         checkReadableBytes0(8);
654         long v = _getLong(readerIndex);
655         readerIndex += 8;
656         return v;
657     }
658 
659     @Override
660     public char readChar() {
661         return (char) readShort();
662     }
663 
664     @Override
665     public float readFloat() {
666         return Float.intBitsToFloat(readInt());
667     }
668 
669     @Override
670     public double readDouble() {
671         return Double.longBitsToDouble(readLong());
672     }
673 
674     @Override
675     public ByteBuf readBytes(int length) {
676         checkReadableBytes(length);
677         if (length == 0) {
678             return Unpooled.EMPTY_BUFFER;
679         }
680 
681         ByteBuf buf = alloc().buffer(length, maxCapacity);
682         buf.writeBytes(this, readerIndex, length);
683         readerIndex += length;
684         return buf;
685     }
686 
687     @Override
688     public ByteBuf readSlice(int length) {
689         checkReadableBytes(length);
690         ByteBuf slice = slice(readerIndex, length);
691         readerIndex += length;
692         return slice;
693     }
694 
695     @Override
696     public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
697         checkReadableBytes(length);
698         getBytes(readerIndex, dst, dstIndex, length);
699         readerIndex += length;
700         return this;
701     }
702 
703     @Override
704     public ByteBuf readBytes(byte[] dst) {
705         readBytes(dst, 0, dst.length);
706         return this;
707     }
708 
709     @Override
710     public ByteBuf readBytes(ByteBuf dst) {
711         readBytes(dst, dst.writableBytes());
712         return this;
713     }
714 
715     @Override
716     public ByteBuf readBytes(ByteBuf dst, int length) {
717         if (length > dst.writableBytes()) {
718             throw new IndexOutOfBoundsException(String.format(
719                     "length(%d) exceeds dst.writableBytes(%d) where dst is: %s", length, dst.writableBytes(), dst));
720         }
721         readBytes(dst, dst.writerIndex(), length);
722         dst.writerIndex(dst.writerIndex() + length);
723         return this;
724     }
725 
726     @Override
727     public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
728         checkReadableBytes(length);
729         getBytes(readerIndex, dst, dstIndex, length);
730         readerIndex += length;
731         return this;
732     }
733 
734     @Override
735     public ByteBuf readBytes(ByteBuffer dst) {
736         int length = dst.remaining();
737         checkReadableBytes(length);
738         getBytes(readerIndex, dst);
739         readerIndex += length;
740         return this;
741     }
742 
743     @Override
744     public int readBytes(GatheringByteChannel out, int length)
745             throws IOException {
746         checkReadableBytes(length);
747         int readBytes = getBytes(readerIndex, out, length);
748         readerIndex += readBytes;
749         return readBytes;
750     }
751 
752     @Override
753     public ByteBuf readBytes(OutputStream out, int length) throws IOException {
754         checkReadableBytes(length);
755         getBytes(readerIndex, out, length);
756         readerIndex += length;
757         return this;
758     }
759 
760     @Override
761     public ByteBuf skipBytes(int length) {
762         checkReadableBytes(length);
763         readerIndex += length;
764         return this;
765     }
766 
767     @Override
768     public ByteBuf writeBoolean(boolean value) {
769         writeByte(value ? 1 : 0);
770         return this;
771     }
772 
773     @Override
774     public ByteBuf writeByte(int value) {
775         ensureWritable0(1);
776         _setByte(writerIndex++, value);
777         return this;
778     }
779 
780     @Override
781     public ByteBuf writeShort(int value) {
782         ensureWritable0(2);
783         _setShort(writerIndex, value);
784         writerIndex += 2;
785         return this;
786     }
787 
788     @Override
789     public ByteBuf writeMedium(int value) {
790         ensureWritable0(3);
791         _setMedium(writerIndex, value);
792         writerIndex += 3;
793         return this;
794     }
795 
796     @Override
797     public ByteBuf writeInt(int value) {
798         ensureWritable0(4);
799         _setInt(writerIndex, value);
800         writerIndex += 4;
801         return this;
802     }
803 
804     @Override
805     public ByteBuf writeLong(long value) {
806         ensureWritable0(8);
807         _setLong(writerIndex, value);
808         writerIndex += 8;
809         return this;
810     }
811 
812     @Override
813     public ByteBuf writeChar(int value) {
814         writeShort(value);
815         return this;
816     }
817 
818     @Override
819     public ByteBuf writeFloat(float value) {
820         writeInt(Float.floatToRawIntBits(value));
821         return this;
822     }
823 
824     @Override
825     public ByteBuf writeDouble(double value) {
826         writeLong(Double.doubleToRawLongBits(value));
827         return this;
828     }
829 
830     @Override
831     public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
832         ensureWritable(length);
833         setBytes(writerIndex, src, srcIndex, length);
834         writerIndex += length;
835         return this;
836     }
837 
838     @Override
839     public ByteBuf writeBytes(byte[] src) {
840         writeBytes(src, 0, src.length);
841         return this;
842     }
843 
844     @Override
845     public ByteBuf writeBytes(ByteBuf src) {
846         writeBytes(src, src.readableBytes());
847         return this;
848     }
849 
850     @Override
851     public ByteBuf writeBytes(ByteBuf src, int length) {
852         if (length > src.readableBytes()) {
853             throw new IndexOutOfBoundsException(String.format(
854                     "length(%d) exceeds src.readableBytes(%d) where src is: %s", length, src.readableBytes(), src));
855         }
856         writeBytes(src, src.readerIndex(), length);
857         src.readerIndex(src.readerIndex() + length);
858         return this;
859     }
860 
861     @Override
862     public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) {
863         ensureWritable(length);
864         setBytes(writerIndex, src, srcIndex, length);
865         writerIndex += length;
866         return this;
867     }
868 
869     @Override
870     public ByteBuf writeBytes(ByteBuffer src) {
871         int length = src.remaining();
872         ensureWritable0(length);
873         setBytes(writerIndex, src);
874         writerIndex += length;
875         return this;
876     }
877 
878     @Override
879     public int writeBytes(InputStream in, int length)
880             throws IOException {
881         ensureWritable(length);
882         int writtenBytes = setBytes(writerIndex, in, length);
883         if (writtenBytes > 0) {
884             writerIndex += writtenBytes;
885         }
886         return writtenBytes;
887     }
888 
889     @Override
890     public int writeBytes(ScatteringByteChannel in, int length) throws IOException {
891         ensureWritable(length);
892         int writtenBytes = setBytes(writerIndex, in, length);
893         if (writtenBytes > 0) {
894             writerIndex += writtenBytes;
895         }
896         return writtenBytes;
897     }
898 
899     @Override
900     public ByteBuf writeZero(int length) {
901         if (length == 0) {
902             return this;
903         }
904 
905         ensureWritable(length);
906         int wIndex = writerIndex;
907         checkIndex0(wIndex, length);
908 
909         int nLong = length >>> 3;
910         int nBytes = length & 7;
911         for (int i = nLong; i > 0; i --) {
912             _setLong(wIndex, 0);
913             wIndex += 8;
914         }
915         if (nBytes == 4) {
916             _setInt(wIndex, 0);
917             wIndex += 4;
918         } else if (nBytes < 4) {
919             for (int i = nBytes; i > 0; i --) {
920                 _setByte(wIndex, (byte) 0);
921                 wIndex++;
922             }
923         } else {
924             _setInt(wIndex, 0);
925             wIndex += 4;
926             for (int i = nBytes - 4; i > 0; i --) {
927                 _setByte(wIndex, (byte) 0);
928                 wIndex++;
929             }
930         }
931         writerIndex = wIndex;
932         return this;
933     }
934 
935     @Override
936     public ByteBuf copy() {
937         return copy(readerIndex, readableBytes());
938     }
939 
940     @Override
941     public ByteBuf duplicate() {
942         return new DuplicatedAbstractByteBuf(this);
943     }
944 
945     @Override
946     public ByteBuf slice() {
947         return slice(readerIndex, readableBytes());
948     }
949 
950     @Override
951     public ByteBuf slice(int index, int length) {
952         return new SlicedAbstractByteBuf(this, index, length);
953     }
954 
955     @Override
956     public ByteBuffer nioBuffer() {
957         return nioBuffer(readerIndex, readableBytes());
958     }
959 
960     @Override
961     public ByteBuffer[] nioBuffers() {
962         return nioBuffers(readerIndex, readableBytes());
963     }
964 
965     @Override
966     public String toString(Charset charset) {
967         return toString(readerIndex, readableBytes(), charset);
968     }
969 
970     @Override
971     public String toString(int index, int length, Charset charset) {
972         return ByteBufUtil.decodeString(this, index, length, charset);
973     }
974 
975     @Override
976     public int indexOf(int fromIndex, int toIndex, byte value) {
977         return ByteBufUtil.indexOf(this, fromIndex, toIndex, value);
978     }
979 
980     @Override
981     public int bytesBefore(byte value) {
982         return bytesBefore(readerIndex(), readableBytes(), value);
983     }
984 
985     @Override
986     public int bytesBefore(int length, byte value) {
987         checkReadableBytes(length);
988         return bytesBefore(readerIndex(), length, value);
989     }
990 
991     @Override
992     public int bytesBefore(int index, int length, byte value) {
993         int endIndex = indexOf(index, index + length, value);
994         if (endIndex < 0) {
995             return -1;
996         }
997         return endIndex - index;
998     }
999 
1000     @Override
1001     public int forEachByte(ByteBufProcessor processor) {
1002         ensureAccessible();
1003         try {
1004             return forEachByteAsc0(readerIndex, writerIndex, processor);
1005         } catch (Exception e) {
1006             PlatformDependent.throwException(e);
1007             return -1;
1008         }
1009     }
1010 
1011     @Override
1012     public int forEachByte(int index, int length, ByteBufProcessor processor) {
1013         checkIndex(index, length);
1014         try {
1015             return forEachByteAsc0(index, index + length, processor);
1016         } catch (Exception e) {
1017             PlatformDependent.throwException(e);
1018             return -1;
1019         }
1020     }
1021 
1022     private int forEachByteAsc0(int start, int end, ByteBufProcessor processor) throws Exception {
1023         for (; start < end; ++start) {
1024             if (!processor.process(_getByte(start))) {
1025                 return start;
1026             }
1027         }
1028 
1029         return -1;
1030     }
1031 
1032     @Override
1033     public int forEachByteDesc(ByteBufProcessor processor) {
1034         ensureAccessible();
1035         try {
1036             return forEachByteDesc0(writerIndex - 1, readerIndex, processor);
1037         } catch (Exception e) {
1038             PlatformDependent.throwException(e);
1039             return -1;
1040         }
1041     }
1042 
1043     @Override
1044     public int forEachByteDesc(int index, int length, ByteBufProcessor processor) {
1045         checkIndex(index, length);
1046         try {
1047             return forEachByteDesc0(index + length - 1, index, processor);
1048         } catch (Exception e) {
1049             PlatformDependent.throwException(e);
1050             return -1;
1051         }
1052     }
1053 
1054     private int forEachByteDesc0(int rStart, final int rEnd, ByteBufProcessor processor) throws Exception {
1055         for (; rStart >= rEnd; --rStart) {
1056             if (!processor.process(_getByte(rStart))) {
1057                 return rStart;
1058             }
1059         }
1060         return -1;
1061     }
1062 
1063     @Override
1064     public int hashCode() {
1065         return ByteBufUtil.hashCode(this);
1066     }
1067 
1068     @Override
1069     public boolean equals(Object o) {
1070         if (this == o) {
1071             return true;
1072         }
1073         if (o instanceof ByteBuf) {
1074             return ByteBufUtil.equals(this, (ByteBuf) o);
1075         }
1076         return false;
1077     }
1078 
1079     @Override
1080     public int compareTo(ByteBuf that) {
1081         return ByteBufUtil.compare(this, that);
1082     }
1083 
1084     @Override
1085     public String toString() {
1086         if (refCnt() == 0) {
1087             return StringUtil.simpleClassName(this) + "(freed)";
1088         }
1089 
1090         StringBuilder buf = new StringBuilder()
1091             .append(StringUtil.simpleClassName(this))
1092             .append("(ridx: ").append(readerIndex)
1093             .append(", widx: ").append(writerIndex)
1094             .append(", cap: ").append(capacity());
1095         if (maxCapacity != Integer.MAX_VALUE) {
1096             buf.append('/').append(maxCapacity);
1097         }
1098 
1099         ByteBuf unwrapped = unwrap();
1100         if (unwrapped != null) {
1101             buf.append(", unwrapped: ").append(unwrapped);
1102         }
1103         buf.append(')');
1104         return buf.toString();
1105     }
1106 
1107     protected final void checkIndex(int index) {
1108         checkIndex(index, 1);
1109     }
1110 
1111     protected final void checkIndex(int index, int fieldLength) {
1112         ensureAccessible();
1113         checkIndex0(index, fieldLength);
1114     }
1115 
1116     final void checkIndex0(int index, int fieldLength) {
1117         if (isOutOfBounds(index, fieldLength, capacity())) {
1118             throw new IndexOutOfBoundsException(String.format(
1119                     "index: %d, length: %d (expected: range(0, %d))", index, fieldLength, capacity()));
1120         }
1121     }
1122 
1123     protected final void checkSrcIndex(int index, int length, int srcIndex, int srcCapacity) {
1124         checkIndex(index, length);
1125         if (isOutOfBounds(srcIndex, length, srcCapacity)) {
1126             throw new IndexOutOfBoundsException(String.format(
1127                     "srcIndex: %d, length: %d (expected: range(0, %d))", srcIndex, length, srcCapacity));
1128         }
1129     }
1130 
1131     protected final void checkDstIndex(int index, int length, int dstIndex, int dstCapacity) {
1132         checkIndex(index, length);
1133         if (isOutOfBounds(dstIndex, length, dstCapacity)) {
1134             throw new IndexOutOfBoundsException(String.format(
1135                     "dstIndex: %d, length: %d (expected: range(0, %d))", dstIndex, length, dstCapacity));
1136         }
1137     }
1138 
1139     /**
1140      * Throws an {@link IndexOutOfBoundsException} if the current
1141      * {@linkplain #readableBytes() readable bytes} of this buffer is less
1142      * than the specified value.
1143      */
1144     protected final void checkReadableBytes(int minimumReadableBytes) {
1145         if (minimumReadableBytes < 0) {
1146             throw new IllegalArgumentException("minimumReadableBytes: " + minimumReadableBytes + " (expected: >= 0)");
1147         }
1148         checkReadableBytes0(minimumReadableBytes);
1149     }
1150 
1151     protected final void checkNewCapacity(int newCapacity) {
1152         ensureAccessible();
1153         if (newCapacity < 0 || newCapacity > maxCapacity()) {
1154             throw new IllegalArgumentException("newCapacity: " + newCapacity + " (expected: 0-" + maxCapacity() + ')');
1155         }
1156     }
1157 
1158     private void checkReadableBytes0(int minimumReadableBytes) {
1159         ensureAccessible();
1160         if (readerIndex > writerIndex - minimumReadableBytes) {
1161             throw new IndexOutOfBoundsException(String.format(
1162                     "readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s",
1163                     readerIndex, minimumReadableBytes, writerIndex, this));
1164         }
1165     }
1166 
1167     /**
1168      * Should be called by every method that tries to access the buffers content to check
1169      * if the buffer was released before.
1170      */
1171     protected final void ensureAccessible() {
1172         if (checkAccessible && refCnt() == 0) {
1173             throw new IllegalReferenceCountException(0);
1174         }
1175     }
1176 
1177     final void setIndex0(int readerIndex, int writerIndex) {
1178         this.readerIndex = readerIndex;
1179         this.writerIndex = writerIndex;
1180     }
1181 
1182     final void discardMarks() {
1183         markedReaderIndex = markedWriterIndex = 0;
1184     }
1185 }