View Javadoc
1   /*
2    * Copyright 2015 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.ReadOnlyBufferException;
26  
27  import static io.netty.util.internal.MathUtil.isOutOfBounds;
28  import static io.netty.util.internal.ObjectUtil.checkNotNull;
29  
30  /**
31   * All operations get and set as {@link ByteOrder#BIG_ENDIAN}.
32   */
33  final class UnsafeByteBufUtil {
34  
35      static final boolean BIG_ENDIAN_NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
36      private static final boolean UNALIGNED = PlatformDependent.isUnaligned();
37      private static final byte ZERO = 0;
38  
39      static byte getByte(long address) {
40          return PlatformDependent.getByte(address);
41      }
42  
43      static short getShort(long address) {
44          if (UNALIGNED) {
45              short v = PlatformDependent.getShort(address);
46              return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
47          }
48          return (short) (PlatformDependent.getByte(address) << 8 | PlatformDependent.getByte(address + 1) & 0xff);
49      }
50  
51      static int getUnsignedMedium(long address) {
52          if (UNALIGNED) {
53              return (PlatformDependent.getByte(address) & 0xff) << 16 |
54                      (BIG_ENDIAN_NATIVE_ORDER ? PlatformDependent.getShort(address + 1)
55                                               : Short.reverseBytes(PlatformDependent.getShort(address + 1))) & 0xffff;
56          }
57          return (PlatformDependent.getByte(address)     & 0xff) << 16 |
58                 (PlatformDependent.getByte(address + 1) & 0xff) << 8  |
59                 PlatformDependent.getByte(address + 2)  & 0xff;
60      }
61  
62      static int getInt(long address) {
63          if (UNALIGNED) {
64              int v = PlatformDependent.getInt(address);
65              return BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
66          }
67          return PlatformDependent.getByte(address) << 24 |
68                 (PlatformDependent.getByte(address + 1) & 0xff) << 16 |
69                 (PlatformDependent.getByte(address + 2) & 0xff) <<  8 |
70                 PlatformDependent.getByte(address + 3)  & 0xff;
71      }
72  
73      static long getLong(long address) {
74          if (UNALIGNED) {
75              long v = PlatformDependent.getLong(address);
76              return BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
77          }
78          return ((long) PlatformDependent.getByte(address)) << 56 |
79                 (PlatformDependent.getByte(address + 1) & 0xffL) << 48 |
80                 (PlatformDependent.getByte(address + 2) & 0xffL) << 40 |
81                 (PlatformDependent.getByte(address + 3) & 0xffL) << 32 |
82                 (PlatformDependent.getByte(address + 4) & 0xffL) << 24 |
83                 (PlatformDependent.getByte(address + 5) & 0xffL) << 16 |
84                 (PlatformDependent.getByte(address + 6) & 0xffL) <<  8 |
85                 (PlatformDependent.getByte(address + 7)) & 0xffL;
86      }
87  
88      static void setByte(long address, int value) {
89          PlatformDependent.putByte(address, (byte) value);
90      }
91  
92      static void setShort(long address, int value) {
93          if (UNALIGNED) {
94              PlatformDependent.putShort(
95                      address, BIG_ENDIAN_NATIVE_ORDER ? (short) value : Short.reverseBytes((short) value));
96          } else {
97              PlatformDependent.putByte(address, (byte) (value >>> 8));
98              PlatformDependent.putByte(address + 1, (byte) value);
99          }
100     }
101 
102     static void setMedium(long address, int value) {
103         PlatformDependent.putByte(address, (byte) (value >>> 16));
104         if (UNALIGNED) {
105             PlatformDependent.putShort(address + 1, BIG_ENDIAN_NATIVE_ORDER ? (short) value
106                                                                             : Short.reverseBytes((short) value));
107         } else {
108             PlatformDependent.putByte(address + 1, (byte) (value >>> 8));
109             PlatformDependent.putByte(address + 2, (byte) value);
110         }
111     }
112 
113     static void setInt(long address, int value) {
114         if (UNALIGNED) {
115             PlatformDependent.putInt(address, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
116         } else {
117             PlatformDependent.putByte(address, (byte) (value >>> 24));
118             PlatformDependent.putByte(address + 1, (byte) (value >>> 16));
119             PlatformDependent.putByte(address + 2, (byte) (value >>> 8));
120             PlatformDependent.putByte(address + 3, (byte) value);
121         }
122     }
123 
124     static void setLong(long address, long value) {
125         if (UNALIGNED) {
126             PlatformDependent.putLong(address, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
127         } else {
128             PlatformDependent.putByte(address, (byte) (value >>> 56));
129             PlatformDependent.putByte(address + 1, (byte) (value >>> 48));
130             PlatformDependent.putByte(address + 2, (byte) (value >>> 40));
131             PlatformDependent.putByte(address + 3, (byte) (value >>> 32));
132             PlatformDependent.putByte(address + 4, (byte) (value >>> 24));
133             PlatformDependent.putByte(address + 5, (byte) (value >>> 16));
134             PlatformDependent.putByte(address + 6, (byte) (value >>> 8));
135             PlatformDependent.putByte(address + 7, (byte) value);
136         }
137     }
138 
139     static byte getByte(byte[] array, int index) {
140         return PlatformDependent.getByte(array, index);
141     }
142 
143     static short getShort(byte[] array, int index) {
144         if (UNALIGNED) {
145             short v = PlatformDependent.getShort(array, index);
146             return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
147         }
148         return (short) (PlatformDependent.getByte(array, index) << 8 |
149                        PlatformDependent.getByte(array, index + 1) & 0xff);
150     }
151 
152     static int getUnsignedMedium(byte[] array, int index) {
153         if (UNALIGNED) {
154             return (PlatformDependent.getByte(array, index) & 0xff) << 16 |
155                     (BIG_ENDIAN_NATIVE_ORDER ? PlatformDependent.getShort(array, index + 1)
156                                              : Short.reverseBytes(PlatformDependent.getShort(array, index + 1)))
157                             & 0xffff;
158         }
159         return (PlatformDependent.getByte(array, index) & 0xff) << 16 |
160                (PlatformDependent.getByte(array, index + 1) & 0xff) <<  8 |
161                PlatformDependent.getByte(array, index + 2) & 0xff;
162     }
163 
164     static int getInt(byte[] array, int index) {
165         if (UNALIGNED) {
166             int v = PlatformDependent.getInt(array, index);
167             return BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
168         }
169         return PlatformDependent.getByte(array, index) << 24 |
170                (PlatformDependent.getByte(array, index + 1) & 0xff) << 16 |
171                (PlatformDependent.getByte(array, index + 2) & 0xff) <<  8 |
172                PlatformDependent.getByte(array, index + 3) & 0xff;
173     }
174 
175     static long getLong(byte[] array, int index) {
176         if (UNALIGNED) {
177             long v =  PlatformDependent.getLong(array, index);
178             return BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
179         }
180         return ((long) PlatformDependent.getByte(array, index)) << 56 |
181                (PlatformDependent.getByte(array, index + 1) & 0xffL) << 48 |
182                (PlatformDependent.getByte(array, index + 2) & 0xffL) << 40 |
183                (PlatformDependent.getByte(array, index + 3) & 0xffL) << 32 |
184                (PlatformDependent.getByte(array, index + 4) & 0xffL) << 24 |
185                (PlatformDependent.getByte(array, index + 5) & 0xffL) << 16 |
186                (PlatformDependent.getByte(array, index + 6) & 0xffL) <<  8 |
187                (PlatformDependent.getByte(array, index + 7)) & 0xffL;
188     }
189 
190     static void setByte(byte[] array, int index, int value) {
191         PlatformDependent.putByte(array, index, (byte) value);
192     }
193 
194     static void setShort(byte[] array, int index, int value) {
195         if (UNALIGNED) {
196             PlatformDependent.putShort(array, index,
197                                        BIG_ENDIAN_NATIVE_ORDER ? (short) value : Short.reverseBytes((short) value));
198         } else {
199             PlatformDependent.putByte(array, index, (byte) (value >>> 8));
200             PlatformDependent.putByte(array, index + 1, (byte) value);
201         }
202     }
203 
204     static void setMedium(byte[] array, int index, int value) {
205         PlatformDependent.putByte(array, index, (byte) (value >>> 16));
206         if (UNALIGNED) {
207             PlatformDependent.putShort(array, index + 1,
208                     BIG_ENDIAN_NATIVE_ORDER ? (short) value
209                             : Short.reverseBytes((short) value));
210         } else {
211             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 8));
212             PlatformDependent.putByte(array, index + 2, (byte) value);
213         }
214     }
215 
216     static void setInt(byte[] array, int index, int value) {
217         if (UNALIGNED) {
218             PlatformDependent.putInt(array, index, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
219         } else {
220             PlatformDependent.putByte(array, index, (byte) (value >>> 24));
221             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 16));
222             PlatformDependent.putByte(array, index + 2, (byte) (value >>> 8));
223             PlatformDependent.putByte(array, index + 3, (byte) value);
224         }
225     }
226 
227     static void setLong(byte[] array, int index, long value) {
228         if (UNALIGNED) {
229             PlatformDependent.putLong(array, index, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
230         } else {
231             PlatformDependent.putByte(array, index, (byte) (value >>> 56));
232             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 48));
233             PlatformDependent.putByte(array, index + 2, (byte) (value >>> 40));
234             PlatformDependent.putByte(array, index + 3, (byte) (value >>> 32));
235             PlatformDependent.putByte(array, index + 4, (byte) (value >>> 24));
236             PlatformDependent.putByte(array, index + 5, (byte) (value >>> 16));
237             PlatformDependent.putByte(array, index + 6, (byte) (value >>> 8));
238             PlatformDependent.putByte(array, index + 7, (byte) value);
239         }
240     }
241 
242     static void setZero(byte[] array, int index, int length) {
243         if (length == 0) {
244             return;
245         }
246         PlatformDependent.setMemory(array, index, length, ZERO);
247     }
248 
249     static ByteBuf copy(AbstractByteBuf buf, long addr, int index, int length) {
250         buf.checkIndex(index, length);
251         ByteBuf copy = buf.alloc().directBuffer(length, buf.maxCapacity());
252         if (length != 0) {
253             if (copy.hasMemoryAddress()) {
254                 PlatformDependent.copyMemory(addr, copy.memoryAddress(), length);
255                 copy.setIndex(0, length);
256             } else {
257                 copy.writeBytes(buf, index, length);
258             }
259         }
260         return copy;
261     }
262 
263     static int setBytes(AbstractByteBuf buf, long addr, int index, InputStream in, int length) throws IOException {
264         buf.checkIndex(index, length);
265         ByteBuf tmpBuf = buf.alloc().heapBuffer(length);
266         try {
267             byte[] tmp = tmpBuf.array();
268             int offset = tmpBuf.arrayOffset();
269             int readBytes = in.read(tmp, offset, length);
270             if (readBytes > 0) {
271                 PlatformDependent.copyMemory(tmp, offset, addr, readBytes);
272             }
273             return readBytes;
274         } finally {
275             tmpBuf.release();
276         }
277     }
278 
279     static void getBytes(AbstractByteBuf buf, long addr, int index, ByteBuf dst, int dstIndex, int length) {
280         buf.checkIndex(index, length);
281         checkNotNull(dst, "dst");
282         if (isOutOfBounds(dstIndex, length, dst.capacity())) {
283             throw new IndexOutOfBoundsException("dstIndex: " + dstIndex);
284         }
285 
286         if (dst.hasMemoryAddress()) {
287             PlatformDependent.copyMemory(addr, dst.memoryAddress() + dstIndex, length);
288         } else if (dst.hasArray()) {
289             PlatformDependent.copyMemory(addr, dst.array(), dst.arrayOffset() + dstIndex, length);
290         } else {
291             dst.setBytes(dstIndex, buf, index, length);
292         }
293     }
294 
295     static void getBytes(AbstractByteBuf buf, long addr, int index, byte[] dst, int dstIndex, int length) {
296         buf.checkIndex(index, length);
297         checkNotNull(dst, "dst");
298         if (isOutOfBounds(dstIndex, length, dst.length)) {
299             throw new IndexOutOfBoundsException("dstIndex: " + dstIndex);
300         }
301         if (length != 0) {
302             PlatformDependent.copyMemory(addr, dst, dstIndex, length);
303         }
304     }
305 
306     static void getBytes(AbstractByteBuf buf, long addr, int index, ByteBuffer dst) {
307         buf.checkIndex(index, dst.remaining());
308         if (dst.remaining() == 0) {
309             return;
310         }
311 
312         if (dst.isDirect()) {
313             if (dst.isReadOnly()) {
314                 // We need to check if dst is ready-only so we not write something in it by using Unsafe.
315                 throw new ReadOnlyBufferException();
316             }
317             // Copy to direct memory
318             long dstAddress = PlatformDependent.directBufferAddress(dst);
319             PlatformDependent.copyMemory(addr, dstAddress + dst.position(), dst.remaining());
320             dst.position(dst.position() + dst.remaining());
321         } else if (dst.hasArray()) {
322             // Copy to array
323             PlatformDependent.copyMemory(addr, dst.array(), dst.arrayOffset() + dst.position(), dst.remaining());
324             dst.position(dst.position() + dst.remaining());
325         } else  {
326             dst.put(buf.nioBuffer());
327         }
328     }
329 
330     static void setBytes(AbstractByteBuf buf, long addr, int index, ByteBuf src, int srcIndex, int length) {
331         buf.checkIndex(index, length);
332         checkNotNull(src, "src");
333         if (isOutOfBounds(srcIndex, length, src.capacity())) {
334             throw new IndexOutOfBoundsException("srcIndex: " + srcIndex);
335         }
336 
337         if (length != 0) {
338             if (src.hasMemoryAddress()) {
339                 PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, addr, length);
340             } else if (src.hasArray()) {
341                 PlatformDependent.copyMemory(src.array(), src.arrayOffset() + srcIndex, addr, length);
342             } else {
343                 src.getBytes(srcIndex, buf, index, length);
344             }
345         }
346     }
347 
348     static void setBytes(AbstractByteBuf buf, long addr, int index, byte[] src, int srcIndex, int length) {
349         buf.checkIndex(index, length);
350         if (length != 0) {
351             PlatformDependent.copyMemory(src, srcIndex, addr, length);
352         }
353     }
354 
355     static void setBytes(AbstractByteBuf buf, long addr, int index, ByteBuffer src) {
356         buf.checkIndex(index, src.remaining());
357 
358         int length = src.remaining();
359         if (length == 0) {
360             return;
361         }
362 
363         if (src.isDirect()) {
364             // Copy from direct memory
365             long srcAddress = PlatformDependent.directBufferAddress(src);
366             PlatformDependent.copyMemory(srcAddress + src.position(), addr, src.remaining());
367             src.position(src.position() + length);
368         } else if (src.hasArray()) {
369             // Copy from array
370             PlatformDependent.copyMemory(src.array(), src.arrayOffset() + src.position(), addr, length);
371             src.position(src.position() + length);
372         } else {
373             ByteBuf tmpBuf = buf.alloc().heapBuffer(length);
374             try {
375                 byte[] tmp = tmpBuf.array();
376                 src.get(tmp, tmpBuf.arrayOffset(), length); // moves the src position too
377                 PlatformDependent.copyMemory(tmp, tmpBuf.arrayOffset(), addr, length);
378             } finally {
379                 tmpBuf.release();
380             }
381         }
382     }
383 
384     static void getBytes(AbstractByteBuf buf, long addr, int index, OutputStream out, int length) throws IOException {
385         buf.checkIndex(index, length);
386         if (length != 0) {
387             ByteBuf tmpBuf = buf.alloc().heapBuffer(length);
388             try {
389                 byte[] tmp = tmpBuf.array();
390                 int offset = tmpBuf.arrayOffset();
391                 PlatformDependent.copyMemory(addr, tmp, offset, length);
392                 out.write(tmp, offset, length);
393             } finally {
394                 tmpBuf.release();
395             }
396         }
397     }
398 
399     static void setZero(long addr, int length) {
400         if (length == 0) {
401             return;
402         }
403 
404         PlatformDependent.setMemory(addr, length, ZERO);
405     }
406 
407     static UnpooledUnsafeDirectByteBuf newUnsafeDirectByteBuf(
408             ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
409         if (PlatformDependent.useDirectBufferNoCleaner()) {
410             return new UnpooledUnsafeNoCleanerDirectByteBuf(alloc, initialCapacity, maxCapacity);
411         }
412         return new UnpooledUnsafeDirectByteBuf(alloc, initialCapacity, maxCapacity);
413     }
414 
415     private UnsafeByteBufUtil() { }
416 }