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 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
- return writeKey(Number(key), target, position, inSequence)
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
- 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;
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
- lowInt = lowInt << 4;
172
- if (size > 8) {
173
- lowInt = lowInt | buffer[position + 8] >> 4;
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
- return writeKey(Number(key), target, position, inSequence)
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
- 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
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
- lowInt = lowInt << 4
168
- if (size > 8) {
169
- lowInt = lowInt | buffer[position + 8] >> 4
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
@@ -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.0",
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,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')