bson 5.4.0 → 5.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/bson.d.ts +20 -0
- package/lib/bson.bundle.js +117 -68
- package/lib/bson.bundle.js.map +1 -1
- package/lib/bson.cjs +117 -68
- package/lib/bson.cjs.map +1 -1
- package/lib/bson.mjs +117 -68
- package/lib/bson.mjs.map +1 -1
- package/lib/bson.rn.cjs +117 -68
- package/lib/bson.rn.cjs.map +1 -1
- package/package.json +1 -1
- package/src/decimal128.ts +165 -84
package/package.json
CHANGED
package/src/decimal128.ts
CHANGED
|
@@ -158,8 +158,35 @@ export class Decimal128 extends BSONValue {
|
|
|
158
158
|
* @param representation - a numeric string representation.
|
|
159
159
|
*/
|
|
160
160
|
static fromString(representation: string): Decimal128 {
|
|
161
|
+
return Decimal128._fromString(representation, { allowRounding: false });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Create a Decimal128 instance from a string representation, allowing for rounding to 34
|
|
166
|
+
* significant digits
|
|
167
|
+
*
|
|
168
|
+
* @example Example of a number that will be rounded
|
|
169
|
+
* ```ts
|
|
170
|
+
* > let d = Decimal128.fromString('37.499999999999999196428571428571375')
|
|
171
|
+
* Uncaught:
|
|
172
|
+
* BSONError: "37.499999999999999196428571428571375" is not a valid Decimal128 string - inexact rounding
|
|
173
|
+
* at invalidErr (/home/wajames/js-bson/lib/bson.cjs:1402:11)
|
|
174
|
+
* at Decimal128.fromStringInternal (/home/wajames/js-bson/lib/bson.cjs:1633:25)
|
|
175
|
+
* at Decimal128.fromString (/home/wajames/js-bson/lib/bson.cjs:1424:27)
|
|
176
|
+
*
|
|
177
|
+
* > d = Decimal128.fromStringWithRounding('37.499999999999999196428571428571375')
|
|
178
|
+
* new Decimal128("37.49999999999999919642857142857138")
|
|
179
|
+
* ```
|
|
180
|
+
* @param representation - a numeric string representation.
|
|
181
|
+
*/
|
|
182
|
+
static fromStringWithRounding(representation: string): Decimal128 {
|
|
183
|
+
return Decimal128._fromString(representation, { allowRounding: true });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private static _fromString(representation: string, options: { allowRounding: boolean }) {
|
|
161
187
|
// Parse state tracking
|
|
162
188
|
let isNegative = false;
|
|
189
|
+
let sawSign = false;
|
|
163
190
|
let sawRadix = false;
|
|
164
191
|
let foundNonZero = false;
|
|
165
192
|
|
|
@@ -180,15 +207,11 @@ export class Decimal128 extends BSONValue {
|
|
|
180
207
|
let nDigitsStored = 0;
|
|
181
208
|
// Insertion pointer for digits
|
|
182
209
|
let digitsInsert = 0;
|
|
183
|
-
// The index of the first non-zero digit
|
|
184
|
-
let firstDigit = 0;
|
|
185
210
|
// The index of the last digit
|
|
186
211
|
let lastDigit = 0;
|
|
187
212
|
|
|
188
213
|
// Exponent
|
|
189
214
|
let exponent = 0;
|
|
190
|
-
// loop index over array
|
|
191
|
-
let i = 0;
|
|
192
215
|
// The high 17 digits of the significand
|
|
193
216
|
let significandHigh = new Long(0, 0);
|
|
194
217
|
// The low 17 digits of the significand
|
|
@@ -241,6 +264,7 @@ export class Decimal128 extends BSONValue {
|
|
|
241
264
|
|
|
242
265
|
// Get the negative or positive sign
|
|
243
266
|
if (representation[index] === '+' || representation[index] === '-') {
|
|
267
|
+
sawSign = true;
|
|
244
268
|
isNegative = representation[index++] === '-';
|
|
245
269
|
}
|
|
246
270
|
|
|
@@ -263,7 +287,7 @@ export class Decimal128 extends BSONValue {
|
|
|
263
287
|
continue;
|
|
264
288
|
}
|
|
265
289
|
|
|
266
|
-
if (nDigitsStored <
|
|
290
|
+
if (nDigitsStored < MAX_DIGITS) {
|
|
267
291
|
if (representation[index] !== '0' || foundNonZero) {
|
|
268
292
|
if (!foundNonZero) {
|
|
269
293
|
firstNonZero = nDigitsRead;
|
|
@@ -307,11 +331,7 @@ export class Decimal128 extends BSONValue {
|
|
|
307
331
|
|
|
308
332
|
// Done reading input
|
|
309
333
|
// Find first non-zero digit in digits
|
|
310
|
-
firstDigit = 0;
|
|
311
|
-
|
|
312
334
|
if (!nDigitsStored) {
|
|
313
|
-
firstDigit = 0;
|
|
314
|
-
lastDigit = 0;
|
|
315
335
|
digits[0] = 0;
|
|
316
336
|
nDigits = 1;
|
|
317
337
|
nDigitsStored = 1;
|
|
@@ -320,7 +340,11 @@ export class Decimal128 extends BSONValue {
|
|
|
320
340
|
lastDigit = nDigitsStored - 1;
|
|
321
341
|
significantDigits = nDigits;
|
|
322
342
|
if (significantDigits !== 1) {
|
|
323
|
-
while (
|
|
343
|
+
while (
|
|
344
|
+
representation[
|
|
345
|
+
firstNonZero + significantDigits - 1 + Number(sawSign) + Number(sawRadix)
|
|
346
|
+
] === '0'
|
|
347
|
+
) {
|
|
324
348
|
significantDigits = significantDigits - 1;
|
|
325
349
|
}
|
|
326
350
|
}
|
|
@@ -331,7 +355,7 @@ export class Decimal128 extends BSONValue {
|
|
|
331
355
|
// to represent user input
|
|
332
356
|
|
|
333
357
|
// Overflow prevention
|
|
334
|
-
if (exponent <= radixPosition && radixPosition
|
|
358
|
+
if (exponent <= radixPosition && radixPosition > exponent + (1 << 14)) {
|
|
335
359
|
exponent = EXPONENT_MIN;
|
|
336
360
|
} else {
|
|
337
361
|
exponent = exponent - radixPosition;
|
|
@@ -341,11 +365,9 @@ export class Decimal128 extends BSONValue {
|
|
|
341
365
|
while (exponent > EXPONENT_MAX) {
|
|
342
366
|
// Shift exponent to significand and decrease
|
|
343
367
|
lastDigit = lastDigit + 1;
|
|
344
|
-
|
|
345
|
-
if (lastDigit - firstDigit > MAX_DIGITS) {
|
|
368
|
+
if (lastDigit >= MAX_DIGITS) {
|
|
346
369
|
// Check if we have a zero then just hard clamp, otherwise fail
|
|
347
|
-
|
|
348
|
-
if (digitsString.match(/^0+$/)) {
|
|
370
|
+
if (significantDigits === 0) {
|
|
349
371
|
exponent = EXPONENT_MAX;
|
|
350
372
|
break;
|
|
351
373
|
}
|
|
@@ -355,86 +377,146 @@ export class Decimal128 extends BSONValue {
|
|
|
355
377
|
exponent = exponent - 1;
|
|
356
378
|
}
|
|
357
379
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
380
|
+
if (options.allowRounding) {
|
|
381
|
+
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
|
|
382
|
+
// Shift last digit. can only do this if < significant digits than # stored.
|
|
383
|
+
if (lastDigit === 0 && significantDigits < nDigitsStored) {
|
|
384
|
+
exponent = EXPONENT_MIN;
|
|
385
|
+
significantDigits = 0;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
365
388
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
389
|
+
if (nDigitsStored < nDigits) {
|
|
390
|
+
// adjust to match digits not stored
|
|
391
|
+
nDigits = nDigits - 1;
|
|
392
|
+
} else {
|
|
393
|
+
// adjust to round
|
|
394
|
+
lastDigit = lastDigit - 1;
|
|
395
|
+
}
|
|
373
396
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
397
|
+
if (exponent < EXPONENT_MAX) {
|
|
398
|
+
exponent = exponent + 1;
|
|
399
|
+
} else {
|
|
400
|
+
// Check if we have a zero then just hard clamp, otherwise fail
|
|
401
|
+
const digitsString = digits.join('');
|
|
402
|
+
if (digitsString.match(/^0+$/)) {
|
|
403
|
+
exponent = EXPONENT_MAX;
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
invalidErr(representation, 'overflow');
|
|
382
407
|
}
|
|
383
|
-
invalidErr(representation, 'overflow');
|
|
384
408
|
}
|
|
385
|
-
}
|
|
386
409
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
410
|
+
// Round
|
|
411
|
+
// We've normalized the exponent, but might still need to round.
|
|
412
|
+
if (lastDigit + 1 < significantDigits) {
|
|
413
|
+
let endOfString = nDigitsRead;
|
|
414
|
+
|
|
415
|
+
// If we have seen a radix point, 'string' is 1 longer than we have
|
|
416
|
+
// documented with ndigits_read, so inc the position of the first nonzero
|
|
417
|
+
// digit and the position that digits are read to.
|
|
418
|
+
if (sawRadix) {
|
|
419
|
+
firstNonZero = firstNonZero + 1;
|
|
420
|
+
endOfString = endOfString + 1;
|
|
421
|
+
}
|
|
422
|
+
// if negative, we need to increment again to account for - sign at start.
|
|
423
|
+
if (sawSign) {
|
|
424
|
+
firstNonZero = firstNonZero + 1;
|
|
425
|
+
endOfString = endOfString + 1;
|
|
426
|
+
}
|
|
404
427
|
|
|
405
|
-
|
|
406
|
-
|
|
428
|
+
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10);
|
|
429
|
+
let roundBit = 0;
|
|
430
|
+
|
|
431
|
+
if (roundDigit >= 5) {
|
|
432
|
+
roundBit = 1;
|
|
433
|
+
if (roundDigit === 5) {
|
|
434
|
+
roundBit = digits[lastDigit] % 2 === 1 ? 1 : 0;
|
|
435
|
+
for (let i = firstNonZero + lastDigit + 2; i < endOfString; i++) {
|
|
436
|
+
if (parseInt(representation[i], 10)) {
|
|
437
|
+
roundBit = 1;
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
407
443
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
444
|
+
if (roundBit) {
|
|
445
|
+
let dIdx = lastDigit;
|
|
446
|
+
|
|
447
|
+
for (; dIdx >= 0; dIdx--) {
|
|
448
|
+
if (++digits[dIdx] > 9) {
|
|
449
|
+
digits[dIdx] = 0;
|
|
450
|
+
|
|
451
|
+
// overflowed most significant digit
|
|
452
|
+
if (dIdx === 0) {
|
|
453
|
+
if (exponent < EXPONENT_MAX) {
|
|
454
|
+
exponent = exponent + 1;
|
|
455
|
+
digits[dIdx] = 1;
|
|
456
|
+
} else {
|
|
457
|
+
return new Decimal128(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
} else {
|
|
415
461
|
break;
|
|
416
462
|
}
|
|
417
463
|
}
|
|
418
464
|
}
|
|
419
465
|
}
|
|
466
|
+
} else {
|
|
467
|
+
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
|
|
468
|
+
// Shift last digit. can only do this if < significant digits than # stored.
|
|
469
|
+
if (lastDigit === 0) {
|
|
470
|
+
if (significantDigits === 0) {
|
|
471
|
+
exponent = EXPONENT_MIN;
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
420
474
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
for (; dIdx >= 0; dIdx--) {
|
|
425
|
-
if (++digits[dIdx] > 9) {
|
|
426
|
-
digits[dIdx] = 0;
|
|
475
|
+
invalidErr(representation, 'exponent underflow');
|
|
476
|
+
}
|
|
427
477
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
return new Decimal128(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
478
|
+
if (nDigitsStored < nDigits) {
|
|
479
|
+
if (
|
|
480
|
+
representation[nDigits - 1 + Number(sawSign) + Number(sawRadix)] !== '0' &&
|
|
481
|
+
significantDigits !== 0
|
|
482
|
+
) {
|
|
483
|
+
invalidErr(representation, 'inexact rounding');
|
|
437
484
|
}
|
|
485
|
+
// adjust to match digits not stored
|
|
486
|
+
nDigits = nDigits - 1;
|
|
487
|
+
} else {
|
|
488
|
+
if (digits[lastDigit] !== 0) {
|
|
489
|
+
invalidErr(representation, 'inexact rounding');
|
|
490
|
+
}
|
|
491
|
+
// adjust to round
|
|
492
|
+
lastDigit = lastDigit - 1;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (exponent < EXPONENT_MAX) {
|
|
496
|
+
exponent = exponent + 1;
|
|
497
|
+
} else {
|
|
498
|
+
invalidErr(representation, 'overflow');
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Round
|
|
503
|
+
// We've normalized the exponent, but might still need to round.
|
|
504
|
+
if (lastDigit + 1 < significantDigits) {
|
|
505
|
+
// If we have seen a radix point, 'string' is 1 longer than we have
|
|
506
|
+
// documented with ndigits_read, so inc the position of the first nonzero
|
|
507
|
+
// digit and the position that digits are read to.
|
|
508
|
+
if (sawRadix) {
|
|
509
|
+
firstNonZero = firstNonZero + 1;
|
|
510
|
+
}
|
|
511
|
+
// if saw sign, we need to increment again to account for - or + sign at start.
|
|
512
|
+
if (sawSign) {
|
|
513
|
+
firstNonZero = firstNonZero + 1;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10);
|
|
517
|
+
|
|
518
|
+
if (roundDigit !== 0) {
|
|
519
|
+
invalidErr(representation, 'inexact rounding');
|
|
438
520
|
}
|
|
439
521
|
}
|
|
440
522
|
}
|
|
@@ -449,8 +531,8 @@ export class Decimal128 extends BSONValue {
|
|
|
449
531
|
if (significantDigits === 0) {
|
|
450
532
|
significandHigh = Long.fromNumber(0);
|
|
451
533
|
significandLow = Long.fromNumber(0);
|
|
452
|
-
} else if (lastDigit
|
|
453
|
-
let dIdx =
|
|
534
|
+
} else if (lastDigit < 17) {
|
|
535
|
+
let dIdx = 0;
|
|
454
536
|
significandLow = Long.fromNumber(digits[dIdx++]);
|
|
455
537
|
significandHigh = new Long(0, 0);
|
|
456
538
|
|
|
@@ -459,7 +541,7 @@ export class Decimal128 extends BSONValue {
|
|
|
459
541
|
significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
|
|
460
542
|
}
|
|
461
543
|
} else {
|
|
462
|
-
let dIdx =
|
|
544
|
+
let dIdx = 0;
|
|
463
545
|
significandHigh = Long.fromNumber(digits[dIdx++]);
|
|
464
546
|
|
|
465
547
|
for (; dIdx <= lastDigit - 17; dIdx++) {
|
|
@@ -539,7 +621,6 @@ export class Decimal128 extends BSONValue {
|
|
|
539
621
|
// Return the new Decimal128
|
|
540
622
|
return new Decimal128(buffer);
|
|
541
623
|
}
|
|
542
|
-
|
|
543
624
|
/** Create a string representation of the raw Decimal128 value */
|
|
544
625
|
toString(): string {
|
|
545
626
|
// Note: bits in this routine are referred to starting at 0,
|