1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 @InterfaceAudience.Public
269 @InterfaceStability.Evolving
270 public class OrderedBytes {
271
272
273
274
275
276
277
278
279
280 private static final byte NULL = 0x05;
281 private static final byte NEG_INF = 0x07;
282 private static final byte NEG_LARGE = 0x08;
283 private static final byte NEG_MED_MIN = 0x09;
284 private static final byte NEG_MED_MAX = 0x13;
285 private static final byte NEG_SMALL = 0x14;
286 private static final byte ZERO = 0x15;
287 private static final byte POS_SMALL = 0x16;
288 private static final byte POS_MED_MIN = 0x17;
289 private static final byte POS_MED_MAX = 0x21;
290 private static final byte POS_LARGE = 0x22;
291 private static final byte POS_INF = 0x23;
292 private static final byte NAN = 0x25;
293 private static final byte FIXED_INT32 = 0x27;
294 private static final byte FIXED_INT64 = 0x28;
295 private static final byte FIXED_FLOAT32 = 0x30;
296 private static final byte FIXED_FLOAT64 = 0x31;
297 private static final byte TEXT = 0x33;
298 private static final byte BLOB_VAR = 0x35;
299 private static final byte BLOB_COPY = 0x36;
300
301
302
303
304
305 public static final Charset UTF8 = Charset.forName("UTF-8");
306 private static final byte TERM = 0x00;
307 private static final BigDecimal E8 = BigDecimal.valueOf(1e8);
308 private static final BigDecimal E32 = BigDecimal.valueOf(1e32);
309 private static final BigDecimal EN2 = BigDecimal.valueOf(1e-2);
310 private static final BigDecimal EN10 = BigDecimal.valueOf(1e-10);
311
312
313
314
315 public static final int MAX_PRECISION = 31;
316
317
318
319
320 public static final MathContext DEFAULT_MATH_CONTEXT =
321 new MathContext(MAX_PRECISION, RoundingMode.HALF_UP);
322
323
324
325
326
327
328 private static IllegalArgumentException unexpectedHeader(byte header) {
329 throw new IllegalArgumentException("unexpected value in first byte: 0x"
330 + Long.toHexString(header));
331 }
332
333
334
335
336
337 private static int unsignedCmp(long x1, long x2) {
338 int cmp;
339 if ((cmp = (x1 < x2 ? -1 : (x1 == x2 ? 0 : 1))) == 0) return 0;
340
341 if ((x1 < 0) != (x2 < 0)) return -cmp;
342 return cmp;
343 }
344
345
346
347
348
349 private static int putUint32(PositionedByteRange dst, int val) {
350 dst.put((byte) (val >>> 24))
351 .put((byte) (val >>> 16))
352 .put((byte) (val >>> 8))
353 .put((byte) val);
354 return 4;
355 }
356
357
358
359
360
361
362
363
364 @VisibleForTesting
365 static int putVaruint64(PositionedByteRange dst, long val, boolean comp) {
366 int w, y, len = 0;
367 final int offset = dst.getOffset(), start = dst.getPosition();
368 byte[] a = dst.getBytes();
369 Order ord = comp ? DESCENDING : ASCENDING;
370 if (-1 == unsignedCmp(val, 241L)) {
371 dst.put((byte) val);
372 len = dst.getPosition() - start;
373 ord.apply(a, offset + start, len);
374 return len;
375 }
376 if (-1 == unsignedCmp(val, 2288L)) {
377 y = (int) (val - 240);
378 dst.put((byte) (y / 256 + 241))
379 .put((byte) (y % 256));
380 len = dst.getPosition() - start;
381 ord.apply(a, offset + start, len);
382 return len;
383 }
384 if (-1 == unsignedCmp(val, 67824L)) {
385 y = (int) (val - 2288);
386 dst.put((byte) 249)
387 .put((byte) (y / 256))
388 .put((byte) (y % 256));
389 len = dst.getPosition() - start;
390 ord.apply(a, offset + start, len);
391 return len;
392 }
393 y = (int) val;
394 w = (int) (val >>> 32);
395 if (w == 0) {
396 if (-1 == unsignedCmp(y, 16777216L)) {
397 dst.put((byte) 250)
398 .put((byte) (y >>> 16))
399 .put((byte) (y >>> 8))
400 .put((byte) y);
401 len = dst.getPosition() - start;
402 ord.apply(a, offset + start, len);
403 return len;
404 }
405 dst.put((byte) 251);
406 putUint32(dst, y);
407 len = dst.getPosition() - start;
408 ord.apply(a, offset + start, len);
409 return len;
410 }
411 if (-1 == unsignedCmp(w, 256L)) {
412 dst.put((byte) 252)
413 .put((byte) w);
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, 65536L)) {
420 dst.put((byte) 253)
421 .put((byte) (w >>> 8))
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, 16777216L)) {
429 dst.put((byte) 254)
430 .put((byte) (w >>> 16))
431 .put((byte) (w >>> 8))
432 .put((byte) w);
433 putUint32(dst, y);
434 len = dst.getPosition() - start;
435 ord.apply(a, offset + start, len);
436 return len;
437 }
438 dst.put((byte) 255);
439 putUint32(dst, w);
440 putUint32(dst, y);
441 len = dst.getPosition() - start;
442 ord.apply(a, offset + start, len);
443 return len;
444 }
445
446
447
448
449
450
451
452
453 @VisibleForTesting
454 static int lengthVaruint64(PositionedByteRange src, boolean comp) {
455 int a0 = (comp ? DESCENDING : ASCENDING).apply(src.peek()) & 0xff;
456 if (a0 <= 240) return 1;
457 if (a0 >= 241 && a0 <= 248) return 2;
458 if (a0 == 249) return 3;
459 if (a0 == 250) return 4;
460 if (a0 == 251) return 5;
461 if (a0 == 252) return 6;
462 if (a0 == 253) return 7;
463 if (a0 == 254) return 8;
464 if (a0 == 255) return 9;
465 throw unexpectedHeader(src.peek());
466 }
467
468
469
470
471
472
473
474 @VisibleForTesting
475 static int skipVaruint64(PositionedByteRange src, boolean cmp) {
476 final int len = lengthVaruint64(src, cmp);
477 src.setPosition(src.getPosition() + len);
478 return len;
479 }
480
481
482
483
484
485
486 @VisibleForTesting
487 static long getVaruint64(PositionedByteRange src, boolean comp) {
488 assert src.getRemaining() >= lengthVaruint64(src, comp);
489 final long ret;
490 Order ord = comp ? DESCENDING : ASCENDING;
491 byte x = src.get();
492 final int a0 = ord.apply(x) & 0xff, a1, a2, a3, a4, a5, a6, a7, a8;
493 if (-1 == unsignedCmp(a0, 241)) {
494 return a0;
495 }
496 x = src.get();
497 a1 = ord.apply(x) & 0xff;
498 if (-1 == unsignedCmp(a0, 249)) {
499 return (a0 - 241) * 256 + a1 + 240;
500 }
501 x = src.get();
502 a2 = ord.apply(x) & 0xff;
503 if (a0 == 249) {
504 return 2288 + 256 * a1 + a2;
505 }
506 x = src.get();
507 a3 = ord.apply(x) & 0xff;
508 if (a0 == 250) {
509 return (a1 << 16) | (a2 << 8) | a3;
510 }
511 x = src.get();
512 a4 = ord.apply(x) & 0xff;
513 ret = (((long) a1) << 24) | (a2 << 16) | (a3 << 8) | a4;
514 if (a0 == 251) {
515 return ret;
516 }
517 x = src.get();
518 a5 = ord.apply(x) & 0xff;
519 if (a0 == 252) {
520 return (ret << 8) | a5;
521 }
522 x = src.get();
523 a6 = ord.apply(x) & 0xff;
524 if (a0 == 253) {
525 return (ret << 16) | (a5 << 8) | a6;
526 }
527 x = src.get();
528 a7 = ord.apply(x) & 0xff;
529 if (a0 == 254) {
530 return (ret << 24) | (a5 << 16) | (a6 << 8) | a7;
531 }
532 x = src.get();
533 a8 = ord.apply(x) & 0xff;
534 return (ret << 32) | (((long) a5) << 24) | (a6 << 16) | (a7 << 8) | a8;
535 }
536
537
538
539
540
541
542
543 @VisibleForTesting
544 static BigDecimal normalize(BigDecimal val) {
545 return null == val ? null : val.stripTrailingZeros().round(DEFAULT_MATH_CONTEXT);
546 }
547
548
549
550
551
552
553
554
555
556
557
558 private static BigDecimal decodeSignificand(PositionedByteRange src, int e, boolean comp) {
559
560 byte[] a = src.getBytes();
561 final int start = src.getPosition(), offset = src.getOffset(), remaining = src.getRemaining();
562 Order ord = comp ? DESCENDING : ASCENDING;
563 BigDecimal m = BigDecimal.ZERO;
564 e--;
565 for (int i = 0;; i++) {
566 if (i > remaining) {
567
568 src.setPosition(start);
569 throw new IllegalArgumentException(
570 "Read exceeds range before termination byte found. offset: " + offset + " position: "
571 + (start + i));
572 }
573
574 m = m.add(
575 new BigDecimal(BigInteger.ONE, e * -2).multiply(
576 BigDecimal.valueOf((ord.apply(a[offset + start + i]) & 0xff) / 2)));
577 e--;
578
579 if ((ord.apply(a[offset + start + i]) & 1) == 0) {
580 src.setPosition(start + i + 1);
581 break;
582 }
583 }
584 return normalize(m);
585 }
586
587
588
589
590
591
592
593 private static int skipSignificand(PositionedByteRange src, boolean comp) {
594 byte[] a = src.getBytes();
595 final int offset = src.getOffset(), start = src.getPosition();
596 int i = src.getPosition();
597 while (((comp ? DESCENDING : ASCENDING).apply(a[offset + i++]) & 1) != 0)
598 ;
599 src.setPosition(i);
600 return i - start;
601 }
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627 private static int encodeNumericSmall(PositionedByteRange dst, BigDecimal val) {
628
629
630 BigDecimal abs = val.abs();
631 assert BigDecimal.ZERO.compareTo(abs) < 0 && BigDecimal.ONE.compareTo(abs) > 0;
632 byte[] a = dst.getBytes();
633 boolean isNeg = val.signum() == -1;
634 final int offset = dst.getOffset(), start = dst.getPosition();
635 int e = 0, d, startM;
636
637 if (isNeg) {
638 dst.put(NEG_SMALL);
639 } else {
640 dst.put(POS_SMALL);
641 }
642
643
644 while (abs.compareTo(EN10) < 0) { abs = abs.movePointRight(8); e += 4; }
645 while (abs.compareTo(EN2) < 0) { abs = abs.movePointRight(2); e++; }
646
647 putVaruint64(dst, e, !isNeg);
648
649
650 startM = dst.getPosition();
651
652
653 for (int i = 0; i < 18 && abs.compareTo(BigDecimal.ZERO) != 0; i++) {
654 abs = abs.movePointRight(2);
655 d = abs.intValue();
656 dst.put((byte) ((2 * d + 1) & 0xff));
657 abs = abs.subtract(BigDecimal.valueOf(d));
658 }
659 a[offset + dst.getPosition() - 1] &= 0xfe;
660 if (isNeg) {
661
662 DESCENDING.apply(a, offset + startM, dst.getPosition() - startM);
663 }
664 return dst.getPosition() - start;
665 }
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703 private static int encodeNumericLarge(PositionedByteRange dst, BigDecimal val) {
704
705 BigDecimal abs = val.abs();
706 byte[] a = dst.getBytes();
707 boolean isNeg = val.signum() == -1;
708 final int start = dst.getPosition(), offset = dst.getOffset();
709 int e = 0, d, startM;
710
711 if (isNeg) {
712 dst.put(NEG_LARGE);
713 } else {
714 dst.put(POS_LARGE);
715 }
716
717
718 while (abs.compareTo(E32) >= 0 && e <= 350) { abs = abs.movePointLeft(32); e +=16; }
719 while (abs.compareTo(E8) >= 0 && e <= 350) { abs = abs.movePointLeft(8); e+= 4; }
720 while (abs.compareTo(BigDecimal.ONE) >= 0 && e <= 350) { abs = abs.movePointLeft(2); e++; }
721
722
723 if (e > 10) {
724 putVaruint64(dst, e, isNeg);
725 } else {
726 if (isNeg) {
727 dst.put(start, (byte) (NEG_MED_MAX - e));
728 } else {
729 dst.put(start, (byte) (POS_MED_MIN + e));
730 }
731 }
732
733
734 startM = dst.getPosition();
735
736
737 for (int i = 0; i < 18 && abs.compareTo(BigDecimal.ZERO) != 0; i++) {
738 abs = abs.movePointRight(2);
739 d = abs.intValue();
740 dst.put((byte) (2 * d + 1));
741 abs = abs.subtract(BigDecimal.valueOf(d));
742 }
743
744 a[offset + dst.getPosition() - 1] &= 0xfe;
745 if (isNeg) {
746
747 DESCENDING.apply(a, offset + startM, dst.getPosition() - startM);
748 }
749 return dst.getPosition() - start;
750 }
751
752
753
754
755
756
757
758
759 public static int encodeNumeric(PositionedByteRange dst, long val, Order ord) {
760 return encodeNumeric(dst, BigDecimal.valueOf(val), ord);
761 }
762
763
764
765
766
767
768
769
770 public static int encodeNumeric(PositionedByteRange dst, double val, Order ord) {
771 if (val == 0.0) {
772 dst.put(ord.apply(ZERO));
773 return 1;
774 }
775 if (Double.isNaN(val)) {
776 dst.put(ord.apply(NAN));
777 return 1;
778 }
779 if (val == Double.NEGATIVE_INFINITY) {
780 dst.put(ord.apply(NEG_INF));
781 return 1;
782 }
783 if (val == Double.POSITIVE_INFINITY) {
784 dst.put(ord.apply(POS_INF));
785 return 1;
786 }
787 return encodeNumeric(dst, BigDecimal.valueOf(val), ord);
788 }
789
790
791
792
793
794
795
796
797 public static int encodeNumeric(PositionedByteRange dst, BigDecimal val, Order ord) {
798 final int len, offset = dst.getOffset(), start = dst.getPosition();
799 if (null == val) {
800 return encodeNull(dst, ord);
801 } else if (BigDecimal.ZERO.compareTo(val) == 0) {
802 dst.put(ord.apply(ZERO));
803 return 1;
804 }
805 BigDecimal abs = val.abs();
806 if (BigDecimal.ONE.compareTo(abs) <= 0) {
807 len = encodeNumericLarge(dst, normalize(val));
808 } else {
809 len = encodeNumericSmall(dst, normalize(val));
810 }
811 ord.apply(dst.getBytes(), offset + start, len);
812 return len;
813 }
814
815
816
817
818
819
820
821
822 private static BigDecimal decodeNumericValue(PositionedByteRange src) {
823 final int e;
824 byte header = src.get();
825 boolean dsc = -1 == Integer.signum(header);
826 header = dsc ? DESCENDING.apply(header) : header;
827
828 if (header == NULL) return null;
829 if (header == NEG_LARGE) {
830 e = (int) getVaruint64(src, !dsc);
831 return decodeSignificand(src, e, !dsc).negate();
832 }
833 if (header >= NEG_MED_MIN && header <= NEG_MED_MAX) {
834
835 e = NEG_MED_MAX - header;
836 return decodeSignificand(src, e, !dsc).negate();
837 }
838 if (header == NEG_SMALL) {
839 e = (int) -getVaruint64(src, dsc);
840 return decodeSignificand(src, e, !dsc).negate();
841 }
842 if (header == ZERO) {
843 return BigDecimal.ZERO;
844 }
845 if (header == POS_SMALL) {
846 e = (int) -getVaruint64(src, !dsc);
847 return decodeSignificand(src, e, dsc);
848 }
849 if (header >= POS_MED_MIN && header <= POS_MED_MAX) {
850
851 e = header - POS_MED_MIN;
852 return decodeSignificand(src, e, dsc);
853 }
854 if (header == POS_LARGE) {
855 e = (int) getVaruint64(src, dsc);
856 return decodeSignificand(src, e, dsc);
857 }
858 throw unexpectedHeader(header);
859 }
860
861
862
863
864
865
866
867
868
869
870
871
872 public static double decodeNumericAsDouble(PositionedByteRange src) {
873
874 if (isNull(src)) {
875 throw new NullPointerException("A null value cannot be decoded to a double.");
876 }
877 if (isNumericNaN(src)) {
878 src.get();
879 return Double.NaN;
880 }
881 if (isNumericZero(src)) {
882 src.get();
883 return Double.valueOf(0.0);
884 }
885
886 byte header = -1 == Integer.signum(src.peek()) ? DESCENDING.apply(src.peek()) : src.peek();
887
888 if (header == NEG_INF) {
889 src.get();
890 return Double.NEGATIVE_INFINITY;
891 } else if (header == POS_INF) {
892 src.get();
893 return Double.POSITIVE_INFINITY;
894 } else {
895 return decodeNumericValue(src).doubleValue();
896 }
897 }
898
899
900
901
902
903
904
905
906
907
908
909
910 public static long decodeNumericAsLong(PositionedByteRange src) {
911
912 if (isNull(src)) throw new NullPointerException();
913 if (!isNumeric(src)) throw unexpectedHeader(src.peek());
914 if (isNumericNaN(src)) throw unexpectedHeader(src.peek());
915 if (isNumericInfinite(src)) throw unexpectedHeader(src.peek());
916
917 if (isNumericZero(src)) {
918 src.get();
919 return Long.valueOf(0);
920 }
921 return decodeNumericValue(src).longValue();
922 }
923
924
925
926
927
928
929 public static BigDecimal decodeNumericAsBigDecimal(PositionedByteRange src) {
930 if (isNull(src)) {
931 src.get();
932 return null;
933 }
934 if (!isNumeric(src)) throw unexpectedHeader(src.peek());
935 if (isNumericNaN(src)) throw unexpectedHeader(src.peek());
936 if (isNumericInfinite(src)) throw unexpectedHeader(src.peek());
937 return decodeNumericValue(src);
938 }
939
940
941
942
943
944
945
946
947
948
949 public static int encodeString(PositionedByteRange dst, String val, Order ord) {
950 if (null == val) {
951 return encodeNull(dst, ord);
952 }
953 if (val.contains("\u0000"))
954 throw new IllegalArgumentException("Cannot encode String values containing '\\u0000'");
955 final int offset = dst.getOffset(), start = dst.getPosition();
956 dst.put(TEXT);
957
958 dst.put(val.getBytes(UTF8));
959 dst.put(TERM);
960 ord.apply(dst.getBytes(), offset + start, dst.getPosition() - start);
961 return dst.getPosition() - start;
962 }
963
964
965
966
967 public static String decodeString(PositionedByteRange src) {
968 final byte header = src.get();
969 if (header == NULL || header == DESCENDING.apply(NULL))
970 return null;
971 assert header == TEXT || header == DESCENDING.apply(TEXT);
972 Order ord = header == TEXT ? ASCENDING : DESCENDING;
973 byte[] a = src.getBytes();
974 final int offset = src.getOffset(), start = src.getPosition();
975 final byte terminator = ord.apply(TERM);
976 int i = offset + start;
977 for (; a[i] != terminator; i++)
978 ;
979 src.setPosition(i - offset + 1);
980 if (DESCENDING == ord) {
981
982 byte[] copy = new byte[i - offset - 1];
983 System.arraycopy(a, offset + start, copy, 0, copy.length);
984 ord.apply(copy);
985 return new String(copy, UTF8);
986 } else {
987 return new String(a, offset + start, i - offset - 1, UTF8);
988 }
989 }
990
991
992
993
994 public static int blobVarEncodedLength(int len) {
995 if (0 == len)
996 return 2;
997 else
998 return (int)
999 Math.ceil(
1000 (len * 8)
1001 / 7.0)
1002 + 1;
1003 }
1004
1005
1006
1007
1008 @VisibleForTesting
1009 static int blobVarDecodedLength(int len) {
1010 return
1011 ((len
1012 - 1)
1013 * 7)
1014 / 8;
1015 }
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032 public static int encodeBlobVar(PositionedByteRange dst, byte[] val, int voff, int vlen,
1033 Order ord) {
1034 if (null == val) {
1035 return encodeNull(dst, ord);
1036 }
1037
1038 assert dst.getRemaining() >= blobVarEncodedLength(vlen) : "buffer overflow expected.";
1039 final int offset = dst.getOffset(), start = dst.getPosition();
1040 dst.put(BLOB_VAR);
1041 if (0 == vlen) {
1042 dst.put(TERM);
1043 } else {
1044 byte s = 1, t = 0;
1045 for (int i = voff; i < vlen; i++) {
1046 dst.put((byte) (0x80 | t | ((val[i] & 0xff) >>> s)));
1047 if (s < 7) {
1048 t = (byte) (val[i] << (7 - s));
1049 s++;
1050 } else {
1051 dst.put((byte) (0x80 | val[i]));
1052 s = 1;
1053 t = 0;
1054 }
1055 }
1056 if (s > 1) {
1057 dst.put((byte) (0x7f & t));
1058 } else {
1059 dst.getBytes()[offset + dst.getPosition() - 1] &= 0x7f;
1060 }
1061 }
1062 ord.apply(dst.getBytes(), offset + start, dst.getPosition() - start);
1063 return dst.getPosition() - start;
1064 }
1065
1066
1067
1068
1069
1070
1071 public static int encodeBlobVar(PositionedByteRange dst, byte[] val, Order ord) {
1072 return encodeBlobVar(dst, val, 0, null != val ? val.length : 0, ord);
1073 }
1074
1075
1076
1077
1078 public static byte[] decodeBlobVar(PositionedByteRange src) {
1079 final byte header = src.get();
1080 if (header == NULL || header == DESCENDING.apply(NULL)) {
1081 return null;
1082 }
1083 assert header == BLOB_VAR || header == DESCENDING.apply(BLOB_VAR);
1084 Order ord = BLOB_VAR == header ? ASCENDING : DESCENDING;
1085 if (src.peek() == ord.apply(TERM)) {
1086
1087 src.get();
1088 return new byte[0];
1089 }
1090 final int offset = src.getOffset(), start = src.getPosition();
1091 int end;
1092 byte[] a = src.getBytes();
1093 for (end = start; (byte) (ord.apply(a[offset + end]) & 0x80) != TERM; end++)
1094 ;
1095 end++;
1096
1097 PositionedByteRange ret = new SimplePositionedByteRange(blobVarDecodedLength(end - start + 1));
1098 int s = 6;
1099 byte t = (byte) ((ord.apply(a[offset + start]) << 1) & 0xff);
1100 for (int i = start + 1; i < end; i++) {
1101 if (s == 7) {
1102 ret.put((byte) (t | (ord.apply(a[offset + i]) & 0x7f)));
1103 i++;
1104 } else {
1105 ret.put((byte) (t | ((ord.apply(a[offset + i]) & 0x7f) >>> s)));
1106 }
1107 if (i == end) break;
1108 t = (byte) ((ord.apply(a[offset + i]) << 8 - s) & 0xff);
1109 s = s == 1 ? 7 : s - 1;
1110 }
1111 src.setPosition(end);
1112 assert t == 0 : "Unexpected bits remaining after decoding blob.";
1113 assert ret.getPosition() == ret.getLength() : "Allocated unnecessarily large return buffer.";
1114 return ret.getBytes();
1115 }
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125 public static int encodeBlobCopy(PositionedByteRange dst, byte[] val, int voff, int vlen,
1126 Order ord) {
1127 if (null == val) {
1128 encodeNull(dst, ord);
1129 if (ASCENDING == ord) return 1;
1130 else {
1131
1132
1133 dst.put(ord.apply(TERM));
1134 return 2;
1135 }
1136 }
1137
1138 assert dst.getRemaining() >= vlen + (ASCENDING == ord ? 1 : 2);
1139 if (DESCENDING == ord) {
1140 for (int i = 0; i < vlen; i++) {
1141 if (TERM == val[voff + i]) {
1142 throw new IllegalArgumentException("0x00 bytes not permitted in value.");
1143 }
1144 }
1145 }
1146 final int offset = dst.getOffset(), start = dst.getPosition();
1147 dst.put(BLOB_COPY);
1148 dst.put(val, voff, vlen);
1149
1150
1151 if (DESCENDING == ord) dst.put(TERM);
1152 ord.apply(dst.getBytes(), offset + start, dst.getPosition() - start);
1153 return dst.getPosition() - start;
1154 }
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165 public static int encodeBlobCopy(PositionedByteRange dst, byte[] val, Order ord) {
1166 return encodeBlobCopy(dst, val, 0, null != val ? val.length : 0, ord);
1167 }
1168
1169
1170
1171
1172
1173 public static byte[] decodeBlobCopy(PositionedByteRange src) {
1174 byte header = src.get();
1175 if (header == NULL || header == DESCENDING.apply(NULL)) {
1176 return null;
1177 }
1178 assert header == BLOB_COPY || header == DESCENDING.apply(BLOB_COPY);
1179 Order ord = header == BLOB_COPY ? ASCENDING : DESCENDING;
1180 final int length = src.getRemaining() - (ASCENDING == ord ? 0 : 1);
1181 byte[] ret = new byte[length];
1182 src.get(ret);
1183 ord.apply(ret, 0, ret.length);
1184
1185
1186 if (DESCENDING == ord) src.get();
1187 return ret;
1188 }
1189
1190
1191
1192
1193
1194
1195
1196 public static int encodeNull(PositionedByteRange dst, Order ord) {
1197 dst.put(ord.apply(NULL));
1198 return 1;
1199 }
1200
1201
1202
1203
1204
1205
1206
1207 public static int encodeInt32(PositionedByteRange dst, int val, Order ord) {
1208 final int offset = dst.getOffset(), start = dst.getPosition();
1209 dst.put(FIXED_INT32)
1210 .put((byte) ((val >> 24) ^ 0x80))
1211 .put((byte) (val >> 16))
1212 .put((byte) (val >> 8))
1213 .put((byte) val);
1214 ord.apply(dst.getBytes(), offset + start, 5);
1215 return 5;
1216 }
1217
1218
1219
1220
1221
1222 public static int decodeInt32(PositionedByteRange src) {
1223 final byte header = src.get();
1224 assert header == FIXED_INT32 || header == DESCENDING.apply(FIXED_INT32);
1225 Order ord = header == FIXED_INT32 ? ASCENDING : DESCENDING;
1226 int val = (ord.apply(src.get()) ^ 0x80) & 0xff;
1227 for (int i = 1; i < 4; i++) {
1228 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1229 }
1230 return val;
1231 }
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270 public static int encodeInt64(PositionedByteRange dst, long val, Order ord) {
1271 final int offset = dst.getOffset(), start = dst.getPosition();
1272 dst.put(FIXED_INT64)
1273 .put((byte) ((val >> 56) ^ 0x80))
1274 .put((byte) (val >> 48))
1275 .put((byte) (val >> 40))
1276 .put((byte) (val >> 32))
1277 .put((byte) (val >> 24))
1278 .put((byte) (val >> 16))
1279 .put((byte) (val >> 8))
1280 .put((byte) val);
1281 ord.apply(dst.getBytes(), offset + start, 9);
1282 return 9;
1283 }
1284
1285
1286
1287
1288
1289 public static long decodeInt64(PositionedByteRange src) {
1290 final byte header = src.get();
1291 assert header == FIXED_INT64 || header == DESCENDING.apply(FIXED_INT64);
1292 Order ord = header == FIXED_INT64 ? ASCENDING : DESCENDING;
1293 long val = (ord.apply(src.get()) ^ 0x80) & 0xff;
1294 for (int i = 1; i < 8; i++) {
1295 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1296 }
1297 return val;
1298 }
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308 public static int encodeFloat32(PositionedByteRange dst, float val, Order ord) {
1309 final int offset = dst.getOffset(), start = dst.getPosition();
1310 int i = Float.floatToIntBits(val);
1311 i ^= ((i >> Integer.SIZE - 1) | Integer.MIN_VALUE);
1312 dst.put(FIXED_FLOAT32)
1313 .put((byte) (i >> 24))
1314 .put((byte) (i >> 16))
1315 .put((byte) (i >> 8))
1316 .put((byte) i);
1317 ord.apply(dst.getBytes(), offset + start, 5);
1318 return 5;
1319 }
1320
1321
1322
1323
1324
1325 public static float decodeFloat32(PositionedByteRange src) {
1326 final byte header = src.get();
1327 assert header == FIXED_FLOAT32 || header == DESCENDING.apply(FIXED_FLOAT32);
1328 Order ord = header == FIXED_FLOAT32 ? ASCENDING : DESCENDING;
1329 int val = ord.apply(src.get()) & 0xff;
1330 for (int i = 1; i < 4; i++) {
1331 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1332 }
1333 val ^= (~val >> Integer.SIZE - 1) | Integer.MIN_VALUE;
1334 return Float.intBitsToFloat(val);
1335 }
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 public static int encodeFloat64(PositionedByteRange dst, double val, Order ord) {
1402 final int offset = dst.getOffset(), start = dst.getPosition();
1403 long lng = Double.doubleToLongBits(val);
1404 lng ^= ((lng >> Long.SIZE - 1) | Long.MIN_VALUE);
1405 dst.put(FIXED_FLOAT64)
1406 .put((byte) (lng >> 56))
1407 .put((byte) (lng >> 48))
1408 .put((byte) (lng >> 40))
1409 .put((byte) (lng >> 32))
1410 .put((byte) (lng >> 24))
1411 .put((byte) (lng >> 16))
1412 .put((byte) (lng >> 8))
1413 .put((byte) lng);
1414 ord.apply(dst.getBytes(), offset + start, 9);
1415 return 9;
1416 }
1417
1418
1419
1420
1421
1422 public static double decodeFloat64(PositionedByteRange src) {
1423 final byte header = src.get();
1424 assert header == FIXED_FLOAT64 || header == DESCENDING.apply(FIXED_FLOAT64);
1425 Order ord = header == FIXED_FLOAT64 ? ASCENDING : DESCENDING;
1426 long val = ord.apply(src.get()) & 0xff;
1427 for (int i = 1; i < 8; i++) {
1428 val = (val << 8) + (ord.apply(src.get()) & 0xff);
1429 }
1430 val ^= (~val >> Long.SIZE - 1) | Long.MIN_VALUE;
1431 return Double.longBitsToDouble(val);
1432 }
1433
1434
1435
1436
1437
1438 public static boolean isEncodedValue(PositionedByteRange src) {
1439 return isNull(src) || isNumeric(src) || isFixedInt32(src) || isFixedInt64(src)
1440 || isFixedFloat32(src) || isFixedFloat64(src) || isText(src) || isBlobCopy(src)
1441 || isBlobVar(src);
1442 }
1443
1444
1445
1446
1447
1448 public static boolean isNull(PositionedByteRange src) {
1449 return NULL ==
1450 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1451 }
1452
1453
1454
1455
1456
1457
1458 public static boolean isNumeric(PositionedByteRange src) {
1459 byte x = (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1460 return x >= NEG_INF && x <= NAN;
1461 }
1462
1463
1464
1465
1466
1467 public static boolean isNumericInfinite(PositionedByteRange src) {
1468 byte x = (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1469 return NEG_INF == x || POS_INF == x;
1470 }
1471
1472
1473
1474
1475
1476 public static boolean isNumericNaN(PositionedByteRange src) {
1477 return NAN == (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1478 }
1479
1480
1481
1482
1483
1484 public static boolean isNumericZero(PositionedByteRange src) {
1485 return ZERO ==
1486 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1487 }
1488
1489
1490
1491
1492
1493 public static boolean isFixedInt32(PositionedByteRange src) {
1494 return FIXED_INT32 ==
1495 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1496 }
1497
1498
1499
1500
1501
1502 public static boolean isFixedInt64(PositionedByteRange src) {
1503 return FIXED_INT64 ==
1504 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1505 }
1506
1507
1508
1509
1510
1511 public static boolean isFixedFloat32(PositionedByteRange src) {
1512 return FIXED_FLOAT32 ==
1513 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1514 }
1515
1516
1517
1518
1519
1520 public static boolean isFixedFloat64(PositionedByteRange src) {
1521 return FIXED_FLOAT64 ==
1522 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1523 }
1524
1525
1526
1527
1528
1529 public static boolean isText(PositionedByteRange src) {
1530 return TEXT ==
1531 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1532 }
1533
1534
1535
1536
1537
1538 public static boolean isBlobVar(PositionedByteRange src) {
1539 return BLOB_VAR ==
1540 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1541 }
1542
1543
1544
1545
1546
1547 public static boolean isBlobCopy(PositionedByteRange src) {
1548 return BLOB_COPY ==
1549 (-1 == Integer.signum(src.peek()) ? DESCENDING : ASCENDING).apply(src.peek());
1550 }
1551
1552
1553
1554
1555
1556 public static int skip(PositionedByteRange src) {
1557 final int start = src.getPosition();
1558 byte header = src.get();
1559 Order ord = (-1 == Integer.signum(header)) ? DESCENDING : ASCENDING;
1560 header = ord.apply(header);
1561
1562 switch (header) {
1563 case NULL:
1564 case NEG_INF:
1565 return 1;
1566 case NEG_LARGE:
1567 skipVaruint64(src, DESCENDING != ord);
1568 skipSignificand(src, DESCENDING != ord);
1569 return src.getPosition() - start;
1570 case NEG_MED_MIN:
1571 case NEG_MED_MIN + 0x01:
1572 case NEG_MED_MIN + 0x02:
1573 case NEG_MED_MIN + 0x03:
1574 case NEG_MED_MIN + 0x04:
1575 case NEG_MED_MIN + 0x05:
1576 case NEG_MED_MIN + 0x06:
1577 case NEG_MED_MIN + 0x07:
1578 case NEG_MED_MIN + 0x08:
1579 case NEG_MED_MIN + 0x09:
1580 case NEG_MED_MAX:
1581 skipSignificand(src, DESCENDING != ord);
1582 return src.getPosition() - start;
1583 case NEG_SMALL:
1584 skipVaruint64(src, DESCENDING == ord);
1585 skipSignificand(src, DESCENDING != ord);
1586 return src.getPosition() - start;
1587 case ZERO:
1588 return 1;
1589 case POS_SMALL:
1590 skipVaruint64(src, DESCENDING != ord);
1591 skipSignificand(src, DESCENDING == ord);
1592 return src.getPosition() - start;
1593 case POS_MED_MIN:
1594 case POS_MED_MIN + 0x01:
1595 case POS_MED_MIN + 0x02:
1596 case POS_MED_MIN + 0x03:
1597 case POS_MED_MIN + 0x04:
1598 case POS_MED_MIN + 0x05:
1599 case POS_MED_MIN + 0x06:
1600 case POS_MED_MIN + 0x07:
1601 case POS_MED_MIN + 0x08:
1602 case POS_MED_MIN + 0x09:
1603 case POS_MED_MAX:
1604 skipSignificand(src, DESCENDING == ord);
1605 return src.getPosition() - start;
1606 case POS_LARGE:
1607 skipVaruint64(src, DESCENDING == ord);
1608 skipSignificand(src, DESCENDING == ord);
1609 return src.getPosition() - start;
1610 case POS_INF:
1611 return 1;
1612 case NAN:
1613 return 1;
1614 case FIXED_INT32:
1615 src.setPosition(src.getPosition() + 4);
1616 return src.getPosition() - start;
1617 case FIXED_INT64:
1618 src.setPosition(src.getPosition() + 8);
1619 return src.getPosition() - start;
1620 case FIXED_FLOAT32:
1621 src.setPosition(src.getPosition() + 4);
1622 return src.getPosition() - start;
1623 case FIXED_FLOAT64:
1624 src.setPosition(src.getPosition() + 8);
1625 return src.getPosition() - start;
1626 case TEXT:
1627
1628 do {
1629 header = ord.apply(src.get());
1630 } while (header != TERM);
1631 return src.getPosition() - start;
1632 case BLOB_VAR:
1633
1634 do {
1635 header = ord.apply(src.get());
1636 } while ((byte) (header & 0x80) != TERM);
1637 return src.getPosition() - start;
1638 case BLOB_COPY:
1639 if (Order.DESCENDING == ord) {
1640
1641 do {
1642 header = ord.apply(src.get());
1643 } while (header != TERM);
1644 return src.getPosition() - start;
1645 } else {
1646
1647 src.setPosition(src.getLength());
1648 return src.getPosition() - start;
1649 }
1650 default:
1651 throw unexpectedHeader(header);
1652 }
1653 }
1654
1655
1656
1657
1658
1659 public static int length(PositionedByteRange buff) {
1660 PositionedByteRange b =
1661 new SimplePositionedByteRange(buff.getBytes(), buff.getOffset(), buff.getLength());
1662 b.setPosition(buff.getPosition());
1663 int cnt = 0;
1664 for (; isEncodedValue(b); skip(buff), cnt++)
1665 ;
1666 return cnt;
1667 }
1668 }