View Javadoc

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