|
11 | 11 | package org.eclipse.rdf4j.sail.lmdb; |
12 | 12 |
|
13 | 13 | import java.nio.ByteBuffer; |
| 14 | +import java.nio.ByteOrder; |
14 | 15 |
|
15 | 16 | /** |
16 | 17 | * Encodes and decodes unsigned values using variable-length encoding. |
@@ -89,26 +90,54 @@ private Varint() { |
89 | 90 | * @param value value to encode |
90 | 91 | */ |
91 | 92 | public static void writeUnsigned(final ByteBuffer bb, final long value) { |
| 93 | + if (bb.order() == ByteOrder.BIG_ENDIAN) { |
| 94 | + writeUnsignedBigEndian(bb, value); |
| 95 | + } else { |
| 96 | + writeUnsignedLittleEndian(bb, value); |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + private static void writeUnsignedBigEndian(final ByteBuffer bb, final long value) { |
| 101 | + if (value <= 240) { |
| 102 | + bb.put((byte) value); |
| 103 | + } else if (value <= 2287) { |
| 104 | + int v = (int) (value - 240); |
| 105 | + bb.putShort((short) (((v >>> 8) + 241) << 8 | (v & 0xFF))); |
| 106 | + } else if (value <= 67823) { |
| 107 | + int v = (int) (value - 2288); |
| 108 | + bb.put((byte) 249); |
| 109 | + bb.putShort((short) ((v >>> 8) << 8 | (v & 0xFF))); |
| 110 | + } else { |
| 111 | + int bytes = descriptor(value) + 1; |
| 112 | + writeSignificantBitsBigEndian(bb, value, bytes); |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + private static void writeUnsignedLittleEndian(final ByteBuffer bb, final long value) { |
92 | 117 | if (value <= 240) { |
93 | 118 | bb.put((byte) value); |
94 | 119 | } else if (value <= 2287) { |
95 | | - bb.put((byte) ((value - 240) / 256 + 241)); |
96 | | - bb.put((byte) ((value - 240) % 256)); |
| 120 | + int v = (int) (value - 240); |
| 121 | + bb.putShort((short) ((v & 0xFF) << 8 | ((v >>> 8) + 241))); |
97 | 122 | } else if (value <= 67823) { |
| 123 | + int v = (int) (value - 2288); |
98 | 124 | bb.put((byte) 249); |
99 | | - bb.put((byte) ((value - 2288) / 256)); |
100 | | - bb.put((byte) ((value - 2288) % 256)); |
| 125 | + bb.putShort((short) ((v & 0xFF) << 8 | (v >>> 8))); |
101 | 126 | } else { |
102 | 127 | int bytes = descriptor(value) + 1; |
103 | | - bb.put((byte) (250 + (bytes - 3))); |
104 | | - writeSignificantBits(bb, value, bytes); |
| 128 | + bb.order(ByteOrder.BIG_ENDIAN); |
| 129 | + try { |
| 130 | + writeSignificantBitsBigEndian(bb, value, bytes); |
| 131 | + } finally { |
| 132 | + bb.order(ByteOrder.LITTLE_ENDIAN); |
| 133 | + } |
105 | 134 | } |
106 | 135 | } |
107 | 136 |
|
108 | 137 | /** |
109 | 138 | * Calculates required length in bytes to encode the given long value using variable-length encoding. |
110 | 139 | * |
111 | | - * @param value the value value |
| 140 | + * @param value the value |
112 | 141 | * @return length in bytes |
113 | 142 | */ |
114 | 143 | public static int calcLengthUnsigned(long value) { |
@@ -245,22 +274,8 @@ public static long readListElementUnsigned(ByteBuffer bb, int index) { |
245 | 274 | * @param values array with values to write |
246 | 275 | */ |
247 | 276 | public static void writeListUnsigned(final ByteBuffer bb, final long[] values) { |
248 | | - for (int i = 0; i < values.length; i++) { |
249 | | - final long value = values[i]; |
250 | | - if (value <= 240) { |
251 | | - bb.put((byte) value); |
252 | | - } else if (value <= 2287) { |
253 | | - bb.put((byte) ((value - 240) / 256 + 241)); |
254 | | - bb.put((byte) ((value - 240) % 256)); |
255 | | - } else if (value <= 67823) { |
256 | | - bb.put((byte) 249); |
257 | | - bb.put((byte) ((value - 2288) / 256)); |
258 | | - bb.put((byte) ((value - 2288) % 256)); |
259 | | - } else { |
260 | | - int bytes = descriptor(value) + 1; |
261 | | - bb.put((byte) (250 + (bytes - 3))); |
262 | | - writeSignificantBits(bb, value, bytes); |
263 | | - } |
| 277 | + for (final long value : values) { |
| 278 | + writeUnsigned(bb, value); |
264 | 279 | } |
265 | 280 | } |
266 | 281 |
|
@@ -296,9 +311,35 @@ public static void readListUnsigned(ByteBuffer bb, int[] indexMap, long[] values |
296 | 311 | * @param value value to encode |
297 | 312 | * @param bytes number of significant bytes |
298 | 313 | */ |
299 | | - private static void writeSignificantBits(ByteBuffer bb, long value, int bytes) { |
300 | | - while (bytes-- > 0) { |
301 | | - bb.put((byte) (0xFF & (value >>> (bytes * 8)))); |
| 314 | + private static void writeSignificantBitsBigEndian(ByteBuffer bb, long value, int bytes) { |
| 315 | + switch (bytes) { |
| 316 | + case 3: |
| 317 | + bb.putInt((int) ((((250 << 8) | ((value >>> 16) & 0xFF)) << 16) | (value & 0xFFFF))); |
| 318 | + break; |
| 319 | + case 4: |
| 320 | + bb.put((byte) 251); // 250 + (4 - 3) |
| 321 | + bb.putInt((int) (value & 0xFFFFFFFFL)); |
| 322 | + break; |
| 323 | + case 5: |
| 324 | + bb.putShort((short) ((252 << 8) | ((value >>> 32) & 0xFF))); |
| 325 | + bb.putInt((int) (value & 0xFFFFFFFFL)); |
| 326 | + break; |
| 327 | + case 6: |
| 328 | + bb.put((byte) 253); |
| 329 | + bb.putShort((short) ((value >>> 32) & 0xFFFF)); |
| 330 | + bb.putInt((int) (value & 0xFFFFFFFFL)); |
| 331 | + break; |
| 332 | + case 7: |
| 333 | + bb.putLong(((254 << 8 | ((value >>> 48) & 0xFF)) << 48) | (((value >>> 32) & 0xFFFF) << 32) |
| 334 | + | (value & 0xFFFFFFFFL)); |
| 335 | + break; |
| 336 | + case 8: |
| 337 | + bb.put((byte) 255); |
| 338 | + bb.putLong(value); |
| 339 | + break; |
| 340 | + default: |
| 341 | + throw new IllegalArgumentException( |
| 342 | + "Invalid number of bytes " + bytes + " for value " + value + " (must be 3..8)"); |
302 | 343 | } |
303 | 344 | } |
304 | 345 |
|
|
0 commit comments