[6a3a178] | 1 | /*
|
---|
| 2 | * This is a TypeScript port of the original Java version, which was written by
|
---|
| 3 | * Gil Tene as described in
|
---|
| 4 | * https://github.com/HdrHistogram/HdrHistogram
|
---|
| 5 | * and released to the public domain, as explained at
|
---|
| 6 | * http://creativecommons.org/publicdomain/zero/1.0/
|
---|
| 7 | */
|
---|
| 8 | import ByteBuffer from "./ByteBuffer";
|
---|
| 9 |
|
---|
| 10 | const { pow, floor } = Math;
|
---|
| 11 |
|
---|
| 12 | const TWO_POW_7 = pow(2, 7);
|
---|
| 13 | const TWO_POW_14 = pow(2, 14);
|
---|
| 14 | const TWO_POW_21 = pow(2, 21);
|
---|
| 15 | const TWO_POW_28 = pow(2, 28);
|
---|
| 16 | const TWO_POW_35 = pow(2, 35);
|
---|
| 17 | const TWO_POW_42 = pow(2, 42);
|
---|
| 18 | const TWO_POW_49 = pow(2, 49);
|
---|
| 19 | const TWO_POW_56 = pow(2, 56);
|
---|
| 20 |
|
---|
| 21 | /**
|
---|
| 22 | * This class provides encoding and decoding methods for writing and reading
|
---|
| 23 | * ZigZag-encoded LEB128-64b9B-variant (Little Endian Base 128) values to/from a
|
---|
| 24 | * {@link ByteBuffer}. LEB128's variable length encoding provides for using a
|
---|
| 25 | * smaller nuber of bytes for smaller values, and the use of ZigZag encoding
|
---|
| 26 | * allows small (closer to zero) negative values to use fewer bytes. Details
|
---|
| 27 | * on both LEB128 and ZigZag can be readily found elsewhere.
|
---|
| 28 | *
|
---|
| 29 | * The LEB128-64b9B-variant encoding used here diverges from the "original"
|
---|
| 30 | * LEB128 as it extends to 64 bit values: In the original LEB128, a 64 bit
|
---|
| 31 | * value can take up to 10 bytes in the stream, where this variant's encoding
|
---|
| 32 | * of a 64 bit values will max out at 9 bytes.
|
---|
| 33 | *
|
---|
| 34 | * As such, this encoder/decoder should NOT be used for encoding or decoding
|
---|
| 35 | * "standard" LEB128 formats (e.g. Google Protocol Buffers).
|
---|
| 36 | */
|
---|
| 37 | class ZigZagEncoding {
|
---|
| 38 | /**
|
---|
| 39 | * Writes a long value to the given buffer in LEB128 ZigZag encoded format
|
---|
| 40 | * (negative numbers not supported)
|
---|
| 41 | * @param buffer the buffer to write to
|
---|
| 42 | * @param value the value to write to the buffer
|
---|
| 43 | */
|
---|
| 44 | static encode(buffer: ByteBuffer, value: number) {
|
---|
| 45 | if (value >= 0) {
|
---|
| 46 | value = value * 2;
|
---|
| 47 | } else {
|
---|
| 48 | value = -value * 2 - 1;
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | if (value < TWO_POW_7) {
|
---|
| 52 | buffer.put(value);
|
---|
| 53 | } else {
|
---|
| 54 | buffer.put(value | 0x80);
|
---|
| 55 | if (value < TWO_POW_14) {
|
---|
| 56 | buffer.put(floor(value / TWO_POW_7));
|
---|
| 57 | } else {
|
---|
| 58 | buffer.put(floor(value / TWO_POW_7) | 0x80);
|
---|
| 59 | if (value < TWO_POW_21) {
|
---|
| 60 | buffer.put(floor(value / TWO_POW_14));
|
---|
| 61 | } else {
|
---|
| 62 | buffer.put(floor(value / TWO_POW_14) | 0x80);
|
---|
| 63 | if (value < TWO_POW_28) {
|
---|
| 64 | buffer.put(floor(value / TWO_POW_21));
|
---|
| 65 | } else {
|
---|
| 66 | buffer.put(floor(value / TWO_POW_21) | 0x80);
|
---|
| 67 | if (value < TWO_POW_35) {
|
---|
| 68 | buffer.put(floor(value / TWO_POW_28));
|
---|
| 69 | } else {
|
---|
| 70 | buffer.put(floor(value / TWO_POW_28) | 0x80);
|
---|
| 71 | if (value < TWO_POW_42) {
|
---|
| 72 | buffer.put(floor(value / TWO_POW_35));
|
---|
| 73 | } else {
|
---|
| 74 | buffer.put(floor(value / TWO_POW_35) | 0x80);
|
---|
| 75 | if (value < TWO_POW_49) {
|
---|
| 76 | buffer.put(floor(value / TWO_POW_42));
|
---|
| 77 | } else {
|
---|
| 78 | buffer.put(floor(value / TWO_POW_42) | 0x80);
|
---|
| 79 | if (value < TWO_POW_56) {
|
---|
| 80 | buffer.put(floor(value / TWO_POW_49));
|
---|
| 81 | } else {
|
---|
| 82 | // should not happen
|
---|
| 83 | buffer.put(floor(value / TWO_POW_49) + 0x80);
|
---|
| 84 | buffer.put(floor(value / TWO_POW_56));
|
---|
| 85 | }
|
---|
| 86 | }
|
---|
| 87 | }
|
---|
| 88 | }
|
---|
| 89 | }
|
---|
| 90 | }
|
---|
| 91 | }
|
---|
| 92 | }
|
---|
| 93 | }
|
---|
| 94 |
|
---|
| 95 | /**
|
---|
| 96 | * Read an LEB128-64b9B ZigZag encoded long value from the given buffer
|
---|
| 97 | * (negative numbers not supported)
|
---|
| 98 | * @param buffer the buffer to read from
|
---|
| 99 | * @return the value read from the buffer
|
---|
| 100 | */
|
---|
| 101 | static decode(buffer: ByteBuffer): number {
|
---|
| 102 | let v = buffer.get();
|
---|
| 103 | let value = v & 0x7f;
|
---|
| 104 | if ((v & 0x80) != 0) {
|
---|
| 105 | v = buffer.get();
|
---|
| 106 | value += (v & 0x7f) * TWO_POW_7;
|
---|
| 107 | if ((v & 0x80) != 0) {
|
---|
| 108 | v = buffer.get();
|
---|
| 109 | value += (v & 0x7f) * TWO_POW_14;
|
---|
| 110 | if ((v & 0x80) != 0) {
|
---|
| 111 | v = buffer.get();
|
---|
| 112 | value += (v & 0x7f) * TWO_POW_21;
|
---|
| 113 | if ((v & 0x80) != 0) {
|
---|
| 114 | v = buffer.get();
|
---|
| 115 | value += (v & 0x7f) * TWO_POW_28;
|
---|
| 116 | if ((v & 0x80) != 0) {
|
---|
| 117 | v = buffer.get();
|
---|
| 118 | value += (v & 0x7f) * TWO_POW_35;
|
---|
| 119 | if ((v & 0x80) != 0) {
|
---|
| 120 | v = buffer.get();
|
---|
| 121 | value += (v & 0x7f) * TWO_POW_42;
|
---|
| 122 | if ((v & 0x80) != 0) {
|
---|
| 123 | v = buffer.get();
|
---|
| 124 | value += (v & 0x7f) * TWO_POW_49;
|
---|
| 125 | if ((v & 0x80) != 0) {
|
---|
| 126 | v = buffer.get();
|
---|
| 127 | value += (v & 0x7f) * TWO_POW_56;
|
---|
| 128 | }
|
---|
| 129 | }
|
---|
| 130 | }
|
---|
| 131 | }
|
---|
| 132 | }
|
---|
| 133 | }
|
---|
| 134 | }
|
---|
| 135 | }
|
---|
| 136 | if (value % 2 === 0) {
|
---|
| 137 | value = value / 2;
|
---|
| 138 | } else {
|
---|
| 139 | value = -(value + 1) / 2;
|
---|
| 140 | }
|
---|
| 141 |
|
---|
| 142 | return value;
|
---|
| 143 | }
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | export default ZigZagEncoding;
|
---|