mirror of
https://github.com/nodejs/node.git
synced 2025-05-04 08:28:40 +00:00

PR-URL: https://github.com/nodejs/node/pull/47514 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
181 lines
4.6 KiB
JavaScript
181 lines
4.6 KiB
JavaScript
'use strict';
|
||
|
||
const {
|
||
MathAbs,
|
||
MathMax,
|
||
MathMin,
|
||
MathPow,
|
||
MathSign,
|
||
MathTrunc,
|
||
NumberIsNaN,
|
||
NumberMAX_SAFE_INTEGER,
|
||
NumberMIN_SAFE_INTEGER,
|
||
String,
|
||
} = primordials;
|
||
|
||
const {
|
||
codes: {
|
||
ERR_INVALID_ARG_VALUE,
|
||
},
|
||
} = require('internal/errors');
|
||
const { kEmptyObject } = require('internal/util');
|
||
|
||
const converters = { __proto__: null };
|
||
|
||
// 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;
|
||
}
|
||
|
||
/**
|
||
* @see https://webidl.spec.whatwg.org/#es-DOMString
|
||
* @param {any} V
|
||
* @returns {string}
|
||
*/
|
||
converters.DOMString = function DOMString(V) {
|
||
if (typeof V === 'symbol') {
|
||
throw new ERR_INVALID_ARG_VALUE('value', V);
|
||
}
|
||
|
||
return String(V);
|
||
};
|
||
|
||
module.exports = {
|
||
convertToInt,
|
||
evenRound,
|
||
converters,
|
||
};
|