1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.hadoop.hbase.util;
19
20 import static org.apache.hadoop.hbase.util.Order.ASCENDING;
21 import static org.apache.hadoop.hbase.util.Order.DESCENDING;
22
23 import java.math.BigDecimal;
24 import java.math.BigInteger;
25 import java.math.MathContext;
26 import java.math.RoundingMode;
27 import java.nio.charset.Charset;
28
29 import org.apache.hadoop.hbase.classification.InterfaceAudience;
30 import org.apache.hadoop.hbase.classification.InterfaceStability;
31
32 import com.google.common.annotations.VisibleForTesting;
33
34 /**
35 * Utility class that handles ordered byte arrays. That is, unlike
36 * {@link Bytes}, these methods produce byte arrays which maintain the sort
37 * order of the original values.
38 * <h3>Encoding Format summary</h3>
39 * <p>
40 * Each value is encoded as one or more bytes. The first byte of the encoding,
41 * its meaning, and a terse description of the bytes that follow is given by
42 * the following table:
43 * </p>
44 * <table summary="Encodings">
45 * <tr><th>Content Type</th><th>Encoding</th></tr>
46 * <tr><td>NULL</td><td>0x05</td></tr>
47 * <tr><td>negative infinity</td><td>0x07</td></tr>
48 * <tr><td>negative large</td><td>0x08, ~E, ~M</td></tr>
49 * <tr><td>negative medium</td><td>0x13-E, ~M</td></tr>
50 * <tr><td>negative small</td><td>0x14, -E, ~M</td></tr>
51 * <tr><td>zero</td><td>0x15</td></tr>
52 * <tr><td>positive small</td><td>0x16, ~-E, M</td></tr>
53 * <tr><td>positive medium</td><td>0x17+E, M</td></tr>
54 * <tr><td>positive large</td><td>0x22, E, M</td></tr>
55 * <tr><td>positive infinity</td><td>0x23</td></tr>
56 * <tr><td>NaN</td><td>0x25</td></tr>
57 * <tr><td>fixed-length 32-bit integer</td><td>0x27, I</td></tr>
58 * <tr><td>fixed-length 64-bit integer</td><td>0x28, I</td></tr>
59 * <tr><td>fixed-length 8-bit integer</td><td>0x29</td></tr>
60 * <tr><td>fixed-length 16-bit integer</td><td>0x2a</td></tr>
61 * <tr><td>fixed-length 32-bit float</td><td>0x30, F</td></tr>
62 * <tr><td>fixed-length 64-bit float</td><td>0x31, F</td></tr>
63 * <tr><td>TEXT</td><td>0x33, T</td></tr>
64 * <tr><td>variable length BLOB</td><td>0x35, B</td></tr>
65 * <tr><td>byte-for-byte BLOB</td><td>0x36, X</td></tr>
66 * </table>
67 *
68 * <h3>Null Encoding</h3>
69 * <p>
70 * Each value that is a NULL encodes as a single byte of 0x05. Since every
71 * other value encoding begins with a byte greater than 0x05, this forces NULL
72 * values to sort first.
73 * </p>
74 * <h3>Text Encoding</h3>
75 * <p>
76 * Each text value begins with a single byte of 0x33 and ends with a single
77 * byte of 0x00. There are zero or more intervening bytes that encode the text
78 * value. The intervening bytes are chosen so that the encoding will sort in
79 * the desired collating order. The intervening bytes may not contain a 0x00
80 * character; the only 0x00 byte allowed in a text encoding is the final byte.
81 * </p>
82 * <p>
83 * The text encoding ends in 0x00 in order to ensure that when there are two
84 * strings where one is a prefix of the other that the shorter string will
85 * sort first.
86 * </p>
87 * <h3>Binary Encoding</h3>
88 * <p>
89 * There are two encoding strategies for binary fields, referred to as
90 * "BlobVar" and "BlobCopy". BlobVar is less efficient in both space and
91 * encoding time. It has no limitations on the range of encoded values.
92 * BlobCopy is a byte-for-byte copy of the input data followed by a
93 * termination byte. It is extremely fast to encode and decode. It carries the
94 * restriction of not allowing a 0x00 value in the input byte[] as this value
95 * is used as the termination byte.
96 * </p>
97 * <h4>BlobVar</h4>
98 * <p>
99 * "BlobVar" encodes the input byte[] in a manner similar to a variable length
100 * integer encoding. As with the other {@code OrderedBytes} encodings,
101 * the first encoded byte is used to indicate what kind of value follows. This
102 * header byte is 0x37 for BlobVar encoded values. As with the traditional
103 * varint encoding, the most significant bit of each subsequent encoded
104 * {@code byte} is used as a continuation marker. The 7 remaining bits
105 * contain the 7 most significant bits of the first unencoded byte. The next
106 * encoded byte starts with a continuation marker in the MSB. The least
107 * significant bit from the first unencoded byte follows, and the remaining 6
108 * bits contain the 6 MSBs of the second unencoded byte. The encoding
109 * continues, encoding 7 bytes on to 8 encoded bytes. The MSB of the final
110 * encoded byte contains a termination marker rather than a continuation
111 * marker, and any remaining bits from the final input byte. Any trailing bits
112 * in the final encoded byte are zeros.
113 * </p>
114 * <h4>BlobCopy</h4>
115 * <p>
116 * "BlobCopy" is a simple byte-for-byte copy of the input data. It uses 0x38
117 * as the header byte, and is terminated by 0x00 in the DESCENDING case. This
118 * alternative encoding is faster and more space-efficient, but it cannot
119 * accept values containing a 0x00 byte in DESCENDING order.
120 * </p>
121 * <h3>Variable-length Numeric Encoding</h3>
122 * <p>
123 * Numeric values must be coded so as to sort in numeric order. We assume that
124 * numeric values can be both integer and floating point values. Clients must
125 * be careful to use inspection methods for encoded values (such as
126 * {@link #isNumericInfinite(PositionedByteRange)} and
127 * {@link #isNumericNaN(PositionedByteRange)} to protect against decoding
128 * values into object which do not support these numeric concepts (such as
129 * {@link Long} and {@link BigDecimal}).
130 * </p>
131 * <p>
132 * Simplest cases first: If the numeric value is a NaN, then the encoding is a
133 * single byte of 0x25. This causes NaN values to sort after every other
134 * numeric value.
135 * </p>
136 * <p>
137 * If the numeric value is a negative infinity then the encoding is a single
138 * byte of 0x07. Since every other numeric value except NaN has a larger
139 * initial byte, this encoding ensures that negative infinity will sort prior
140 * to every other numeric value other than NaN.
141 * </p>
142 * <p>
143 * If the numeric value is a positive infinity then the encoding is a single
144 * byte of 0x23. Every other numeric value encoding begins with a smaller
145 * byte, ensuring that positive infinity always sorts last among numeric
146 * values. 0x23 is also smaller than 0x33, the initial byte of a text value,
147 * ensuring that every numeric value sorts before every text value.
148 * </p>
149 * <p>
150 * If the numeric value is exactly zero then it is encoded as a single byte of
151 * 0x15. Finite negative values will have initial bytes of 0x08 through 0x14
152 * and finite positive values will have initial bytes of 0x16 through 0x22.
153 * </p>
154 * <p>
155 * For all numeric values, we compute a mantissa M and an exponent E. The
156 * mantissa is a base-100 representation of the value. The exponent E
157 * determines where to put the decimal point.
158 * </p>
159 * <p>
160 * Each centimal digit of the mantissa is stored in a byte. If the value of
161 * the centimal digit is X (hence X≥0 and X≤99) then the byte value will
162 * be 2*X+1 for every byte of the mantissa, except for the last byte which
163 * will be 2*X+0. The mantissa must be the minimum number of bytes necessary
164 * to represent the value; trailing X==0 digits are omitted. This means that
165 * the mantissa will never contain a byte with the value 0x00.
166 * </p>
167 * <p>
168 * If we assume all digits of the mantissa occur to the right of the decimal
169 * point, then the exponent E is the power of one hundred by which one must
170 * multiply the mantissa to recover the original value.
171 * </p>
172 * <p>
173 * Values are classified as large, medium, or small according to the value of
174 * E. If E is 11 or more, the value is large. For E between 0 and 10, the
175 * value is medium. For E less than zero, the value is small.
176 * </p>
177 * <p>
178 * Large positive values are encoded as a single byte 0x22 followed by E as a
179 * varint and then M. Medium positive values are a single byte of 0x17+E
180 * followed by M. Small positive values are encoded as a single byte 0x16
181 * followed by the ones-complement of the varint for -E followed by M.
182 * </p>
183 * <p>
184 * Small negative values are encoded as a single byte 0x14 followed by -E as a
185 * varint and then the ones-complement of M. Medium negative values are
186 * encoded as a byte 0x13-E followed by the ones-complement of M. Large
187 * negative values consist of the single byte 0x08 followed by the
188 * ones-complement of the varint encoding of E followed by the ones-complement
189 * of M.
190 * </p>
191 * <h3>Fixed-length Integer Encoding</h3>
192 * <p>
193 * All 4-byte integers are serialized to a 5-byte, fixed-width, sortable byte
194 * format. All 8-byte integers are serialized to the equivelant 9-byte format.
195 * Serialization is performed by writing a header byte, inverting the integer
196 * sign bit and writing the resulting bytes to the byte array in big endian
197 * order.
198 * </p>
199 * <h3>Fixed-length Floating Point Encoding</h3>
200 * <p>
201 * 32-bit and 64-bit floating point numbers are encoded to a 5-byte and 9-byte
202 * encoding format, respectively. The format is identical, save for the
203 * precision respected in each step of the operation.
204 * <p>
205 * This format ensures the following total ordering of floating point values:
206 * Float.NEGATIVE_INFINITY < -Float.MAX_VALUE < ... <
207 * -Float.MIN_VALUE < -0.0 < +0.0; < Float.MIN_VALUE < ... <
208 * Float.MAX_VALUE < Float.POSITIVE_INFINITY < Float.NaN
209 * </p>
210 * <p>
211 * Floating point numbers are encoded as specified in IEEE 754. A 32-bit
212 * single precision float consists of a sign bit, 8-bit unsigned exponent
213 * encoded in offset-127 notation, and a 23-bit significand. The format is
214 * described further in the <a
215 * href="http://en.wikipedia.org/wiki/Single_precision"> Single Precision
216 * Floating Point Wikipedia page</a>
217 * </p>
218 * <p>
219 * The value of a normal float is -1 <sup>sign bit</sup> ×
220 * 2<sup>exponent - 127</sup> × 1.significand
221 * </p>
222 * <p>
223 * The IEE754 floating point format already preserves sort ordering for
224 * positive floating point numbers when the raw bytes are compared in most
225 * significant byte order. This is discussed further at <a href=
226 * "http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm">
227 * http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm</a>
228 * </p>
229 * <p>
230 * Thus, we need only ensure that negative numbers sort in the the exact
231 * opposite order as positive numbers (so that say, negative infinity is less
232 * than negative 1), and that all negative numbers compare less than any
233 * positive number. To accomplish this, we invert the sign bit of all floating
234 * point numbers, and we also invert the exponent and significand bits if the
235 * floating point number was negative.
236 * </p>
237 * <p>
238 * More specifically, we first store the floating point bits into a 32-bit int
239 * {@code j} using {@link Float#floatToIntBits}. This method collapses
240 * all NaNs into a single, canonical NaN value but otherwise leaves the bits
241 * unchanged. We then compute
242 * </p>
243 *
244 * <pre>
245 * j ˆ= (j >> (Integer.SIZE - 1)) | Integer.MIN_SIZE
246 * </pre>
247 * <p>
248 * which inverts the sign bit and XOR's all other bits with the sign bit
249 * itself. Comparing the raw bytes of {@code j} in most significant byte
250 * order is equivalent to performing a single precision floating point
251 * comparison on the underlying bits (ignoring NaN comparisons, as NaNs don't
252 * compare equal to anything when performing floating point comparisons).
253 * </p>
254 * <p>
255 * The resulting integer is then converted into a byte array by serializing
256 * the integer one byte at a time in most significant byte order. The
257 * serialized integer is prefixed by a single header byte. All serialized
258 * values are 5 bytes in length.
259 * </p>
260 * <p>
261 * {@code OrderedBytes} encodings are heavily influenced by the
262 * <a href="http://sqlite.org/src4/doc/trunk/www/key_encoding.wiki">SQLite4 Key
263 * Encoding</a>. Slight deviations are make in the interest of order
264 * correctness and user extensibility. Fixed-width {@code Long} and
265 * {@link Double} encodings are based on implementations from the now defunct
266 * Orderly library.
267 * </p>
268 */
269 @InterfaceAudience.Public
270 @InterfaceStability.Evolving
271 public class OrderedBytes {
272
273 /*
274 * These constants define header bytes used to identify encoded values. Note
275 * that the values here are not exhaustive as the Numeric format encodes
276 * portions of its value within the header byte. The values listed here are
277 * directly applied to persisted data -- DO NOT modify the values specified
278 * here. Instead, gaps are placed intentionally between values so that new
279 * implementations can be inserted into the total ordering enforced here.
280 */
281 private static final byte NULL = 0x05;
282 // room for 1 expansion type
283 private static final byte NEG_INF = 0x07;
284 private static final byte NEG_LARGE = 0x08;
285 private static final byte NEG_MED_MIN = 0x09;
286 private static final byte NEG_MED_MAX = 0x13;
287 private static final byte NEG_SMALL = 0x14;
288 private static final byte ZERO = 0x15;
289 private static final byte POS_SMALL = 0x16;
290 private static final byte POS_MED_MIN = 0x17;
291 private static final byte POS_MED_MAX = 0x21;
292 private static final byte POS_LARGE = 0x22;
293 private static final byte POS_INF = 0x23;
294 // room for 2 expansion type
295 private static final byte NAN = 0x26;
296 // room for 2 expansion types
297 private static final byte FIXED_INT8 = 0x29;
298 private static final byte FIXED_INT16 = 0x2a;
299 private static final byte FIXED_INT32 = 0x2b;
300 private static final byte FIXED_INT64 = 0x2c;
301 // room for 3 expansion types
302 private static final byte FIXED_FLOAT32 = 0x30;
303 private static final byte FIXED_FLOAT64 = 0x31;
304 // room for 2 expansion type
305 private static final byte TEXT = 0x34;
306 // room for 2 expansion type
307 private static final byte BLOB_VAR = 0x37;
308 private static final byte BLOB_COPY = 0x38;
309
310 /*
311 * The following constant values are used by encoding implementations
312 */
313
314 public static final Charset UTF8 = Charset.forName("UTF-8");
315 private static final byte TERM = 0x00;
316 private static final BigDecimal E8 = BigDecimal.valueOf(1e8);
317 private static final BigDecimal E32 = BigDecimal.valueOf(1e32);
318 private static final BigDecimal EN2 = BigDecimal.valueOf(1e-2);
319 private static final BigDecimal EN10 = BigDecimal.valueOf(1e-10);
320
321 /**
322 * Max precision guaranteed to fit into a {@code long}.
323 */
324 public static final int MAX_PRECISION = 31;
325
326 /**
327 * The context used to normalize {@link BigDecimal} values.
328 */
329 public static final MathContext DEFAULT_MATH_CONTEXT =
330 new MathContext(MAX_PRECISION, RoundingMode.HALF_UP);
331
332 /**
333 * Creates the standard exception when the encoded header byte is unexpected for the decoding
334 * context.
335 * @param header value used in error message.
336 */
337 private static IllegalArgumentException unexpectedHeader(byte header) {
338 throw new IllegalArgumentException("unexpected value in first byte: 0x"
339 + Long.toHexString(header));
340 }
341
342 /**
343 * Perform unsigned comparison between two long values. Conforms to the same interface as
344 * {@link Comparator#compare(Object, Object)}.
345 */
346 private static int unsignedCmp(long x1, long x2) {
347 int cmp;
348 if ((cmp = (x1 < x2 ? -1 : (x1 == x2 ? 0 : 1))) == 0) return 0;
349 // invert the result when either value is negative
350 if ((x1 < 0) != (x2 < 0)) return -cmp;
351 return cmp;
352 }
353
354 /**
355 * Write a 32-bit unsigned integer to {@code dst} as 4 big-endian bytes.
356 * @return number of bytes written.
357 */
358 private static int putUint32(PositionedByteRange dst, int val) {
359 dst.put((byte) (val >>> 24))
360 .put((byte) (val >>> 16))
361 .put((byte) (val >>> 8))
362 .put((byte) val);
363 return 4;
364 }
365
366 /**
367 * Encode an unsigned 64-bit unsigned integer {@code val} into {@code dst}.
368 * @param dst The destination to which encoded bytes are written.
369 * @param val The value to write.
370 * @param comp Compliment the encoded value when {@code comp} is true.
371 * @return number of bytes written.
372 */
373 @VisibleForTesting
374 static int putVaruint64(PositionedByteRange dst, long val, boolean comp) {
375 int w, y, len = 0;
376 final int offset = dst.getOffset(), start = dst.getPosition();
377 byte[] a = dst.getBytes();
378 Order ord = comp ? DESCENDING : ASCENDING;
379 if (-1 == unsignedCmp(val, 241L)) {
380 dst.put((byte) val);
381 len = dst.getPosition() - start;
382 ord.apply(a, offset + start, len);
383 return len;
384 }
385 if (-1 == unsignedCmp(val, 2288L)) {
386 y = (int) (val - 240);
387 dst.put((byte) (y / 256 + 241))
388 .put((byte) (y % 256));
389 len = dst.getPosition() - start;
390 ord.apply(a, offset + start, len);
391 return len;
392 }
393 if (-1 == unsignedCmp(val, 67824L)) {
394 y = (int) (val - 2288);
395 dst.put((byte) 249)
396 .put((byte) (y / 256))
397 .put((byte) (y % 256));
398 len = dst.getPosition() - start;
399 ord.apply(a, offset + start, len);
400 return len;
401 }
402 y = (int) val;
403 w = (int) (val >>> 32);
404 if (w == 0) {
405 if (-1 == unsignedCmp(y, 16777216L)) {
406 dst.put((byte) 250)
407 .put((byte) (y >>> 16))
408 .put((byte) (y >>> 8))
409 .put((byte) y);
410 len = dst.getPosition() - start;
411 ord.apply(a, offset + start, len);
412 return len;
413 }
414 dst.put((byte) 251);
415 putUint32(dst, y);
416 len = dst.getPosition() - start;
417 ord.apply(a, offset + start, len);
418 return len;
419 }
420 if (-1 == unsignedCmp(w, 256L)) {
421 dst.put((byte) 252)
422 .put((byte) w);
423 putUint32(dst, y);
424 len = dst.getPosition() - start;
425 ord.apply(a, offset + start, len);
426 return len;
427 }
428 if (-1 == unsignedCmp(w, 65536L)) {
429 dst.put((byte) 253)
430 .put((byte) (w >>> 8))
431 .put((byte) w);
432 putUint32(dst, y);
433 len = dst.getPosition() - start;
434 ord.apply(a, offset + start, len);
435 return len;
436 }
437 if (-1 == unsignedCmp(w, 16777216L)) {
438 dst.put((byte) 254)
439 .put((byte) (w >>> 16))
440 .put((byte) (w >>> 8))
441 .put((byte) w);
442 putUint32(dst, y);
443 len = dst.getPosition() - start;
444 ord.apply(a, offset + start, len);
445 return len;
446 }
447 dst.put((byte) 255);
448 putUint32(dst, w);
449 putUint32(dst, y);
450 len = dst.getPosition() - start;
451 ord.apply(a, offset + start, len);
452 return len;
453 }
454
455 /**
456 * Inspect {@code src} for an encoded varuint64 for its length in bytes.
457 * Preserves the state of {@code src}.
458 * @param src source buffer
459 * @param comp if true, parse the compliment of the value.
460 * @return the number of bytes consumed by this value.
461 */
462 @VisibleForTesting
463 static int lengthVaruint64(PositionedByteRange src, boolean comp) {
464 int a0 = (comp ? DESCENDING : ASCENDING).apply(src.peek()) & 0xff;
465 if (a0 <= 240) return 1;
466 if (a0 <= 248) return 2;
467 if (a0 == 249) return 3;
468 if (a0 == 250) return 4;
469 if (a0 == 251) return 5;
470 if (a0 == 252) return 6;
471 if (a0 == 253) return 7;
472 if (a0 == 254) return 8;
473 if (a0 == 255) return 9;
474 throw unexpectedHeader(src.peek());
475 }
476
477 /**
478 * Skip {@code src} over the encoded varuint64.
479 * @param src source buffer
480 * @param cmp if true, parse the compliment of the value.
481 * @return the number of bytes skipped.
482 */
483 @VisibleForTesting
484 static int skipVaruint64(PositionedByteRange src, boolean cmp) {
485 final int len = lengthVaruint64(src, cmp);
486 src.setPosition(src.getPosition() + len);
487 return len;
488 }
489
490 /**
491 * Decode a sequence of bytes in {@code src} as a varuint64. Compliment the
492 * encoded value when {@code comp} is true.
493 * @return the decoded value.
494 */
495 @VisibleForTesting
496 static long getVaruint64(PositionedByteRange src, boolean comp) {
497 assert src.getRemaining() >= lengthVaruint64(src, comp);
498 final long ret;
499 Order ord = comp ? DESCENDING : ASCENDING;
500 byte x = src.get();
501 final int a0 = ord.apply(x) & 0xff, a1, a2, a3, a4, a5, a6, a7, a8;
502 if (-1 == unsignedCmp(a0, 241)) {
503 return a0;
504 }
505 x = src.get();
506 a1 = ord.apply(x) & 0xff;
507 if (-1 == unsignedCmp(a0, 249)) {
508 return (a0 - 241L) * 256 + a1 + 240;
509 }
510 x = src.get();
511 a2 = ord.apply(x) & 0xff;
512 if (a0 == 249) {
513 return 2288L + 256 * a1 + a2;
514 }
515 x = src.get();
516 a3 = ord.apply(x) & 0xff;
517 if (a0 == 250) {
518 return ((long) a1 << 16L) | (a2 << 8) | a3;
519 }
520 x = src.get();
521 a4 = ord.apply(x) & 0xff;
522 ret = (((long) a1) << 24) | (a2 << 16) | (a3 << 8) | a4;
523 if (a0 == 251) {
524 return ret;
525 }
526 x = src.get();
527 a5 = ord.apply(x) & 0xff;
528 if (a0 == 252) {
529 return (ret << 8) | a5;
530 }
531 x = src.get();
532 a6 = ord.apply(x) & 0xff;
533 if (a0 == 253) {
534 return (ret << 16) | (a5 << 8) | a6;
535 }
536 x = src.get();
537 a7 = ord.apply(x) & 0xff;
538 if (a0 == 254) {
539 return (ret << 24) | (a5 << 16) | (a6 << 8) | a7;
540 }
541 x = src.get();
542 a8 = ord.apply(x) & 0xff;
543 return (ret << 32) | (((long) a5) << 24) | (a6 << 16) | (a7 << 8) | a8;
544 }
545
546 /**
547 * Strip all trailing zeros to ensure that no digit will be zero and round
548 * using our default context to ensure precision doesn't exceed max allowed.
549 * From Phoenix's {@code NumberUtil}.
550 * @return new {@link BigDecimal} instance
551 */
552 @VisibleForTesting
553 static BigDecimal normalize(BigDecimal val) {
554 return null == val ? null : val.stripTrailingZeros().round(DEFAULT_MATH_CONTEXT);
555 }
556
557 /**
558 * Read significand digits from {@code src} according to the magnitude
559 * of {@code e}.
560 * @param src The source from which to read encoded digits.
561 * @param e The magnitude of the first digit read.
562 * @param comp Treat encoded bytes as compliments when {@code comp} is true.
563 * @return The decoded value.
564 * @throws IllegalArgumentException when read exceeds the remaining length
565 * of {@code src}.
566 */
567 private static BigDecimal decodeSignificand(PositionedByteRange src, int e, boolean comp) {
568 // TODO: can this be made faster?
569 byte[] a = src.getBytes();
570 final int start = src.getPosition(), offset = src.getOffset(), remaining = src.getRemaining();
571 Order ord = comp ? DESCENDING : ASCENDING;
572 BigDecimal m = BigDecimal.ZERO;
573 e--;
574 for (int i = 0;; i++) {
575 if (i > remaining) {
576 // we've exceeded this range's window
577 src.setPosition(start);
578 throw new IllegalArgumentException(
579 "Read exceeds range before termination byte found. offset: " + offset + " position: "
580 + (start + i));
581 }
582 // base-100 digits are encoded as val * 2 + 1 except for the termination digit.
583 m = m.add( // m +=
584 new BigDecimal(BigInteger.ONE, e * -2).multiply( // 100 ^ p * [decoded digit]
585 BigDecimal.valueOf((ord.apply(a[offset + start + i]) & 0xff) / 2)));
586 e--;
587 // detect termination digit
588 if ((ord.apply(a[offset + start + i]) & 1) == 0) {
589 src.setPosition(start + i + 1);
590 break;
591 }
592 }
593 return normalize(m);
594 }
595
596 /**
597 * Skip {@code src} over the significand bytes.
598 * @param src The source from which to read encoded digits.
599 * @param comp Treat encoded bytes as compliments when {@code comp} is true.
600 * @return the number of bytes skipped.
601 */
602 private static int skipSignificand(PositionedByteRange src, boolean comp) {
603 byte[] a = src.getBytes();
604 final int offset = src.getOffset(), start = src.getPosition();
605 int i = src.getPosition();
606 while (((comp ? DESCENDING : ASCENDING).apply(a[offset + i++]) & 1) != 0)
607 ;
608 src.setPosition(i);
609 return i - start;
610 }
611
612 /**
613 * <p>
614 * Encode the small magnitude floating point number {@code val} using the
615 * key encoding. The caller guarantees that 1.0 > abs(val) > 0.0.
616 * </p>
617 * <p>
618 * A floating point value is encoded as an integer exponent {@code E} and a
619 * mantissa {@code M}. The original value is equal to {@code (M * 100^E)}.
620 * {@code E} is set to the smallest value possible without making {@code M}
621 * greater than or equal to 1.0.
622 * </p>
623 * <p>
624 * For this routine, {@code E} will always be zero or negative, since the
625 * original value is less than one. The encoding written by this routine is
626 * the ones-complement of the varint of the negative of {@code E} followed
627 * by the mantissa:
628 * <pre>
629 * Encoding: ~-E M
630 * </pre>
631 * </p>
632 * @param dst The destination to which encoded digits are written.
633 * @param val The value to encode.
634 * @return the number of bytes written.
635 */
636 private static int encodeNumericSmall(PositionedByteRange dst, BigDecimal val) {
637 // TODO: this can be done faster?
638 // assert 1.0 > abs(val) > 0.0
639 BigDecimal abs = val.abs();
640 assert BigDecimal.ZERO.compareTo(abs) < 0 && BigDecimal.ONE.compareTo(abs) > 0;
641 byte[] a = dst.getBytes();
642 boolean isNeg = val.signum() == -1;
643 final int offset = dst.getOffset(), start = dst.getPosition();
644 int e = 0, d, startM;
645
646 if (isNeg) { /* Small negative number: 0x14, -E, ~M */
647 dst.put(NEG_SMALL);
648 } else { /* Small positive number: 0x16, ~-E, M */
649 dst.put(POS_SMALL);
650 }
651
652 // normalize abs(val) to determine E
653 while (abs.compareTo(EN10) < 0) { abs = abs.movePointRight(8); e += 4; }
654 while (abs.compareTo(EN2) < 0) { abs = abs.movePointRight(2); e++; }
655
656 putVaruint64(dst, e, !isNeg); // encode appropriate E value.
657
658 // encode M by peeling off centimal digits, encoding x as 2x+1
659 startM = dst.getPosition();
660 // TODO: 18 is an arbitrary encoding limit. Reevaluate once we have a better handling of
661 // numeric scale.
662 for (int i = 0; i < 18 && abs.compareTo(BigDecimal.ZERO) != 0; i++) {
663 abs = abs.movePointRight(2);
664 d = abs.intValue();
665 dst.put((byte) ((2 * d + 1) & 0xff));
666 abs = abs.subtract(BigDecimal.valueOf(d));
667 }
668 // terminal digit should be 2x
669 a[offset + dst.getPosition() - 1] = (byte) (a[offset + dst.getPosition() - 1] & 0xfe);
670 if (isNeg) {
671 // negative values encoded as ~M
672 DESCENDING.apply(a, offset + startM, dst.getPosition() - startM);
673 }
674 return dst.getPosition() - start;
675 }
676
677 /**
678 * Encode the large magnitude floating point number {@code val} using
679 * the key encoding. The caller guarantees that {@code val} will be
680 * finite and abs(val) >= 1.0.
681 * <p>
682 * A floating point value is encoded as an integer exponent {@code E}
683 * and a mantissa {@code M}. The original value is equal to
684 * {@code (M * 100^E)}. {@code E} is set to the smallest value
685 * possible without making {@code M} greater than or equal to 1.0.
686 * </p>
687 * <p>
688 * Each centimal digit of the mantissa is stored in a byte. If the value of
689 * the centimal digit is {@code X} (hence {@code X>=0} and
690 * {@code X<=99}) then the byte value will be {@code 2*X+1} for
691 * every byte of the mantissa, except for the last byte which will be
692 * {@code 2*X+0}. The mantissa must be the minimum number of bytes
693 * necessary to represent the value; trailing {@code X==0} digits are
694 * omitted. This means that the mantissa will never contain a byte with the
695 * value {@code 0x00}.
696 * </p>
697 * <p>
698 * If {@code E > 10}, then this routine writes of {@code E} as a
699 * varint followed by the mantissa as described above. Otherwise, if
700 * {@code E <= 10}, this routine only writes the mantissa and leaves
701 * the {@code E} value to be encoded as part of the opening byte of the
702 * field by the calling function.
703 *
704 * <pre>
705 * Encoding: M (if E<=10)
706 * E M (if E>10)
707 * </pre>
708 * </p>
709 * @param dst The destination to which encoded digits are written.
710 * @param val The value to encode.
711 * @return the number of bytes written.
712 */
713 private static int encodeNumericLarge(PositionedByteRange dst, BigDecimal val) {
714 // TODO: this can be done faster
715 BigDecimal abs = val.abs();
716 byte[] a = dst.getBytes();
717 boolean isNeg = val.signum() == -1;
718 final int start = dst.getPosition(), offset = dst.getOffset();
719 int e = 0, d, startM;
720
721 if (isNeg) { /* Large negative number: 0x08, ~E, ~M */
722 dst.put(NEG_LARGE);
723 } else { /* Large positive number: 0x22, E, M */
724 dst.put(POS_LARGE);
725 }
726
727 // normalize abs(val) to determine E
728 while (abs.compareTo(E32) >= 0 && e <= 350) { abs = abs.movePointLeft(32); e +=16; }
729 while (abs.compareTo(E8) >= 0 && e <= 350) { abs = abs.movePointLeft(8); e+= 4; }
730 while (abs.compareTo(BigDecimal.ONE) >= 0 && e <= 350) { abs = abs.movePointLeft(2); e++; }
731
732 // encode appropriate header byte and/or E value.
733 if (e > 10) { /* large number, write out {~,}E */
734 putVaruint64(dst, e, isNeg);
735 } else {
736 if (isNeg) { /* Medium negative number: 0x13-E, ~M */
737 dst.put(start, (byte) (NEG_MED_MAX - e));
738 } else { /* Medium positive number: 0x17+E, M */
739 dst.put(start, (byte) (POS_MED_MIN + e));
740 }
741 }
742
743 // encode M by peeling off centimal digits, encoding x as 2x+1
744 startM = dst.getPosition();
745 // TODO: 18 is an arbitrary encoding limit. Reevaluate once we have a better handling of
746 // numeric scale.
747 for (int i = 0; i < 18 && abs.compareTo(BigDecimal.ZERO) != 0; i++) {
748 abs = abs.movePointRight(2);
749 d = abs.intValue();
750 dst.put((byte) (2 * d + 1));
751 abs = abs.subtract(BigDecimal.valueOf(d));
752 }
753 // terminal digit should be 2x
754 a[offset + dst.getPosition() - 1] = (byte) (a[offset + dst.getPosition() - 1] & 0xfe);
755 if (isNeg) {
756 // negative values encoded as ~M
757 DESCENDING.apply(a, offset + startM, dst.getPosition() - startM);
758 }
759 return dst.getPosition() - start;
760 }
761
762 /**
763 * Encode a numerical value using the variable-length encoding.
764 * @param dst The destination to which encoded digits are written.
765 * @param val The value to encode.
766 * @param ord The {@link Order} to respect while encoding {@code val}.
767 * @return the number of bytes written.
768 */
769 public static int encodeNumeric(PositionedByteRange dst, long val, Order ord) {
770 return encodeNumeric(dst, BigDecimal.valueOf(val), ord);
771 }
772
773 /**
774 * Encode a numerical value using the variable-length encoding.
775 * @param dst The destination to which encoded digits are written.
776 * @param val The value to encode.
777 * @param ord The {@link Order} to respect while encoding {@code val}.
778 * @return the number of bytes written.
779 */
780 public static int encodeNumeric(PositionedByteRange dst, double val, Order ord) {
781 if (val == 0.0) {
782 dst.put(ord.apply(ZERO));
783 return 1;
784 }
785 if (Double.isNaN(val)) {
786 dst.put(ord.apply(NAN));
787 return 1;
788 }
789 if (val == Double.NEGATIVE_INFINITY) {
790 dst.put(ord.apply(NEG_INF));
791 return 1;
792 }
793 if (val == Double.POSITIVE_INFINITY) {
794 dst.put(ord.apply(POS_INF));
795 return 1;
796 }
797 return encodeNumeric(dst, BigDecimal.valueOf(val), ord);
798 }
799
800 /**
801 * Encode a numerical value using the variable-length encoding.
802 * @param dst The destination to which encoded digits are written.
803 * @param val The value to encode.
804 * @param ord The {@link Order} to respect while encoding {@code val}.
805 * @return the number of bytes written.
806 */
807 public static int encodeNumeric(PositionedByteRange dst, BigDecimal val, Order ord) {
808 final int len, offset = dst.getOffset(), start = dst.getPosition();
809 if (null == val) {
810 return encodeNull(dst, ord);
811 } else if (BigDecimal.ZERO.compareTo(val) == 0) {
812 dst.put(ord.apply(ZERO));
813 return 1;
814 }
815 BigDecimal abs = val.abs();
816 if (BigDecimal.ONE.compareTo(abs) <= 0) { // abs(v) >= 1.0
817 len = encodeNumericLarge(dst, normalize(val));
818 } else { // 1.0 > abs(v) >= 0.0
819 len = encodeNumericSmall(dst, normalize(val));
820 }
821 ord.apply(dst.getBytes(), offset + start, len);
822 return len;
823 }
824
825 /**
826 * Decode a {@link BigDecimal} from {@code src}. Assumes {@code src} encodes
827 * a value in Numeric encoding and is within the valid range of
828 * {@link BigDecimal} values. {@link BigDecimal} does not support {@code NaN}
829 * or {@code Infinte} values.
830 * @see #decodeNumericAsDouble(PositionedByteRange)
831 */
832 private static BigDecimal decodeNumericValue(PositionedByteRange src) {
833 final int e;
834 byte header = src.get();
835 boolean dsc = -1 == Integer.signum(header);
836 header = dsc ? DESCENDING.apply(header) : header;
837
838 if (header == NULL) return null;
839 if (header == NEG_LARGE) { /* Large negative number: 0x08, ~E, ~M */
840 e = (int) getVaruint64(src, !dsc);
841 return decodeSignificand(src, e, !dsc).negate();
842 }
843 if (header >= NEG_MED_MIN && header <= NEG_MED_MAX) {
844 /* Medium negative number: 0x13-E, ~M */
845 e = NEG_MED_MAX - header;
846 return decodeSignificand(src, e, !dsc).negate();
847 }
848 if (header == NEG_SMALL) { /* Small negative number: 0x14, -E, ~M */
849 e = (int) -getVaruint64(src, dsc);
850 return decodeSignificand(src, e, !dsc).negate();
851 }
852 if (header == ZERO) {
853 return BigDecimal.ZERO;
854 }
855 if (header == POS_SMALL) { /* Small positive number: 0x16, ~-E, M */
856 e = (int) -getVaruint64(src, !dsc);
857 return decodeSignificand(src, e, dsc);
858 }
859 if (header >= POS_MED_MIN && header <= POS_MED_MAX) {
860 /* Medium positive number: 0x17+E, M */
861 e = header - POS_MED_MIN;
862 return decodeSignificand(src, e, dsc);
863 }
864 if (header == POS_LARGE) { /* Large positive number: 0x22, E, M */
865 e = (int) getVaruint64(src, dsc);
866 return decodeSignificand(src, e, dsc);
867 }
868 throw unexpectedHeader(header);
869 }
870
871 /**
872 * Decode a primitive {@code double} value from the Numeric encoding. Numeric
873 * encoding is based on {@link BigDecimal}; in the event the encoded value is
874 * larger than can be represented in a {@code double}, this method performs
875 * an implicit narrowing conversion as described in
876 * {@link BigDecimal#doubleValue()}.
877 * @throws NullPointerException when the encoded value is {@code NULL}.
878 * @throws IllegalArgumentException when the encoded value is not a Numeric.
879 * @see #encodeNumeric(PositionedByteRange, double, Order)
880 * @see BigDecimal#doubleValue()
881 */
882 public static double decodeNumericAsDouble(PositionedByteRange src) {
883 // TODO: should an encoded NULL value throw unexpectedHeader() instead?
884 if (isNull(src)) {
885 throw new NullPointerException("A null value cannot be decoded to a double.");
886 }
887 if (isNumericNaN(src)) {
888 src.get();
889 return Double.NaN;
890 }
891 if (isNumericZero(src)) {
892 src.get();
893 return Double.valueOf(0.0);
894 }
895
896 byte header = -1 == Integer.signum(src.peek()) ? DESCENDING.apply(src.peek()) : src.peek();
897
898 if (header == NEG_INF) {
899 src.get();
900 return Double.NEGATIVE_INFINITY;
901 } else if (header == POS_INF) {
902 src.get();
903 return Double.POSITIVE_INFINITY;
904 } else {
905 return decodeNumericValue(src).doubleValue();
906 }
907 }
908
909 /**
910 * Decode a primitive {@code long} value from the Numeric encoding. Numeric
911 * encoding is based on {@link BigDecimal}; in the event the encoded value is
912 * larger than can be represented in a {@code long}, this method performs an
913 * implicit narrowing conversion as described in
914 * {@link BigDecimal#doubleValue()}.
915 * @throws NullPointerException when the encoded value is {@code NULL}.
916 * @throws IllegalArgumentException when the encoded value is not a Numeric.
917 * @see #encodeNumeric(PositionedByteRange, long, Order)
918 * @see BigDecimal#longValue()
919 */
920 public static long decodeNumericAsLong(PositionedByteRange src) {
921 // TODO: should an encoded NULL value throw unexpectedHeader() instead?
922 if (isNull(src)) throw new NullPointerException();
923 if (!isNumeric(src)) throw unexpectedHeader(src.peek());
924 if (isNumericNaN(src)) throw unexpectedHeader(src.peek());
925 if (isNumericInfinite(src)) throw unexpectedHeader(src.peek());
926
927 if (isNumericZero(src)) {
928 src.get();
929 return Long.valueOf(0);
930 }
931 return decodeNumericValue(src).longValue();
932 }
933
934 /**
935 * Decode a {@link BigDecimal} value from the variable-length encoding.
936 * @throws IllegalArgumentException when the encoded value is not a Numeric.
937 * @see #encodeNumeric(PositionedByteRange, BigDecimal, Order)
938 */
939 public static BigDecimal decodeNumericAsBigDecimal(PositionedByteRange src) {
940 if (isNull(src)) {
941 src.get();
942 return null;
943 }
944 if (!isNumeric(src)) throw unexpectedHeader(src.peek());
945 if (isNumericNaN(src)) throw unexpectedHeader(src.peek());
946 if (isNumericInfinite(src)) throw unexpectedHeader(src.peek());
947 return decodeNumericValue(src);
948 }
949
950 /**
951 * Encode a String value. String encoding is 0x00-terminated and so it does
952 * not support {@code \u0000} codepoints in the value.
953 * @param dst The destination to which the encoded value is written.
954 * @param val The value to encode.
955 * @param ord The {@link Order} to respect while encoding {@code val}.
956 * @return the number of bytes written.
957 * @throws IllegalArgumentException when {@code val} contains a {@code \u0000}.
958 */
959 public static int encodeString(PositionedByteRange dst, String val, Order ord) {
960 if (null == val) {
961 return encodeNull(dst, ord);
962 }
963 if (val.contains("\u0000"))
964 throw new IllegalArgumentException("Cannot encode String values containing '\\u0000'");
965 final int offset = dst.getOffset(), start = dst.getPosition();
966 dst.put(TEXT);
967 // TODO: is there no way to decode into dst directly?
968 dst.put(val.getBytes(UTF8));
969 dst.put(TERM);
970 ord.apply(dst.getBytes(), offset + start, dst.getPosition() - start);
971 return dst.getPosition() - start;
972 }
973
974 /**
975 * Decode a String value.
976 */
977 public static String decodeString(PositionedByteRange src) {
978 final byte header = src.get();
979 if (header == NULL || header == DESCENDING.apply(NULL))
980 return null;
981 assert header == TEXT || header == DESCENDING.apply(TEXT);
982 Order ord = header == TEXT ? ASCENDING : DESCENDING;
983 byte[] a = src.getBytes();
984 final int offset = src.getOffset(), start = src.getPosition();
985 final byte terminator = ord.apply(TERM);
986 int rawStartPos = offset + start, rawTermPos = rawStartPos;
987 for (; a[rawTermPos] != terminator; rawTermPos++)
988 ;
989 src.setPosition(rawTermPos - offset + 1); // advance position to TERM + 1
990 if (DESCENDING == ord) {
991 // make a copy so that we don't disturb encoded value with ord.
992 byte[] copy = new byte[rawTermPos - rawStartPos];
993 System.arraycopy(a, rawStartPos, copy, 0, copy.length);
994 ord.apply(copy);
995 return new String(copy, UTF8);
996 } else {
997 return new String(a, rawStartPos, rawTermPos - rawStartPos, UTF8);
998 }
999 }
1000
1001 /**
1002 * Calculate the expected BlobVar encoded length based on unencoded length.
1003 */
1004 public static int blobVarEncodedLength(int len) {
1005 if (0 == len)
1006 return 2; // 1-byte header + 1-byte terminator
1007 else
1008 return (int)
1009 Math.ceil(
1010 (len * 8) // 8-bits per input byte
1011 / 7.0) // 7-bits of input data per encoded byte, rounded up
1012 + 1; // + 1-byte header
1013 }
1014
1015 /**
1016 * Calculate the expected BlobVar decoded length based on encoded length.
1017 */
1018 @VisibleForTesting
1019 static int blobVarDecodedLength(int len) {
1020 return
1021 ((len
1022 - 1) // 1-byte header
1023 * 7) // 7-bits of payload per encoded byte
1024 / 8; // 8-bits per byte
1025 }
1026
1027 /**
1028 * Encode a Blob value using a modified varint encoding scheme.
1029 * <p>
1030 * This format encodes a byte[] value such that no limitations on the input
1031 * value are imposed. The first byte encodes the encoding scheme that
1032 * follows, {@link #BLOB_VAR}. Each encoded byte thereafter consists of a
1033 * header bit followed by 7 bits of payload. A header bit of '1' indicates
1034 * continuation of the encoding. A header bit of '0' indicates this byte
1035 * contains the last of the payload. An empty input value is encoded as the
1036 * header byte immediately followed by a termination byte {@code 0x00}. This
1037 * is not ambiguous with the encoded value of {@code []}, which results in
1038 * {@code [0x80, 0x00]}.
1039 * </p>
1040 * @return the number of bytes written.
1041 */
1042 public static int encodeBlobVar(PositionedByteRange dst, byte[] val, int voff, int vlen,
1043 Order ord) {
1044 if (null == val) {
1045 return encodeNull(dst, ord);
1046 }
1047 // Empty value is null-terminated. All other values are encoded as 7-bits per byte.
1048 assert dst.getRemaining() >= blobVarEncodedLength(vlen) : "buffer overflow expected.";
1049 final int offset = dst.getOffset(), start = dst.getPosition();
1050 dst.put(BLOB_VAR);
1051 if (0 == vlen) {
1052 dst.put(TERM);
1053 } else {
1054 byte s = 1, t = 0;
1055 for (int i = voff; i < vlen; i++) {
1056 dst.put((byte) (0x80 | t | ((val[i] & 0xff) >>> s)));
1057 if (s < 7) {
1058 t = (byte) (val[i] << (7 - s));
1059 s++;
1060 } else {
1061 dst.put((byte) (0x80 | val[i]));
1062 s = 1;
1063 t = 0;
1064 }
1065 }
1066 if (s > 1) {
1067 dst.put((byte) (0x7f & t));
1068 } else {
1069 dst.getBytes()[offset + dst.getPosition() - 1] =
1070 (byte) (dst.getBytes()[offset + dst.getPosition() - 1] & 0x7f);
1071 }
1072 }
1073 ord.apply(dst.getBytes(), offset + start, dst.getPosition() - start);
1074 return dst.getPosition() - start;
1075 }
1076
1077 /**
1078 * Encode a blob value using a modified varint encoding scheme.
1079 * @return the number of bytes written.
1080 * @see #encodeBlobVar(PositionedByteRange, byte[], int, int, Order)
1081 */
1082 public static int encodeBlobVar(PositionedByteRange dst, byte[] val, Order ord) {
1083 return encodeBlobVar(dst, val, 0, null != val ? val.length : 0, ord);
1084 }
1085
1086 /**
1087 * Decode a blob value that was encoded using BlobVar encoding.
1088 */
1089 public static byte[] decodeBlobVar(PositionedByteRange src) {
1090 final byte header = src.get();
1091 if (header == NULL || header == DESCENDING.apply(NULL)) {
1092 return null;
1093 }
1094 assert header == BLOB_VAR || header == DESCENDING.apply(BLOB_VAR);
1095 Order ord = BLOB_VAR == header ? ASCENDING : DESCENDING;
1096 if (src.peek() == ord.apply(TERM)) {
1097 // skip empty input buffer.
1098 src.get();
1099 return new byte[0];
1100 }
1101 final int offset = src.getOffset(), start = src.getPosition();
1102 int end;
1103 byte[] a = src.getBytes();
1104 for (end = start; (byte) (ord.apply(a[offset + end]) & 0x80) != TERM; end++)
1105 ;
1106 end++; // increment end to 1-past last byte
1107 // create ret buffer using length of encoded data + 1 (header byte)
1108 PositionedByteRange ret = new SimplePositionedMutableByteRange(blobVarDecodedLength(end - start
1109 + 1));
1110 int s = 6;
1111 byte t = (byte) ((ord.apply(a[offset + start]) << 1) & 0xff);
1112 for (int i = start + 1; i < end; i++) {
1113 if (s == 7) {
1114 ret.put((byte) (t | (ord.apply(a[offset + i]) & 0x7f)));
1115 i++;
1116 // explicitly reset t -- clean up overflow buffer after decoding
1117 // a full cycle and retain assertion condition below. This happens
1118 t = 0; // when the LSB in the last encoded byte is 1. (HBASE-9893)
1119 } else {
1120 ret.put((byte) (t | ((ord.apply(a[offset + i]) & 0x7f) >>> s)));
1121 }
1122 if (i == end) break;
1123 t = (byte) ((ord.apply(a[offset + i]) << (8 - s)) & 0xff);
1124 s = s == 1 ? 7 : s - 1;
1125 }
1126 src.setPosition(end);
1127 assert t == 0 : "Unexpected bits remaining after decoding blob.";
1128 assert ret.getPosition() == ret.getLength() : "Allocated unnecessarily large return buffer.";
1129 return ret.getBytes();
1130 }
1131
1132 /**
1133 * Encode a Blob value as a byte-for-byte copy. BlobCopy encoding in
1134 * DESCENDING order is NULL terminated so as to preserve proper sorting of
1135 * {@code []} and so it does not support {@code 0x00} in the value.
1136 * @return the number of bytes written.
1137 * @throws IllegalArgumentException when {@code ord} is DESCENDING and
1138 * {@code val} contains a {@code 0x00} byte.
1139 */
1140 public static int encodeBlobCopy(PositionedByteRange dst, byte[] val, int voff, int vlen,
1141 Order ord) {
1142 if (null == val) {
1143 encodeNull(dst, ord);
1144 if (ASCENDING == ord) return 1;
1145 else {
1146 // DESCENDING ordered BlobCopy requires a termination bit to preserve
1147 // sort-order semantics of null values.
1148 dst.put(ord.apply(TERM));
1149 return 2;
1150 }
1151 }
1152 // Blobs as final entry in a compound key are written unencoded.
1153 assert dst.getRemaining() >= vlen + (ASCENDING == ord ? 1 : 2);
1154 if (DESCENDING == ord) {
1155 for (int i = 0; i < vlen; i++) {
1156 if (TERM == val[voff + i]) {
1157 throw new IllegalArgumentException("0x00 bytes not permitted in value.");
1158 }
1159 }
1160 }
1161 final int offset = dst.getOffset(), start = dst.getPosition();
1162 dst.put(BLOB_COPY);
1163 dst.put(val, voff, vlen);
1164 // DESCENDING ordered BlobCopy requires a termination bit to preserve
1165 // sort-order semantics of null values.
1166 if (DESCENDING == ord) dst.put(TERM);
1167 ord.apply(dst.getBytes(), offset + start, dst.getPosition() - start);
1168 return dst.getPosition() - start;
1169 }
1170
1171 /**
1172 * Encode a Blob value as a byte-for-byte copy. BlobCopy encoding in
1173 * DESCENDING order is NULL terminated so as to preserve proper sorting of
1174 * {@code []} and so it does not support {@code 0x00} in the value.
1175 * @return the number of bytes written.
1176 * @throws IllegalArgumentException when {@code ord} is DESCENDING and
1177 * {@code val} contains a {@code 0x00} byte.
1178 * @see #encodeBlobCopy(PositionedByteRange, byte[], int, int, Order)
1179 */
1180 public static int encodeBlobCopy(PositionedByteRange dst, byte[] val, Order ord) {
1181 return encodeBlobCopy(dst, val, 0, null != val ? val.length : 0, ord);
1182 }
1183
1184 /**
1185 * Decode a Blob value, byte-for-byte copy.
1186 * @see #encodeBlobCopy(PositionedByteRange, byte[], int, int, Order)
1187 */
1188 public static byte[] decodeBlobCopy(PositionedByteRange src) {
1189 byte header = src.get();
1190 if (header == NULL || header == DESCENDING.apply(NULL)) {
1191 return null;
1192 }
1193 assert header == BLOB_COPY || header == DESCENDING.apply(BLOB_COPY);
1194 Order ord = header == BLOB_COPY ? ASCENDING : DESCENDING;
1195 final int length = src.getRemaining() - (ASCENDING == ord ? 0 : 1);
1196 byte[] ret = new byte[length];
1197 src.get(ret);
1198 ord.apply(ret, 0, ret.length);
1199 // DESCENDING ordered BlobCopy requires a termination bit to preserve
1200 // sort-order semantics of null values.
1201 if (DESCENDING == ord) src.get();
1202 return ret;
1203 }
1204
1205 /**
1206 * Encode a null value.
1207 * @param dst The destination to which encoded digits are written.
1208 * @param ord The {@link Order} to respect while encoding {@code val}.
1209 * @return the number of bytes written.
1210 */
1211 public static int encodeNull(PositionedByteRange dst, Order ord) {
1212 dst.put(ord.apply(NULL));
1213 return 1;
1214 }
1215
1216 /**
1217 * Encode an {@code int8} value using the fixed-length encoding.
1218 * @return the number of bytes written.
1219 * @see #encodeInt64(PositionedByteRange, long, Order)
1220 * @see #decodeInt8(PositionedByteRange)
1221 */
1222 public static int encodeInt8(PositionedByteRange dst, byte val, Order ord) {
1223 final int offset = dst.getOffset(), start = dst.getPosition();
1224 dst.put(FIXED_INT8)
1225 .put((byte) (val ^ 0x80));
1226 ord.apply(dst.getBytes(), offset + start, 2);
1227 return 2;
1228 }
1229
1230 /**
1231 * Decode an {@code int8} value.
1232 * @see #encodeInt8(PositionedByteRange, byte, Order)
1233 */
1234 public static byte decodeInt8(PositionedByteRange src) {
1235 final byte header = src.get();
1236 assert header == FIXED_INT8 || header == DESCENDING.apply(FIXED_INT8);
1237 Order ord = header == FIXED_INT8 ? ASCENDING : DESCENDING;
1238 return (byte)((ord.apply(src.get()) ^ 0x80) & 0xff);
1239 }
1240
1241 /**
1242 * Encode an {@code int16} value using the fixed-length encoding.
1243 * @return the number of bytes written.
1244 * @see #encodeInt64(PositionedByteRange, long, Order)
1245 * @see #decodeInt16(PositionedByteRange)
1246 */
1247 public static int encodeInt16(PositionedByteRange dst, short val, Order ord) {
1248 final int offset = dst.getOffset(), start = dst.getPosition();
1249 dst.put(FIXED_INT16)
1250 .put((byte) ((val >> 8) ^ 0x80))
1251 .put((byte) val);
1252 ord.apply(dst.getBytes(), offset + start, 3);
1253 return 3;
1254 }
1255
1256 /**
1257 * Decode an {@code int16} value.
1258 * @see #encodeInt16(PositionedByteRange, short, Order)
1259 */
1260 public static short decodeInt16(PositionedByteRange src) {
1261 final byte header = src.get();
1262 assert header == FIXED_INT16 || header == DESCENDING.apply(FIXED_INT16);
1263 Order ord = header == FIXED_INT16 ? ASCENDING : DESCENDING;
1264 short val = (short) ((ord.apply(src.get()) ^ 0x80) & 0xff);
1265 val = (short) ((val << 8) + (ord.apply(src.get()) & 0xff));
1266 return val;
1267 }
1268
1269 /**
1270 * Encode an {@code int32} value using the fixed-length encoding.
1271 * @return the number of bytes written.
1272 * @see #encodeInt64(PositionedByteRange, long, Order)
1273 * @see #decodeInt32(PositionedByteRange)
1274 */
1275 public static int encodeInt32(PositionedByteRange dst, int val, Order ord) {
1276 final int offset = dst.getOffset(), start = dst.getPosition();
1277 dst.put(FIXED_INT32)
1278 .put((byte) ((val >> 24) ^ 0x80))
1279 .put((byte) (val >> 16))
1280 .put((byte) (val >> 8))
1281 .put((byte) val);
1282 ord.apply(dst.getBytes(), offset + start, 5);
1283 return 5;
1284 }
1285
1286 /**
1287 * Decode an {@code int32} value.
1288 * @see #encodeInt32(PositionedByteRange, int, Order)
1289 */
1290 public static int decodeInt32(PositionedByteRange src) {
1291 final byte header = src.get();
1292 assert header == FIXED_INT32 || header == DESCENDING.apply(FIXED_INT32);
1293 Order ord = header == FIXED_INT32 ? ASCENDING : DESCENDING;
1294 int val = (ord.apply(src.get()) ^ 0x80) & 0xff;
1295 for (int i = 1; i < 4; i++) {
1296 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1297 }
1298 return val;
1299 }
1300
1301 /**
1302 * Encode an {@code int64} value using the fixed-length encoding.
1303 * <p>
1304 * This format ensures that all longs sort in their natural order, as they
1305 * would sort when using signed long comparison.
1306 * </p>
1307 * <p>
1308 * All Longs are serialized to an 8-byte, fixed-width sortable byte format.
1309 * Serialization is performed by inverting the integer sign bit and writing
1310 * the resulting bytes to the byte array in big endian order. The encoded
1311 * value is prefixed by the {@link #FIXED_INT64} header byte. This encoding
1312 * is designed to handle java language primitives and so Null values are NOT
1313 * supported by this implementation.
1314 * </p>
1315 * <p>
1316 * For example:
1317 * </p>
1318 * <pre>
1319 * Input: 0x0000000000000005 (5)
1320 * Result: 0x288000000000000005
1321 *
1322 * Input: 0xfffffffffffffffb (-4)
1323 * Result: 0x280000000000000004
1324 *
1325 * Input: 0x7fffffffffffffff (Long.MAX_VALUE)
1326 * Result: 0x28ffffffffffffffff
1327 *
1328 * Input: 0x8000000000000000 (Long.MIN_VALUE)
1329 * Result: 0x287fffffffffffffff
1330 * </pre>
1331 * <p>
1332 * This encoding format, and much of this documentation string, is based on
1333 * Orderly's {@code FixedIntWritableRowKey}.
1334 * </p>
1335 * @return the number of bytes written.
1336 * @see #decodeInt64(PositionedByteRange)
1337 */
1338 public static int encodeInt64(PositionedByteRange dst, long val, Order ord) {
1339 final int offset = dst.getOffset(), start = dst.getPosition();
1340 dst.put(FIXED_INT64)
1341 .put((byte) ((val >> 56) ^ 0x80))
1342 .put((byte) (val >> 48))
1343 .put((byte) (val >> 40))
1344 .put((byte) (val >> 32))
1345 .put((byte) (val >> 24))
1346 .put((byte) (val >> 16))
1347 .put((byte) (val >> 8))
1348 .put((byte) val);
1349 ord.apply(dst.getBytes(), offset + start, 9);
1350 return 9;
1351 }
1352
1353 /**
1354 * Decode an {@code int64} value.
1355 * @see #encodeInt64(PositionedByteRange, long, Order)
1356 */
1357 public static long decodeInt64(PositionedByteRange src) {
1358 final byte header = src.get();
1359 assert header == FIXED_INT64 || header == DESCENDING.apply(FIXED_INT64);
1360 Order ord = header == FIXED_INT64 ? ASCENDING : DESCENDING;
1361 long val = (ord.apply(src.get()) ^ 0x80) & 0xff;
1362 for (int i = 1; i < 8; i++) {
1363 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1364 }
1365 return val;
1366 }
1367
1368 /**
1369 * Encode a 32-bit floating point value using the fixed-length encoding.
1370 * Encoding format is described at length in
1371 * {@link #encodeFloat64(PositionedByteRange, double, Order)}.
1372 * @return the number of bytes written.
1373 * @see #decodeFloat32(PositionedByteRange)
1374 * @see #encodeFloat64(PositionedByteRange, double, Order)
1375 */
1376 public static int encodeFloat32(PositionedByteRange dst, float val, Order ord) {
1377 final int offset = dst.getOffset(), start = dst.getPosition();
1378 int i = Float.floatToIntBits(val);
1379 i ^= ((i >> (Integer.SIZE - 1)) | Integer.MIN_VALUE);
1380 dst.put(FIXED_FLOAT32)
1381 .put((byte) (i >> 24))
1382 .put((byte) (i >> 16))
1383 .put((byte) (i >> 8))
1384 .put((byte) i);
1385 ord.apply(dst.getBytes(), offset + start, 5);
1386 return 5;
1387 }
1388
1389 /**
1390 * Decode a 32-bit floating point value using the fixed-length encoding.
1391 * @see #encodeFloat32(PositionedByteRange, float, Order)
1392 */
1393 public static float decodeFloat32(PositionedByteRange src) {
1394 final byte header = src.get();
1395 assert header == FIXED_FLOAT32 || header == DESCENDING.apply(FIXED_FLOAT32);
1396 Order ord = header == FIXED_FLOAT32 ? ASCENDING : DESCENDING;
1397 int val = ord.apply(src.get()) & 0xff;
1398 for (int i = 1; i < 4; i++) {
1399 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1400 }
1401 val ^= (~val >> (Integer.SIZE - 1)) | Integer.MIN_VALUE;
1402 return Float.intBitsToFloat(val);
1403 }
1404
1405 /**
1406 * Encode a 64-bit floating point value using the fixed-length encoding.
1407 * <p>
1408 * This format ensures the following total ordering of floating point
1409 * values: Double.NEGATIVE_INFINITY < -Double.MAX_VALUE < ... <
1410 * -Double.MIN_VALUE < -0.0 < +0.0; < Double.MIN_VALUE < ...
1411 * < Double.MAX_VALUE < Double.POSITIVE_INFINITY < Double.NaN
1412 * </p>
1413 * <p>
1414 * Floating point numbers are encoded as specified in IEEE 754. A 64-bit
1415 * double precision float consists of a sign bit, 11-bit unsigned exponent
1416 * encoded in offset-1023 notation, and a 52-bit significand. The format is
1417 * described further in the <a
1418 * href="http://en.wikipedia.org/wiki/Double_precision"> Double Precision
1419 * Floating Point Wikipedia page</a> </p>
1420 * <p>
1421 * The value of a normal float is -1 <sup>sign bit</sup> ×
1422 * 2<sup>exponent - 1023</sup> × 1.significand
1423 * </p>
1424 * <p>
1425 * The IEE754 floating point format already preserves sort ordering for
1426 * positive floating point numbers when the raw bytes are compared in most
1427 * significant byte order. This is discussed further at <a href=
1428 * "http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm"
1429 * > http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.
1430 * htm</a>
1431 * </p>
1432 * <p>
1433 * Thus, we need only ensure that negative numbers sort in the the exact
1434 * opposite order as positive numbers (so that say, negative infinity is
1435 * less than negative 1), and that all negative numbers compare less than
1436 * any positive number. To accomplish this, we invert the sign bit of all
1437 * floating point numbers, and we also invert the exponent and significand
1438 * bits if the floating point number was negative.
1439 * </p>
1440 * <p>
1441 * More specifically, we first store the floating point bits into a 64-bit
1442 * long {@code l} using {@link Double#doubleToLongBits}. This method
1443 * collapses all NaNs into a single, canonical NaN value but otherwise
1444 * leaves the bits unchanged. We then compute
1445 * </p>
1446 * <pre>
1447 * l ˆ= (l >> (Long.SIZE - 1)) | Long.MIN_SIZE
1448 * </pre>
1449 * <p>
1450 * which inverts the sign bit and XOR's all other bits with the sign bit
1451 * itself. Comparing the raw bytes of {@code l} in most significant
1452 * byte order is equivalent to performing a double precision floating point
1453 * comparison on the underlying bits (ignoring NaN comparisons, as NaNs
1454 * don't compare equal to anything when performing floating point
1455 * comparisons).
1456 * </p>
1457 * <p>
1458 * The resulting long integer is then converted into a byte array by
1459 * serializing the long one byte at a time in most significant byte order.
1460 * The serialized integer is prefixed by a single header byte. All
1461 * serialized values are 9 bytes in length.
1462 * </p>
1463 * <p>
1464 * This encoding format, and much of this highly detailed documentation
1465 * string, is based on Orderly's {@code DoubleWritableRowKey}.
1466 * </p>
1467 * @return the number of bytes written.
1468 * @see #decodeFloat64(PositionedByteRange)
1469 */
1470 public static int encodeFloat64(PositionedByteRange dst, double val, Order ord) {
1471 final int offset = dst.getOffset(), start = dst.getPosition();
1472 long lng = Double.doubleToLongBits(val);
1473 lng ^= ((lng >> (Long.SIZE - 1)) | Long.MIN_VALUE);
1474 dst.put(FIXED_FLOAT64)
1475 .put((byte) (lng >> 56))
1476 .put((byte) (lng >> 48))
1477 .put((byte) (lng >> 40))
1478 .put((byte) (lng >> 32))
1479 .put((byte) (lng >> 24))
1480 .put((byte) (lng >> 16))
1481 .put((byte) (lng >> 8))
1482 .put((byte) lng);
1483 ord.apply(dst.getBytes(), offset + start, 9);
1484 return 9;
1485 }
1486
1487 /**
1488 * Decode a 64-bit floating point value using the fixed-length encoding.
1489 * @see #encodeFloat64(PositionedByteRange, double, Order)
1490 */
1491 public static double decodeFloat64(PositionedByteRange src) {
1492 final byte header = src.get();
1493 assert header == FIXED_FLOAT64 || header == DESCENDING.apply(FIXED_FLOAT64);
1494 Order ord = header == FIXED_FLOAT64 ? ASCENDING : DESCENDING;
1495 long val = ord.apply(src.get()) & 0xff;
1496 for (int i = 1; i < 8; i++) {
1497 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1498 }
1499 val ^= (~val >> (Long.SIZE - 1)) | Long.MIN_VALUE;
1500 return Double.longBitsToDouble(val);
1501 }
1502
1503 /**
1504 * Returns true when {@code src} appears to be positioned an encoded value,
1505 * false otherwise.
1506 */
1507 public static boolean isEncodedValue(PositionedByteRange src) {
1508 return isNull(src) || isNumeric(src) || isFixedInt8(src) || isFixedInt16(src)
1509 || isFixedInt32(src) || isFixedInt64(src)
1510 || isFixedFloat32(src) || isFixedFloat64(src) || isText(src) || isBlobCopy(src)
1511 || isBlobVar(src);
1512 }
1513
1514 /**
1515 * Return true when the next encoded value in {@code src} is null, false
1516 * otherwise.
1517 */
1518 public static boolean isNull(PositionedByteRange src) {
1519 return NULL ==
1520 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1521 }
1522
1523 /**
1524 * Return true when the next encoded value in {@code src} uses Numeric
1525 * encoding, false otherwise. {@code NaN}, {@code +/-Inf} are valid Numeric
1526 * values.
1527 */
1528 public static boolean isNumeric(PositionedByteRange src) {
1529 byte x = (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1530 return x >= NEG_INF && x <= NAN;
1531 }
1532
1533 /**
1534 * Return true when the next encoded value in {@code src} uses Numeric
1535 * encoding and is {@code Infinite}, false otherwise.
1536 */
1537 public static boolean isNumericInfinite(PositionedByteRange src) {
1538 byte x = (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1539 return NEG_INF == x || POS_INF == x;
1540 }
1541
1542 /**
1543 * Return true when the next encoded value in {@code src} uses Numeric
1544 * encoding and is {@code NaN}, false otherwise.
1545 */
1546 public static boolean isNumericNaN(PositionedByteRange src) {
1547 return NAN == (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1548 }
1549
1550 /**
1551 * Return true when the next encoded value in {@code src} uses Numeric
1552 * encoding and is {@code 0}, false otherwise.
1553 */
1554 public static boolean isNumericZero(PositionedByteRange src) {
1555 return ZERO ==
1556 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1557 }
1558
1559 /**
1560 * Return true when the next encoded value in {@code src} uses fixed-width
1561 * Int8 encoding, false otherwise.
1562 */
1563 public static boolean isFixedInt8(PositionedByteRange src) {
1564 return FIXED_INT8 ==
1565 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1566 }
1567
1568 /**
1569 * Return true when the next encoded value in {@code src} uses fixed-width
1570 * Int16 encoding, false otherwise.
1571 */
1572 public static boolean isFixedInt16(PositionedByteRange src) {
1573 return FIXED_INT16 ==
1574 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1575 }
1576
1577 /**
1578 * Return true when the next encoded value in {@code src} uses fixed-width
1579 * Int32 encoding, false otherwise.
1580 */
1581 public static boolean isFixedInt32(PositionedByteRange src) {
1582 return FIXED_INT32 ==
1583 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1584 }
1585
1586 /**
1587 * Return true when the next encoded value in {@code src} uses fixed-width
1588 * Int64 encoding, false otherwise.
1589 */
1590 public static boolean isFixedInt64(PositionedByteRange src) {
1591 return FIXED_INT64 ==
1592 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1593 }
1594
1595 /**
1596 * Return true when the next encoded value in {@code src} uses fixed-width
1597 * Float32 encoding, false otherwise.
1598 */
1599 public static boolean isFixedFloat32(PositionedByteRange src) {
1600 return FIXED_FLOAT32 ==
1601 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1602 }
1603
1604 /**
1605 * Return true when the next encoded value in {@code src} uses fixed-width
1606 * Float64 encoding, false otherwise.
1607 */
1608 public static boolean isFixedFloat64(PositionedByteRange src) {
1609 return FIXED_FLOAT64 ==
1610 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1611 }
1612
1613 /**
1614 * Return true when the next encoded value in {@code src} uses Text encoding,
1615 * false otherwise.
1616 */
1617 public static boolean isText(PositionedByteRange src) {
1618 return TEXT ==
1619 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1620 }
1621
1622 /**
1623 * Return true when the next encoded value in {@code src} uses BlobVar
1624 * encoding, false otherwise.
1625 */
1626 public static boolean isBlobVar(PositionedByteRange src) {
1627 return BLOB_VAR ==
1628 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1629 }
1630
1631 /**
1632 * Return true when the next encoded value in {@code src} uses BlobCopy
1633 * encoding, false otherwise.
1634 */
1635 public static boolean isBlobCopy(PositionedByteRange src) {
1636 return BLOB_COPY ==
1637 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1638 }
1639
1640 /**
1641 * Skip {@code buff}'s position forward over one encoded value.
1642 * @return number of bytes skipped.
1643 */
1644 public static int skip(PositionedByteRange src) {
1645 final int start = src.getPosition();
1646 byte header = src.get();
1647 Order ord = (-1 == Integer.signum(header)) ? DESCENDING : ASCENDING;
1648 header = ord.apply(header);
1649
1650 switch (header) {
1651 case NULL:
1652 case NEG_INF:
1653 return 1;
1654 case NEG_LARGE: /* Large negative number: 0x08, ~E, ~M */
1655 skipVaruint64(src, DESCENDING != ord);
1656 skipSignificand(src, DESCENDING != ord);
1657 return src.getPosition() - start;
1658 case NEG_MED_MIN: /* Medium negative number: 0x13-E, ~M */
1659 case NEG_MED_MIN + 0x01:
1660 case NEG_MED_MIN + 0x02:
1661 case NEG_MED_MIN + 0x03:
1662 case NEG_MED_MIN + 0x04:
1663 case NEG_MED_MIN + 0x05:
1664 case NEG_MED_MIN + 0x06:
1665 case NEG_MED_MIN + 0x07:
1666 case NEG_MED_MIN + 0x08:
1667 case NEG_MED_MIN + 0x09:
1668 case NEG_MED_MAX:
1669 skipSignificand(src, DESCENDING != ord);
1670 return src.getPosition() - start;
1671 case NEG_SMALL: /* Small negative number: 0x14, -E, ~M */
1672 skipVaruint64(src, DESCENDING == ord);
1673 skipSignificand(src, DESCENDING != ord);
1674 return src.getPosition() - start;
1675 case ZERO:
1676 return 1;
1677 case POS_SMALL: /* Small positive number: 0x16, ~-E, M */
1678 skipVaruint64(src, DESCENDING != ord);
1679 skipSignificand(src, DESCENDING == ord);
1680 return src.getPosition() - start;
1681 case POS_MED_MIN: /* Medium positive number: 0x17+E, M */
1682 case POS_MED_MIN + 0x01:
1683 case POS_MED_MIN + 0x02:
1684 case POS_MED_MIN + 0x03:
1685 case POS_MED_MIN + 0x04:
1686 case POS_MED_MIN + 0x05:
1687 case POS_MED_MIN + 0x06:
1688 case POS_MED_MIN + 0x07:
1689 case POS_MED_MIN + 0x08:
1690 case POS_MED_MIN + 0x09:
1691 case POS_MED_MAX:
1692 skipSignificand(src, DESCENDING == ord);
1693 return src.getPosition() - start;
1694 case POS_LARGE: /* Large positive number: 0x22, E, M */
1695 skipVaruint64(src, DESCENDING == ord);
1696 skipSignificand(src, DESCENDING == ord);
1697 return src.getPosition() - start;
1698 case POS_INF:
1699 return 1;
1700 case NAN:
1701 return 1;
1702 case FIXED_INT8:
1703 src.setPosition(src.getPosition() + 1);
1704 return src.getPosition() - start;
1705 case FIXED_INT16:
1706 src.setPosition(src.getPosition() + 2);
1707 return src.getPosition() - start;
1708 case FIXED_INT32:
1709 src.setPosition(src.getPosition() + 4);
1710 return src.getPosition() - start;
1711 case FIXED_INT64:
1712 src.setPosition(src.getPosition() + 8);
1713 return src.getPosition() - start;
1714 case FIXED_FLOAT32:
1715 src.setPosition(src.getPosition() + 4);
1716 return src.getPosition() - start;
1717 case FIXED_FLOAT64:
1718 src.setPosition(src.getPosition() + 8);
1719 return src.getPosition() - start;
1720 case TEXT:
1721 // for null-terminated values, skip to the end.
1722 do {
1723 header = ord.apply(src.get());
1724 } while (header != TERM);
1725 return src.getPosition() - start;
1726 case BLOB_VAR:
1727 // read until we find a 0 in the MSB
1728 do {
1729 header = ord.apply(src.get());
1730 } while ((byte) (header & 0x80) != TERM);
1731 return src.getPosition() - start;
1732 case BLOB_COPY:
1733 if (Order.DESCENDING == ord) {
1734 // if descending, read to termination byte.
1735 do {
1736 header = ord.apply(src.get());
1737 } while (header != TERM);
1738 return src.getPosition() - start;
1739 } else {
1740 // otherwise, just skip to the end.
1741 src.setPosition(src.getLength());
1742 return src.getPosition() - start;
1743 }
1744 default:
1745 throw unexpectedHeader(header);
1746 }
1747 }
1748
1749 /**
1750 * Return the number of encoded entries remaining in {@code buff}. The
1751 * state of {@code buff} is not modified through use of this method.
1752 */
1753 public static int length(PositionedByteRange buff) {
1754 PositionedByteRange b =
1755 new SimplePositionedMutableByteRange(buff.getBytes(), buff.getOffset(), buff.getLength());
1756 b.setPosition(buff.getPosition());
1757 int cnt = 0;
1758 for (; isEncodedValue(b); skip(b), cnt++)
1759 ;
1760 return cnt;
1761 }
1762 }