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 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
- return writeKey(Number(key), target, position, inSequence)
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
- if (controlByte < 8) {
149
- position++;
150
- if (controlByte == 6) {
151
- value = false;
152
- } else if (controlByte == 7) {
153
- value = true;
154
- } else if (controlByte == 0) {
155
- value = null;
156
- } else if (controlByte == 2) {
157
- value = Symbol.for(readString(buffer));
158
- } else
159
- return Uint8Array.prototype.slice.call(buffer, start, end)
160
- } else {
161
- let dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2));
162
- let highInt = dataView.getInt32(position) << 4;
163
- let size = end - position;
164
- let lowInt;
165
- if (size > 4) {
166
- lowInt = dataView.getInt32(position + 4);
167
- highInt |= lowInt >>> 28;
168
- if (size <= 6) { // clear the last bits
169
- lowInt &= -0x1000;
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
- lowInt = lowInt << 4;
172
- if (size > 8) {
173
- lowInt = lowInt | buffer[position + 8] >> 4;
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
- return writeKey(Number(key), target, position, inSequence)
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
- if (controlByte < 8) {
145
- position++
146
- if (controlByte == 6) {
147
- value = false
148
- } else if (controlByte == 7) {
149
- value = true
150
- } else if (controlByte == 0) {
151
- value = null
152
- } else if (controlByte == 2) {
153
- value = Symbol.for(readString(buffer))
154
- } else
155
- return Uint8Array.prototype.slice.call(buffer, start, end)
156
- } else {
157
- let dataView = buffer.dataView || (buffer.dataView = new DataView(buffer.buffer, buffer.byteOffset, ((buffer.byteLength + 3) >> 2) << 2))
158
- let highInt = dataView.getInt32(position) << 4
159
- let size = end - position
160
- let lowInt
161
- if (size > 4) {
162
- lowInt = dataView.getInt32(position + 4)
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
- lowInt = lowInt << 4
168
- if (size > 8) {
169
- lowInt = lowInt | buffer[position + 8] >> 4
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ordered-binary",
3
3
  "author": "Kris Zyp",
4
- "version": "1.4.1",
4
+ "version": "1.5.1",
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
@@ -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')