001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2000,2008 Oracle. All rights reserved.
005: *
006: * $Id: PackedInteger.java,v 1.4.2.2 2008/01/07 15:14:21 cwl Exp $
007: */
008:
009: package com.sleepycat.util;
010:
011: /**
012: * Static methods for reading and writing packed integers.
013: *
014: * <p>Note that packed integers are not sorted naturally for a byte-by-byte
015: * comparison because they have a preceding length and are little endian;
016: * therefore, they are typically not used for keys.</p>
017: *
018: * <p>Values in the inclusive range [-119,119] are stored in a single byte.
019: * For values outside that range, the first byte stores the sign and the number
020: * of additional bytes. The additional bytes store (abs(value) - 119) as an
021: * unsigned little endian integer.</p>
022: *
023: * <p>To read and write packed integer values, call {@link #readInt} and {@link
024: * #writeInt}. To get the length of a packed integer without reading it, call
025: * {@link #getReadIntLength}. To get the length of an unpacked integer without
026: * writing it, call {@link #getWriteIntLength}.</p>
027: *
028: * <p>Note that the packed integer format is designed to accomodate long
029: * integers using up to 9 bytes of storage. Currently only int values are
030: * implemented, but the same format may be used in future for long values.</p>
031: */
032: public class PackedInteger {
033:
034: /**
035: * The maximum number of bytes needed to store an int value (5). The fifth
036: * byte is only needed for values greater than (Integer.MAX_VALUE - 119) or
037: * less than (Integer.MIN_VALUE + 119).
038: */
039: public static final int MAX_LENGTH = 5;
040:
041: /**
042: * Reads a packed integer at the given buffer offset and returns it.
043: *
044: * @param buf the buffer to read from.
045: *
046: * @param off the offset in the buffer at which to start reading.
047: *
048: * @return the integer that was read.
049: */
050: public static int readInt(byte[] buf, int off) {
051:
052: boolean negative;
053: int byteLen;
054:
055: int b1 = buf[off++];
056: if (b1 < -119) {
057: negative = true;
058: byteLen = -b1 - 119;
059: } else if (b1 > 119) {
060: negative = false;
061: byteLen = b1 - 119;
062: } else {
063: return b1;
064: }
065:
066: int value = buf[off++] & 0xFF;
067: if (byteLen > 1) {
068: value |= (buf[off++] & 0xFF) << 8;
069: if (byteLen > 2) {
070: value |= (buf[off++] & 0xFF) << 16;
071: if (byteLen > 3) {
072: value |= (buf[off++] & 0xFF) << 24;
073: }
074: }
075: }
076:
077: return negative ? (-value - 119) : (value + 119);
078: }
079:
080: /**
081: * Returns the number of bytes that would be read by {@link #readInt}.
082: *
083: * @param buf the buffer to read from.
084: *
085: * @param off the offset in the buffer at which to start reading.
086: *
087: * @return the number of bytes that would be read.
088: */
089: public static int getReadIntLength(byte[] buf, int off) {
090:
091: int b1 = buf[off];
092: if (b1 < -119) {
093: return -b1 - 119 + 1;
094: } else if (b1 > 119) {
095: return b1 - 119 + 1;
096: } else {
097: return 1;
098: }
099: }
100:
101: /**
102: * Writes a packed integer starting at the given buffer offset and returns
103: * the next offset to be written.
104: *
105: * @param buf the buffer to write to.
106: *
107: * @param offset the offset in the buffer at which to start writing.
108: *
109: * @param value the integer to be written.
110: *
111: * @return the offset past the bytes written.
112: */
113: public static int writeInt(byte[] buf, int offset, int value) {
114:
115: int byte1Off = offset;
116: boolean negative;
117:
118: if (value < -119) {
119: negative = true;
120: value = -value - 119;
121: } else if (value > 119) {
122: negative = false;
123: value = value - 119;
124: } else {
125: buf[offset++] = (byte) value;
126: return offset;
127: }
128: offset++;
129:
130: buf[offset++] = (byte) value;
131: if ((value & 0xFFFFFF00) == 0) {
132: buf[byte1Off] = negative ? (byte) -120 : (byte) 120;
133: return offset;
134: }
135:
136: buf[offset++] = (byte) (value >>> 8);
137: if ((value & 0xFFFF0000) == 0) {
138: buf[byte1Off] = negative ? (byte) -121 : (byte) 121;
139: return offset;
140: }
141:
142: buf[offset++] = (byte) (value >>> 16);
143: if ((value & 0xFF000000) == 0) {
144: buf[byte1Off] = negative ? (byte) -122 : (byte) 122;
145: return offset;
146: }
147:
148: buf[offset++] = (byte) (value >>> 24);
149: buf[byte1Off] = negative ? (byte) -123 : (byte) 123;
150: return offset;
151: }
152:
153: /**
154: * Returns the number of bytes that would be written by {@link #writeInt}.
155: *
156: * @param value the integer to be written.
157: *
158: * @return the number of bytes that would be used to write the given
159: * integer.
160: */
161: public static int getWriteIntLength(int value) {
162:
163: if (value < -119) {
164: value = -value - 119;
165: } else if (value > 119) {
166: value = value - 119;
167: } else {
168: return 1;
169: }
170:
171: if ((value & 0xFFFFFF00) == 0) {
172: return 2;
173: }
174: if ((value & 0xFFFF0000) == 0) {
175: return 3;
176: }
177: if ((value & 0xFF000000) == 0) {
178: return 4;
179: }
180: return 5;
181: }
182: }
|