stringFromCodeUnits,
stringReplace,
} from "./string.js";
+import { ITERATOR } from "./value.js";
const Buffer = ArrayBuffer;
const View = DataView;
const TypedArray = Object.getPrototypeOf(Uint8Array);
const { prototype: arrayPrototype } = Array;
const { prototype: bufferPrototype } = Buffer;
-const { iterator: iteratorSymbol } = Symbol;
+const { prototype: sharedBufferPrototype } = SharedArrayBuffer;
const { prototype: rePrototype } = RegExp;
const { prototype: typedArrayPrototype } = TypedArray;
const { prototype: viewPrototype } = View;
-const { [iteratorSymbol]: arrayIterator } = arrayPrototype;
+const { [ITERATOR]: arrayIterator } = arrayPrototype;
const {
next: arrayIteratorNext,
-} = Object.getPrototypeOf([][iteratorSymbol]());
+} = Object.getPrototypeOf([][ITERATOR]());
const argumentIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(
arrayIteratorNext,
},
};
const binaryCodeUnitIterablePrototype = {
- [iteratorSymbol]() {
+ [ITERATOR]() {
return {
next: bind(
arrayIteratorNext,
},
};
+const { exec: reExec } = rePrototype;
+const { slice: bufferSlice } = bufferPrototype;
const getBufferByteLength =
Object.getOwnPropertyDescriptor(bufferPrototype, "byteLength").get;
+const { slice: sharedBufferSlice } = sharedBufferPrototype;
+const getSharedBufferByteLength =
+ Object.getOwnPropertyDescriptor(sharedBufferPrototype, "byteLength")
+ .get;
const getTypedArrayBuffer =
Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
+const getTypedArrayByteLength =
+ Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")
+ .get;
+const getTypedArrayByteOffset =
+ Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset")
+ .get;
const getViewBuffer =
Object.getOwnPropertyDescriptor(viewPrototype, "buffer").get;
-const { exec: reExec } = rePrototype;
+const getViewByteLength =
+ Object.getOwnPropertyDescriptor(viewPrototype, "byteLength").get;
+const getViewByteOffset =
+ Object.getOwnPropertyDescriptor(viewPrototype, "byteOffset").get;
const {
+ getBigInt64: viewGetInt64,
+ getBigUint64: viewGetUint64,
+ getFloat32: viewGetFloat32,
+ getFloat64: viewGetFloat64,
+ getInt8: viewGetInt8,
+ getInt16: viewGetInt16,
+ getInt32: viewGetInt32,
getUint8: viewGetUint8,
+ getUint16: viewGetUint16,
+ getUint32: viewGetUint32,
+ setFloat32: viewSetFloat32,
+ setFloat64: viewSetFloat64,
setUint8: viewSetUint8,
setUint16: viewSetUint16,
+ setUint32: viewSetUint32,
+ setBigUint64: viewSetUint64,
} = viewPrototype;
/**
* Returns an ArrayBuffer for encoding generated from the provided
* arguments.
*/
-const bufferFromArgs = ($, $s) =>
- $ instanceof Buffer
- ? $
- : $ instanceof View
- ? call(getViewBuffer, $, [])
- : $ instanceof TypedArray
- ? call(getTypedArrayBuffer, $, [])
- : ((string) =>
+const bufferFromArgs = ($, $s) => {
+ try {
+ // Try just getting the array buffer associated with the first
+ // argument and returning it if possible.
+ return toArrayBuffer($);
+ } catch {
+ // There is no array buffer associated with the first argument.
+ //
+ // Construct a string and convert it to an array buffer instead.
+ return ((string) =>
call(
getViewBuffer,
reduce(
),
[],
))(
- typeof $ == "string"
+ typeof $ === "string"
? $
: hasOwnProperty($, "raw")
? rawString(
)
: `${$}`,
);
+ }
+};
/**
* Returns the result of decoding the provided base16 string into an
? code - 87
: -1;
if (result < 0) {
+ // The source contains an invalid character.
throw new RangeError(
`Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
);
} else {
+ // The source contains a valid character with a recognized
+ // mapping.
return result;
}
},
);
const { length } = u4s;
- if (length % 2 == 1) {
+ if (length % 2 === 1) {
// The length is such that an entire letter would be dropped during
// a forgiving decode.
throw new RangeError(
// Every letter contributes at least some bits to the result.
const dataView = new View(new Buffer(floor(length / 2)));
for (let index = 0; index < length - 1;) {
+ // Iterate over the characters and assign their bits to the
+ // buffer.
call(viewSetUint8, dataView, [
floor(index / 2),
(u4s[index] << 4) | u4s[++index, index++],
const u5s = map(
wrmg
? stringReplace(source, /-/gu, "")
- : source.length % 8 == 0
+ : source.length % 8 === 0
? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
: source,
(ucsCharacter) => {
? code - 48
: code >= 0x41 && code <= 0x48
? code - 55
- : code == 0x49
+ : code === 0x49
? 1 // I
: code >= 0x4A && code <= 0x4B
? code - 56
- : code == 0x4C
+ : code === 0x4C
? 1 // L
: code >= 0x4D && code <= 0x4E
? code - 57
- : code == 0x4F
+ : code === 0x4F
? 0 // O
: code >= 0x50 && code <= 0x54
? code - 58
? code - 59
: code >= 0x61 && code <= 0x68
? code - 87
- : code == 0x69
+ : code === 0x69
? 1 // i
: code >= 0x6A && code <= 0x6B
? code - 88
- : code == 0x6C
+ : code === 0x6C
? 1 // l
: code >= 0x6D && code <= 0x6E
? code - 89
- : code == 0x6F
+ : code === 0x6F
? 0 // o
: code >= 0x70 && code <= 0x74
? code - 90
? code - 24 // digits 2–7 map to 26–31
: -1;
if (result < 0) {
+ // The source contains an invalid character.
throw new RangeError(
`Piscēs: Invalid character in Base32: ${ucsCharacter}.`,
);
} else {
+ // The source contains a valid character with a recognized
+ // mapping.
return result;
}
},
);
const { length } = u5s;
const lengthMod8 = length % 8;
- if (lengthMod8 == 1 || lengthMod8 == 3 || lengthMod8 == 6) {
+ if (lengthMod8 === 1 || lengthMod8 === 3 || lengthMod8 === 6) {
// The length is such that an entire letter would be dropped during
// a forgiving decode.
throw new RangeError(
// Every letter contributes at least some bits to the result.
const dataView = new View(new Buffer(floor(length * 5 / 8)));
for (let index = 0; index < length - 1;) {
+ // Iterate over the characters and assign their bits to the
+ // buffer.
+ //
// The final index is not handled; if the string is not divisible
// by 8, some bits might be dropped. This matches the “forgiving
// decode” behaviour specified by WhatW·G for base64.
const dataIndex = ceil(index * 5 / 8);
const remainder = index % 8;
- if (remainder == 0) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 3 | u5s[++index] >> 2,
- ]);
- } else if (remainder == 1) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 6 | u5s[++index] << 1 | u5s[++index] >> 4,
- ]);
- } else if (remainder == 3) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 4 | u5s[++index] >> 1,
- ]);
- } else if (remainder == 4) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 7 | u5s[++index] << 2 | u5s[++index] >> 3,
- ]);
- } else { // remainder == 6
- call(viewSetUint8, dataView, [
- dataIndex,
- u5s[index] << 5 | u5s[++index, index++],
- ]);
- }
+ call(viewSetUint8, dataView, [
+ dataIndex,
+ remainder === 0
+ ? u5s[index] << 3 | u5s[++index] >> 2
+ : remainder === 1
+ ? u5s[index] << 6 | u5s[++index] << 1 | u5s[++index] >> 4
+ : remainder === 3
+ ? u5s[index] << 4 | u5s[++index] >> 1
+ : remainder === 4
+ ? u5s[index] << 7 | u5s[++index] << 2 | u5s[++index] >> 3
+ : u5s[index] << 5 | u5s[++index, index++], // remainder === 6
+ ]);
}
return call(getViewBuffer, dataView, []);
}
*/
const decodeBase64 = (source, safe = false) => {
const u6s = map(
- source.length % 4 == 0
+ source.length % 4 === 0
? stringReplace(source, /={1,2}$/u, "")
: source,
(ucsCharacter) => {
? code - 71
: code >= 0x30 && code <= 0x39
? code + 4
- : code == (safe ? 0x2D : 0x2B)
+ : code === (safe ? 0x2D : 0x2B)
? 62
- : code == (safe ? 0x5F : 0x2F)
+ : code === (safe ? 0x5F : 0x2F)
? 63
: -1;
if (result < 0) {
+ // The source contains an invalid character.
throw new RangeError(
`Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
);
} else {
+ // The source contains a valid character with a recognized
+ // mapping.
return result;
}
},
);
const { length } = u6s;
- if (length % 4 == 1) {
+ if (length % 4 === 1) {
// The length is such that an entire letter would be dropped during
// a forgiving decode.
throw new RangeError(
// Every letter contributes at least some bits to the result.
const dataView = new View(new Buffer(floor(length * 3 / 4)));
for (let index = 0; index < length - 1;) {
+ // Iterate over the characters and assign their bits to the
+ // buffer.
+ //
// The final index is not handled; if the string is not divisible
// by 4, some bits might be dropped. This matches the “forgiving
// decode” behaviour specified by WhatW·G for base64.
const dataIndex = ceil(index * 3 / 4);
const remainder = index % 4;
- if (remainder == 0) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u6s[index] << 2 | u6s[++index] >> 4,
- ]);
- } else if (remainder == 1) {
- call(viewSetUint8, dataView, [
- dataIndex,
- u6s[index] << 4 | u6s[++index] >> 2,
- ]);
- } else { // remainder == 2
- call(viewSetUint8, dataView, [
- dataIndex,
- u6s[index] << 6 | u6s[++index, index++],
- ]);
- }
+ call(viewSetUint8, dataView, [
+ dataIndex,
+ remainder === 0
+ ? u6s[index] << 2 | u6s[++index] >> 4
+ : remainder === 1
+ ? u6s[index] << 4 | u6s[++index] >> 2
+ : u6s[index] << 6 | u6s[++index, index++], // remainder === 2
+ ]);
}
return call(getViewBuffer, dataView, []);
}
0x3D,
);
for (let index = 0; index < byteLength;) {
+ // Iterate over the bytes and generate code units for them.
const codeUnitIndex = index * 2;
const datum = call(viewGetUint8, dataView, [index++]);
const u4s = [datum >> 4, datum & 0xF];
for (let u4i = 0; u4i < 2; ++u4i) {
+ // Handle the high four bits, then the low four bits.
const u4 = u4s[u4i];
const result = u4 < 10 ? u4 + 48 : u4 < 16 ? u4 + 55 : -1;
if (result < 0) {
+ // No mapping exists for these four bits.
+ //
+ // ※ This shouldn’t be possible!
throw new RangeError(
`Piscēs: Unexpected Base16 value: ${u4}.`,
);
} else {
+ // A mapping exists for the bits.
resultingCodeUnits[codeUnitIndex + u4i] = result;
}
}
fillByte,
);
for (let index = 0; index < byteLength;) {
+ // Iterate over the bytes and generate code units for them.
const codeUnitIndex = ceil(index * 8 / 5);
const currentIndex = codeUnitIndex + +(
0b01011 & 1 << index % 5 &&
// digits 1, 3, 4 & 6 span multiple bytes
? call(viewGetUint8, dataView, [index])
: 0;
- const u5 = remainder == 0
+ const u5 = remainder === 0
? currentByte >> 3
- : remainder == 1
+ : remainder === 1
? (currentByte & 0b00000111) << 2 | nextByte >> 6
- : remainder == 2
+ : remainder === 2
? (currentByte & 0b00111111) >> 1
- : remainder == 3
+ : remainder === 3
? (currentByte & 0b00000001) << 4 | nextByte >> 4
- : remainder == 4
+ : remainder === 4
? (currentByte & 0b00001111) << 1 | nextByte >> 7
- : remainder == 5
+ : remainder === 5
? (currentByte & 0b01111111) >> 2
- : remainder == 6
+ : remainder === 6
? (currentByte & 0b00000011) << 3 | nextByte >> 5
- : (++index, currentByte & 0b00011111); // remainder == 7
+ : (++index, currentByte & 0b00011111); // remainder === 7
const result = wrmg
? u5 < 10 ? u5 + 48 : u5 < 18
? u5 + 55
? u5 + 24
: -1;
if (result < 0) {
+ // No mapping exists for these five bits.
+ //
+ // ※ This shouldn’t be possible!
throw new RangeError(`Piscēs: Unexpected Base32 value: ${u5}.`);
} else {
+ // A mapping exists for the bits.
resultingCodeUnits[currentIndex] = result;
}
}
0x3D,
);
for (let index = 0; index < byteLength;) {
+ // Iterate over the bytes and generate code units for them.
const codeUnitIndex = ceil(index * 4 / 3);
const currentIndex = codeUnitIndex + +(
- index % 3 == 0 && resultingCodeUnits[codeUnitIndex] != 0x3D
+ index % 3 === 0 && resultingCodeUnits[codeUnitIndex] != 0x3D
); // every third byte handles two letters; this is for the second
const remainder = currentIndex % 4;
const currentByte = call(viewGetUint8, dataView, [index]);
// digits 1 & 2 span multiple bytes
? call(viewGetUint8, dataView, [index])
: 0;
- const u6 = remainder == 0
+ const u6 = remainder === 0
? currentByte >> 2
- : remainder == 1
+ : remainder === 1
? (currentByte & 0b00000011) << 4 | nextByte >> 4
- : remainder == 2
+ : remainder === 2
? (currentByte & 0b00001111) << 2 | nextByte >> 6
- : (++index, currentByte & 0b00111111); // remainder == 3
+ : (++index, currentByte & 0b00111111); // remainder === 3
const result = u6 < 26
? u6 + 65
: u6 < 52
? (safe ? 0x5F : 0x2F)
: -1;
if (result < 0) {
+ // No mapping exists for these six bits.
+ //
+ // ※ This shouldn’t be possible!
throw new RangeError(`Piscēs: Unexpected Base64 value: ${u6}.`);
} else {
+ // A mapping exists for the bits.
resultingCodeUnits[currentIndex] = result;
}
}
*/
const sourceFromArgs = ($, $s) =>
stringReplace(
- typeof $ == "string" ? $ : hasOwnProperty($, "raw")
+ typeof $ === "string" ? $ : hasOwnProperty($, "raw")
? rawString(
$,
...objectCreate(argumentIterablePrototype, {
"",
);
+/**
+ * Returns a slice of the provided value according to the algorithm of
+ * `ArrayBuffer::slice` (or `SharedArrayBuffer::slice`).
+ *
+ * ☡ This function throws if the provided value is not an array buffer.
+ */
+export const arrayBufferSlice = ($, start, end, ...args) =>
+ call(
+ isSharedArrayBuffer($) ? sharedBufferSlice : bufferSlice,
+ $,
+ [
+ start,
+ end,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ],
+ );
+
/**
* Returns an ArrayBuffer generated from the provided base16 string.
*
export const filenameSafeBase64String = ($, ...$s) =>
encodeBase64(bufferFromArgs($, $s), true);
+export const {
+ /**
+ * Returns the signed 8‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getInt8`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get8BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 8‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getUint8`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get8BitUnsignedIntegralItem,
+
+ /**
+ * Returns the signed 16‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getInt16`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get16BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 16‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getUint16`, but works on all
+ * array buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get16BitUnsignedIntegralItem,
+
+ /**
+ * Returns the 32‐bit floating point value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getFloat32`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get32BitFloatingPointItem,
+
+ /**
+ * Returns the signed 32‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getInt32`, but works on all array
+ * buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get32BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 32‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getUint32`, but works on all
+ * array buffers and array buffer views and returns a big·int.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get32BitUnsignedIntegralItem,
+
+ /**
+ * Returns the 64‐bit floating point value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getFloat64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get64BitFloatingPointItem,
+
+ /**
+ * Returns the signed 64‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getBigInt64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get64BitSignedIntegralItem,
+
+ /**
+ * Returns the unsigned 64‐bit integral value in the provided array
+ * buffer or array buffer view at the provided byte offset.
+ *
+ * ※ The retrieved value will be big·endian unless a third argument
+ * is specified and truthy.
+ *
+ * ※ This is similar to `DataView::getBigUint64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ get64BitUnsignedIntegralItem,
+
+ /**
+ * Sets the 8‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt8`, but works on all array
+ * buffers and array buffer views and accepts both numeric and
+ * big·int values.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set8BitIntegralItem,
+
+ /**
+ * Sets the 16‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt16`, but works on all array
+ * buffers and array buffer views and accepts both numeric and
+ * big·int values.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set16BitIntegralItem,
+
+ /**
+ * Sets the 32‐bit floating point value in the provided array buffer
+ * or array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setFloat32`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set32BitFloatingPointItem,
+
+ /**
+ * Sets the 32‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt32`, but works on all array
+ * buffers and array buffer views and accepts both numeric and
+ * big·int values.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set32BitIntegralItem,
+
+ /**
+ * Sets the 64‐bit floating point value in the provided array buffer
+ * or array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setFloat64`, but works on all
+ * array buffers and array buffer views.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array.
+ */
+ set64BitFloatingPointItem,
+
+ /**
+ * Sets the 64‐bit integral value in the provided array buffer or
+ * array buffer view at the provided byte offset to the provided
+ * value.
+ *
+ * ※ The value will be set as big·endian unless a fourth argument is
+ * specified and truthy.
+ *
+ * ※ This is similar to `DataView::setInt32`, but works on all array
+ * buffers and array buffer views.
+ *
+ * ※ It doesn’t matter whether the provided value is signed or
+ * unsigned, as the algorithm will cast one to the other.
+ *
+ * ☡ This function throws if the first argument is not an array
+ * buffer, data view, or typed array, or if the third argument is not
+ * a big·int.
+ */
+ set64BitIntegralItem,
+} = (() => {
+ const makeBigInt = BigInt;
+ const { asUintN } = BigInt;
+ const makeNumber = Number;
+
+ const viewMap = new WeakMap();
+ const view = ($) => {
+ const buffer = toArrayBuffer($);
+ if (viewMap.has(buffer)) {
+ // A view has already been allocated for this buffer; use it.
+ return viewMap.get(buffer);
+ } else {
+ // No view has been created for this buffer yet.
+ const result = new View(buffer);
+ viewMap.set(buffer, result);
+ return result;
+ }
+ };
+
+ return {
+ get8BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetInt8, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get8BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetUint8, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get16BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetInt16, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get16BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetUint16, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get32BitFloatingPointItem: ($, byteOffset, ...args) =>
+ call(viewGetFloat32, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ get32BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetInt32, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get32BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ makeBigInt(
+ call(viewGetUint32, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ ),
+ get64BitFloatingPointItem: ($, byteOffset, ...args) =>
+ call(viewGetFloat64, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ get64BitSignedIntegralItem: ($, byteOffset, ...args) =>
+ call(viewGetInt64, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ get64BitUnsignedIntegralItem: ($, byteOffset, ...args) =>
+ call(viewGetUint64, view($), [
+ getByteOffset($) + byteOffset,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set8BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint8, view($), [
+ getByteOffset($) + byteOffset,
+ makeNumber(value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set16BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint16, view($), [
+ getByteOffset($) + byteOffset,
+ makeNumber(value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set32BitFloatingPointItem: ($, byteOffset, value, ...args) =>
+ call(viewSetFloat32, view($), [
+ getByteOffset($) + byteOffset,
+ value,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set32BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint32, view($), [
+ getByteOffset($) + byteOffset,
+ makeNumber(value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set64BitFloatingPointItem: ($, byteOffset, value, ...args) =>
+ call(viewSetFloat64, view($), [
+ getByteOffset($) + byteOffset,
+ value,
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ set64BitIntegralItem: ($, byteOffset, value, ...args) =>
+ call(viewSetUint64, view($), [
+ getByteOffset($) + byteOffset,
+ asUintN(64, value),
+ ...objectCreate(
+ argumentIterablePrototype,
+ { args: { value: args } },
+ ),
+ ]),
+ };
+})();
+
+/**
+ * Returns the byte length for the provided array buffer or array
+ * buffer view.
+ *
+ * ☡ This function throws if the provided value is not an array buffer,
+ * data view, or typed array.
+ */
+export const getByteLength = ($) => {
+ try {
+ // Attempt to get the byte length from the provided value as an
+ // `ArrayBuffer`.
+ return call(getBufferByteLength, $, []);
+ } catch {
+ // The provided value is not an `ArrayBuffer`.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte length from the provided value as a
+ // `SharedArrayBuffer`.
+ return call(getSharedBufferByteLength, $, []);
+ } catch {
+ // The provided value is not a `SharedArrayBuffer`.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte length from the provided value as a
+ // data view.
+ return call(getViewByteLength, $, []);
+ } catch {
+ // The provided value is not a data view.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte length from the provided value as a
+ // typed array.
+ return call(getTypedArrayByteLength, $, []);
+ } catch {
+ // The provided value is not a typed array.
+ /* do nothing */
+ }
+ throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
+};
+
+/**
+ * Returns the byte offset for the provided array buffer or array
+ * buffer view.
+ *
+ * ※ This function always returns `0` for array buffers.
+ *
+ * ☡ This function throws if the provided value is not an array buffer,
+ * data view, or typed array.
+ */
+export const getByteOffset = ($) => {
+ if (isArrayBuffer($)) {
+ // The provided value is an array buffer.
+ return 0;
+ } else {
+ try {
+ // Attempt to get the byte offset from the provided value as a
+ // data view.
+ return call(getViewByteOffset, $, []);
+ } catch {
+ // The provided value is not a data view.
+ /* do nothing */
+ }
+ try {
+ // Attempt to get the byte offset from the provided value as a
+ // typed array.
+ return call(getTypedArrayByteOffset, $, []);
+ } catch {
+ // The provided value is not a typed array.
+ /* do nothing */
+ }
+ throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
+ }
+};
+
+/**
+ * Returns whether the provided value is a view on an underlying array
+ * buffer.
+ *
+ * ※ This function returns true for typed arrays and data views.
+ */
+export const { isView: isArrayBufferView } = Buffer;
+
+/**
+ * Returns whether the provided value is an array buffer.
+ *
+ * ※ This function returns true for both `ArrayBuffer`s and
+ * `SharedArrayBuffer`s.
+ */
+export const isArrayBuffer = ($) => {
+ try {
+ // Try to see if the provided argument has array buffer internal
+ // slots and return true if so.
+ return call(getBufferByteLength, $, []), true;
+ } catch {
+ // The provided argument does not have array buffer internal slots.
+ /* do nothing */
+ }
+ try {
+ // Try to see if the provided argument has array buffer internal
+ // slots and return true if so.
+ return call(getSharedBufferByteLength, $, []), true;
+ } catch {
+ // The provided argument does not have array buffer internal slots.
+ /* do nothing */
+ }
+ return false;
+};
+
/**
* Returns whether the provided value is a base16 string.
*
*/
export const isBase16 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- return source.length % 2 != 1 &&
- call(reExec, /[^0-9A-F]/iu, [source]) == null;
+ return source.length % 2 !== 1 &&
+ call(reExec, /[^0-9A-F]/iu, [source]) === null;
}
};
*/
export const isBase32 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- const trimmed = source.length % 8 == 0
+ const trimmed = source.length % 8 === 0
? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
: source;
- return trimmed.length % 8 != 1 &&
- call(reExec, /[^2-7A-Z/]/iu, [trimmed]) == null;
+ return trimmed.length % 8 !== 1 &&
+ call(reExec, /[^2-7A-Z/]/iu, [trimmed]) === null;
}
};
*/
export const isBase64 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- const trimmed = source.length % 4 == 0
+ const trimmed = source.length % 4 === 0
? stringReplace(source, /={1,2}$/u, "")
: source;
- return trimmed.length % 4 != 1 &&
- call(reExec, /[^0-9A-Za-z+\/]/u, [trimmed]) == null;
+ return trimmed.length % 4 !== 1 &&
+ call(reExec, /[^0-9A-Za-z+\/]/u, [trimmed]) === null;
}
};
*/
export const isFilenameSafeBase64 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
- const trimmed = source.length % 4 == 0
+ const trimmed = source.length % 4 === 0
? stringReplace(source, /={1,2}$/u, "")
: source;
- return trimmed.length % 4 != 1 &&
- call(reExec, /[^0-9A-Za-z_-]/u, [trimmed]) == null;
+ return trimmed.length % 4 !== 1 &&
+ call(reExec, /[^0-9A-Za-z_-]/u, [trimmed]) === null;
+ }
+};
+
+/** Returns whether the provided value is a shared array buffer. */
+export const isSharedArrayBuffer = ($) => {
+ try {
+ // Try to see if the provided argument has shared array buffer
+ // internal slots and return true if so.
+ return call(getSharedBufferByteLength, $, []), true;
+ } catch {
+ // The provided argument does not have data view internal slots.
+ return false;
+ }
+};
+
+/** Returns whether the provided value is a typed array. */
+export const isTypedArray = ($) => {
+ try {
+ // Try to see if the provided argument has typed array internal
+ // slots and return true if so.
+ return call(getTypedArrayBuffer, $, []), true;
+ } catch {
+ // The provided argument does not have typed array internal slots.
+ return false;
}
};
*/
export const isWRMGBase32 = ($) => {
if (typeof $ !== "string") {
+ // The provided value is not a string.
return false;
} else {
+ // The provided value is a string.
const source = stringReplace($, /[\t\n\f\r ]+/gu, "");
const trimmed = stringReplace(source, /-/gu, "");
- return trimmed.length % 8 != 1 &&
- call(reExec, /[^0-9A-TV-Z]/iu, [trimmed]) == null;
+ return trimmed.length % 8 !== 1 &&
+ call(reExec, /[^0-9A-TV-Z]/iu, [trimmed]) === null;
+ }
+};
+
+/**
+ * Returns the array buffer associated with the provided object.
+ *
+ * ☡ This function throws if the provided object is not a data view or
+ * typed array.
+ */
+export const toArrayBuffer = ($) => {
+ if (isArrayBuffer($)) {
+ // The provided argument has array buffer internal slots.
+ return $;
+ } else {
+ // The provided argument does not have array buffer internal slots.
+ try {
+ // The provided argument has typed array internal slots.
+ return call(getTypedArrayBuffer, $, []);
+ } catch {
+ /* do nothing */
+ }
+ try {
+ // The provided argument has data view internal slots.
+ return call(getViewBuffer, $, []);
+ } catch {
+ /* do nothing */
+ }
+ throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
}
};