“use strict”;

var conversions = {}; module.exports = conversions;

function sign(x) {

return x < 0 ? -1 : 1;

}

function evenRound(x) {

// Round x to the nearest integer, choosing the even integer if it lies halfway between two.
if ((x % 1) === 0.5 && (x & 1) === 0) { // [even number].5; round down (i.e. floor)
    return Math.floor(x);
} else {
    return Math.round(x);
}

}

function createNumberConversion(bitLength, typeOpts) {

if (!typeOpts.unsigned) {
    --bitLength;
}
const lowerBound = typeOpts.unsigned ? 0 : -Math.pow(2, bitLength);
const upperBound = Math.pow(2, bitLength) - 1;

const moduloVal = typeOpts.moduloBitLength ? Math.pow(2, typeOpts.moduloBitLength) : Math.pow(2, bitLength);
const moduloBound = typeOpts.moduloBitLength ? Math.pow(2, typeOpts.moduloBitLength - 1) : Math.pow(2, bitLength - 1);

return function(V, opts) {
    if (!opts) opts = {};

    let x = +V;

    if (opts.enforceRange) {
        if (!Number.isFinite(x)) {
            throw new TypeError("Argument is not a finite number");
        }

        x = sign(x) * Math.floor(Math.abs(x));
        if (x < lowerBound || x > upperBound) {
            throw new TypeError("Argument is not in byte range");
        }

        return x;
    }

    if (!isNaN(x) && opts.clamp) {
        x = evenRound(x);

        if (x < lowerBound) x = lowerBound;
        if (x > upperBound) x = upperBound;
        return x;
    }

    if (!Number.isFinite(x) || x === 0) {
        return 0;
    }

    x = sign(x) * Math.floor(Math.abs(x));
    x = x % moduloVal;

    if (!typeOpts.unsigned && x >= moduloBound) {
        return x - moduloVal;
    } else if (typeOpts.unsigned) {
        if (x < 0) {
          x += moduloVal;
        } else if (x === -0) { // don't return negative zero
          return 0;
        }
    }

    return x;
}

}

conversions = function () {

return undefined;

};

conversions = function (val) {

return !!val;

};

conversions = createNumberConversion(8, { unsigned: false }); conversions = createNumberConversion(8, { unsigned: true });

conversions = createNumberConversion(16, { unsigned: false }); conversions[“unsigned short”] = createNumberConversion(16, { unsigned: true });

conversions = createNumberConversion(32, { unsigned: false }); conversions[“unsigned long”] = createNumberConversion(32, { unsigned: true });

conversions[“long long”] = createNumberConversion(32, { unsigned: false, moduloBitLength: 64 }); conversions[“unsigned long long”] = createNumberConversion(32, { unsigned: true, moduloBitLength: 64 });

conversions = function (V) {

const x = +V;

if (!Number.isFinite(x)) {
    throw new TypeError("Argument is not a finite floating-point value");
}

return x;

};

conversions[“unrestricted double”] = function (V) {

const x = +V;

if (isNaN(x)) {
    throw new TypeError("Argument is NaN");
}

return x;

};

// not quite valid, but good enough for JS conversions = conversions; conversions[“unrestricted float”] = conversions[“unrestricted double”];

conversions = function (V, opts) {

if (!opts) opts = {};

if (opts.treatNullAsEmptyString && V === null) {
    return "";
}

return String(V);

};

conversions = function (V, opts) {

const x = String(V);
let c = undefined;
for (let i = 0; (c = x.codePointAt(i)) !== undefined; ++i) {
    if (c > 255) {
        throw new TypeError("Argument is not a valid bytestring");
    }
}

return x;

};

conversions = function (V) {

const S = String(V);
const n = S.length;
const U = [];
for (let i = 0; i < n; ++i) {
    const c = S.charCodeAt(i);
    if (c < 0xD800 || c > 0xDFFF) {
        U.push(String.fromCodePoint(c));
    } else if (0xDC00 <= c && c <= 0xDFFF) {
        U.push(String.fromCodePoint(0xFFFD));
    } else {
        if (i === n - 1) {
            U.push(String.fromCodePoint(0xFFFD));
        } else {
            const d = S.charCodeAt(i + 1);
            if (0xDC00 <= d && d <= 0xDFFF) {
                const a = c & 0x3FF;
                const b = d & 0x3FF;
                U.push(String.fromCodePoint((2 << 15) + (2 << 9) * a + b));
                ++i;
            } else {
                U.push(String.fromCodePoint(0xFFFD));
            }
        }
    }
}

return U.join('');

};

conversions = function (V, opts) {

if (!(V instanceof Date)) {
    throw new TypeError("Argument is not a Date object");
}
if (isNaN(V)) {
    return undefined;
}

return V;

};

conversions = function (V, opts) {

if (!(V instanceof RegExp)) {
    V = new RegExp(V);
}

return V;

};