]> Lady’s Gitweb - Pisces/blobdiff - binary.js
Add methods for own entries and values to object.js
[Pisces] / binary.js
index deb13dba190cab9afd28d1dcfabf16a4b93723d9..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,17 +56,45 @@ 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;
 
 /**
@@ -129,10 +158,13 @@ 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;
       }
     },
@@ -148,6 +180,8 @@ const decodeBase16 = (source) => {
     // 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++],
@@ -222,10 +256,13 @@ 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;
       }
     },
@@ -242,37 +279,26 @@ const decodeBase32 = (source, wrmg) => {
     // 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, []);
   }
@@ -303,10 +329,13 @@ const decodeBase64 = (source, safe = false) => {
         ? 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;
       }
     },
@@ -322,27 +351,22 @@ const decodeBase64 = (source, safe = false) => {
     // 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, []);
   }
@@ -366,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;
       }
     }
@@ -408,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 &&
@@ -457,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;
     }
   }
@@ -489,6 +524,7 @@ 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
@@ -518,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;
     }
   }
@@ -546,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.
  *
@@ -635,6 +695,514 @@ 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.
@@ -643,7 +1211,12 @@ export const filenameSafeBase64String = ($, ...$s) =>
  */
 export const { isView: isArrayBufferView } = Buffer;
 
-/** Returns whether the provided value is an array 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
@@ -651,8 +1224,17 @@ export const isArrayBuffer = ($) => {
     return call(getBufferByteLength, $, []), true;
   } catch {
     // The provided argument does not have array buffer internal slots.
-    return false;
+    /* 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;
 };
 
 /**
@@ -663,8 +1245,10 @@ export const isArrayBuffer = ($) => {
  */
 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;
@@ -679,8 +1263,10 @@ 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
       ? stringReplace(source, /(?:=|={3,4}|={6})$/u, "")
@@ -698,8 +1284,10 @@ 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
       ? stringReplace(source, /={1,2}$/u, "")
@@ -709,18 +1297,6 @@ export const isBase64 = ($) => {
   }
 };
 
-/** Returns whether the provided value is a data view. */
-export const isDataView = ($) => {
-  try {
-    // Try to see if the provided argument has data view internal slots
-    // and return true if so.
-    return call(getViewBuffer, $, []), true;
-  } catch {
-    // The provided argument does not have data view internal slots.
-    return false;
-  }
-};
-
 /**
  * Returns whether the provided value is a filename‐safe base64 string.
  *
@@ -729,8 +1305,10 @@ export const isDataView = ($) => {
  */
 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
       ? stringReplace(source, /={1,2}$/u, "")
@@ -740,6 +1318,18 @@ export const isFilenameSafeBase64 = ($) => {
   }
 };
 
+/** 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 {
@@ -761,8 +1351,10 @@ export const isTypedArray = ($) => {
  */
 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 &&
@@ -777,19 +1369,25 @@ export const isWRMGBase32 = ($) => {
  * typed array.
  */
 export const toArrayBuffer = ($) => {
-  try {
+  if (isArrayBuffer($)) {
     // The provided argument has array buffer internal slots.
-    return call(getBufferByteLength, $, []), $;
-  } catch {}
-  try {
-    // The provided argument has typed array internal slots.
-    return call(getTypedArrayBuffer, $, []);
-  } catch {}
-  try {
-    // The provided argument has data view internal slots.
-    return call(getViewBuffer, $, []);
-  } catch {}
-  throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
+    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.041947 seconds and 4 git commands to generate.