ordered-binary 1.4.1 → 1.5.1
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 +95 -41
- package/index.js +95 -38
- package/package.json +1 -1
- package/tests/test.js +30 -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,44 @@ 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 (asFloat > 0) {
|
|
129
|
+
if (int32Array[0])
|
|
130
|
+
int32Array[0]--;
|
|
131
|
+
else {
|
|
132
|
+
int32Array[1]--;
|
|
133
|
+
int32Array[0] = 0xffffffff;
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
if (int32Array[0] < 0xffffffff)
|
|
137
|
+
int32Array[0]++;
|
|
138
|
+
else {
|
|
139
|
+
int32Array[1]++;
|
|
140
|
+
int32Array[0] = 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
asFloat = float64Array[0];
|
|
144
|
+
}
|
|
145
|
+
let difference = key - BigInt(asFloat);
|
|
146
|
+
if (difference === 0n)
|
|
147
|
+
return writeKey(asFloat, target, position, inSequence)
|
|
148
|
+
writeKey(asFloat, target, position, inSequence);
|
|
149
|
+
position += 9; // always increment by 9 if we are adding fractional bits
|
|
150
|
+
let exponent = BigInt((int32Array[1] >> 20 & 0x7ff) - 1079);
|
|
151
|
+
let nextByte = difference >> exponent;
|
|
152
|
+
target[position - 1] |= Number(nextByte);
|
|
153
|
+
difference -= nextByte << exponent;
|
|
154
|
+
let first = true;
|
|
155
|
+
while (difference || first) {
|
|
156
|
+
first = false;
|
|
157
|
+
exponent -= 7n;
|
|
158
|
+
let nextByte = difference >> exponent;
|
|
159
|
+
target[position++] = Number(nextByte) | 0x80;
|
|
160
|
+
difference -= nextByte << exponent;
|
|
161
|
+
}
|
|
162
|
+
return position;
|
|
127
163
|
case 'undefined':
|
|
128
164
|
return position
|
|
129
165
|
// undefined is interpreted as the absence of a key, signified by zero length
|
|
@@ -145,45 +181,63 @@ function readKey(buffer, start, end, inSequence) {
|
|
|
145
181
|
let controlByte = buffer[position];
|
|
146
182
|
let value;
|
|
147
183
|
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
|
-
|
|
184
|
+
if (controlByte < 8) {
|
|
185
|
+
position++;
|
|
186
|
+
if (controlByte == 6) {
|
|
187
|
+
value = false;
|
|
188
|
+
} else if (controlByte == 7) {
|
|
189
|
+
value = true;
|
|
190
|
+
} else if (controlByte == 0) {
|
|
191
|
+
value = null;
|
|
192
|
+
} else if (controlByte == 2) {
|
|
193
|
+
value = Symbol.for(readString(buffer));
|
|
194
|
+
} else
|
|
195
|
+
return Uint8Array.prototype.slice.call(buffer, start, end)
|
|
196
|
+
} else {
|
|
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
|
+
|
|
205
|
+
let highInt = dataView.getInt32(position) << 4;
|
|
206
|
+
let size = end - position;
|
|
207
|
+
let lowInt;
|
|
208
|
+
if (size > 4) {
|
|
209
|
+
lowInt = dataView.getInt32(position + 4);
|
|
210
|
+
highInt |= lowInt >>> 28;
|
|
211
|
+
if (size <= 6) { // clear the last bits
|
|
212
|
+
lowInt &= -0x1000;
|
|
213
|
+
}
|
|
214
|
+
lowInt = lowInt << 4;
|
|
215
|
+
if (size > 8) {
|
|
216
|
+
lowInt = lowInt | buffer[position + 8] >> 4;
|
|
217
|
+
}
|
|
218
|
+
} else
|
|
219
|
+
lowInt = 0;
|
|
220
|
+
if (controlByte < 16) {
|
|
221
|
+
// negative gets negated
|
|
222
|
+
highInt = highInt ^ 0x7fffffff;
|
|
223
|
+
lowInt = ~lowInt;
|
|
170
224
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
225
|
+
int32Array[1] = highInt;
|
|
226
|
+
int32Array[0] = lowInt;
|
|
227
|
+
value = float64Array[0];
|
|
228
|
+
position += 9;
|
|
229
|
+
if (size > 9 && buffer[position] > 0) {
|
|
230
|
+
// convert the float to bigint, and then we will add precision as we enumerate through the
|
|
231
|
+
// extra bytes
|
|
232
|
+
value = BigInt(value);
|
|
233
|
+
let exponent = highInt >> 20 & 0x7ff;
|
|
234
|
+
let next_byte = buffer[position - 1] & 0xf;
|
|
235
|
+
value += BigInt(next_byte) << BigInt(exponent - 1079);
|
|
236
|
+
while ((next_byte = buffer[position]) > 0 && position++ < end) {
|
|
237
|
+
value += BigInt(next_byte & 0x7f) << BigInt((start - position) * 7 + exponent - 1016);
|
|
238
|
+
}
|
|
174
239
|
}
|
|
175
|
-
} else
|
|
176
|
-
lowInt = 0;
|
|
177
|
-
if (controlByte < 16) {
|
|
178
|
-
// negative gets negated
|
|
179
|
-
highInt = highInt ^ 0x7fffffff;
|
|
180
|
-
lowInt = ~lowInt;
|
|
181
240
|
}
|
|
182
|
-
int32Array[1] = highInt;
|
|
183
|
-
int32Array[0] = lowInt;
|
|
184
|
-
value = float64Array[0];
|
|
185
|
-
position += 9;
|
|
186
|
-
}
|
|
187
241
|
} else {
|
|
188
242
|
if (controlByte == 27) {
|
|
189
243
|
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,44 @@ 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 (asFloat > 0) {
|
|
128
|
+
if (int32Array[0])
|
|
129
|
+
int32Array[0]--;
|
|
130
|
+
else {
|
|
131
|
+
int32Array[1]--;
|
|
132
|
+
int32Array[0] = 0xffffffff;
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
if (int32Array[0] < 0xffffffff)
|
|
136
|
+
int32Array[0]++;
|
|
137
|
+
else {
|
|
138
|
+
int32Array[1]++;
|
|
139
|
+
int32Array[0] = 0;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
asFloat = float64Array[0];
|
|
143
|
+
}
|
|
144
|
+
let difference = key - BigInt(asFloat);
|
|
145
|
+
if (difference === 0n)
|
|
146
|
+
return writeKey(asFloat, target, position, inSequence)
|
|
147
|
+
writeKey(asFloat, target, position, inSequence)
|
|
148
|
+
position += 9; // always increment by 9 if we are adding fractional bits
|
|
149
|
+
let exponent = BigInt((int32Array[1] >> 20 & 0x7ff) - 1079);
|
|
150
|
+
let nextByte = difference >> exponent;
|
|
151
|
+
target[position - 1] |= Number(nextByte);
|
|
152
|
+
difference -= nextByte << exponent;
|
|
153
|
+
let first = true;
|
|
154
|
+
while (difference || first) {
|
|
155
|
+
first = false;
|
|
156
|
+
exponent -= 7n;
|
|
157
|
+
let nextByte = difference >> exponent;
|
|
158
|
+
target[position++] = Number(nextByte) | 0x80;
|
|
159
|
+
difference -= nextByte << exponent;
|
|
160
|
+
}
|
|
161
|
+
return position;
|
|
123
162
|
case 'undefined':
|
|
124
163
|
return position
|
|
125
164
|
// undefined is interpreted as the absence of a key, signified by zero length
|
|
@@ -141,45 +180,63 @@ export function readKey(buffer, start, end, inSequence) {
|
|
|
141
180
|
let controlByte = buffer[position]
|
|
142
181
|
let value
|
|
143
182
|
if (controlByte < 24) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
highInt |= lowInt >>> 28
|
|
164
|
-
if (size <= 6) { // clear the last bits
|
|
165
|
-
lowInt &= -0x1000
|
|
183
|
+
if (controlByte < 8) {
|
|
184
|
+
position++
|
|
185
|
+
if (controlByte == 6) {
|
|
186
|
+
value = false
|
|
187
|
+
} else if (controlByte == 7) {
|
|
188
|
+
value = true
|
|
189
|
+
} else if (controlByte == 0) {
|
|
190
|
+
value = null
|
|
191
|
+
} else if (controlByte == 2) {
|
|
192
|
+
value = Symbol.for(readString(buffer))
|
|
193
|
+
} else
|
|
194
|
+
return Uint8Array.prototype.slice.call(buffer, start, end)
|
|
195
|
+
} else {
|
|
196
|
+
let dataView;
|
|
197
|
+
try {
|
|
198
|
+
dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2))
|
|
199
|
+
} catch(error) {
|
|
200
|
+
// if it is write at the end of the ArrayBuffer, we may need to retry with the exact remaining bytes
|
|
201
|
+
dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, buffer.buffer.byteLength - buffer.byteOffset))
|
|
166
202
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
203
|
+
|
|
204
|
+
let highInt = dataView.getInt32(position) << 4
|
|
205
|
+
let size = end - position
|
|
206
|
+
let lowInt
|
|
207
|
+
if (size > 4) {
|
|
208
|
+
lowInt = dataView.getInt32(position + 4)
|
|
209
|
+
highInt |= lowInt >>> 28
|
|
210
|
+
if (size <= 6) { // clear the last bits
|
|
211
|
+
lowInt &= -0x1000
|
|
212
|
+
}
|
|
213
|
+
lowInt = lowInt << 4
|
|
214
|
+
if (size > 8) {
|
|
215
|
+
lowInt = lowInt | buffer[position + 8] >> 4
|
|
216
|
+
}
|
|
217
|
+
} else
|
|
218
|
+
lowInt = 0
|
|
219
|
+
if (controlByte < 16) {
|
|
220
|
+
// negative gets negated
|
|
221
|
+
highInt = highInt ^ 0x7fffffff
|
|
222
|
+
lowInt = ~lowInt
|
|
223
|
+
}
|
|
224
|
+
int32Array[1] = highInt
|
|
225
|
+
int32Array[0] = lowInt
|
|
226
|
+
value = float64Array[0]
|
|
227
|
+
position += 9
|
|
228
|
+
if (size > 9 && buffer[position] > 0) {
|
|
229
|
+
// convert the float to bigint, and then we will add precision as we enumerate through the
|
|
230
|
+
// extra bytes
|
|
231
|
+
value = BigInt(value);
|
|
232
|
+
let exponent = highInt >> 20 & 0x7ff;
|
|
233
|
+
let next_byte = buffer[position - 1] & 0xf;
|
|
234
|
+
value += BigInt(next_byte) << BigInt(exponent - 1079);
|
|
235
|
+
while ((next_byte = buffer[position]) > 0 && position++ < end) {
|
|
236
|
+
value += BigInt(next_byte & 0x7f) << BigInt((start - position) * 7 + exponent - 1016);
|
|
237
|
+
}
|
|
170
238
|
}
|
|
171
|
-
} else
|
|
172
|
-
lowInt = 0
|
|
173
|
-
if (controlByte < 16) {
|
|
174
|
-
// negative gets negated
|
|
175
|
-
highInt = highInt ^ 0x7fffffff
|
|
176
|
-
lowInt = ~lowInt
|
|
177
239
|
}
|
|
178
|
-
int32Array[1] = highInt
|
|
179
|
-
int32Array[0] = lowInt
|
|
180
|
-
value = float64Array[0]
|
|
181
|
-
position += 9
|
|
182
|
-
}
|
|
183
240
|
} else {
|
|
184
241
|
if (controlByte == 27) {
|
|
185
242
|
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,30 @@ 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(-35913040084491349n)), -35913040084491349n)
|
|
51
|
+
assert.strictEqual(fromBufferKey(toBufferKey(6135421331404949076605986n)), 6135421331404949076605986n)
|
|
52
|
+
assert.strictEqual(fromBufferKey(toBufferKey(0xfffffffffffffffffffffn)), 0xfffffffffffffffffffffn)
|
|
53
|
+
assert.strictEqual(fromBufferKey(toBufferKey(12345678901234567890n)), 12345678901234567890n)
|
|
54
|
+
assert.deepEqual(fromBufferKey(toBufferKey([12345678901234567890n, 44])), [12345678901234567890n, 44])
|
|
55
|
+
assert.deepEqual(fromBufferKey(toBufferKey(['hi', 12345678901234567890n])), ['hi', 12345678901234567890n])
|
|
56
|
+
assert.deepEqual(fromBufferKey(toBufferKey([6135421331404949076605986n, 'after'])), [6135421331404949076605986n, 'after'])
|
|
57
|
+
assert.strictEqual(fromBufferKey(toBufferKey(132923456789012345678903533235253252353211125n)), 132923456789012345678903533235253252353211125n)
|
|
58
|
+
assert.strictEqual(fromBufferKey(toBufferKey(352n)), 352)
|
|
59
|
+
let num = 5325n
|
|
60
|
+
for (let i = 0; i < 1100; i++) {
|
|
61
|
+
num *= BigInt(Math.floor(random() * 3 + 1));
|
|
62
|
+
num -= BigInt(Math.floor(random() * 1000));
|
|
63
|
+
assert.strictEqual(BigInt(fromBufferKey(toBufferKey(num))), num)
|
|
64
|
+
assert.strictEqual(BigInt(fromBufferKey(toBufferKey(-num))), -num)
|
|
65
|
+
}
|
|
66
|
+
assert.strictEqual(fromBufferKey(toBufferKey(-352n)), -352)
|
|
67
|
+
})
|
|
68
|
+
test('bigint comparison', () => {
|
|
69
|
+
assertBufferComparison(toBufferKey(0xfffffffffffffffffffffn), toBufferKey(0x100fffffffffffffffffffn))
|
|
70
|
+
assertBufferComparison(toBufferKey(12345678901234567890), toBufferKey(12345678901234567890n))
|
|
71
|
+
})
|
|
72
|
+
|
|
43
73
|
test('string equivalence', () => {
|
|
44
74
|
assert.strictEqual(fromBufferKey(toBufferKey('4')), '4')
|
|
45
75
|
assert.strictEqual(fromBufferKey(toBufferKey('hello')), 'hello')
|