]> Lady’s Gitweb - Pisces/blobdiff - collection.js
Add buffer getters and setters to binary.js
[Pisces] / collection.js
index 10172e643b29fbe5b0dc741f531fc28d1f9f4875..3cfe9385acfbd44423d777c104ad590c8a4d6704 100644 (file)
@@ -1,25 +1,46 @@
 // ♓🌟 Piscēs ∷ collection.js
 // ====================================================================
 //
-// Copyright © 2020–2022 Lady [@ Lady’s Computer].
+// Copyright © 2020–2023 Lady [@ Lady’s Computer].
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
 
-import { MAX_SAFE_INTEGER } from "./numeric.js";
-import { isObject, sameValue } from "./object.js";
+import { call, makeCallable } from "./function.js";
+import {
+  floor,
+  isIntegralNumber,
+  isNan,
+  max,
+  MAXIMUM_SAFE_INTEGRAL_NUMBER,
+  min,
+} from "./numeric.js";
+import { sameValue, type } from "./value.js";
+
+const { prototype: arrayPrototype } = Array;
+
+export const {
+  /** Returns an array of the provided values. */
+  of: array,
+
+  /** Returns whether the provided value is an array. */
+  isArray,
+
+  /** Returns an array created from the provided arraylike. */
+  from: toArray,
+} = Array;
 
 /**
- * Returns -0 if the provided argument is "-0"; returns a number
+ * Returns 0 if the provided argument is "-0"; returns a number
  * representing the index if the provided argument is a canonical
  * numeric index string; otherwise, returns undefined.
  *
  * There is no clamping of the numeric index, but note that numbers
- * above 2^53 − 1 are not safe nor valid integer indices.
+ * above 2^53 − 1 are not safe nor valid integer indices.
  */
 export const canonicalNumericIndexString = ($) => {
-  if (typeof $ != "string") {
+  if (typeof $ !== "string") {
     return undefined;
   } else if ($ === "-0") {
     return -0;
@@ -29,13 +50,161 @@ export const canonicalNumericIndexString = ($) => {
   }
 };
 
-/** Returns whether the provided value is an array index. */
-export const isArrayIndex = ($) => {
+/**
+ * Returns the result of catenating the provided arraylikes into a new
+ * collection according to the algorithm of `Array::concat`.
+ */
+export const catenate = makeCallable(arrayPrototype.concat);
+
+/**
+ * Copies the items in the provided object to a new location according
+ * to the algorithm of `Array::copyWithin`.
+ */
+export const copyWithin = makeCallable(arrayPrototype.copyWithin);
+
+/**
+ * Fills the provided object with the provided value according to the
+ * algorithm of `Array::fill`.
+ */
+export const fill = makeCallable(arrayPrototype.fill);
+
+/**
+ * Returns the result of filtering the provided object with the
+ * provided callback, according to the algorithm of `Array::filter`.
+ */
+export const filter = makeCallable(arrayPrototype.filter);
+
+/**
+ * Returns the first index in the provided object whose value satisfies
+ * the provided callback according to the algorithm of
+ * `Array::findIndex`.
+ */
+export const findIndex = makeCallable(arrayPrototype.findIndex);
+
+/**
+ * Returns the first indexed entry in the provided object whose value
+ * satisfies the provided callback.
+ *
+ * If a third argument is supplied, it will be used as the this value
+ * of the callback.
+ */
+export const findIndexedEntry = (
+  $,
+  callback,
+  thisArg = undefined,
+) => {
+  let result = undefined;
+  findItem($, (kValue, k, O) => {
+    if (call(callback, thisArg, [kValue, k, O])) {
+      // The callback succeeded.
+      result = [k, kValue];
+      return true;
+    } else {
+      // The callback failed.
+      return false;
+    }
+  });
+  return result;
+};
+
+/**
+ * Returns the first indexed value in the provided object which
+ * satisfies the provided callback, according to the algorithm of
+ * `Array::find`.
+ */
+export const findItem = makeCallable(arrayPrototype.find);
+
+/**
+ * Returns the result of flatmapping the provided value with the
+ * provided callback according to the algorithm of `Array::flatMap`.
+ */
+export const flatmap = makeCallable(arrayPrototype.flatMap);
+
+/**
+ * Returns the result of flattening the provided object according to
+ * the algorithm of `Array::flat`.
+ */
+export const flatten = makeCallable(arrayPrototype.flat);
+
+/**
+ * Returns the first index of the provided object with a value
+ * equivalent to the provided value according to the algorithm of
+ * `Array::indexOf`.
+ */
+export const getFirstIndex = makeCallable(arrayPrototype.indexOf);
+
+/**
+ * Returns the item on the provided object at the provided index
+ * according to the algorithm of `Array::at`.
+ */
+export const getItem = makeCallable(arrayPrototype.at);
+
+/**
+ * Returns the last index of the provided object with a value
+ * equivalent to the provided value according to the algorithm of
+ * `Array::lastIndexOf`.
+ */
+export const getLastIndex = makeCallable(arrayPrototype.lastIndexOf);
+
+/**
+ * Returns whether every indexed value in the provided object satisfies
+ * the provided function, according to the algorithm of `Array::every`.
+ */
+export const hasEvery = makeCallable(arrayPrototype.every);
+
+/**
+ * Returns whether the provided object has an indexed value which
+ * satisfies the provided function, according to the algorithm of
+ * `Array::some`.
+ */
+export const hasSome = makeCallable(arrayPrototype.some);
+
+/**
+ * Returns whether the provided object has an indexed value equivalent
+ * to the provided value according to the algorithm of
+ * `Array::includes`.
+ *
+ * ※ This algorithm treats missing values as `undefined` rather than
+ * skipping them.
+ */
+export const includes = makeCallable(arrayPrototype.includes);
+
+/**
+ * Returns an iterator over the indexed entries in the provided value
+ * according to the algorithm of `Array::entries`.
+ */
+export const indexedEntries = makeCallable(arrayPrototype.entries);
+
+/**
+ * Returns an iterator over the indices in the provided value according
+ * to the algorithm of `Array::keys`.
+ */
+export const indices = makeCallable(arrayPrototype.keys);
+
+/** Returns whether the provided value is an array index string. */
+export const isArrayIndexString = ($) => {
   const value = canonicalNumericIndexString($);
   if (value !== undefined) {
-    return sameValue(value, 0) || value > 0 && value < -1 >>> 0;
+    // The provided value is a canonical numeric index string.
+    return sameValue(value, 0) || value > 0 && value < -1 >>> 0 &&
+        value === toLength(value);
   } else {
+    // The provided value is not a canonical numeric index string.
+    return false;
+  }
+};
+
+/** Returns whether the provided value is arraylike. */
+export const isArraylikeObject = ($) => {
+  if (type($) !== "object") {
     return false;
+  } else {
+    try {
+      lengthOfArraylike($); // throws if not arraylike
+      return true;
+    } catch {
+      return false;
+    }
   }
 };
 
@@ -44,18 +213,17 @@ export const isArrayIndex = ($) => {
  *
  * The definition of “collection” used by Piscēs is similar to
  * Ecmascript’s definition of an arraylike object, but it differs in
- * a few ways:—
+ * a few ways :—
  *
  * - It requires the provided value to be a proper object.
  *
- * - It requires the `length` property to be an integer corresponding
- *   to an integer index.
+ * - It requires the `length` property to be an integer index.
  *
  * - It requires the object to be concat‐spreadable, meaning it must
- *   either be an array or have `[Symbol.isConcatSpreadable]` be true.
+ *   either be an array or have `.[Symbol.isConcatSpreadable]` be true.
  */
 export const isCollection = ($) => {
-  if (!(isObject($) && "length" in $)) {
+  if (!(type($) === "object" && "length" in $)) {
     // The provided value is not an object or does not have a `length`.
     return false;
   } else {
@@ -76,46 +244,107 @@ export const isCollection = ($) => {
  * collections.
  */
 export const isConcatSpreadable = ($) => {
-  if (!isObject($)) {
+  if (type($) !== "object") {
     // The provided value is not an object.
     return false;
   } else {
     // The provided value is an object.
-    return !!($[Symbol.isConcatSpreadable] ?? Array.isArray($));
+    const spreadable = $[Symbol.isConcatSpreadable];
+    return spreadable !== undefined ? !!spreadable : isArray($);
   }
 };
 
-/** Returns whether the provided value is an integer index. */
-export const isIntegerIndex = ($) => {
+/** Returns whether the provided value is an integer index string. */
+export const isIntegerIndexString = ($) => {
   const value = canonicalNumericIndexString($);
-  if (value !== undefined) {
+  if (value !== undefined && isIntegralNumber(value)) {
+    // The provided value is a canonical numeric index string.
     return sameValue(value, 0) ||
-      value > 0 && value <= MAX_SAFE_INTEGER;
+      value > 0 && value <= MAXIMUM_SAFE_INTEGRAL_NUMBER &&
+        value === toLength(value);
   } else {
+    // The provided value is not a canonical numeric index string.
     return false;
   }
 };
 
+/**
+ * Returns an iterator over the items in the provided value according
+ * to the algorithm of `Array::values`.
+ */
+export const items = makeCallable(arrayPrototype.values);
+
 /**
  * Returns the length of the provided arraylike object.
  *
  * Will throw if the provided object is not arraylike.
  *
- * This produces larger lengths than can actually be stored in arrays,
- * because no such restrictions exist on arraylike methods. Use
- * `isIndex` to determine if a value is an actual array index.
+ * This can produce larger lengths than can actually be stored in
+ * arrays, because no such restrictions exist on arraylike methods.
  */
-export const lengthOfArrayLike = ({ length }) => {
-  return toLength(length);
-};
+export const lengthOfArraylike = ({ length }) => toLength(length);
+
+/**
+ * Returns the result of mapping the provided value with the provided
+ * callback according to the algorithm of `Array::map`.
+ */
+export const map = makeCallable(arrayPrototype.map);
+
+/**
+ * Pops from the provided value according to the algorithm of
+ * `Array::pop`.
+ */
+export const pop = makeCallable(arrayPrototype.pop);
+
+/**
+ * Pushes onto the provided value according to the algorithm of
+ * `Array::push`.
+ */
+export const push = makeCallable(arrayPrototype.push);
+
+/**
+ * Returns the result of reducing the provided value with the provided
+ * callback, according to the algorithm of `Array::reduce`.
+ */
+export const reduce = makeCallable(arrayPrototype.reduce);
+
+/**
+ * Reverses the provided value according to the algorithm of
+ * `Array::reverse`.
+ */
+export const reverse = makeCallable(arrayPrototype.reverse);
+
+/**
+ * Shifts the provided value according to the algorithm of
+ * `Array::shift`.
+ */
+export const shift = makeCallable(arrayPrototype.shift);
+
+/**
+ * Returns a slice of the provided value according to the algorithm of
+ * `Array::slice`.
+ */
+export const slice = makeCallable(arrayPrototype.slice);
+
+/**
+ * Sorts the provided value in‐place according to the algorithm of
+ * `Array::sort`.
+ */
+export const sort = makeCallable(arrayPrototype.sort);
 
 /**
- * Converts the provided value to an array index, or throws an error if
- * it is out of range.
+ * Splices into and out of the provided value according to the
+ * algorithm of `Array::splice`.
+ */
+export const splice = makeCallable(arrayPrototype.splice);
+
+/**
+ * Returns the result of converting the provided value to an array
+ * index, or throws an error if it is out of range.
  */
 export const toIndex = ($) => {
-  const integer = Math.floor($);
-  if (isNaN(integer) || integer == 0) {
+  const integer = floor($);
+  if (isNan(integer) || integer == 0) {
     // The value is zero·like.
     return 0;
   } else {
@@ -131,10 +360,16 @@ export const toIndex = ($) => {
   }
 };
 
-/** Converts the provided value to a length. */
+/** Returns the result of converting the provided value to a length. */
 export const toLength = ($) => {
-  const len = Math.floor($);
-  return isNaN(len) || len == 0
+  const len = floor($);
+  return isNan(len) || len == 0
     ? 0
-    : Math.max(Math.min(len, MAX_SAFE_INTEGER), 0);
+    : max(min(len, MAXIMUM_SAFE_INTEGRAL_NUMBER), 0);
 };
+
+/**
+ * Unshifts the provided value according to the algorithm of
+ * `Array::unshift`.
+ */
+export const unshift = makeCallable(arrayPrototype.unshift);
This page took 0.035374 seconds and 4 git commands to generate.