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 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 (int32Array[0])
129
- int32Array[0]--;
130
- else {
131
- int32Array[1]--;
132
- int32Array[0] = 0xffffffff;
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(readString(buffer));
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 = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2));
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 &= -0x1000;
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 = readString(buffer);
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 (int32Array[0])
128
- int32Array[0]--;
129
- else {
130
- int32Array[1]--;
131
- int32Array[0] = 0xffffffff;
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(readString(buffer))
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 = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2))
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 &= -0x1000
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 = readString(buffer)
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ordered-binary",
3
3
  "author": "Kris Zyp",
4
- "version": "1.5.0",
4
+ "version": "1.5.2",
5
5
  "description": "Conversion of JavaScript primitives to and from Buffer with binary order matching natural primitive order",
6
6
  "license": "MIT",
7
7
  "repository": {
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', () => {