ordered-binary 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +80 -41
- package/index.js +80 -38
- package/package.json +1 -1
- package/tests/test.js +28 -0
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
require('constants');
|
|
6
|
+
|
|
5
7
|
/*
|
|
6
8
|
control character types:
|
|
7
9
|
1 - metadata
|
|
@@ -14,9 +16,6 @@ control character types:
|
|
|
14
16
|
0 - multipart separator
|
|
15
17
|
> 27 normal string characters
|
|
16
18
|
*/
|
|
17
|
-
/*
|
|
18
|
-
* Convert arbitrary scalar values to buffer bytes with type preservation and type-appropriate ordering
|
|
19
|
-
*/
|
|
20
19
|
|
|
21
20
|
const float64Array = new Float64Array(2);
|
|
22
21
|
const int32Array = new Int32Array(float64Array.buffer, 0, 4);
|
|
@@ -114,7 +113,7 @@ function writeKey(key, target, position, inSequence) {
|
|
|
114
113
|
position += key.length;
|
|
115
114
|
break
|
|
116
115
|
} else {
|
|
117
|
-
throw new Error('Unable to serialize object as a key')
|
|
116
|
+
throw new Error('Unable to serialize object as a key: ' + JSON.stringify(key))
|
|
118
117
|
}
|
|
119
118
|
} else // null
|
|
120
119
|
target[position++] = 0;
|
|
@@ -123,7 +122,35 @@ function writeKey(key, target, position, inSequence) {
|
|
|
123
122
|
targetView.setUint32(position++, key ? 7 : 6, true);
|
|
124
123
|
return position
|
|
125
124
|
case 'bigint':
|
|
126
|
-
|
|
125
|
+
let asFloat = Number(key);
|
|
126
|
+
if (BigInt(asFloat) > key) {
|
|
127
|
+
float64Array[0] = asFloat;
|
|
128
|
+
if (int32Array[0])
|
|
129
|
+
int32Array[0]--;
|
|
130
|
+
else {
|
|
131
|
+
int32Array[1]--;
|
|
132
|
+
int32Array[0] = 0xffffffff;
|
|
133
|
+
}
|
|
134
|
+
asFloat = float64Array[0];
|
|
135
|
+
}
|
|
136
|
+
let difference = key - BigInt(asFloat);
|
|
137
|
+
if (difference === 0n)
|
|
138
|
+
return writeKey(asFloat, target, position, inSequence)
|
|
139
|
+
writeKey(asFloat, target, position, inSequence);
|
|
140
|
+
position += 9; // always increment by 9 if we are adding fractional bits
|
|
141
|
+
let exponent = BigInt((int32Array[1] >> 20) - 1079);
|
|
142
|
+
let nextByte = difference >> exponent;
|
|
143
|
+
target[position - 1] |= Number(nextByte);
|
|
144
|
+
difference -= nextByte << exponent;
|
|
145
|
+
let first = true;
|
|
146
|
+
while (difference || first) {
|
|
147
|
+
first = false;
|
|
148
|
+
exponent -= 7n;
|
|
149
|
+
let nextByte = difference >> exponent;
|
|
150
|
+
target[position++] = Number(nextByte) | 0x80;
|
|
151
|
+
difference -= nextByte << exponent;
|
|
152
|
+
}
|
|
153
|
+
return position;
|
|
127
154
|
case 'undefined':
|
|
128
155
|
return position
|
|
129
156
|
// undefined is interpreted as the absence of a key, signified by zero length
|
|
@@ -145,45 +172,57 @@ function readKey(buffer, start, end, inSequence) {
|
|
|
145
172
|
let controlByte = buffer[position];
|
|
146
173
|
let value;
|
|
147
174
|
if (controlByte < 24) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
175
|
+
if (controlByte < 8) {
|
|
176
|
+
position++;
|
|
177
|
+
if (controlByte == 6) {
|
|
178
|
+
value = false;
|
|
179
|
+
} else if (controlByte == 7) {
|
|
180
|
+
value = true;
|
|
181
|
+
} else if (controlByte == 0) {
|
|
182
|
+
value = null;
|
|
183
|
+
} else if (controlByte == 2) {
|
|
184
|
+
value = Symbol.for(readString(buffer));
|
|
185
|
+
} else
|
|
186
|
+
return Uint8Array.prototype.slice.call(buffer, start, end)
|
|
187
|
+
} else {
|
|
188
|
+
let dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2));
|
|
189
|
+
let highInt = dataView.getInt32(position) << 4;
|
|
190
|
+
let size = end - position;
|
|
191
|
+
let lowInt;
|
|
192
|
+
if (size > 4) {
|
|
193
|
+
lowInt = dataView.getInt32(position + 4);
|
|
194
|
+
highInt |= lowInt >>> 28;
|
|
195
|
+
if (size <= 6) { // clear the last bits
|
|
196
|
+
lowInt &= -0x1000;
|
|
197
|
+
}
|
|
198
|
+
lowInt = lowInt << 4;
|
|
199
|
+
if (size > 8) {
|
|
200
|
+
lowInt = lowInt | buffer[position + 8] >> 4;
|
|
201
|
+
}
|
|
202
|
+
} else
|
|
203
|
+
lowInt = 0;
|
|
204
|
+
if (controlByte < 16) {
|
|
205
|
+
// negative gets negated
|
|
206
|
+
highInt = highInt ^ 0x7fffffff;
|
|
207
|
+
lowInt = ~lowInt;
|
|
170
208
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
209
|
+
int32Array[1] = highInt;
|
|
210
|
+
int32Array[0] = lowInt;
|
|
211
|
+
value = float64Array[0];
|
|
212
|
+
position += 9;
|
|
213
|
+
if (size > 9 && buffer[position] > 0) {
|
|
214
|
+
// convert the float to bigint, and then we will add precision as we enumerate through the
|
|
215
|
+
// extra bytes
|
|
216
|
+
value = BigInt(value);
|
|
217
|
+
let exponent = highInt >> 20;
|
|
218
|
+
// TODO: negatives?
|
|
219
|
+
let next_byte = buffer[position - 1] & 0xf;
|
|
220
|
+
value += BigInt(next_byte) << BigInt(exponent - 1079);
|
|
221
|
+
while ((next_byte = buffer[position]) > 0 && position++ < end) {
|
|
222
|
+
value += BigInt(next_byte & 0x7f) << BigInt((start - position) * 7 + exponent - 1016);
|
|
223
|
+
}
|
|
174
224
|
}
|
|
175
|
-
} else
|
|
176
|
-
lowInt = 0;
|
|
177
|
-
if (controlByte < 16) {
|
|
178
|
-
// negative gets negated
|
|
179
|
-
highInt = highInt ^ 0x7fffffff;
|
|
180
|
-
lowInt = ~lowInt;
|
|
181
225
|
}
|
|
182
|
-
int32Array[1] = highInt;
|
|
183
|
-
int32Array[0] = lowInt;
|
|
184
|
-
value = float64Array[0];
|
|
185
|
-
position += 9;
|
|
186
|
-
}
|
|
187
226
|
} else {
|
|
188
227
|
if (controlByte == 27) {
|
|
189
228
|
position++;
|
package/index.js
CHANGED
|
@@ -14,6 +14,8 @@ control character types:
|
|
|
14
14
|
* Convert arbitrary scalar values to buffer bytes with type preservation and type-appropriate ordering
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import exp from "constants"
|
|
18
|
+
|
|
17
19
|
const float64Array = new Float64Array(2)
|
|
18
20
|
const int32Array = new Int32Array(float64Array.buffer, 0, 4)
|
|
19
21
|
let nullTerminate = false
|
|
@@ -110,7 +112,7 @@ export function writeKey(key, target, position, inSequence) {
|
|
|
110
112
|
position += key.length
|
|
111
113
|
break
|
|
112
114
|
} else {
|
|
113
|
-
throw new Error('Unable to serialize object as a key')
|
|
115
|
+
throw new Error('Unable to serialize object as a key: ' + JSON.stringify(key))
|
|
114
116
|
}
|
|
115
117
|
} else // null
|
|
116
118
|
target[position++] = 0
|
|
@@ -119,7 +121,35 @@ export function writeKey(key, target, position, inSequence) {
|
|
|
119
121
|
targetView.setUint32(position++, key ? 7 : 6, true)
|
|
120
122
|
return position
|
|
121
123
|
case 'bigint':
|
|
122
|
-
|
|
124
|
+
let asFloat = Number(key)
|
|
125
|
+
if (BigInt(asFloat) > key) {
|
|
126
|
+
float64Array[0] = asFloat;
|
|
127
|
+
if (int32Array[0])
|
|
128
|
+
int32Array[0]--;
|
|
129
|
+
else {
|
|
130
|
+
int32Array[1]--;
|
|
131
|
+
int32Array[0] = 0xffffffff;
|
|
132
|
+
}
|
|
133
|
+
asFloat = float64Array[0];
|
|
134
|
+
}
|
|
135
|
+
let difference = key - BigInt(asFloat);
|
|
136
|
+
if (difference === 0n)
|
|
137
|
+
return writeKey(asFloat, target, position, inSequence)
|
|
138
|
+
writeKey(asFloat, target, position, inSequence)
|
|
139
|
+
position += 9; // always increment by 9 if we are adding fractional bits
|
|
140
|
+
let exponent = BigInt((int32Array[1] >> 20) - 1079);
|
|
141
|
+
let nextByte = difference >> exponent;
|
|
142
|
+
target[position - 1] |= Number(nextByte);
|
|
143
|
+
difference -= nextByte << exponent;
|
|
144
|
+
let first = true;
|
|
145
|
+
while (difference || first) {
|
|
146
|
+
first = false;
|
|
147
|
+
exponent -= 7n;
|
|
148
|
+
let nextByte = difference >> exponent;
|
|
149
|
+
target[position++] = Number(nextByte) | 0x80;
|
|
150
|
+
difference -= nextByte << exponent;
|
|
151
|
+
}
|
|
152
|
+
return position;
|
|
123
153
|
case 'undefined':
|
|
124
154
|
return position
|
|
125
155
|
// undefined is interpreted as the absence of a key, signified by zero length
|
|
@@ -141,45 +171,57 @@ export function readKey(buffer, start, end, inSequence) {
|
|
|
141
171
|
let controlByte = buffer[position]
|
|
142
172
|
let value
|
|
143
173
|
if (controlByte < 24) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
if (controlByte < 8) {
|
|
175
|
+
position++
|
|
176
|
+
if (controlByte == 6) {
|
|
177
|
+
value = false
|
|
178
|
+
} else if (controlByte == 7) {
|
|
179
|
+
value = true
|
|
180
|
+
} else if (controlByte == 0) {
|
|
181
|
+
value = null
|
|
182
|
+
} else if (controlByte == 2) {
|
|
183
|
+
value = Symbol.for(readString(buffer))
|
|
184
|
+
} else
|
|
185
|
+
return Uint8Array.prototype.slice.call(buffer, start, end)
|
|
186
|
+
} else {
|
|
187
|
+
let dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2))
|
|
188
|
+
let highInt = dataView.getInt32(position) << 4
|
|
189
|
+
let size = end - position
|
|
190
|
+
let lowInt
|
|
191
|
+
if (size > 4) {
|
|
192
|
+
lowInt = dataView.getInt32(position + 4)
|
|
193
|
+
highInt |= lowInt >>> 28
|
|
194
|
+
if (size <= 6) { // clear the last bits
|
|
195
|
+
lowInt &= -0x1000
|
|
196
|
+
}
|
|
197
|
+
lowInt = lowInt << 4
|
|
198
|
+
if (size > 8) {
|
|
199
|
+
lowInt = lowInt | buffer[position + 8] >> 4
|
|
200
|
+
}
|
|
201
|
+
} else
|
|
202
|
+
lowInt = 0
|
|
203
|
+
if (controlByte < 16) {
|
|
204
|
+
// negative gets negated
|
|
205
|
+
highInt = highInt ^ 0x7fffffff
|
|
206
|
+
lowInt = ~lowInt
|
|
166
207
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
208
|
+
int32Array[1] = highInt
|
|
209
|
+
int32Array[0] = lowInt
|
|
210
|
+
value = float64Array[0]
|
|
211
|
+
position += 9
|
|
212
|
+
if (size > 9 && buffer[position] > 0) {
|
|
213
|
+
// convert the float to bigint, and then we will add precision as we enumerate through the
|
|
214
|
+
// extra bytes
|
|
215
|
+
value = BigInt(value);
|
|
216
|
+
let exponent = highInt >> 20;
|
|
217
|
+
// TODO: negatives?
|
|
218
|
+
let next_byte = buffer[position - 1] & 0xf;
|
|
219
|
+
value += BigInt(next_byte) << BigInt(exponent - 1079);
|
|
220
|
+
while ((next_byte = buffer[position]) > 0 && position++ < end) {
|
|
221
|
+
value += BigInt(next_byte & 0x7f) << BigInt((start - position) * 7 + exponent - 1016);
|
|
222
|
+
}
|
|
170
223
|
}
|
|
171
|
-
} else
|
|
172
|
-
lowInt = 0
|
|
173
|
-
if (controlByte < 16) {
|
|
174
|
-
// negative gets negated
|
|
175
|
-
highInt = highInt ^ 0x7fffffff
|
|
176
|
-
lowInt = ~lowInt
|
|
177
224
|
}
|
|
178
|
-
int32Array[1] = highInt
|
|
179
|
-
int32Array[0] = lowInt
|
|
180
|
-
value = float64Array[0]
|
|
181
|
-
position += 9
|
|
182
|
-
}
|
|
183
225
|
} else {
|
|
184
226
|
if (controlByte == 27) {
|
|
185
227
|
position++
|
package/package.json
CHANGED
package/tests/test.js
CHANGED
|
@@ -13,6 +13,12 @@ function assertBufferComparison(lesser, greater) {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
//var inspector = require('inspector'); inspector.open(9330, null, true); debugger
|
|
16
|
+
let seed = 0;
|
|
17
|
+
export function random() {
|
|
18
|
+
seed++;
|
|
19
|
+
let a = seed * 15485863;
|
|
20
|
+
return ((a * a * a) % 2038074743) / 2038074743;
|
|
21
|
+
}
|
|
16
22
|
|
|
17
23
|
suite('key buffers', () => {
|
|
18
24
|
|
|
@@ -40,6 +46,28 @@ suite('key buffers', () => {
|
|
|
40
46
|
assertBufferComparison(toBufferKey(-0.001), toBufferKey(-0.000001))
|
|
41
47
|
assertBufferComparison(toBufferKey(-5236532532532), toBufferKey(-5236532532531))
|
|
42
48
|
})
|
|
49
|
+
test('bigint equivalence', () => {
|
|
50
|
+
assert.strictEqual(fromBufferKey(toBufferKey(6135421331404949076605986n)), 6135421331404949076605986n)
|
|
51
|
+
assert.strictEqual(fromBufferKey(toBufferKey(0xfffffffffffffffffffffn)), 0xfffffffffffffffffffffn)
|
|
52
|
+
assert.strictEqual(fromBufferKey(toBufferKey(12345678901234567890n)), 12345678901234567890n)
|
|
53
|
+
assert.deepEqual(fromBufferKey(toBufferKey([12345678901234567890n, 44])), [12345678901234567890n, 44])
|
|
54
|
+
assert.deepEqual(fromBufferKey(toBufferKey(['hi', 12345678901234567890n])), ['hi', 12345678901234567890n])
|
|
55
|
+
assert.deepEqual(fromBufferKey(toBufferKey([6135421331404949076605986n, 'after'])), [6135421331404949076605986n, 'after'])
|
|
56
|
+
assert.strictEqual(fromBufferKey(toBufferKey(132923456789012345678903533235253252353211125n)), 132923456789012345678903533235253252353211125n)
|
|
57
|
+
assert.strictEqual(fromBufferKey(toBufferKey(352n)), 352)
|
|
58
|
+
let num = 5325n
|
|
59
|
+
for (let i = 0; i < 1100; i++) {
|
|
60
|
+
num *= BigInt(Math.floor(random() * 3 + 1));
|
|
61
|
+
num -= BigInt(Math.floor(random() * 1000));
|
|
62
|
+
assert.strictEqual(BigInt(fromBufferKey(toBufferKey(num))), num)
|
|
63
|
+
}
|
|
64
|
+
assert.strictEqual(fromBufferKey(toBufferKey(-352n)), -352)
|
|
65
|
+
})
|
|
66
|
+
test('bigint comparison', () => {
|
|
67
|
+
assertBufferComparison(toBufferKey(0xfffffffffffffffffffffn), toBufferKey(0x100fffffffffffffffffffn))
|
|
68
|
+
assertBufferComparison(toBufferKey(12345678901234567890), toBufferKey(12345678901234567890n))
|
|
69
|
+
})
|
|
70
|
+
|
|
43
71
|
test('string equivalence', () => {
|
|
44
72
|
assert.strictEqual(fromBufferKey(toBufferKey('4')), '4')
|
|
45
73
|
assert.strictEqual(fromBufferKey(toBufferKey('hello')), 'hello')
|