| 'use strict'; |
| |
| const { |
| MathAbs, |
| MathMax, |
| MathMin, |
| MathPow, |
| MathSign, |
| MathTrunc, |
| NumberIsNaN, |
| NumberMAX_SAFE_INTEGER, |
| NumberMIN_SAFE_INTEGER, |
| } = primordials; |
| |
| const { |
| codes: { |
| ERR_INVALID_ARG_VALUE, |
| }, |
| } = require('internal/errors'); |
| const { kEmptyObject } = require('internal/util'); |
| |
| // https://webidl.spec.whatwg.org/#abstract-opdef-integerpart |
| const integerPart = MathTrunc; |
| |
| /* eslint-disable node-core/non-ascii-character */ |
| // Round x to the nearest integer, choosing the even integer if it lies halfway |
| // between two, and choosing +0 rather than -0. |
| // This is different from Math.round, which rounds to the next integer in the |
| // direction of +∞ when the fraction portion is exactly 0.5. |
| /* eslint-enable node-core/non-ascii-character */ |
| function evenRound(x) { |
| // Convert -0 to +0. |
| const i = integerPart(x) + 0; |
| const reminder = MathAbs(x % 1); |
| const sign = MathSign(i); |
| if (reminder === 0.5) { |
| return i % 2 === 0 ? i : i + sign; |
| } |
| const r = reminder < 0.5 ? i : i + sign; |
| // Convert -0 to +0. |
| if (r === 0) { |
| return 0; |
| } |
| return r; |
| } |
| |
| function pow2(exponent) { |
| // << operates on 32 bit signed integers. |
| if (exponent < 31) { |
| return 1 << exponent; |
| } |
| if (exponent === 31) { |
| return 0x8000_0000; |
| } |
| if (exponent === 32) { |
| return 0x1_0000_0000; |
| } |
| return MathPow(2, exponent); |
| } |
| |
| // https://tc39.es/ecma262/#eqn-modulo |
| // The notation “x modulo y” computes a value k of the same sign as y. |
| function modulo(x, y) { |
| const r = x % y; |
| // Convert -0 to +0. |
| if (r === 0) { |
| return 0; |
| } |
| return r; |
| } |
| |
| // https://webidl.spec.whatwg.org/#abstract-opdef-converttoint |
| function convertToInt(name, value, bitLength, options = kEmptyObject) { |
| const { signed = false, enforceRange = false, clamp = false } = options; |
| |
| let upperBound; |
| let lowerBound; |
| // 1. If bitLength is 64, then: |
| if (bitLength === 64) { |
| // 1.1. Let upperBound be 2^53 − 1. |
| upperBound = NumberMAX_SAFE_INTEGER; |
| // 1.2. If signedness is "unsigned", then let lowerBound be 0. |
| // 1.3. Otherwise let lowerBound be −2^53 + 1. |
| lowerBound = !signed ? 0 : NumberMIN_SAFE_INTEGER; |
| } else if (!signed) { |
| // 2. Otherwise, if signedness is "unsigned", then: |
| // 2.1. Let lowerBound be 0. |
| // 2.2. Let upperBound be 2^bitLength − 1. |
| lowerBound = 0; |
| upperBound = pow2(bitLength) - 1; |
| } else { |
| // 3. Otherwise: |
| // 3.1. Let lowerBound be -2^(bitLength − 1). |
| // 3.2. Let upperBound be 2^(bitLength − 1) − 1. |
| lowerBound = -pow2(bitLength - 1); |
| upperBound = pow2(bitLength - 1) - 1; |
| } |
| |
| // 4. Let x be ? ToNumber(V). |
| let x = +value; |
| // 5. If x is −0, then set x to +0. |
| if (x === 0) { |
| x = 0; |
| } |
| |
| // 6. If the conversion is to an IDL type associated with the [EnforceRange] |
| // extended attribute, then: |
| if (enforceRange) { |
| // 6.1. If x is NaN, +∞, or −∞, then throw a TypeError. |
| if (NumberIsNaN(x) || x === Infinity || x === -Infinity) { |
| throw new ERR_INVALID_ARG_VALUE(name, x); |
| } |
| // 6.2. Set x to IntegerPart(x). |
| x = integerPart(x); |
| |
| // 6.3. If x < lowerBound or x > upperBound, then throw a TypeError. |
| if (x < lowerBound || x > upperBound) { |
| throw new ERR_INVALID_ARG_VALUE(name, x); |
| } |
| |
| // 6.4. Return x. |
| return x; |
| } |
| |
| // 7. If x is not NaN and the conversion is to an IDL type associated with |
| // the [Clamp] extended attribute, then: |
| if (clamp && !NumberIsNaN(x)) { |
| // 7.1. Set x to min(max(x, lowerBound), upperBound). |
| x = MathMin(MathMax(x, lowerBound), upperBound); |
| |
| // 7.2. Round x to the nearest integer, choosing the even integer if it |
| // lies halfway between two, and choosing +0 rather than −0. |
| x = evenRound(x); |
| |
| // 7.3. Return x. |
| return x; |
| } |
| |
| // 8. If x is NaN, +0, +∞, or −∞, then return +0. |
| if (NumberIsNaN(x) || x === 0 || x === Infinity || x === -Infinity) { |
| return 0; |
| } |
| |
| // 9. Set x to IntegerPart(x). |
| x = integerPart(x); |
| |
| // 10. Set x to x modulo 2^bitLength. |
| x = modulo(x, pow2(bitLength)); |
| |
| // 11. If signedness is "signed" and x ≥ 2^(bitLength − 1), then return x − |
| // 2^bitLength. |
| if (signed && x >= pow2(bitLength - 1)) { |
| return x - pow2(bitLength); |
| } |
| |
| // 12. Otherwise, return x. |
| return x; |
| } |
| |
| module.exports = { |
| convertToInt, |
| evenRound, |
| }; |