]> Lady’s Gitweb - Pisces/blobdiff - binary.js
Add methods for own entries and values to object.js
[Pisces] / binary.js
index 5c78d3916cc1dabd25d528d3a72bba443091c8bb..c149daf82d8245c78c418bda46b1175b1e284b22 100644 (file)
--- a/binary.js
+++ b/binary.js
@@ -17,23 +17,24 @@ import {
   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,
@@ -44,7 +45,7 @@ const argumentIterablePrototype = {
   },
 };
 const binaryCodeUnitIterablePrototype = {
-  [iteratorSymbol]() {
+  [ITERATOR]() {
     return {
       next: bind(
         arrayIteratorNext,
@@ -55,31 +56,61 @@ const binaryCodeUnitIterablePrototype = {
   },
 };
 
+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(
@@ -94,7 +125,7 @@ const bufferFromArgs = ($, $s) =>
         ),
         [],
       ))(
-        typeof $ == "string"
+        typeof $ === "string"
           ? $
           : hasOwnProperty($, "raw")
           ? rawString(
@@ -105,6 +136,8 @@ const bufferFromArgs = ($, $s) =>
           )
           : `${$}`,
       );
+  }
+};
 
 /**
  * Returns the result of decoding the provided base16 string into an
@@ -125,22 +158,30 @@ const decodeBase16 = (source) => {
         ? 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(
       `Piscēs: Base16 string has invalid length: ${source}.`,
     );
   } else {
+    // 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++],
@@ -164,7 +205,7 @@ const decodeBase32 = (source, wrmg) => {
   const u5s = map(
     wrmg
       ? stringReplace(source, /-/gu, "")
-      : source.length % 8 == 0
+      : source.length % 8 === 0
       ? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
       : source,
     (ucsCharacter) => {
@@ -174,15 +215,15 @@ const decodeBase32 = (source, wrmg) => {
           ? 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
@@ -191,15 +232,15 @@ const decodeBase32 = (source, wrmg) => {
           ? 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
@@ -215,53 +256,49 @@ const decodeBase32 = (source, wrmg) => {
         ? 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;
-  if (length % 8 == 1) {
+  const lengthMod8 = length % 8;
+  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(
       `Piscēs: Base32 string has invalid length: ${source}.`,
     );
   } else {
+    // 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, []);
   }
@@ -275,7 +312,7 @@ const decodeBase32 = (source, wrmg) => {
  */
 const decodeBase64 = (source, safe = false) => {
   const u6s = map(
-    source.length % 4 == 0
+    source.length % 4 === 0
       ? stringReplace(source, /={1,2}$/u, "")
       : source,
     (ucsCharacter) => {
@@ -286,49 +323,50 @@ const decodeBase64 = (source, safe = false) => {
         ? 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(
       `Piscēs: Base64 string has invalid length: ${source}.`,
     );
   } else {
+    // 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, []);
   }
@@ -352,17 +390,23 @@ const encodeBase16 = (buffer) => {
     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;
       }
     }
@@ -394,6 +438,7 @@ const encodeBase32 = (buffer, wrmg = false) => {
     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 &&
@@ -406,21 +451,21 @@ const encodeBase32 = (buffer, wrmg = false) => {
         // 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
@@ -443,8 +488,12 @@ const encodeBase32 = (buffer, wrmg = false) => {
       ? 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;
     }
   }
@@ -475,9 +524,10 @@ const encodeBase64 = (buffer, safe = false) => {
     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]);
@@ -485,13 +535,13 @@ const encodeBase64 = (buffer, safe = false) => {
       // 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
@@ -504,8 +554,12 @@ const encodeBase64 = (buffer, safe = false) => {
       ? (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;
     }
   }
@@ -520,7 +574,7 @@ const encodeBase64 = (buffer, safe = false) => {
  */
 const sourceFromArgs = ($, $s) =>
   stringReplace(
-    typeof $ == "string" ? $ : hasOwnProperty($, "raw")
+    typeof $ === "string" ? $ : hasOwnProperty($, "raw")
       ? rawString(
         $,
         ...objectCreate(argumentIterablePrototype, {
@@ -532,6 +586,26 @@ const sourceFromArgs = ($, $s) =>
     "",
   );
 
+/**
+ * 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.
  *
@@ -621,6 +695,548 @@ export const filenameSafeBase64Binary = ($, ...$s) =>
 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.
  *
@@ -629,11 +1245,13 @@ export const filenameSafeBase64String = ($, ...$s) =>
  */
 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;
   }
 };
 
@@ -645,14 +1263,16 @@ export const isBase16 = ($) => {
  */
 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;
   }
 };
 
@@ -664,14 +1284,16 @@ export const isBase32 = ($) => {
  */
 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;
   }
 };
 
@@ -683,14 +1305,40 @@ export const isBase64 = ($) => {
  */
 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;
   }
 };
 
@@ -703,12 +1351,42 @@ export const isFilenameSafeBase64 = ($) => {
  */
 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: ${$}.`);
   }
 };
 
This page took 0.051949 seconds and 4 git commands to generate.