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  
17  package io.netty.buffer;
18  
19  import io.netty.util.Recycler;
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.channels.ClosedChannelException;
26  import java.nio.channels.FileChannel;
27  import java.nio.channels.GatheringByteChannel;
28  import java.nio.channels.ScatteringByteChannel;
29  
30  final class PooledDirectByteBuf extends PooledByteBuf<ByteBuffer> {
31  
32      private static final Recycler<PooledDirectByteBuf> RECYCLER = new Recycler<PooledDirectByteBuf>() {
33          @Override
34          protected PooledDirectByteBuf newObject(Handle<PooledDirectByteBuf> handle) {
35              return new PooledDirectByteBuf(handle, 0);
36          }
37      };
38  
39      static PooledDirectByteBuf newInstance(int maxCapacity) {
40          PooledDirectByteBuf buf = RECYCLER.get();
41          buf.reuse(maxCapacity);
42          return buf;
43      }
44  
45      private PooledDirectByteBuf(Recycler.Handle<PooledDirectByteBuf> recyclerHandle, int maxCapacity) {
46          super(recyclerHandle, maxCapacity);
47      }
48  
49      @Override
50      protected ByteBuffer newInternalNioBuffer(ByteBuffer memory) {
51          return memory.duplicate();
52      }
53  
54      @Override
55      public boolean isDirect() {
56          return true;
57      }
58  
59      @Override
60      protected byte _getByte(int index) {
61          return memory.get(idx(index));
62      }
63  
64      @Override
65      protected short _getShort(int index) {
66          return memory.getShort(idx(index));
67      }
68  
69      @Override
70      protected short _getShortLE(int index) {
71          return ByteBufUtil.swapShort(_getShort(index));
72      }
73  
74      @Override
75      protected int _getUnsignedMedium(int index) {
76          index = idx(index);
77          return (memory.get(index) & 0xff)     << 16 |
78                 (memory.get(index + 1) & 0xff) << 8  |
79                 memory.get(index + 2) & 0xff;
80      }
81  
82      @Override
83      protected int _getUnsignedMediumLE(int index) {
84          index = idx(index);
85          return memory.get(index)      & 0xff        |
86                 (memory.get(index + 1) & 0xff) << 8  |
87                 (memory.get(index + 2) & 0xff) << 16;
88      }
89  
90      @Override
91      protected int _getInt(int index) {
92          return memory.getInt(idx(index));
93      }
94  
95      @Override
96      protected int _getIntLE(int index) {
97          return ByteBufUtil.swapInt(_getInt(index));
98      }
99  
100     @Override
101     protected long _getLong(int index) {
102         return memory.getLong(idx(index));
103     }
104 
105     @Override
106     protected long _getLongLE(int index) {
107         return ByteBufUtil.swapLong(_getLong(index));
108     }
109 
110     @Override
111     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
112         checkDstIndex(index, length, dstIndex, dst.capacity());
113         if (dst.hasArray()) {
114             getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
115         } else if (dst.nioBufferCount() > 0) {
116             for (ByteBuffer bb: dst.nioBuffers(dstIndex, length)) {
117                 int bbLen = bb.remaining();
118                 getBytes(index, bb);
119                 index += bbLen;
120             }
121         } else {
122             dst.setBytes(dstIndex, this, index, length);
123         }
124         return this;
125     }
126 
127     @Override
128     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
129         getBytes(index, dst, dstIndex, length, false);
130         return this;
131     }
132 
133     private void getBytes(int index, byte[] dst, int dstIndex, int length, boolean internal) {
134         checkDstIndex(index, length, dstIndex, dst.length);
135         ByteBuffer tmpBuf;
136         if (internal) {
137             tmpBuf = internalNioBuffer();
138         } else {
139             tmpBuf = memory.duplicate();
140         }
141         index = idx(index);
142         tmpBuf.clear().position(index).limit(index + length);
143         tmpBuf.get(dst, dstIndex, length);
144     }
145 
146     @Override
147     public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
148         checkReadableBytes(length);
149         getBytes(readerIndex, dst, dstIndex, length, true);
150         readerIndex += length;
151         return this;
152     }
153 
154     @Override
155     public ByteBuf getBytes(int index, ByteBuffer dst) {
156         getBytes(index, dst, false);
157         return this;
158     }
159 
160     private void getBytes(int index, ByteBuffer dst, boolean internal) {
161         checkIndex(index, dst.remaining());
162         ByteBuffer tmpBuf;
163         if (internal) {
164             tmpBuf = internalNioBuffer();
165         } else {
166             tmpBuf = memory.duplicate();
167         }
168         index = idx(index);
169         tmpBuf.clear().position(index).limit(index + dst.remaining());
170         dst.put(tmpBuf);
171     }
172 
173     @Override
174     public ByteBuf readBytes(ByteBuffer dst) {
175         int length = dst.remaining();
176         checkReadableBytes(length);
177         getBytes(readerIndex, dst, true);
178         readerIndex += length;
179         return this;
180     }
181 
182     @Override
183     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
184         getBytes(index, out, length, false);
185         return this;
186     }
187 
188     private void getBytes(int index, OutputStream out, int length, boolean internal) throws IOException {
189         checkIndex(index, length);
190         if (length == 0) {
191             return;
192         }
193 
194         byte[] tmp = new byte[length];
195         ByteBuffer tmpBuf;
196         if (internal) {
197             tmpBuf = internalNioBuffer();
198         } else {
199             tmpBuf = memory.duplicate();
200         }
201         tmpBuf.clear().position(idx(index));
202         tmpBuf.get(tmp);
203         out.write(tmp);
204     }
205 
206     @Override
207     public ByteBuf readBytes(OutputStream out, int length) throws IOException {
208         checkReadableBytes(length);
209         getBytes(readerIndex, out, length, true);
210         readerIndex += length;
211         return this;
212     }
213 
214     @Override
215     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
216         return getBytes(index, out, length, false);
217     }
218 
219     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
220         checkIndex(index, length);
221         if (length == 0) {
222             return 0;
223         }
224 
225         ByteBuffer tmpBuf;
226         if (internal) {
227             tmpBuf = internalNioBuffer();
228         } else {
229             tmpBuf = memory.duplicate();
230         }
231         index = idx(index);
232         tmpBuf.clear().position(index).limit(index + length);
233         return out.write(tmpBuf);
234     }
235 
236     @Override
237     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
238         return getBytes(index, out, position, length, false);
239     }
240 
241     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
242         checkIndex(index, length);
243         if (length == 0) {
244             return 0;
245         }
246 
247         ByteBuffer tmpBuf = internal ? internalNioBuffer() : memory.duplicate();
248         index = idx(index);
249         tmpBuf.clear().position(index).limit(index + length);
250         return out.write(tmpBuf, position);
251     }
252 
253     @Override
254     public int readBytes(GatheringByteChannel out, int length) throws IOException {
255         checkReadableBytes(length);
256         int readBytes = getBytes(readerIndex, out, length, true);
257         readerIndex += readBytes;
258         return readBytes;
259     }
260 
261     @Override
262     public int readBytes(FileChannel out, long position, int length) throws IOException {
263         checkReadableBytes(length);
264         int readBytes = getBytes(readerIndex, out, position, length, true);
265         readerIndex += readBytes;
266         return readBytes;
267     }
268 
269     @Override
270     protected void _setByte(int index, int value) {
271         memory.put(idx(index), (byte) value);
272     }
273 
274     @Override
275     protected void _setShort(int index, int value) {
276         memory.putShort(idx(index), (short) value);
277     }
278 
279     @Override
280     protected void _setShortLE(int index, int value) {
281         _setShort(index, ByteBufUtil.swapShort((short) value));
282     }
283 
284     @Override
285     protected void _setMedium(int index, int value) {
286         index = idx(index);
287         memory.put(index, (byte) (value >>> 16));
288         memory.put(index + 1, (byte) (value >>> 8));
289         memory.put(index + 2, (byte) value);
290     }
291 
292     @Override
293     protected void _setMediumLE(int index, int value) {
294         index = idx(index);
295         memory.put(index, (byte) value);
296         memory.put(index + 1, (byte) (value >>> 8));
297         memory.put(index + 2, (byte) (value >>> 16));
298     }
299 
300     @Override
301     protected void _setInt(int index, int value) {
302         memory.putInt(idx(index), value);
303     }
304 
305     @Override
306     protected void _setIntLE(int index, int value) {
307         _setInt(index, ByteBufUtil.swapInt(value));
308     }
309 
310     @Override
311     protected void _setLong(int index, long value) {
312         memory.putLong(idx(index), value);
313     }
314 
315     @Override
316     protected void _setLongLE(int index, long value) {
317         _setLong(index, ByteBufUtil.swapLong(value));
318     }
319 
320     @Override
321     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
322         checkSrcIndex(index, length, srcIndex, src.capacity());
323         if (src.hasArray()) {
324             setBytes(index, src.array(), src.arrayOffset() + srcIndex, length);
325         } else if (src.nioBufferCount() > 0) {
326             for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) {
327                 int bbLen = bb.remaining();
328                 setBytes(index, bb);
329                 index += bbLen;
330             }
331         } else {
332             src.getBytes(srcIndex, this, index, length);
333         }
334         return this;
335     }
336 
337     @Override
338     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
339         checkSrcIndex(index, length, srcIndex, src.length);
340         ByteBuffer tmpBuf = internalNioBuffer();
341         index = idx(index);
342         tmpBuf.clear().position(index).limit(index + length);
343         tmpBuf.put(src, srcIndex, length);
344         return this;
345     }
346 
347     @Override
348     public ByteBuf setBytes(int index, ByteBuffer src) {
349         checkIndex(index, src.remaining());
350         ByteBuffer tmpBuf = internalNioBuffer();
351         if (src == tmpBuf) {
352             src = src.duplicate();
353         }
354 
355         index = idx(index);
356         tmpBuf.clear().position(index).limit(index + src.remaining());
357         tmpBuf.put(src);
358         return this;
359     }
360 
361     @Override
362     public int setBytes(int index, InputStream in, int length) throws IOException {
363         checkIndex(index, length);
364         byte[] tmp = new byte[length];
365         int readBytes = in.read(tmp);
366         if (readBytes <= 0) {
367             return readBytes;
368         }
369         ByteBuffer tmpBuf = internalNioBuffer();
370         tmpBuf.clear().position(idx(index));
371         tmpBuf.put(tmp, 0, readBytes);
372         return readBytes;
373     }
374 
375     @Override
376     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
377         checkIndex(index, length);
378         ByteBuffer tmpBuf = internalNioBuffer();
379         index = idx(index);
380         tmpBuf.clear().position(index).limit(index + length);
381         try {
382             return in.read(tmpBuf);
383         } catch (ClosedChannelException ignored) {
384             return -1;
385         }
386     }
387 
388     @Override
389     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
390         checkIndex(index, length);
391         ByteBuffer tmpBuf = internalNioBuffer();
392         index = idx(index);
393         tmpBuf.clear().position(index).limit(index + length);
394         try {
395             return in.read(tmpBuf, position);
396         } catch (ClosedChannelException ignored) {
397             return -1;
398         }
399     }
400 
401     @Override
402     public ByteBuf copy(int index, int length) {
403         checkIndex(index, length);
404         ByteBuf copy = alloc().directBuffer(length, maxCapacity());
405         copy.writeBytes(this, index, length);
406         return copy;
407     }
408 
409     @Override
410     public int nioBufferCount() {
411         return 1;
412     }
413 
414     @Override
415     public ByteBuffer nioBuffer(int index, int length) {
416         checkIndex(index, length);
417         index = idx(index);
418         return ((ByteBuffer) memory.duplicate().position(index).limit(index + length)).slice();
419     }
420 
421     @Override
422     public ByteBuffer[] nioBuffers(int index, int length) {
423         return new ByteBuffer[] { nioBuffer(index, length) };
424     }
425 
426     @Override
427     public ByteBuffer internalNioBuffer(int index, int length) {
428         checkIndex(index, length);
429         index = idx(index);
430         return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
431     }
432 
433     @Override
434     public boolean hasArray() {
435         return false;
436     }
437 
438     @Override
439     public byte[] array() {
440         throw new UnsupportedOperationException("direct buffer");
441     }
442 
443     @Override
444     public int arrayOffset() {
445         throw new UnsupportedOperationException("direct buffer");
446     }
447 
448     @Override
449     public boolean hasMemoryAddress() {
450         return false;
451     }
452 
453     @Override
454     public long memoryAddress() {
455         throw new UnsupportedOperationException();
456     }
457 }