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.EmptyArrays;
19  import io.netty.util.internal.PlatformDependent;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.nio.ByteBuffer;
25  import java.nio.ByteOrder;
26  import java.nio.channels.ClosedChannelException;
27  import java.nio.channels.FileChannel;
28  import java.nio.channels.GatheringByteChannel;
29  import java.nio.channels.ScatteringByteChannel;
30  
31  import static io.netty.util.internal.ObjectUtil.checkNotNull;
32  
33  /**
34   * Big endian Java heap buffer implementation. It is recommended to use
35   * {@link UnpooledByteBufAllocator#heapBuffer(int, int)}, {@link Unpooled#buffer(int)} and
36   * {@link Unpooled#wrappedBuffer(byte[])} instead of calling the constructor explicitly.
37   */
38  public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
39  
40      private final ByteBufAllocator alloc;
41      byte[] array;
42      private ByteBuffer tmpNioBuf;
43  
44      /**
45       * Creates a new heap buffer with a newly allocated byte array.
46       *
47       * @param initialCapacity the initial capacity of the underlying byte array
48       * @param maxCapacity the max capacity of the underlying byte array
49       */
50      public UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
51          super(maxCapacity);
52  
53          checkNotNull(alloc, "alloc");
54  
55          if (initialCapacity > maxCapacity) {
56              throw new IllegalArgumentException(String.format(
57                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
58          }
59  
60          this.alloc = alloc;
61          setArray(allocateArray(initialCapacity));
62          setIndex(0, 0);
63      }
64  
65      /**
66       * Creates a new heap buffer with an existing byte array.
67       *
68       * @param initialArray the initial underlying byte array
69       * @param maxCapacity the max capacity of the underlying byte array
70       */
71      protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
72          super(maxCapacity);
73  
74          checkNotNull(alloc, "alloc");
75          checkNotNull(initialArray, "initialArray");
76  
77          if (initialArray.length > maxCapacity) {
78              throw new IllegalArgumentException(String.format(
79                      "initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
80          }
81  
82          this.alloc = alloc;
83          setArray(initialArray);
84          setIndex(0, initialArray.length);
85      }
86  
87      byte[] allocateArray(int initialCapacity) {
88          return new byte[initialCapacity];
89      }
90  
91      void freeArray(byte[] array) {
92          // NOOP
93      }
94  
95      private void setArray(byte[] initialArray) {
96          array = initialArray;
97          tmpNioBuf = null;
98      }
99  
100     @Override
101     public ByteBufAllocator alloc() {
102         return alloc;
103     }
104 
105     @Override
106     public ByteOrder order() {
107         return ByteOrder.BIG_ENDIAN;
108     }
109 
110     @Override
111     public boolean isDirect() {
112         return false;
113     }
114 
115     @Override
116     public int capacity() {
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 = EmptyArrays.EMPTY_BYTES;
556     }
557 
558     @Override
559     public ByteBuf unwrap() {
560         return null;
561     }
562 }