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
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
294 private static final byte NAN = 0x26;
295
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
301 private static final byte FIXED_FLOAT32 = 0x30;
302 private static final byte FIXED_FLOAT64 = 0x31;
303
304 private static final byte TEXT = 0x34;
305
306 private static final byte BLOB_VAR = 0x37;
307 private static final byte BLOB_COPY = 0x38;
308
309
310
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
322
323 public static final int MAX_PRECISION = 31;
324
325
326
327
328 public static final MathContext DEFAULT_MATH_CONTEXT =
329 new MathContext(MAX_PRECISION, RoundingMode.HALF_UP);
330
331
332
333
334
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
343
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
349 if ((x1 < 0) != (x2 < 0)) return -cmp;
350 return cmp;
351 }
352
353
354
355
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
367
368
369
370
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
456
457
458
459
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
478
479
480
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
491
492
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
547
548
549
550
551 @VisibleForTesting
552 static BigDecimal normalize(BigDecimal val) {
553 return null == val ? null : val.stripTrailingZeros().round(DEFAULT_MATH_CONTEXT);
554 }
555
556
557
558
559
560
561
562
563
564
565
566 private static BigDecimal decodeSignificand(PositionedByteRange src, int e, boolean comp) {
567
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
576 src.setPosition(start);
577 throw new IllegalArgumentException(
578 "Read exceeds range before termination byte found. offset: " + offset + " position: "
579 + (start + i));
580 }
581
582 m = m.add(
583 new BigDecimal(BigInteger.ONE, e * -2).multiply(
584 BigDecimal.valueOf((ord.apply(a[offset + start + i]) & 0xff) / 2)));
585 e--;
586
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
597
598
599
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
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635 private static int encodeNumericSmall(PositionedByteRange dst, BigDecimal val) {
636
637
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) {
646 dst.put(NEG_SMALL);
647 } else {
648 dst.put(POS_SMALL);
649 }
650
651
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);
656
657
658 startM = dst.getPosition();
659
660
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;
668 if (isNeg) {
669
670 DESCENDING.apply(a, offset + startM, dst.getPosition() - startM);
671 }
672 return dst.getPosition() - start;
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
704
705
706
707
708
709
710
711 private static int encodeNumericLarge(PositionedByteRange dst, BigDecimal val) {
712
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) {
720 dst.put(NEG_LARGE);
721 } else {
722 dst.put(POS_LARGE);
723 }
724
725
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
731 if (e > 10) {
732 putVaruint64(dst, e, isNeg);
733 } else {
734 if (isNeg) {
735 dst.put(start, (byte) (NEG_MED_MAX - e));
736 } else {
737 dst.put(start, (byte) (POS_MED_MIN + e));
738 }
739 }
740
741
742 startM = dst.getPosition();
743
744
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;
753 if (isNeg) {
754
755 DESCENDING.apply(a, offset + startM, dst.getPosition() - startM);
756 }
757 return dst.getPosition() - start;
758 }
759
760
761
762
763
764
765
766
767 public static int encodeNumeric(PositionedByteRange dst, long val, Order ord) {
768 return encodeNumeric(dst, BigDecimal.valueOf(val), ord);
769 }
770
771
772
773
774
775
776
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
800
801
802
803
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) {
815 len = encodeNumericLarge(dst, normalize(val));
816 } else {
817 len = encodeNumericSmall(dst, normalize(val));
818 }
819 ord.apply(dst.getBytes(), offset + start, len);
820 return len;
821 }
822
823
824
825
826
827
828
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) {
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
843 e = NEG_MED_MAX - header;
844 return decodeSignificand(src, e, !dsc).negate();
845 }
846 if (header == NEG_SMALL) {
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) {
854 e = (int) -getVaruint64(src, !dsc);
855 return decodeSignificand(src, e, dsc);
856 }
857 if (header >= POS_MED_MIN && header <= POS_MED_MAX) {
858
859 e = header - POS_MED_MIN;
860 return decodeSignificand(src, e, dsc);
861 }
862 if (header == POS_LARGE) {
863 e = (int) getVaruint64(src, dsc);
864 return decodeSignificand(src, e, dsc);
865 }
866 throw unexpectedHeader(header);
867 }
868
869
870
871
872
873
874
875
876
877
878
879
880 public static double decodeNumericAsDouble(PositionedByteRange src) {
881
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
909
910
911
912
913
914
915
916
917
918 public static long decodeNumericAsLong(PositionedByteRange src) {
919
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
934
935
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
950
951
952
953
954
955
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
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
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);
988 if (DESCENDING == ord) {
989
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
1001
1002 public static int blobVarEncodedLength(int len) {
1003 if (0 == len)
1004 return 2;
1005 else
1006 return (int)
1007 Math.ceil(
1008 (len * 8)
1009 / 7.0)
1010 + 1;
1011 }
1012
1013
1014
1015
1016 @VisibleForTesting
1017 static int blobVarDecodedLength(int len) {
1018 return
1019 ((len
1020 - 1)
1021 * 7)
1022 / 8;
1023 }
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
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
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
1076
1077
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
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
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++;
1104
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
1113
1114 t = 0;
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
1130
1131
1132
1133
1134
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
1143
1144 dst.put(ord.apply(TERM));
1145 return 2;
1146 }
1147 }
1148
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
1161
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
1169
1170
1171
1172
1173
1174
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
1182
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
1196
1197 if (DESCENDING == ord) src.get();
1198 return ret;
1199 }
1200
1201
1202
1203
1204
1205
1206
1207 public static int encodeNull(PositionedByteRange dst, Order ord) {
1208 dst.put(ord.apply(NULL));
1209 return 1;
1210 }
1211
1212
1213
1214
1215
1216
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
1228
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
1239
1240
1241
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
1254
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
1267
1268
1269
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
1284
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
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
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
1351
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
1366
1367
1368
1369
1370
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
1387
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
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
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
1484
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
1500
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
1510
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
1519
1520
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
1529
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
1538
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
1546
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
1555
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
1564
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
1573
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
1582
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
1591
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
1600
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
1609
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
1618
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:
1631 skipVaruint64(src, DESCENDING != ord);
1632 skipSignificand(src, DESCENDING != ord);
1633 return src.getPosition() - start;
1634 case NEG_MED_MIN:
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:
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:
1654 skipVaruint64(src, DESCENDING != ord);
1655 skipSignificand(src, DESCENDING == ord);
1656 return src.getPosition() - start;
1657 case POS_MED_MIN:
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:
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
1698 do {
1699 header = ord.apply(src.get());
1700 } while (header != TERM);
1701 return src.getPosition() - start;
1702 case BLOB_VAR:
1703
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
1711 do {
1712 header = ord.apply(src.get());
1713 } while (header != TERM);
1714 return src.getPosition() - start;
1715 } else {
1716
1717 src.setPosition(src.getLength());
1718 return src.getPosition() - start;
1719 }
1720 default:
1721 throw unexpectedHeader(header);
1722 }
1723 }
1724
1725
1726
1727
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 }