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