| /*- |
| * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved. |
| * |
| * This file was distributed by Oracle as part of a version of Oracle Berkeley |
| * DB Java Edition made available at: |
| * |
| * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html |
| * |
| * Please see the LICENSE file included in the top-level directory of the |
| * appropriate version of Oracle Berkeley DB Java Edition for a copy of the |
| * license and additional information. |
| */ |
| |
| package com.sleepycat.util; |
| |
| /** |
| * Static methods for reading and writing packed integers. |
| * |
| * <p>Most applications should use the classes in the {@link |
| * com.sleepycat.bind.tuple} package rather than using this class directly.</p> |
| * |
| * @see <a href="../bind/tuple/package-summary.html#integerFormats">Integer Formats</a> |
| */ |
| public class PackedInteger { |
| |
| /** |
| * The maximum number of bytes needed to store an int value (5). |
| */ |
| public static final int MAX_LENGTH = 5; |
| |
| /** |
| * The maximum number of bytes needed to store a long value (9). |
| */ |
| public static final int MAX_LONG_LENGTH = 9; |
| |
| /** |
| * Reads a packed integer at the given buffer offset and returns it. |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the integer that was read. |
| */ |
| public static int readInt(byte[] buf, int off) { |
| |
| boolean negative; |
| int byteLen; |
| |
| int b1 = buf[off++]; |
| if (b1 < -119) { |
| negative = true; |
| byteLen = -b1 - 119; |
| } else if (b1 > 119) { |
| negative = false; |
| byteLen = b1 - 119; |
| } else { |
| return b1; |
| } |
| |
| int value = buf[off++] & 0xFF; |
| if (byteLen > 1) { |
| value |= (buf[off++] & 0xFF) << 8; |
| if (byteLen > 2) { |
| value |= (buf[off++] & 0xFF) << 16; |
| if (byteLen > 3) { |
| value |= (buf[off++] & 0xFF) << 24; |
| } |
| } |
| } |
| |
| return negative ? (-value - 119) : (value + 119); |
| } |
| |
| /** |
| * Reads a packed long integer at the given buffer offset and returns it. |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the long integer that was read. |
| */ |
| public static long readLong(byte[] buf, int off) { |
| |
| boolean negative; |
| int byteLen; |
| |
| int b1 = buf[off++]; |
| if (b1 < -119) { |
| negative = true; |
| byteLen = -b1 - 119; |
| } else if (b1 > 119) { |
| negative = false; |
| byteLen = b1 - 119; |
| } else { |
| return b1; |
| } |
| |
| long value = buf[off++] & 0xFFL; |
| if (byteLen > 1) { |
| value |= (buf[off++] & 0xFFL) << 8; |
| if (byteLen > 2) { |
| value |= (buf[off++] & 0xFFL) << 16; |
| if (byteLen > 3) { |
| value |= (buf[off++] & 0xFFL) << 24; |
| if (byteLen > 4) { |
| value |= (buf[off++] & 0xFFL) << 32; |
| if (byteLen > 5) { |
| value |= (buf[off++] & 0xFFL) << 40; |
| if (byteLen > 6) { |
| value |= (buf[off++] & 0xFFL) << 48; |
| if (byteLen > 7) { |
| value |= (buf[off++] & 0xFFL) << 56; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return negative ? (-value - 119) : (value + 119); |
| } |
| |
| /** |
| * Returns the number of bytes that would be read by {@link #readInt}. |
| * |
| * <p>Because the length is stored in the first byte, this method may be |
| * called with only the first byte of the packed integer in the given |
| * buffer. This method only accesses one byte at the given offset.</p> |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the number of bytes that would be read. |
| */ |
| public static int getReadIntLength(byte[] buf, int off) { |
| |
| int b1 = buf[off]; |
| if (b1 < -119) { |
| return -b1 - 119 + 1; |
| } else if (b1 > 119) { |
| return b1 - 119 + 1; |
| } else { |
| return 1; |
| } |
| } |
| |
| /** |
| * Returns the number of bytes that would be read by {@link #readLong}. |
| * |
| * <p>Because the length is stored in the first byte, this method may be |
| * called with only the first byte of the packed integer in the given |
| * buffer. This method only accesses one byte at the given offset.</p> |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the number of bytes that would be read. |
| */ |
| public static int getReadLongLength(byte[] buf, int off) { |
| |
| /* The length is stored in the same way for int and long. */ |
| return getReadIntLength(buf, off); |
| } |
| |
| /** |
| * Writes a packed integer starting at the given buffer offset and returns |
| * the next offset to be written. |
| * |
| * @param buf the buffer to write to. |
| * |
| * @param offset the offset in the buffer at which to start writing. |
| * |
| * @param value the integer to be written. |
| * |
| * @return the offset past the bytes written. |
| */ |
| public static int writeInt(byte[] buf, int offset, int value) { |
| |
| int byte1Off = offset; |
| boolean negative; |
| |
| if (value < -119) { |
| negative = true; |
| value = -value - 119; |
| } else if (value > 119) { |
| negative = false; |
| value = value - 119; |
| } else { |
| buf[offset++] = (byte) value; |
| return offset; |
| } |
| offset++; |
| |
| buf[offset++] = (byte) value; |
| if ((value & 0xFFFFFF00) == 0) { |
| buf[byte1Off] = negative ? (byte) -120 : (byte) 120; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 8); |
| if ((value & 0xFFFF0000) == 0) { |
| buf[byte1Off] = negative ? (byte) -121 : (byte) 121; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 16); |
| if ((value & 0xFF000000) == 0) { |
| buf[byte1Off] = negative ? (byte) -122 : (byte) 122; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 24); |
| buf[byte1Off] = negative ? (byte) -123 : (byte) 123; |
| return offset; |
| } |
| |
| /** |
| * Writes a packed long integer starting at the given buffer offset and |
| * returns the next offset to be written. |
| * |
| * @param buf the buffer to write to. |
| * |
| * @param offset the offset in the buffer at which to start writing. |
| * |
| * @param value the long integer to be written. |
| * |
| * @return the offset past the bytes written. |
| */ |
| public static int writeLong(byte[] buf, int offset, long value) { |
| |
| int byte1Off = offset; |
| boolean negative; |
| |
| if (value < -119) { |
| negative = true; |
| value = -value - 119; |
| } else if (value > 119) { |
| negative = false; |
| value = value - 119; |
| } else { |
| buf[offset++] = (byte) value; |
| return offset; |
| } |
| offset++; |
| |
| buf[offset++] = (byte) value; |
| if ((value & 0xFFFFFFFFFFFFFF00L) == 0) { |
| buf[byte1Off] = negative ? (byte) -120 : (byte) 120; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 8); |
| if ((value & 0xFFFFFFFFFFFF0000L) == 0) { |
| buf[byte1Off] = negative ? (byte) -121 : (byte) 121; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 16); |
| if ((value & 0xFFFFFFFFFF000000L) == 0) { |
| buf[byte1Off] = negative ? (byte) -122 : (byte) 122; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 24); |
| if ((value & 0xFFFFFFFF00000000L) == 0) { |
| buf[byte1Off] = negative ? (byte) -123 : (byte) 123; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 32); |
| if ((value & 0xFFFFFF0000000000L) == 0) { |
| buf[byte1Off] = negative ? (byte) -124 : (byte) 124; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 40); |
| if ((value & 0xFFFF000000000000L) == 0) { |
| buf[byte1Off] = negative ? (byte) -125 : (byte) 125; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 48); |
| if ((value & 0xFF00000000000000L) == 0) { |
| buf[byte1Off] = negative ? (byte) -126 : (byte) 126; |
| return offset; |
| } |
| |
| buf[offset++] = (byte) (value >>> 56); |
| buf[byte1Off] = negative ? (byte) -127 : (byte) 127; |
| return offset; |
| } |
| |
| /** |
| * Returns the number of bytes that would be written by {@link #writeInt}. |
| * |
| * @param value the integer to be written. |
| * |
| * @return the number of bytes that would be used to write the given |
| * integer. |
| */ |
| public static int getWriteIntLength(int value) { |
| |
| if (value < -119) { |
| value = -value - 119; |
| } else if (value > 119) { |
| value = value - 119; |
| } else { |
| return 1; |
| } |
| |
| if ((value & 0xFFFFFF00) == 0) { |
| return 2; |
| } |
| if ((value & 0xFFFF0000) == 0) { |
| return 3; |
| } |
| if ((value & 0xFF000000) == 0) { |
| return 4; |
| } |
| return 5; |
| } |
| |
| /** |
| * Returns the number of bytes that would be written by {@link #writeLong}. |
| * |
| * @param value the long integer to be written. |
| * |
| * @return the number of bytes that would be used to write the given long |
| * integer. |
| */ |
| public static int getWriteLongLength(long value) { |
| |
| if (value < -119) { |
| value = -value - 119; |
| } else if (value > 119) { |
| value = value - 119; |
| } else { |
| return 1; |
| } |
| |
| if ((value & 0xFFFFFFFFFFFFFF00L) == 0) { |
| return 2; |
| } |
| if ((value & 0xFFFFFFFFFFFF0000L) == 0) { |
| return 3; |
| } |
| if ((value & 0xFFFFFFFFFF000000L) == 0) { |
| return 4; |
| } |
| if ((value & 0xFFFFFFFF00000000L) == 0) { |
| return 5; |
| } |
| if ((value & 0xFFFFFF0000000000L) == 0) { |
| return 6; |
| } |
| if ((value & 0xFFFF000000000000L) == 0) { |
| return 7; |
| } |
| if ((value & 0xFF00000000000000L) == 0) { |
| return 8; |
| } |
| return 9; |
| } |
| |
| /** |
| * Reads a sorted packed integer at the given buffer offset and returns it. |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the integer that was read. |
| */ |
| public static int readSortedInt(byte[] buf, int off) { |
| |
| int byteLen; |
| boolean negative; |
| |
| /* The first byte of the buf stores the length of the value part. */ |
| int b1 = buf[off++] & 0xff; |
| /* Adjust the byteLen to the real length of the value part. */ |
| if (b1 < 0x08) { |
| byteLen = 0x08 - b1; |
| negative = true; |
| } else if (b1 > 0xf7) { |
| byteLen = b1 - 0xf7; |
| negative = false; |
| } else { |
| return b1 - 127; |
| } |
| |
| /* |
| * The following bytes on the buf store the value as a big endian |
| * integer. We extract the significant bytes from the buf and put them |
| * into the value in big endian order. |
| */ |
| int value; |
| if (negative) { |
| value = 0xFFFFFFFF; |
| } else { |
| value = 0; |
| } |
| if (byteLen > 3) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 2) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 1) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| value = (value << 8) | (buf[off++] & 0xFF); |
| |
| /* |
| * After get the adjusted value, we have to adjust it back to the |
| * original value. |
| */ |
| if (negative) { |
| value -= 119; |
| } else { |
| value += 121; |
| } |
| return value; |
| } |
| |
| /** |
| * Reads a sorted packed long integer at the given buffer offset and |
| * returns it. |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the long integer that was read. |
| */ |
| public static long readSortedLong(byte[] buf, int off) { |
| |
| int byteLen; |
| boolean negative; |
| |
| /* The first byte of the buf stores the length of the value part. */ |
| int b1 = buf[off++] & 0xff; |
| /* Adjust the byteLen to the real length of the value part. */ |
| if (b1 < 0x08) { |
| byteLen = 0x08 - b1; |
| negative = true; |
| } else if (b1 > 0xf7) { |
| byteLen = b1 - 0xf7; |
| negative = false; |
| } else { |
| return b1 - 127; |
| } |
| |
| /* |
| * The following bytes on the buf store the value as a big endian |
| * integer. We extract the significant bytes from the buf and put them |
| * into the value in big endian order. |
| */ |
| long value; |
| if (negative) { |
| value = 0xFFFFFFFFFFFFFFFFL; |
| } else { |
| value = 0; |
| } |
| if (byteLen > 7) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 6) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 5) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 4) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 3) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 2) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| if (byteLen > 1) { |
| value = (value << 8) | (buf[off++] & 0xFF); |
| } |
| value = (value << 8) | (buf[off++] & 0xFF); |
| |
| /* |
| * After obtaining the adjusted value, we have to adjust it back to the |
| * original value. |
| */ |
| if (negative) { |
| value -= 119; |
| } else { |
| value += 121; |
| } |
| return value; |
| } |
| |
| /** |
| * Returns the number of bytes that would be read by {@link |
| * #readSortedInt}. |
| * |
| * <p>Because the length is stored in the first byte, this method may be |
| * called with only the first byte of the packed integer in the given |
| * buffer. This method only accesses one byte at the given offset.</p> |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the number of bytes that would be read. |
| */ |
| public static int getReadSortedIntLength(byte[] buf, int off) { |
| |
| /* The first byte of the buf stores the length of the value part. */ |
| int b1 = buf[off] & 0xff; |
| if (b1 < 0x08) { |
| return 1 + 0x08 - b1; |
| } |
| if (b1 > 0xf7) { |
| return 1 + b1 - 0xf7; |
| } |
| return 1; |
| } |
| |
| /** |
| * Returns the number of bytes that would be read by {@link |
| * #readSortedLong}. |
| * |
| * <p>Because the length is stored in the first byte, this method may be |
| * called with only the first byte of the packed integer in the given |
| * buffer. This method only accesses one byte at the given offset.</p> |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading. |
| * |
| * @return the number of bytes that would be read. |
| */ |
| public static int getReadSortedLongLength(byte[] buf, int off) { |
| |
| /* The length is stored in the same way for int and long. */ |
| return getReadSortedIntLength(buf, off); |
| } |
| |
| /** |
| * Writes a packed sorted integer starting at the given buffer offset and |
| * returns the next offset to be written. |
| * |
| * @param buf the buffer to write to. |
| * |
| * @param offset the offset in the buffer at which to start writing. |
| * |
| * @param value the integer to be written. |
| * |
| * @return the offset past the bytes written. |
| */ |
| public static int writeSortedInt(byte[] buf, int offset, int value) { |
| |
| /* |
| * Values in the inclusive range [-119,120] are stored in a single |
| * byte. For values outside that range, the first byte stores the |
| * number of additional bytes. The additional bytes store |
| * (value + 119 for negative and value - 121 for positive) as an |
| * unsigned big endian integer. |
| */ |
| int byte1Off = offset; |
| offset++; |
| if (value < -119) { |
| |
| /* |
| * If the value < -119, then first adjust the value by adding 119. |
| * Then the adjusted value is stored as an unsigned big endian |
| * integer. |
| */ |
| value += 119; |
| |
| /* |
| * Store the adjusted value as an unsigned big endian integer. |
| * For an negative integer, from left to right, the first |
| * significant byte is the byte which is not equal to 0xFF. Also |
| * please note that, because the adjusted value is stored in big |
| * endian integer, we extract the significant byte from left to |
| * right. |
| * |
| * In the left to right order, if the first byte of the adjusted |
| * value is a significant byte, it will be stored in the 2nd byte |
| * of the buf. Then we will look at the 2nd byte of the adjusted |
| * value to see if this byte is the significant byte, if yes, this |
| * byte will be stored in the 3rd byte of the buf, and the like. |
| */ |
| if ((value | 0x00FFFFFF) != 0xFFFFFFFF) { |
| buf[offset++] = (byte) (value >> 24); |
| } |
| if ((value | 0x0000FFFF) != 0xFFFFFFFF) { |
| buf[offset++] = (byte) (value >> 16); |
| } |
| if ((value | 0x000000FF) != 0xFFFFFFFF) { |
| buf[offset++] = (byte) (value >> 8); |
| } |
| buf[offset++] = (byte) value; |
| |
| /* |
| * valueLen is the length of the value part stored in buf. Because |
| * the first byte of buf is used to stored the length, we need |
| * to subtract one. |
| */ |
| int valueLen = offset - byte1Off - 1; |
| |
| /* |
| * The first byte stores the number of additional bytes. Here we |
| * store the result of 0x08 - valueLen, rather than directly store |
| * valueLen. The reason is to implement natural sort order for |
| * byte-by-byte comparison. |
| */ |
| buf[byte1Off] = (byte) (0x08 - valueLen); |
| } else if (value > 120) { |
| |
| /* |
| * If the value > 120, then first adjust the value by subtracting |
| * 121. Then the adjusted value is stored as an unsigned big endian |
| * integer. |
| */ |
| value -= 121; |
| |
| /* |
| * Store the adjusted value as an unsigned big endian integer. |
| * For a positive integer, from left to right, the first |
| * significant byte is the byte which is not equal to 0x00. |
| * |
| * In the left to right order, if the first byte of the adjusted |
| * value is a significant byte, it will be stored in the 2nd byte |
| * of the buf. Then we will look at the 2nd byte of the adjusted |
| * value to see if this byte is the significant byte, if yes, this |
| * byte will be stored in the 3rd byte of the buf, and the like. |
| */ |
| if ((value & 0xFF000000) != 0) { |
| buf[offset++] = (byte) (value >> 24); |
| } |
| if ((value & 0xFFFF0000) != 0) { |
| buf[offset++] = (byte) (value >> 16); |
| } |
| if ((value & 0xFFFFFF00) != 0) { |
| buf[offset++] = (byte) (value >> 8); |
| } |
| buf[offset++] = (byte) value; |
| |
| /* |
| * valueLen is the length of the value part stored in buf. Because |
| * the first byte of buf is used to stored the length, we need to |
| * subtract one. |
| */ |
| int valueLen = offset - byte1Off - 1; |
| |
| /* |
| * The first byte stores the number of additional bytes. Here we |
| * store the result of 0xF7 + valueLen, rather than directly store |
| * valueLen. The reason is to implement natural sort order for |
| * byte-by-byte comparison. |
| */ |
| buf[byte1Off] = (byte) (0xF7 + valueLen); |
| } else { |
| |
| /* |
| * If -119 <= value <= 120, only one byte is needed to store the |
| * value. The stored value is the original value plus 127. |
| */ |
| buf[byte1Off] = (byte) (value + 127); |
| } |
| return offset; |
| } |
| |
| /** |
| * Writes a packed sorted long integer starting at the given buffer offset |
| * and returns the next offset to be written. |
| * |
| * @param buf the buffer to write to. |
| * |
| * @param offset the offset in the buffer at which to start writing. |
| * |
| * @param value the long integer to be written. |
| * |
| * @return the offset past the bytes written. |
| */ |
| public static int writeSortedLong(byte[] buf, int offset, long value) { |
| |
| /* |
| * Values in the inclusive range [-119,120] are stored in a single |
| * byte. For values outside that range, the first byte stores the |
| * number of additional bytes. The additional bytes store |
| * (value + 119 for negative and value - 121 for positive) as an |
| * unsigned big endian integer. |
| */ |
| int byte1Off = offset; |
| offset++; |
| if (value < -119) { |
| |
| /* |
| * If the value < -119, then first adjust the value by adding 119. |
| * Then the adjusted value is stored as an unsigned big endian |
| * integer. |
| */ |
| value += 119; |
| |
| /* |
| * Store the adjusted value as an unsigned big endian integer. |
| * For an negative integer, from left to right, the first |
| * significant byte is the byte which is not equal to 0xFF. Also |
| * please note that, because the adjusted value is stored in big |
| * endian integer, we extract the significant byte from left to |
| * right. |
| * |
| * In the left to right order, if the first byte of the adjusted |
| * value is a significant byte, it will be stored in the 2nd byte |
| * of the buf. Then we will look at the 2nd byte of the adjusted |
| * value to see if this byte is the significant byte, if yes, this |
| * byte will be stored in the 3rd byte of the buf, and the like. |
| */ |
| if ((value | 0x00FFFFFFFFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) { |
| buf[offset++] = (byte) (value >> 56); |
| } |
| if ((value | 0x0000FFFFFFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) { |
| buf[offset++] = (byte) (value >> 48); |
| } |
| if ((value | 0x000000FFFFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) { |
| buf[offset++] = (byte) (value >> 40); |
| } |
| if ((value | 0x00000000FFFFFFFFL) != 0xFFFFFFFFFFFFFFFFL) { |
| buf[offset++] = (byte) (value >> 32); |
| } |
| if ((value | 0x0000000000FFFFFFL) != 0xFFFFFFFFFFFFFFFFL) { |
| buf[offset++] = (byte) (value >> 24); |
| } |
| if ((value | 0x000000000000FFFFL) != 0xFFFFFFFFFFFFFFFFL) { |
| buf[offset++] = (byte) (value >> 16); |
| } |
| if ((value | 0x00000000000000FFL) != 0xFFFFFFFFFFFFFFFFL) { |
| buf[offset++] = (byte) (value >> 8); |
| } |
| buf[offset++] = (byte) value; |
| |
| /* |
| * valueLen is the length of the value part stored in buf. Because |
| * the first byte of buf is used to stored the length, so we need |
| * to minus one. |
| */ |
| int valueLen = offset - byte1Off - 1; |
| |
| /* |
| * The first byte stores the number of additional bytes. Here we |
| * store the result of 0x08 - valueLen, rather than directly store |
| * valueLen. The reason is to implement nature sort order for |
| * byte-by-byte comparison. |
| */ |
| buf[byte1Off] = (byte) (0x08 - valueLen); |
| } else if (value > 120) { |
| |
| /* |
| * If the value > 120, then first adjust the value by subtracting |
| * 119. Then the adjusted value is stored as an unsigned big endian |
| * integer. |
| */ |
| value -= 121; |
| |
| /* |
| * Store the adjusted value as an unsigned big endian integer. |
| * For a positive integer, from left to right, the first |
| * significant byte is the byte which is not equal to 0x00. |
| * |
| * In the left to right order, if the first byte of the adjusted |
| * value is a significant byte, it will be stored in the 2nd byte |
| * of the buf. Then we will look at the 2nd byte of the adjusted |
| * value to see if this byte is the significant byte, if yes, this |
| * byte will be stored in the 3rd byte of the buf, and the like. |
| */ |
| if ((value & 0xFF00000000000000L) != 0L) { |
| buf[offset++] = (byte) (value >> 56); |
| } |
| if ((value & 0xFFFF000000000000L) != 0L) { |
| buf[offset++] = (byte) (value >> 48); |
| } |
| if ((value & 0xFFFFFF0000000000L) != 0L) { |
| buf[offset++] = (byte) (value >> 40); |
| } |
| if ((value & 0xFFFFFFFF00000000L) != 0L) { |
| buf[offset++] = (byte) (value >> 32); |
| } |
| if ((value & 0xFFFFFFFFFF000000L) != 0L) { |
| buf[offset++] = (byte) (value >> 24); |
| } |
| if ((value & 0xFFFFFFFFFFFF0000L) != 0L) { |
| buf[offset++] = (byte) (value >> 16); |
| } |
| if ((value & 0xFFFFFFFFFFFFFF00L) != 0L) { |
| buf[offset++] = (byte) (value >> 8); |
| } |
| buf[offset++] = (byte) value; |
| |
| /* |
| * valueLen is the length of the value part stored in buf. Because |
| * the first byte of buf is used to stored the length, so we need |
| * to minus one. |
| */ |
| int valueLen = offset - byte1Off - 1; |
| |
| /* |
| * The first byte stores the number of additional bytes. Here we |
| * store the result of 0xF7 + valueLen, rather than directly store |
| * valueLen. The reason is to implement nature sort order for |
| * byte-by-byte comparison. |
| */ |
| buf[byte1Off] = (byte) (0xF7 + valueLen); |
| } else { |
| |
| /* |
| * If -119 <= value <= 120, only one byte is needed to store the |
| * value. The stored value is the original value adds 127. |
| */ |
| buf[byte1Off] = (byte) (value + 127); |
| } |
| return offset; |
| } |
| |
| /** |
| * Returns the number of bytes that would be written by {@link |
| * #writeSortedInt}. |
| * |
| * @param value the integer to be written. |
| * |
| * @return the number of bytes that would be used to write the given |
| * integer. |
| */ |
| public static int getWriteSortedIntLength(int value) { |
| |
| if (value < -119) { |
| /* Adjust the value. */ |
| value += 119; |
| |
| /* |
| * Find the left most significant byte of the adjusted value, and |
| * return the length accordingly. |
| */ |
| if ((value | 0x000000FF) == 0xFFFFFFFF) { |
| return 2; |
| } |
| if ((value | 0x0000FFFF) == 0xFFFFFFFF) { |
| return 3; |
| } |
| if ((value | 0x00FFFFFF) == 0xFFFFFFFF) { |
| return 4; |
| } |
| } else if (value > 120) { |
| /* Adjust the value. */ |
| value -= 121; |
| |
| /* |
| * Find the left most significant byte of the adjusted value, and |
| * return the length accordingly. |
| */ |
| if ((value & 0xFFFFFF00) == 0) { |
| return 2; |
| } |
| if ((value & 0xFFFF0000) == 0) { |
| return 3; |
| } |
| if ((value & 0xFF000000) == 0) { |
| return 4; |
| } |
| } else { |
| |
| /* |
| * If -119 <= value <= 120, only one byte is needed to store the |
| * value. |
| */ |
| return 1; |
| } |
| return 5; |
| } |
| |
| /** |
| * Returns the number of bytes that would be written by {@link |
| * #writeSortedLong}. |
| * |
| * @param value the long integer to be written. |
| * |
| * @return the number of bytes that would be used to write the given long |
| * integer. |
| */ |
| public static int getWriteSortedLongLength(long value) { |
| |
| if (value < -119) { |
| /* Adjust the value. */ |
| value += 119; |
| |
| /* |
| * Find the left most significant byte of the adjusted value, and |
| * return the length accordingly. |
| */ |
| if ((value | 0x00000000000000FFL) == 0xFFFFFFFFFFFFFFFFL) { |
| return 2; |
| } |
| if ((value | 0x000000000000FFFFL) == 0xFFFFFFFFFFFFFFFFL) { |
| return 3; |
| } |
| if ((value | 0x0000000000FFFFFFL) == 0xFFFFFFFFFFFFFFFFL) { |
| return 4; |
| } |
| if ((value | 0x00000000FFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) { |
| return 5; |
| } |
| if ((value | 0x000000FFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) { |
| return 6; |
| } |
| if ((value | 0x0000FFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) { |
| return 7; |
| } |
| if ((value | 0x00FFFFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL) { |
| return 8; |
| } |
| } else if (value > 120) { |
| /* Adjust the value. */ |
| value -= 121; |
| |
| /* |
| * Find the left most significant byte of the adjusted value, and |
| * return the length accordingly. |
| */ |
| if ((value & 0xFFFFFFFFFFFFFF00L) == 0L) { |
| return 2; |
| } |
| if ((value & 0xFFFFFFFFFFFF0000L) == 0L) { |
| return 3; |
| } |
| if ((value & 0xFFFFFFFFFF000000L) == 0L) { |
| return 4; |
| } |
| if ((value & 0xFFFFFFFF00000000L) == 0L) { |
| return 5; |
| } |
| if ((value & 0xFFFFFF0000000000L) == 0L) { |
| return 6; |
| } |
| if ((value & 0xFFFF000000000000L) == 0L) { |
| return 7; |
| } |
| if ((value & 0xFF00000000000000L) == 0L) { |
| return 8; |
| } |
| } else { |
| |
| /* |
| * If -119 <= value <= 120, only one byte is needed to store the |
| * value. |
| */ |
| return 1; |
| } |
| return 9; |
| } |
| |
| /* <!-- begin JE only --> */ |
| |
| /** |
| * @hidden |
| * Reads a reverse-packed integer ending at the given buffer offset and |
| * returns it. |
| * |
| * To get the length of a reverse-packed integer before reading, call |
| * {@link #getReadIntLength} passing the offset to the last byte. |
| * |
| * @param buf the buffer to read from. |
| * |
| * @param off the offset in the buffer at which to start reading, which is |
| * the index of the last byte of the integer in the buffer. |
| * |
| * @return the integer that was read. |
| */ |
| public static int readReverseInt(byte[] buf, int off) { |
| |
| boolean negative; |
| int byteLen; |
| |
| int b1 = buf[off]; |
| if (b1 < -119) { |
| negative = true; |
| byteLen = -b1 - 119; |
| } else if (b1 > 119) { |
| negative = false; |
| byteLen = b1 - 119; |
| } else { |
| return b1; |
| } |
| |
| int value = buf[--off] & 0xFF; |
| if (byteLen > 1) { |
| value |= (buf[--off] & 0xFF) << 8; |
| if (byteLen > 2) { |
| value |= (buf[--off] & 0xFF) << 16; |
| if (byteLen > 3) { |
| value |= (buf[--off] & 0xFF) << 24; |
| } |
| } |
| } |
| |
| return negative ? (-value - 119) : (value + 119); |
| } |
| |
| /** |
| * @hidden |
| * Writes a reverse-packed integer starting at the given buffer offset and |
| * returns the next offset to be written. |
| * |
| * To get the length of a reverse-packed integer before writing, call |
| * {@link #getWriteIntLength}. |
| * |
| * @param buf the buffer to write to. |
| * |
| * @param off the offset in the buffer at which to start writing, which |
| * will be the index of the first byte of the integer in the buffer. |
| * |
| * @param value the integer to be written. |
| * |
| * @return the offset past the bytes written. |
| */ |
| public static int writeReverseInt(byte[] buf, int off, int value) { |
| |
| final boolean negative; |
| |
| final int nextOff = off + getWriteIntLength(value); |
| if (value < -119) { |
| negative = true; |
| value = -value - 119; |
| } else if (value > 119) { |
| negative = false; |
| value = value - 119; |
| } else { |
| buf[off] = (byte) value; |
| return off + 1; |
| } |
| final int byte1Off = nextOff - 1; |
| off = byte1Off; |
| |
| buf[--off] = (byte) value; |
| if ((value & 0xFFFFFF00) == 0) { |
| buf[byte1Off] = negative ? (byte) -120 : (byte) 120; |
| return nextOff; |
| } |
| |
| buf[--off] = (byte) (value >>> 8); |
| if ((value & 0xFFFF0000) == 0) { |
| buf[byte1Off] = negative ? (byte) -121 : (byte) 121; |
| return nextOff; |
| } |
| |
| buf[--off] = (byte) (value >>> 16); |
| if ((value & 0xFF000000) == 0) { |
| buf[byte1Off] = negative ? (byte) -122 : (byte) 122; |
| return nextOff; |
| } |
| |
| buf[--off] = (byte) (value >>> 24); |
| buf[byte1Off] = negative ? (byte) -123 : (byte) 123; |
| return nextOff; |
| } |
| |
| /* <!-- end JE only --> */ |
| } |