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