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         ByteBufUtil.readBytes(alloc(), internal ? internalNioBuffer() : memory.duplicate(), idx(index), length, out);
194     }
195 
196     @Override
197     public ByteBuf readBytes(OutputStream out, int length) throws IOException {
198         checkReadableBytes(length);
199         getBytes(readerIndex, out, length, true);
200         readerIndex += length;
201         return this;
202     }
203 
204     @Override
205     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
206         return getBytes(index, out, length, false);
207     }
208 
209     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
210         checkIndex(index, length);
211         if (length == 0) {
212             return 0;
213         }
214 
215         ByteBuffer tmpBuf;
216         if (internal) {
217             tmpBuf = internalNioBuffer();
218         } else {
219             tmpBuf = memory.duplicate();
220         }
221         index = idx(index);
222         tmpBuf.clear().position(index).limit(index + length);
223         return out.write(tmpBuf);
224     }
225 
226     @Override
227     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
228         return getBytes(index, out, position, length, false);
229     }
230 
231     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
232         checkIndex(index, length);
233         if (length == 0) {
234             return 0;
235         }
236 
237         ByteBuffer tmpBuf = internal ? internalNioBuffer() : memory.duplicate();
238         index = idx(index);
239         tmpBuf.clear().position(index).limit(index + length);
240         return out.write(tmpBuf, position);
241     }
242 
243     @Override
244     public int readBytes(GatheringByteChannel out, int length) throws IOException {
245         checkReadableBytes(length);
246         int readBytes = getBytes(readerIndex, out, length, true);
247         readerIndex += readBytes;
248         return readBytes;
249     }
250 
251     @Override
252     public int readBytes(FileChannel out, long position, int length) throws IOException {
253         checkReadableBytes(length);
254         int readBytes = getBytes(readerIndex, out, position, length, true);
255         readerIndex += readBytes;
256         return readBytes;
257     }
258 
259     @Override
260     protected void _setByte(int index, int value) {
261         memory.put(idx(index), (byte) value);
262     }
263 
264     @Override
265     protected void _setShort(int index, int value) {
266         memory.putShort(idx(index), (short) value);
267     }
268 
269     @Override
270     protected void _setShortLE(int index, int value) {
271         _setShort(index, ByteBufUtil.swapShort((short) value));
272     }
273 
274     @Override
275     protected void _setMedium(int index, int value) {
276         index = idx(index);
277         memory.put(index, (byte) (value >>> 16));
278         memory.put(index + 1, (byte) (value >>> 8));
279         memory.put(index + 2, (byte) value);
280     }
281 
282     @Override
283     protected void _setMediumLE(int index, int value) {
284         index = idx(index);
285         memory.put(index, (byte) value);
286         memory.put(index + 1, (byte) (value >>> 8));
287         memory.put(index + 2, (byte) (value >>> 16));
288     }
289 
290     @Override
291     protected void _setInt(int index, int value) {
292         memory.putInt(idx(index), value);
293     }
294 
295     @Override
296     protected void _setIntLE(int index, int value) {
297         _setInt(index, ByteBufUtil.swapInt(value));
298     }
299 
300     @Override
301     protected void _setLong(int index, long value) {
302         memory.putLong(idx(index), value);
303     }
304 
305     @Override
306     protected void _setLongLE(int index, long value) {
307         _setLong(index, ByteBufUtil.swapLong(value));
308     }
309 
310     @Override
311     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
312         checkSrcIndex(index, length, srcIndex, src.capacity());
313         if (src.hasArray()) {
314             setBytes(index, src.array(), src.arrayOffset() + srcIndex, length);
315         } else if (src.nioBufferCount() > 0) {
316             for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) {
317                 int bbLen = bb.remaining();
318                 setBytes(index, bb);
319                 index += bbLen;
320             }
321         } else {
322             src.getBytes(srcIndex, this, index, length);
323         }
324         return this;
325     }
326 
327     @Override
328     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
329         checkSrcIndex(index, length, srcIndex, src.length);
330         ByteBuffer tmpBuf = internalNioBuffer();
331         index = idx(index);
332         tmpBuf.clear().position(index).limit(index + length);
333         tmpBuf.put(src, srcIndex, length);
334         return this;
335     }
336 
337     @Override
338     public ByteBuf setBytes(int index, ByteBuffer src) {
339         checkIndex(index, src.remaining());
340         ByteBuffer tmpBuf = internalNioBuffer();
341         if (src == tmpBuf) {
342             src = src.duplicate();
343         }
344 
345         index = idx(index);
346         tmpBuf.clear().position(index).limit(index + src.remaining());
347         tmpBuf.put(src);
348         return this;
349     }
350 
351     @Override
352     public int setBytes(int index, InputStream in, int length) throws IOException {
353         checkIndex(index, length);
354         byte[] tmp = new byte[length];
355         int readBytes = in.read(tmp);
356         if (readBytes <= 0) {
357             return readBytes;
358         }
359         ByteBuffer tmpBuf = internalNioBuffer();
360         tmpBuf.clear().position(idx(index));
361         tmpBuf.put(tmp, 0, readBytes);
362         return readBytes;
363     }
364 
365     @Override
366     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
367         checkIndex(index, length);
368         ByteBuffer tmpBuf = internalNioBuffer();
369         index = idx(index);
370         tmpBuf.clear().position(index).limit(index + length);
371         try {
372             return in.read(tmpBuf);
373         } catch (ClosedChannelException ignored) {
374             return -1;
375         }
376     }
377 
378     @Override
379     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
380         checkIndex(index, length);
381         ByteBuffer tmpBuf = internalNioBuffer();
382         index = idx(index);
383         tmpBuf.clear().position(index).limit(index + length);
384         try {
385             return in.read(tmpBuf, position);
386         } catch (ClosedChannelException ignored) {
387             return -1;
388         }
389     }
390 
391     @Override
392     public ByteBuf copy(int index, int length) {
393         checkIndex(index, length);
394         ByteBuf copy = alloc().directBuffer(length, maxCapacity());
395         copy.writeBytes(this, index, length);
396         return copy;
397     }
398 
399     @Override
400     public int nioBufferCount() {
401         return 1;
402     }
403 
404     @Override
405     public ByteBuffer nioBuffer(int index, int length) {
406         checkIndex(index, length);
407         index = idx(index);
408         return ((ByteBuffer) memory.duplicate().position(index).limit(index + length)).slice();
409     }
410 
411     @Override
412     public ByteBuffer[] nioBuffers(int index, int length) {
413         return new ByteBuffer[] { nioBuffer(index, length) };
414     }
415 
416     @Override
417     public ByteBuffer internalNioBuffer(int index, int length) {
418         checkIndex(index, length);
419         index = idx(index);
420         return (ByteBuffer) internalNioBuffer().clear().position(index).limit(index + length);
421     }
422 
423     @Override
424     public boolean hasArray() {
425         return false;
426     }
427 
428     @Override
429     public byte[] array() {
430         throw new UnsupportedOperationException("direct buffer");
431     }
432 
433     @Override
434     public int arrayOffset() {
435         throw new UnsupportedOperationException("direct buffer");
436     }
437 
438     @Override
439     public boolean hasMemoryAddress() {
440         return false;
441     }
442 
443     @Override
444     public long memoryAddress() {
445         throw new UnsupportedOperationException();
446     }
447 }