View Javadoc

1   /*
2    * Copyright 2013 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.RecyclableArrayList;
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.ReadOnlyBufferException;
27  import java.nio.channels.GatheringByteChannel;
28  import java.nio.channels.ScatteringByteChannel;
29  import java.util.Collections;
30  
31  /**
32   * {@link ByteBuf} implementation which allows to wrap an array of {@link ByteBuf} in a read-only mode.
33   * This is useful to write an array of {@link ByteBuf}s.
34   */
35  final class FixedCompositeByteBuf extends AbstractReferenceCountedByteBuf {
36      private static final ByteBuf[] EMPTY = { Unpooled.EMPTY_BUFFER };
37      private final int nioBufferCount;
38      private final int capacity;
39      private final ByteBufAllocator allocator;
40      private final ByteOrder order;
41      private final Object[] buffers;
42      private final boolean direct;
43  
44      FixedCompositeByteBuf(ByteBufAllocator allocator, ByteBuf... buffers) {
45          super(AbstractByteBufAllocator.DEFAULT_MAX_CAPACITY);
46          if (buffers.length == 0) {
47              this.buffers = EMPTY;
48              order = ByteOrder.BIG_ENDIAN;
49              nioBufferCount = 1;
50              capacity = 0;
51              direct = false;
52          } else {
53              ByteBuf b = buffers[0];
54              this.buffers = new Object[buffers.length];
55              this.buffers[0] = b;
56              boolean direct = true;
57              int nioBufferCount = b.nioBufferCount();
58              int capacity = b.readableBytes();
59              order = b.order();
60              for (int i = 1; i < buffers.length; i++) {
61                  b = buffers[i];
62                  if (buffers[i].order() != order) {
63                      throw new IllegalArgumentException("All ByteBufs need to have same ByteOrder");
64                  }
65                  nioBufferCount += b.nioBufferCount();
66                  capacity += b.readableBytes();
67                  if (!b.isDirect()) {
68                      direct = false;
69                  }
70                  this.buffers[i] = b;
71              }
72              this.nioBufferCount = nioBufferCount;
73              this.capacity = capacity;
74              this.direct = direct;
75          }
76          setIndex(0, capacity());
77          this.allocator = allocator;
78      }
79  
80      @Override
81      public boolean isWritable() {
82          return false;
83      }
84  
85      @Override
86      public boolean isWritable(int size) {
87          return false;
88      }
89  
90      @Override
91      public ByteBuf discardReadBytes() {
92          throw new ReadOnlyBufferException();
93      }
94  
95      @Override
96      public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
97          throw new ReadOnlyBufferException();
98      }
99  
100     @Override
101     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
102         throw new ReadOnlyBufferException();
103     }
104 
105     @Override
106     public ByteBuf setBytes(int index, ByteBuffer src) {
107         throw new ReadOnlyBufferException();
108     }
109 
110     @Override
111     public ByteBuf setByte(int index, int value) {
112         throw new ReadOnlyBufferException();
113     }
114 
115     @Override
116     protected void _setByte(int index, int value) {
117         throw new ReadOnlyBufferException();
118     }
119 
120     @Override
121     public ByteBuf setShort(int index, int value) {
122         throw new ReadOnlyBufferException();
123     }
124 
125     @Override
126     protected void _setShort(int index, int value) {
127         throw new ReadOnlyBufferException();
128     }
129 
130     @Override
131     public ByteBuf setMedium(int index, int value) {
132         throw new ReadOnlyBufferException();
133     }
134 
135     @Override
136     protected void _setMedium(int index, int value) {
137         throw new ReadOnlyBufferException();
138     }
139 
140     @Override
141     public ByteBuf setInt(int index, int value) {
142         throw new ReadOnlyBufferException();
143     }
144 
145     @Override
146     protected void _setInt(int index, int value) {
147         throw new ReadOnlyBufferException();
148     }
149 
150     @Override
151     public ByteBuf setLong(int index, long value) {
152         throw new ReadOnlyBufferException();
153     }
154 
155     @Override
156     protected void _setLong(int index, long value) {
157         throw new ReadOnlyBufferException();
158     }
159 
160     @Override
161     public int setBytes(int index, InputStream in, int length) {
162         throw new ReadOnlyBufferException();
163     }
164 
165     @Override
166     public int setBytes(int index, ScatteringByteChannel in, int length) {
167         throw new ReadOnlyBufferException();
168     }
169 
170     @Override
171     public int capacity() {
172         return capacity;
173     }
174 
175     @Override
176     public int maxCapacity() {
177         return capacity;
178     }
179 
180     @Override
181     public ByteBuf capacity(int newCapacity) {
182         throw new ReadOnlyBufferException();
183     }
184 
185     @Override
186     public ByteBufAllocator alloc() {
187         return allocator;
188     }
189 
190     @Override
191     public ByteOrder order() {
192         return order;
193     }
194 
195     @Override
196     public ByteBuf unwrap() {
197         return null;
198     }
199 
200     @Override
201     public boolean isDirect() {
202         return direct;
203     }
204 
205     private Component findComponent(int index) {
206         int readable = 0;
207         for (int i = 0 ; i < buffers.length; i++) {
208             Component comp = null;
209             ByteBuf b;
210             Object obj = buffers[i];
211             boolean isBuffer;
212             if (obj instanceof ByteBuf) {
213                 b = (ByteBuf) obj;
214                 isBuffer = true;
215             } else {
216                 comp = (Component) obj;
217                 b = comp.buf;
218                 isBuffer = false;
219             }
220             readable += b.readableBytes();
221             if (index < readable) {
222                 if (isBuffer) {
223                     // Create a new component and store it in the array so it not create a new object
224                     // on the next access.
225                     comp = new Component(i, readable - b.readableBytes(), b);
226                     buffers[i] = comp;
227                 }
228                 return comp;
229             }
230         }
231         throw new IllegalStateException();
232     }
233 
234     /**
235      * Return the {@link ByteBuf} stored at the given index of the array.
236      */
237     private ByteBuf buffer(int i) {
238         Object obj = buffers[i];
239         if (obj instanceof ByteBuf) {
240             return (ByteBuf) obj;
241         }
242         return ((Component) obj).buf;
243     }
244 
245     @Override
246     public byte getByte(int index) {
247         return _getByte(index);
248     }
249 
250     @Override
251     protected byte _getByte(int index) {
252         Component c = findComponent(index);
253         return c.buf.getByte(index - c.offset);
254     }
255 
256     @Override
257     protected short _getShort(int index) {
258         Component c = findComponent(index);
259         if (index + 2 <= c.endOffset) {
260             return c.buf.getShort(index - c.offset);
261         } else if (order() == ByteOrder.BIG_ENDIAN) {
262             return (short) ((_getByte(index) & 0xff) << 8 | _getByte(index + 1) & 0xff);
263         } else {
264             return (short) (_getByte(index) & 0xff | (_getByte(index + 1) & 0xff) << 8);
265         }
266     }
267 
268     @Override
269     protected int _getUnsignedMedium(int index) {
270         Component c = findComponent(index);
271         if (index + 3 <= c.endOffset) {
272             return c.buf.getUnsignedMedium(index - c.offset);
273         } else if (order() == ByteOrder.BIG_ENDIAN) {
274             return (_getShort(index) & 0xffff) << 8 | _getByte(index + 2) & 0xff;
275         } else {
276             return _getShort(index) & 0xFFFF | (_getByte(index + 2) & 0xFF) << 16;
277         }
278     }
279 
280     @Override
281     protected int _getInt(int index) {
282         Component c = findComponent(index);
283         if (index + 4 <= c.endOffset) {
284             return c.buf.getInt(index - c.offset);
285         } else if (order() == ByteOrder.BIG_ENDIAN) {
286             return (_getShort(index) & 0xffff) << 16 | _getShort(index + 2) & 0xffff;
287         } else {
288             return _getShort(index) & 0xFFFF | (_getShort(index + 2) & 0xFFFF) << 16;
289         }
290     }
291 
292     @Override
293     protected long _getLong(int index) {
294         Component c = findComponent(index);
295         if (index + 8 <= c.endOffset) {
296             return c.buf.getLong(index - c.offset);
297         } else if (order() == ByteOrder.BIG_ENDIAN) {
298             return (_getInt(index) & 0xffffffffL) << 32 | _getInt(index + 4) & 0xffffffffL;
299         } else {
300             return _getInt(index) & 0xFFFFFFFFL | (_getInt(index + 4) & 0xFFFFFFFFL) << 32;
301         }
302     }
303 
304     @Override
305     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
306         checkDstIndex(index, length, dstIndex, dst.length);
307         if (length == 0) {
308             return this;
309         }
310 
311         Component c = findComponent(index);
312         int i = c.index;
313         int adjustment = c.offset;
314         ByteBuf s = c.buf;
315         for (;;) {
316             int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
317             s.getBytes(index - adjustment, dst, dstIndex, localLength);
318             index += localLength;
319             dstIndex += localLength;
320             length -= localLength;
321             adjustment += s.readableBytes();
322             if (length <= 0) {
323                 break;
324             }
325             s = buffer(++i);
326         }
327         return this;
328     }
329 
330     @Override
331     public ByteBuf getBytes(int index, ByteBuffer dst) {
332         int limit = dst.limit();
333         int length = dst.remaining();
334 
335         checkIndex(index, length);
336         if (length == 0) {
337             return this;
338         }
339 
340         try {
341             Component c = findComponent(index);
342             int i = c.index;
343             int adjustment = c.offset;
344             ByteBuf s = c.buf;
345             for (;;) {
346                 int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
347                 dst.limit(dst.position() + localLength);
348                 s.getBytes(index - adjustment, dst);
349                 index += localLength;
350                 length -= localLength;
351                 adjustment += s.readableBytes();
352                 if (length <= 0) {
353                     break;
354                 }
355                 s = buffer(++i);
356             }
357         } finally {
358             dst.limit(limit);
359         }
360         return this;
361     }
362 
363     @Override
364     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
365         checkDstIndex(index, length, dstIndex, dst.capacity());
366         if (length == 0) {
367             return this;
368         }
369 
370         Component c = findComponent(index);
371         int i = c.index;
372         int adjustment = c.offset;
373         ByteBuf s = c.buf;
374         for (;;) {
375             int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
376             s.getBytes(index - adjustment, dst, dstIndex, localLength);
377             index += localLength;
378             dstIndex += localLength;
379             length -= localLength;
380             adjustment += s.readableBytes();
381             if (length <= 0) {
382                 break;
383             }
384             s = buffer(++i);
385         }
386         return this;
387     }
388 
389     @Override
390     public int getBytes(int index, GatheringByteChannel out, int length)
391             throws IOException {
392         int count = nioBufferCount();
393         if (count == 1) {
394             return out.write(internalNioBuffer(index, length));
395         } else {
396             long writtenBytes = out.write(nioBuffers(index, length));
397             if (writtenBytes > Integer.MAX_VALUE) {
398                 return Integer.MAX_VALUE;
399             } else {
400                 return (int) writtenBytes;
401             }
402         }
403     }
404 
405     @Override
406     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
407         checkIndex(index, length);
408         if (length == 0) {
409             return this;
410         }
411 
412         Component c = findComponent(index);
413         int i = c.index;
414         int adjustment = c.offset;
415         ByteBuf s = c.buf;
416         for (;;) {
417             int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
418             s.getBytes(index - adjustment, out, localLength);
419             index += localLength;
420             length -= localLength;
421             adjustment += s.readableBytes();
422             if (length <= 0) {
423                 break;
424             }
425             s = buffer(++i);
426         }
427         return this;
428     }
429 
430     @Override
431     public ByteBuf copy(int index, int length) {
432         checkIndex(index, length);
433         boolean release = true;
434         ByteBuf buf = alloc().buffer(length);
435         try {
436             buf.writeBytes(this, index, length);
437             release = false;
438             return buf;
439         } finally {
440             if (release) {
441                 buf.release();
442             }
443         }
444     }
445 
446     @Override
447     public int nioBufferCount() {
448         return nioBufferCount;
449     }
450 
451     @Override
452     public ByteBuffer nioBuffer(int index, int length) {
453         checkIndex(index, length);
454         if (buffers.length == 1) {
455             ByteBuf buf = buffer(0);
456             if (buf.nioBufferCount() == 1) {
457                 return buf.nioBuffer(index, length);
458             }
459         }
460         ByteBuffer merged = ByteBuffer.allocate(length).order(order());
461         ByteBuffer[] buffers = nioBuffers(index, length);
462 
463         //noinspection ForLoopReplaceableByForEach
464         for (int i = 0; i < buffers.length; i++) {
465             merged.put(buffers[i]);
466         }
467 
468         merged.flip();
469         return merged;
470     }
471 
472     @Override
473     public ByteBuffer internalNioBuffer(int index, int length) {
474         if (buffers.length == 1) {
475             return buffer(0).internalNioBuffer(index, length);
476         }
477         throw new UnsupportedOperationException();
478     }
479 
480     @Override
481     public ByteBuffer[] nioBuffers(int index, int length) {
482         checkIndex(index, length);
483         if (length == 0) {
484             return EmptyArrays.EMPTY_BYTE_BUFFERS;
485         }
486 
487         RecyclableArrayList array = RecyclableArrayList.newInstance(buffers.length);
488         try {
489             Component c = findComponent(index);
490             int i = c.index;
491             int adjustment = c.offset;
492             ByteBuf s = c.buf;
493             for (;;) {
494                 int localLength = Math.min(length, s.readableBytes() - (index - adjustment));
495                 switch (s.nioBufferCount()) {
496                     case 0:
497                         throw new UnsupportedOperationException();
498                     case 1:
499                         array.add(s.nioBuffer(index - adjustment, localLength));
500                         break;
501                     default:
502                         Collections.addAll(array, s.nioBuffers(index - adjustment, localLength));
503                 }
504 
505                 index += localLength;
506                 length -= localLength;
507                 adjustment += s.readableBytes();
508                 if (length <= 0) {
509                     break;
510                 }
511                 s = buffer(++i);
512             }
513 
514             return array.toArray(new ByteBuffer[array.size()]);
515         } finally {
516             array.recycle();
517         }
518     }
519 
520     @Override
521     public boolean hasArray() {
522         return false;
523     }
524 
525     @Override
526     public byte[] array() {
527         throw new UnsupportedOperationException();
528     }
529 
530     @Override
531     public int arrayOffset() {
532         throw new UnsupportedOperationException();
533     }
534 
535     @Override
536     public boolean hasMemoryAddress() {
537         return false;
538     }
539 
540     @Override
541     public long memoryAddress() {
542         throw new UnsupportedOperationException();
543     }
544 
545     @Override
546     protected void deallocate() {
547         for (int i = 0; i < buffers.length; i++) {
548              buffer(i).release();
549         }
550     }
551 
552     @Override
553     public String toString() {
554         String result = super.toString();
555         result = result.substring(0, result.length() - 1);
556         return result + ", components=" + buffers.length + ')';
557     }
558 
559     private static final class Component {
560         private final int index;
561         private final int offset;
562         private final ByteBuf buf;
563         private final int endOffset;
564 
565         Component(int index, int offset, ByteBuf buf) {
566             this.index = index;
567             this.offset = offset;
568             endOffset = offset + buf.readableBytes();
569             this.buf = buf;
570         }
571     }
572 }