ordered-binary 1.5.0 → 1.5.2
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 +43 -24
- package/index.js +40 -24
- package/package.json +1 -1
- package/tests/test.js +18 -0
package/dist/index.cjs
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
require('constants');
|
|
6
|
-
|
|
7
5
|
/*
|
|
8
6
|
control character types:
|
|
9
7
|
1 - metadata
|
|
@@ -16,6 +14,9 @@ control character types:
|
|
|
16
14
|
0 - multipart separator
|
|
17
15
|
> 27 normal string characters
|
|
18
16
|
*/
|
|
17
|
+
/*
|
|
18
|
+
* Convert arbitrary scalar values to buffer bytes with type preservation and type-appropriate ordering
|
|
19
|
+
*/
|
|
19
20
|
|
|
20
21
|
const float64Array = new Float64Array(2);
|
|
21
22
|
const int32Array = new Int32Array(float64Array.buffer, 0, 4);
|
|
@@ -125,11 +126,20 @@ function writeKey(key, target, position, inSequence) {
|
|
|
125
126
|
let asFloat = Number(key);
|
|
126
127
|
if (BigInt(asFloat) > key) {
|
|
127
128
|
float64Array[0] = asFloat;
|
|
128
|
-
if (
|
|
129
|
-
int32Array[0]
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
if (asFloat > 0) {
|
|
130
|
+
if (int32Array[0])
|
|
131
|
+
int32Array[0]--;
|
|
132
|
+
else {
|
|
133
|
+
int32Array[1]--;
|
|
134
|
+
int32Array[0] = 0xffffffff;
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
if (int32Array[0] < 0xffffffff)
|
|
138
|
+
int32Array[0]++;
|
|
139
|
+
else {
|
|
140
|
+
int32Array[1]++;
|
|
141
|
+
int32Array[0] = 0;
|
|
142
|
+
}
|
|
133
143
|
}
|
|
134
144
|
asFloat = float64Array[0];
|
|
135
145
|
}
|
|
@@ -138,7 +148,7 @@ function writeKey(key, target, position, inSequence) {
|
|
|
138
148
|
return writeKey(asFloat, target, position, inSequence)
|
|
139
149
|
writeKey(asFloat, target, position, inSequence);
|
|
140
150
|
position += 9; // always increment by 9 if we are adding fractional bits
|
|
141
|
-
let exponent = BigInt((int32Array[1] >> 20) - 1079);
|
|
151
|
+
let exponent = BigInt((int32Array[1] >> 20 & 0x7ff) - 1079);
|
|
142
152
|
let nextByte = difference >> exponent;
|
|
143
153
|
target[position - 1] |= Number(nextByte);
|
|
144
154
|
difference -= nextByte << exponent;
|
|
@@ -167,7 +177,6 @@ function writeKey(key, target, position, inSequence) {
|
|
|
167
177
|
|
|
168
178
|
let position;
|
|
169
179
|
function readKey(buffer, start, end, inSequence) {
|
|
170
|
-
buffer[end] = 0; // make sure it is null terminated
|
|
171
180
|
position = start;
|
|
172
181
|
let controlByte = buffer[position];
|
|
173
182
|
let value;
|
|
@@ -181,11 +190,18 @@ function readKey(buffer, start, end, inSequence) {
|
|
|
181
190
|
} else if (controlByte == 0) {
|
|
182
191
|
value = null;
|
|
183
192
|
} else if (controlByte == 2) {
|
|
184
|
-
value = Symbol.for(
|
|
193
|
+
value = Symbol.for(readStringSafely(buffer, end));
|
|
185
194
|
} else
|
|
186
195
|
return Uint8Array.prototype.slice.call(buffer, start, end)
|
|
187
196
|
} else {
|
|
188
|
-
let dataView
|
|
197
|
+
let dataView;
|
|
198
|
+
try {
|
|
199
|
+
dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2));
|
|
200
|
+
} catch(error) {
|
|
201
|
+
// if it is write at the end of the ArrayBuffer, we may need to retry with the exact remaining bytes
|
|
202
|
+
dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.buffer.byteLength - buffer.byteOffset));
|
|
203
|
+
}
|
|
204
|
+
|
|
189
205
|
let highInt = dataView.getInt32(position) << 4;
|
|
190
206
|
let size = end - position;
|
|
191
207
|
let lowInt;
|
|
@@ -193,7 +209,7 @@ function readKey(buffer, start, end, inSequence) {
|
|
|
193
209
|
lowInt = dataView.getInt32(position + 4);
|
|
194
210
|
highInt |= lowInt >>> 28;
|
|
195
211
|
if (size <= 6) { // clear the last bits
|
|
196
|
-
lowInt &= -
|
|
212
|
+
lowInt &= -0x10000;
|
|
197
213
|
}
|
|
198
214
|
lowInt = lowInt << 4;
|
|
199
215
|
if (size > 8) {
|
|
@@ -214,8 +230,7 @@ function readKey(buffer, start, end, inSequence) {
|
|
|
214
230
|
// convert the float to bigint, and then we will add precision as we enumerate through the
|
|
215
231
|
// extra bytes
|
|
216
232
|
value = BigInt(value);
|
|
217
|
-
let exponent = highInt >> 20;
|
|
218
|
-
// TODO: negatives?
|
|
233
|
+
let exponent = highInt >> 20 & 0x7ff;
|
|
219
234
|
let next_byte = buffer[position - 1] & 0xf;
|
|
220
235
|
value += BigInt(next_byte) << BigInt(exponent - 1079);
|
|
221
236
|
while ((next_byte = buffer[position]) > 0 && position++ < end) {
|
|
@@ -227,15 +242,7 @@ function readKey(buffer, start, end, inSequence) {
|
|
|
227
242
|
if (controlByte == 27) {
|
|
228
243
|
position++;
|
|
229
244
|
}
|
|
230
|
-
value =
|
|
231
|
-
/*let strStart = position
|
|
232
|
-
let strEnd = end
|
|
233
|
-
for (; position < end; position++) {
|
|
234
|
-
if (buffer[position] == 0) {
|
|
235
|
-
break
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
value = buffer.toString('utf8', strStart, position++)*/
|
|
245
|
+
value = readStringSafely(buffer, end);
|
|
239
246
|
}
|
|
240
247
|
while (position < end) {
|
|
241
248
|
if (buffer[position] === 0)
|
|
@@ -364,7 +371,19 @@ const readString =
|
|
|
364
371
|
'getPosition() { return position },' +
|
|
365
372
|
'readString }'))(fromCharCode)) :
|
|
366
373
|
eval(makeStringBuilder());
|
|
367
|
-
|
|
374
|
+
function readStringSafely(source, end) {
|
|
375
|
+
if (source[end] > 0) {
|
|
376
|
+
let previous = source[end];
|
|
377
|
+
try {
|
|
378
|
+
// read string expects a null terminator, that is a 0 or undefined from reading past the end of the buffer, so we
|
|
379
|
+
// have to ensure that, but do so safely, restoring the buffer to its original state
|
|
380
|
+
source[end] = 0;
|
|
381
|
+
return readString(source)
|
|
382
|
+
} finally {
|
|
383
|
+
source[end] = previous;
|
|
384
|
+
}
|
|
385
|
+
} else return readString(source);
|
|
386
|
+
}
|
|
368
387
|
function compareKeys(a, b) {
|
|
369
388
|
// compare with type consistency that matches binary comparison
|
|
370
389
|
if (typeof a == 'object') {
|
package/index.js
CHANGED
|
@@ -14,8 +14,6 @@ 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
|
-
|
|
19
17
|
const float64Array = new Float64Array(2)
|
|
20
18
|
const int32Array = new Int32Array(float64Array.buffer, 0, 4)
|
|
21
19
|
let nullTerminate = false
|
|
@@ -124,11 +122,20 @@ export function writeKey(key, target, position, inSequence) {
|
|
|
124
122
|
let asFloat = Number(key)
|
|
125
123
|
if (BigInt(asFloat) > key) {
|
|
126
124
|
float64Array[0] = asFloat;
|
|
127
|
-
if (
|
|
128
|
-
int32Array[0]
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
125
|
+
if (asFloat > 0) {
|
|
126
|
+
if (int32Array[0])
|
|
127
|
+
int32Array[0]--;
|
|
128
|
+
else {
|
|
129
|
+
int32Array[1]--;
|
|
130
|
+
int32Array[0] = 0xffffffff;
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
if (int32Array[0] < 0xffffffff)
|
|
134
|
+
int32Array[0]++;
|
|
135
|
+
else {
|
|
136
|
+
int32Array[1]++;
|
|
137
|
+
int32Array[0] = 0;
|
|
138
|
+
}
|
|
132
139
|
}
|
|
133
140
|
asFloat = float64Array[0];
|
|
134
141
|
}
|
|
@@ -137,7 +144,7 @@ export function writeKey(key, target, position, inSequence) {
|
|
|
137
144
|
return writeKey(asFloat, target, position, inSequence)
|
|
138
145
|
writeKey(asFloat, target, position, inSequence)
|
|
139
146
|
position += 9; // always increment by 9 if we are adding fractional bits
|
|
140
|
-
let exponent = BigInt((int32Array[1] >> 20) - 1079);
|
|
147
|
+
let exponent = BigInt((int32Array[1] >> 20 & 0x7ff) - 1079);
|
|
141
148
|
let nextByte = difference >> exponent;
|
|
142
149
|
target[position - 1] |= Number(nextByte);
|
|
143
150
|
difference -= nextByte << exponent;
|
|
@@ -166,7 +173,6 @@ export function writeKey(key, target, position, inSequence) {
|
|
|
166
173
|
|
|
167
174
|
let position
|
|
168
175
|
export function readKey(buffer, start, end, inSequence) {
|
|
169
|
-
buffer[end] = 0 // make sure it is null terminated
|
|
170
176
|
position = start
|
|
171
177
|
let controlByte = buffer[position]
|
|
172
178
|
let value
|
|
@@ -180,11 +186,18 @@ export function readKey(buffer, start, end, inSequence) {
|
|
|
180
186
|
} else if (controlByte == 0) {
|
|
181
187
|
value = null
|
|
182
188
|
} else if (controlByte == 2) {
|
|
183
|
-
value = Symbol.for(
|
|
189
|
+
value = Symbol.for(readStringSafely(buffer, end))
|
|
184
190
|
} else
|
|
185
191
|
return Uint8Array.prototype.slice.call(buffer, start, end)
|
|
186
192
|
} else {
|
|
187
|
-
let dataView
|
|
193
|
+
let dataView;
|
|
194
|
+
try {
|
|
195
|
+
dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2))
|
|
196
|
+
} catch(error) {
|
|
197
|
+
// if it is write at the end of the ArrayBuffer, we may need to retry with the exact remaining bytes
|
|
198
|
+
dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.buffer.byteLength - buffer.byteOffset))
|
|
199
|
+
}
|
|
200
|
+
|
|
188
201
|
let highInt = dataView.getInt32(position) << 4
|
|
189
202
|
let size = end - position
|
|
190
203
|
let lowInt
|
|
@@ -192,7 +205,7 @@ export function readKey(buffer, start, end, inSequence) {
|
|
|
192
205
|
lowInt = dataView.getInt32(position + 4)
|
|
193
206
|
highInt |= lowInt >>> 28
|
|
194
207
|
if (size <= 6) { // clear the last bits
|
|
195
|
-
lowInt &= -
|
|
208
|
+
lowInt &= -0x10000
|
|
196
209
|
}
|
|
197
210
|
lowInt = lowInt << 4
|
|
198
211
|
if (size > 8) {
|
|
@@ -213,8 +226,7 @@ export function readKey(buffer, start, end, inSequence) {
|
|
|
213
226
|
// convert the float to bigint, and then we will add precision as we enumerate through the
|
|
214
227
|
// extra bytes
|
|
215
228
|
value = BigInt(value);
|
|
216
|
-
let exponent = highInt >> 20;
|
|
217
|
-
// TODO: negatives?
|
|
229
|
+
let exponent = highInt >> 20 & 0x7ff;
|
|
218
230
|
let next_byte = buffer[position - 1] & 0xf;
|
|
219
231
|
value += BigInt(next_byte) << BigInt(exponent - 1079);
|
|
220
232
|
while ((next_byte = buffer[position]) > 0 && position++ < end) {
|
|
@@ -226,15 +238,7 @@ export function readKey(buffer, start, end, inSequence) {
|
|
|
226
238
|
if (controlByte == 27) {
|
|
227
239
|
position++
|
|
228
240
|
}
|
|
229
|
-
value =
|
|
230
|
-
/*let strStart = position
|
|
231
|
-
let strEnd = end
|
|
232
|
-
for (; position < end; position++) {
|
|
233
|
-
if (buffer[position] == 0) {
|
|
234
|
-
break
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
value = buffer.toString('utf8', strStart, position++)*/
|
|
241
|
+
value = readStringSafely(buffer, end)
|
|
238
242
|
}
|
|
239
243
|
while (position < end) {
|
|
240
244
|
if (buffer[position] === 0)
|
|
@@ -363,7 +367,19 @@ const readString =
|
|
|
363
367
|
'getPosition() { return position },' +
|
|
364
368
|
'readString }'))(fromCharCode)) :
|
|
365
369
|
eval(makeStringBuilder())
|
|
366
|
-
|
|
370
|
+
function readStringSafely(source, end) {
|
|
371
|
+
if (source[end] > 0) {
|
|
372
|
+
let previous = source[end]
|
|
373
|
+
try {
|
|
374
|
+
// read string expects a null terminator, that is a 0 or undefined from reading past the end of the buffer, so we
|
|
375
|
+
// have to ensure that, but do so safely, restoring the buffer to its original state
|
|
376
|
+
source[end] = 0
|
|
377
|
+
return readString(source)
|
|
378
|
+
} finally {
|
|
379
|
+
source[end] = previous
|
|
380
|
+
}
|
|
381
|
+
} else return readString(source);
|
|
382
|
+
}
|
|
367
383
|
export function compareKeys(a, b) {
|
|
368
384
|
// compare with type consistency that matches binary comparison
|
|
369
385
|
if (typeof a == 'object') {
|
package/package.json
CHANGED
package/tests/test.js
CHANGED
|
@@ -27,6 +27,7 @@ suite('key buffers', () => {
|
|
|
27
27
|
assert.strictEqual(fromBufferKey(toBufferKey(-4)), -4)
|
|
28
28
|
assert.strictEqual(fromBufferKey(toBufferKey(3.4)), 3.4)
|
|
29
29
|
assert.strictEqual(fromBufferKey(toBufferKey(Math.PI)), Math.PI)
|
|
30
|
+
assert.strictEqual(fromBufferKey(toBufferKey(2002225)), 2002225)
|
|
30
31
|
assert.strictEqual(fromBufferKey(toBufferKey(9377288)), 9377288)
|
|
31
32
|
assert.strictEqual(fromBufferKey(toBufferKey(1503579323825)), 1503579323825)
|
|
32
33
|
assert.strictEqual(fromBufferKey(toBufferKey(1503579323825.3523532)), 1503579323825.3523532)
|
|
@@ -35,6 +36,18 @@ suite('key buffers', () => {
|
|
|
35
36
|
assert.strictEqual(fromBufferKey(toBufferKey(-0.00005032)), -0.00005032)
|
|
36
37
|
assert.strictEqual(fromBufferKey(toBufferKey(0.00000000000000000000000005431)), 0.00000000000000000000000005431)
|
|
37
38
|
})
|
|
39
|
+
test('within buffer equivalence', () => {
|
|
40
|
+
let buffer = Buffer.alloc(1024, 0xff);
|
|
41
|
+
let length = writeKey(2002225, buffer, 0);
|
|
42
|
+
let position = length;
|
|
43
|
+
buffer[position++] = 0xff;
|
|
44
|
+
buffer[position++] = 0xff;
|
|
45
|
+
assert.strictEqual(readKey(buffer, 0, length), 2002225);
|
|
46
|
+
length = writeKey('hello, world', buffer, 0);
|
|
47
|
+
assert.strictEqual(readKey(buffer, 0, length), 'hello, world');
|
|
48
|
+
// ensure that reading the string didn't modify the buffer after the string (or is restored at least)
|
|
49
|
+
assert.strictEqual(buffer[length], 0xff);
|
|
50
|
+
});
|
|
38
51
|
test('number comparison', () => {
|
|
39
52
|
assertBufferComparison(toBufferKey(4), toBufferKey(5))
|
|
40
53
|
assertBufferComparison(toBufferKey(1503579323824), toBufferKey(1503579323825))
|
|
@@ -47,6 +60,7 @@ suite('key buffers', () => {
|
|
|
47
60
|
assertBufferComparison(toBufferKey(-5236532532532), toBufferKey(-5236532532531))
|
|
48
61
|
})
|
|
49
62
|
test('bigint equivalence', () => {
|
|
63
|
+
assert.strictEqual(fromBufferKey(toBufferKey(-35913040084491349n)), -35913040084491349n)
|
|
50
64
|
assert.strictEqual(fromBufferKey(toBufferKey(6135421331404949076605986n)), 6135421331404949076605986n)
|
|
51
65
|
assert.strictEqual(fromBufferKey(toBufferKey(0xfffffffffffffffffffffn)), 0xfffffffffffffffffffffn)
|
|
52
66
|
assert.strictEqual(fromBufferKey(toBufferKey(12345678901234567890n)), 12345678901234567890n)
|
|
@@ -60,12 +74,16 @@ suite('key buffers', () => {
|
|
|
60
74
|
num *= BigInt(Math.floor(random() * 3 + 1));
|
|
61
75
|
num -= BigInt(Math.floor(random() * 1000));
|
|
62
76
|
assert.strictEqual(BigInt(fromBufferKey(toBufferKey(num))), num)
|
|
77
|
+
assert.strictEqual(BigInt(fromBufferKey(toBufferKey(-num))), -num)
|
|
63
78
|
}
|
|
64
79
|
assert.strictEqual(fromBufferKey(toBufferKey(-352n)), -352)
|
|
65
80
|
})
|
|
66
81
|
test('bigint comparison', () => {
|
|
67
82
|
assertBufferComparison(toBufferKey(0xfffffffffffffffffffffn), toBufferKey(0x100fffffffffffffffffffn))
|
|
68
83
|
assertBufferComparison(toBufferKey(12345678901234567890), toBufferKey(12345678901234567890n))
|
|
84
|
+
assertBufferComparison(toBufferKey(6135421331404949076605986n), toBufferKey(6135421331404949076605987n))
|
|
85
|
+
assertBufferComparison(toBufferKey(-6135421331404949076605986n), toBufferKey(-6135421331404949076605985n))
|
|
86
|
+
assertBufferComparison(toBufferKey(-35913040084491349n), toBufferKey(-35913040084491348n))
|
|
69
87
|
})
|
|
70
88
|
|
|
71
89
|
test('string equivalence', () => {
|