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.internal.PlatformDependent;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.nio.ByteBuffer;
24  import java.nio.ByteOrder;
25  import java.nio.channels.ClosedChannelException;
26  import java.nio.channels.FileChannel;
27  import java.nio.channels.GatheringByteChannel;
28  import java.nio.channels.ScatteringByteChannel;
29  
30  import static io.netty.util.internal.ObjectUtil.checkNotNull;
31  
32  /**
33   * Big endian Java heap buffer implementation. It is recommended to use
34   * {@link UnpooledByteBufAllocator#heapBuffer(int, int)}, {@link Unpooled#buffer(int)} and
35   * {@link Unpooled#wrappedBuffer(byte[])} instead of calling the constructor explicitly.
36   */
37  public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
38  
39      private final ByteBufAllocator alloc;
40      byte[] array;
41      private ByteBuffer tmpNioBuf;
42  
43      /**
44       * Creates a new heap buffer with a newly allocated byte array.
45       *
46       * @param initialCapacity the initial capacity of the underlying byte array
47       * @param maxCapacity the max capacity of the underlying byte array
48       */
49      public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
50          super(maxCapacity);
51  
52          checkNotNull(alloc, "alloc");
53  
54          if (initialCapacity > maxCapacity) {
55              throw new IllegalArgumentException(String.format(
56                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
57          }
58  
59          this.alloc = alloc;
60          setArray(allocateArray(initialCapacity));
61          setIndex(0, 0);
62      }
63  
64      /**
65       * Creates a new heap buffer with an existing byte array.
66       *
67       * @param initialArray the initial underlying byte array
68       * @param maxCapacity the max capacity of the underlying byte array
69       */
70      protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
71          super(maxCapacity);
72  
73          checkNotNull(alloc, "alloc");
74          checkNotNull(initialArray, "initialArray");
75  
76          if (initialArray.length > maxCapacity) {
77              throw new IllegalArgumentException(String.format(
78                      "initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
79          }
80  
81          this.alloc = alloc;
82          setArray(initialArray);
83          setIndex(0, initialArray.length);
84      }
85  
86      byte[] allocateArray(int initialCapacity) {
87          return new byte[initialCapacity];
88      }
89  
90      void freeArray(byte[] array) {
91          // NOOP
92      }
93  
94      private void setArray(byte[] initialArray) {
95          array = initialArray;
96          tmpNioBuf = null;
97      }
98  
99      @Override
100     public ByteBufAllocator alloc() {
101         return alloc;
102     }
103 
104     @Override
105     public ByteOrder order() {
106         return ByteOrder.BIG_ENDIAN;
107     }
108 
109     @Override
110     public boolean isDirect() {
111         return false;
112     }
113 
114     @Override
115     public int capacity() {
116         ensureAccessible();
117         return array.length;
118     }
119 
120     @Override
121     public ByteBuf capacity(int newCapacity) {
122         checkNewCapacity(newCapacity);
123 
124         int oldCapacity = array.length;
125         byte[] oldArray = array;
126         if (newCapacity > oldCapacity) {
127             byte[] newArray = allocateArray(newCapacity);
128             System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
129             setArray(newArray);
130             freeArray(oldArray);
131         } else if (newCapacity < oldCapacity) {
132             byte[] newArray = allocateArray(newCapacity);
133             int readerIndex = readerIndex();
134             if (readerIndex < newCapacity) {
135                 int writerIndex = writerIndex();
136                 if (writerIndex > newCapacity) {
137                     writerIndex(writerIndex = newCapacity);
138                 }
139                 System.arraycopy(oldArray, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
140             } else {
141                 setIndex(newCapacity, newCapacity);
142             }
143             setArray(newArray);
144             freeArray(oldArray);
145         }
146         return this;
147     }
148 
149     @Override
150     public boolean hasArray() {
151         return true;
152     }
153 
154     @Override
155     public byte[] array() {
156         ensureAccessible();
157         return array;
158     }
159 
160     @Override
161     public int arrayOffset() {
162         return 0;
163     }
164 
165     @Override
166     public boolean hasMemoryAddress() {
167         return false;
168     }
169 
170     @Override
171     public long memoryAddress() {
172         throw new UnsupportedOperationException();
173     }
174 
175     @Override
176     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
177         checkDstIndex(index, length, dstIndex, dst.capacity());
178         if (dst.hasMemoryAddress()) {
179             PlatformDependent.copyMemory(array, index, dst.memoryAddress() + dstIndex, length);
180         } else if (dst.hasArray()) {
181             getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
182         } else {
183             dst.setBytes(dstIndex, array, index, length);
184         }
185         return this;
186     }
187 
188     @Override
189     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
190         checkDstIndex(index, length, dstIndex, dst.length);
191         System.arraycopy(array, index, dst, dstIndex, length);
192         return this;
193     }
194 
195     @Override
196     public ByteBuf getBytes(int index, ByteBuffer dst) {
197         checkIndex(index, dst.remaining());
198         dst.put(array, index, dst.remaining());
199         return this;
200     }
201 
202     @Override
203     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
204         ensureAccessible();
205         out.write(array, index, length);
206         return this;
207     }
208 
209     @Override
210     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
211         ensureAccessible();
212         return getBytes(index, out, length, false);
213     }
214 
215     @Override
216     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
217         ensureAccessible();
218         return getBytes(index, out, position, length, false);
219     }
220 
221     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
222         ensureAccessible();
223         ByteBuffer tmpBuf;
224         if (internal) {
225             tmpBuf = internalNioBuffer();
226         } else {
227             tmpBuf = ByteBuffer.wrap(array);
228         }
229         return out.write((ByteBuffer) tmpBuf.clear().position(index).limit(index + length));
230     }
231 
232     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
233         ensureAccessible();
234         ByteBuffer tmpBuf = internal ? internalNioBuffer() : ByteBuffer.wrap(array);
235         return out.write((ByteBuffer) tmpBuf.clear().position(index).limit(index + length), position);
236     }
237 
238     @Override
239     public int readBytes(GatheringByteChannel out, int length) throws IOException {
240         checkReadableBytes(length);
241         int readBytes = getBytes(readerIndex, out, length, true);
242         readerIndex += readBytes;
243         return readBytes;
244     }
245 
246     @Override
247     public int readBytes(FileChannel out, long position, int length) throws IOException {
248         checkReadableBytes(length);
249         int readBytes = getBytes(readerIndex, out, position, length, true);
250         readerIndex += readBytes;
251         return readBytes;
252     }
253 
254     @Override
255     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
256         checkSrcIndex(index, length, srcIndex, src.capacity());
257         if (src.hasMemoryAddress()) {
258             PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, array, index, length);
259         } else  if (src.hasArray()) {
260             setBytes(index, src.array(), src.arrayOffset() + srcIndex, length);
261         } else {
262             src.getBytes(srcIndex, array, index, length);
263         }
264         return this;
265     }
266 
267     @Override
268     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
269         checkSrcIndex(index, length, srcIndex, src.length);
270         System.arraycopy(src, srcIndex, array, index, length);
271         return this;
272     }
273 
274     @Override
275     public ByteBuf setBytes(int index, ByteBuffer src) {
276         ensureAccessible();
277         src.get(array, index, src.remaining());
278         return this;
279     }
280 
281     @Override
282     public int setBytes(int index, InputStream in, int length) throws IOException {
283         ensureAccessible();
284         return in.read(array, index, length);
285     }
286 
287     @Override
288     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
289         ensureAccessible();
290         try {
291             return in.read((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length));
292         } catch (ClosedChannelException ignored) {
293             return -1;
294         }
295     }
296 
297     @Override
298     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
299         ensureAccessible();
300         try {
301             return in.read((ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length), position);
302         } catch (ClosedChannelException ignored) {
303             return -1;
304         }
305     }
306 
307     @Override
308     public int nioBufferCount() {
309         return 1;
310     }
311 
312     @Override
313     public ByteBuffer nioBuffer(int index, int length) {
314         ensureAccessible();
315         return ByteBuffer.wrap(array, index, length).slice();
316     }
317 
318     @Override
319     public ByteBuffer[] nioBuffers(int index, int length) {
320         return new ByteBuffer[] { nioBuffer(index, length) };
321     }
322 
323     @Override
324     public ByteBuffer internalNioBuffer(int index, int length) {
325         checkIndex(index, length);
326         return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
327     }
328 
329     @Override
330     public byte getByte(int index) {
331         ensureAccessible();
332         return _getByte(index);
333     }
334 
335     @Override
336     protected byte _getByte(int index) {
337         return HeapByteBufUtil.getByte(array, index);
338     }
339 
340     @Override
341     public short getShort(int index) {
342         ensureAccessible();
343         return _getShort(index);
344     }
345 
346     @Override
347     protected short _getShort(int index) {
348         return HeapByteBufUtil.getShort(array, index);
349     }
350 
351     @Override
352     public short getShortLE(int index) {
353         ensureAccessible();
354         return _getShortLE(index);
355     }
356 
357     @Override
358     protected short _getShortLE(int index) {
359         return HeapByteBufUtil.getShortLE(array, index);
360     }
361 
362     @Override
363     public int getUnsignedMedium(int index) {
364         ensureAccessible();
365         return _getUnsignedMedium(index);
366     }
367 
368     @Override
369     protected int _getUnsignedMedium(int index) {
370         return HeapByteBufUtil.getUnsignedMedium(array, index);
371     }
372 
373     @Override
374     public int getUnsignedMediumLE(int index) {
375         ensureAccessible();
376         return _getUnsignedMediumLE(index);
377     }
378 
379     @Override
380     protected int _getUnsignedMediumLE(int index) {
381         return HeapByteBufUtil.getUnsignedMediumLE(array, index);
382     }
383 
384     @Override
385     public int getInt(int index) {
386         ensureAccessible();
387         return _getInt(index);
388     }
389 
390     @Override
391     protected int _getInt(int index) {
392         return HeapByteBufUtil.getInt(array, index);
393     }
394 
395     @Override
396     public int getIntLE(int index) {
397         ensureAccessible();
398         return _getIntLE(index);
399     }
400 
401     @Override
402     protected int _getIntLE(int index) {
403         return HeapByteBufUtil.getIntLE(array, index);
404     }
405 
406     @Override
407     public long getLong(int index) {
408         ensureAccessible();
409         return _getLong(index);
410     }
411 
412     @Override
413     protected long _getLong(int index) {
414         return HeapByteBufUtil.getLong(array, index);
415     }
416 
417     @Override
418     public long getLongLE(int index) {
419         ensureAccessible();
420         return _getLongLE(index);
421     }
422 
423     @Override
424     protected long _getLongLE(int index) {
425         return HeapByteBufUtil.getLongLE(array, index);
426     }
427 
428     @Override
429     public ByteBuf setByte(int index, int value) {
430         ensureAccessible();
431         _setByte(index, value);
432         return this;
433     }
434 
435     @Override
436     protected void _setByte(int index, int value) {
437         HeapByteBufUtil.setByte(array, index, value);
438     }
439 
440     @Override
441     public ByteBuf setShort(int index, int value) {
442         ensureAccessible();
443         _setShort(index, value);
444         return this;
445     }
446 
447     @Override
448     protected void _setShort(int index, int value) {
449         HeapByteBufUtil.setShort(array, index, value);
450     }
451 
452     @Override
453     public ByteBuf setShortLE(int index, int value) {
454         ensureAccessible();
455         _setShortLE(index, value);
456         return this;
457     }
458 
459     @Override
460     protected void _setShortLE(int index, int value) {
461         HeapByteBufUtil.setShortLE(array, index, value);
462     }
463 
464     @Override
465     public ByteBuf setMedium(int index, int   value) {
466         ensureAccessible();
467         _setMedium(index, value);
468         return this;
469     }
470 
471     @Override
472     protected void _setMedium(int index, int value) {
473         HeapByteBufUtil.setMedium(array, index, value);
474     }
475 
476     @Override
477     public ByteBuf setMediumLE(int index, int   value) {
478         ensureAccessible();
479         _setMediumLE(index, value);
480         return this;
481     }
482 
483     @Override
484     protected void _setMediumLE(int index, int value) {
485         HeapByteBufUtil.setMediumLE(array, index, value);
486     }
487 
488     @Override
489     public ByteBuf setInt(int index, int   value) {
490         ensureAccessible();
491         _setInt(index, value);
492         return this;
493     }
494 
495     @Override
496     protected void _setInt(int index, int value) {
497         HeapByteBufUtil.setInt(array, index, value);
498     }
499 
500     @Override
501     public ByteBuf setIntLE(int index, int   value) {
502         ensureAccessible();
503         _setIntLE(index, value);
504         return this;
505     }
506 
507     @Override
508     protected void _setIntLE(int index, int value) {
509         HeapByteBufUtil.setIntLE(array, index, value);
510     }
511 
512     @Override
513     public ByteBuf setLong(int index, long  value) {
514         ensureAccessible();
515         _setLong(index, value);
516         return this;
517     }
518 
519     @Override
520     protected void _setLong(int index, long value) {
521         HeapByteBufUtil.setLong(array, index, value);
522     }
523 
524     @Override
525     public ByteBuf setLongLE(int index, long  value) {
526         ensureAccessible();
527         _setLongLE(index, value);
528         return this;
529     }
530 
531     @Override
532     protected void _setLongLE(int index, long value) {
533         HeapByteBufUtil.setLongLE(array, index, value);
534     }
535 
536     @Override
537     public ByteBuf copy(int index, int length) {
538         checkIndex(index, length);
539         byte[] copiedArray = new byte[length];
540         System.arraycopy(array, index, copiedArray, 0, length);
541         return new UnpooledHeapByteBuf(alloc(), copiedArray, maxCapacity());
542     }
543 
544     private ByteBuffer internalNioBuffer() {
545         ByteBuffer tmpNioBuf = this.tmpNioBuf;
546         if (tmpNioBuf == null) {
547             this.tmpNioBuf = tmpNioBuf = ByteBuffer.wrap(array);
548         }
549         return tmpNioBuf;
550     }
551 
552     @Override
553     protected void deallocate() {
554         freeArray(array);
555         array = null;
556     }
557 
558     @Override
559     public ByteBuf unwrap() {
560         return null;
561     }
562 }