]> Lady’s Gitweb - Etiquette/blobdiff - memory.js
Apply some reformatting and make Reuse‐compliant
[Etiquette] / memory.js
index 6773bddfc91b3ee533f7cb5bef46fd864a753534..f4a861b1249ca82ad2e8bf5c82c3c9ad27ad31c0 100644 (file)
--- a/memory.js
+++ b/memory.js
@@ -1,14 +1,19 @@
-// 📧🏷️ Étiquette ∷ memory.js
-// ====================================================================
-//
-// Copyright © 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/>.
+// SPDX-FileCopyrightText: 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
+// SPDX-License-Identifier: MPL-2.0
+/**
+ * ⁌ 📧🏷️ Étiquette ∷ memory.js
+ *
+ * Copyright © 2023, 2025 Lady [@ Ladys 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 { wrmgBase32Binary, wrmgBase32String } from "./deps.js";
 
+const ÉTIQUETTE = "📧🏷️ Étiquette";
+
 /**
  * A symbol which is used internally to identify the constructor
  * associated with a stored object.
@@ -23,33 +28,32 @@ const constructorSymbol = Symbol("constructor");
  * If an argument is provided, it is used as the underlying numeric
  * value for the identifier.
  *
- * The return value is a `String` *object* with a `.value` own property
+ * The return value is a `String´ ⹐object⹑ with a `.value´ own property
  * giving the underlying numeric value for the string.
  *
  * ※ This function is not exposed.
  */
 const mintID = ($ = null) => {
-  const [number, buffer] = $ == null
-    ? (() => {
+  const { number, buffer } = (() => {
+    if ($ == null) {
       // No value was provided; generate a random one and store its
       // buffer.
       const values = crypto.getRandomValues(new Uint32Array(1));
-      const view = new DataView(values.buffer);
-      return [
-        view.getUint32(0) >>> 2, // drop the final 2 bits
-        view.buffer,
-      ];
-    })()
-    : [$ >>> 0 & -1 >>> 2, null];
+      const { buffer } = values;
+      return {
+        number: new DataView(buffer).getUint32(0) >>> 2,
+        buffer,
+      };
+    } else {
+      // A value was provided, so a buffer needs to be generated.
+      const number = $ & -1 >>> 2;
+      const buffer = new ArrayBuffer(4);
+      new DataView(buffer).setUint32(0, number << 2, false);
+      return { number, buffer };
+    }
+  })();
   const checksum = number % 37;
-  const wrmg = wrmgBase32String(
-    buffer ?? (() => {
-      // A value was provided, so a buffer still needs to be generated.
-      const view = new DataView(new ArrayBuffer(4));
-      view.setUint32(0, number << 2, false);
-      return view.buffer;
-    })(),
-  );
+  const wrmg = wrmgBase32String(buffer);
   return Object.assign(
     new String(
       `${"0123456789ABCDEFGHJKMNPQRSTVWXYZ*~$=U"[checksum]}${
@@ -61,9 +65,12 @@ const mintID = ($ = null) => {
 };
 
 /**
- * Validates the checksum prefixing the provided W·R·M·G base32
+ * Validates the checksum prefixing the provided 30‐bit W·R·M·G base32
  * identifier and then returns that same identifier in normalized form.
  *
+ * ☡ This function will throw if the provided value is not a 30‐bit
+ * W·R·M·G base32 value with a leading checksum.
+ *
  * ※ This function is not exposed.
  */
 const normalizeID = ($) => {
@@ -72,34 +79,36 @@ const normalizeID = ($) => {
     identifier[0].toUpperCase(),
   );
   if (checksum == -1) {
-    // The checksum character is invalid.
+    // ☡ The checksum character is invalid.
     throw new RangeError(`Invalid checksum: "${identifier[0]}".`);
   } else {
     // There is a valid checksum.
     const binary = wrmgBase32Binary`${identifier.substring(1)}0`;
     const { byteLength } = binary;
     if (byteLength != 4) {
-      // The identifier was of unexpected size.
+      // ☡ The identifier was of unexpected size.
       throw new RangeError(
-        `Expected id to fit within 4 bytes, but got ${byteLength}.`,
+        `${ÉTIQUETTE}: Expected id to fit within 4 bytes, but got ${byteLength}.`,
       );
     } else {
       // The identifier was correctly‐sized.
       const value = new DataView(binary).getUint32(0, false);
       if (value & 0b11) {
-        // The final two bits, which should have been padded with
+        // ☡ The final two bits, which should have been padded with
         // zeroes, have a nonzero value.
         //
-        // This should be impossible and indicates something went very
-        // wrong in base32 decoding.
-        throw new RangeError("Unexpected values in lower two bits");
+        // ※ This should be impossible and indicates something went
+        // very wrong in base32 decoding.
+        throw new RangeError(
+          `${ÉTIQUETTE}: Unexpected values in lower two bits`,
+        );
       } else {
         // The final two bits are zero as expected.
         const number = value >>> 2;
         if (checksum != number % 37) {
-          // The checksum does not match the number.
+          // ☡ The checksum does not match the number.
           throw new RangeError(
-            `Invalid checksum for id: ${identifier} (${number})`,
+            `${ÉTIQUETTE}: Invalid checksum for id: ${identifier} (${number})`,
           );
         } else {
           // The checksum matches. Mint a new identifier with the same
@@ -115,7 +124,7 @@ const normalizeID = ($) => {
  * A symbol which is used to identify the method for constructing a new
  * instance of a constructor based on stored data.
  *
- * ※ This value is exposed as `Storage.toInstance`.
+ * ※ This value is exposed as `Storage.toInstance´.
  */
 const toInstanceSymbol = Symbol("Storage.toInstance");
 
@@ -124,7 +133,7 @@ const toInstanceSymbol = Symbol("Storage.toInstance");
  * instance into an object of enumerable own properties suitable for
  * persistence.
  *
- * ※ This value is exposed as `Storage.toObject`.
+ * ※ This value is exposed as `Storage.toObject´.
  */
 const toObjectSymbol = Symbol("Storage.toObject");
 
@@ -134,7 +143,7 @@ const toObjectSymbol = Symbol("Storage.toObject");
  */
 export class Storage {
   static {
-    // Define `Storage.toInstance` and `Storage.toObject` as
+    // Define `Storage.toInstance´ and `Storage.toObject´ as
     // nonconfigurable, non·enumerable, read·only properties with the
     // appropriate values.
     Object.defineProperties(this, {
@@ -154,12 +163,15 @@ export class Storage {
   }
 
   /**
-   * A `Set` of deleted identifiers, to ensure they are not
+   * A `Set´ of deleted identifiers, to ensure they are not
    * re·assigned.
+   *
+   * The identifier `000-0000´ is deleted from the start and can only
+   * be manually set.
    */
-  #deleted = new Set();
+  #deleted = new Set([`${mintID(0)}`]);
 
-  /** The `Map` used to actually store the data internally. */
+  /** The `Map´ used to actually store the data internally. */
   #store = new Map();
 
   /**
@@ -172,10 +184,10 @@ export class Storage {
       ...object
     } = data;
     if (!(toInstanceSymbol in constructor)) {
-      // There is no method on the constructor for generating an
+      // ☡ There is no method on the constructor for generating an
       // instance.
       throw new TypeError(
-        "Constructor must implement Storage.toInstance for object to be retrieved.",
+        `${ÉTIQUETTE}: Constructor must implement Storage.toInstance for object to be retrieved.`,
       );
     } else {
       // Generate an instance and return it.
@@ -199,7 +211,7 @@ export class Storage {
       // The provided value does not have a method for generating an
       // object to store.
       throw new TypeError(
-        "Object must implement Storage.toObject to be stored.",
+        `${ÉTIQUETTE}: Object must implement Storage.toObject to be stored.`,
       );
     } else {
       // The provided value has a method for generating a storage
@@ -217,12 +229,18 @@ export class Storage {
           ) {
             // Generate successive identifiers until an available one
             // is reached.
+            //
+            // ※ Successive identifiers are used in order to guarantee
+            // an eventual result; continuing to generate random
+            // identifiers could go on forever.
             id = mintID(id.value + 1);
             literalValue = `${id}`;
           }
           return literalValue;
         } else {
-          // There are no identifiers left to assign.
+          // ☡ There are no identifiers left to assign.
+          //
+          // ※ This is unlikely to ever be possible in practice.
           throw new TypeError("Out of room.");
         }
       })();
@@ -259,9 +277,9 @@ export class Storage {
    */
   delete(id) {
     const store = this.#store;
-    const validID = normalizeID(id);
-    this.#deleted.add(validID);
-    return store.delete(validID);
+    const normalized = normalizeID(id);
+    this.#deleted.add(normalized);
+    return store.delete(normalized);
   }
 
   /** Yields successive identifier~instance pairs from storage. */
@@ -278,9 +296,9 @@ export class Storage {
    * constructed from data in storage.
    *
    * The callback function will be called with the constructed
-   * instance, its identifier, and this `Storage` instance.
+   * instance, its identifier, and this `Storage´ instance.
    *
-   * If a second argument is provided, it will be used as the `this`
+   * If a second argument is provided, it will be used as the `this´
    * value.
    */
   forEach(callback, thisArg = undefined) {
@@ -293,19 +311,19 @@ export class Storage {
 
   /**
    * Returns an instance constructed from the data stored at the
-   * provided identifier, or `null` if the identifier has no data.
+   * provided identifier, or `null´ if the identifier has no data.
    */
   get(id) {
     const store = this.#store;
-    const validID = normalizeID(id);
-    const data = store.get(validID);
+    const normalized = normalizeID(id);
+    const data = store.get(normalized);
     if (data == null) {
       // No object was at the provided identifier.
       return null;
     } else {
       // The provided identifier had a stored object; return the
       // constructed instance.
-      return this.#construct(data, validID);
+      return this.#construct(data, normalized);
     }
   }
 
@@ -325,7 +343,7 @@ export class Storage {
 
   /**
    * Sets the data for the provided identifier to be that generated
-   * from the provided instance, then returns this `Storage` object.
+   * from the provided instance, then returns this `Storage´ object.
    */
   set(id, instance) {
     this.#persist(instance, normalizeID(id));
@@ -336,7 +354,7 @@ export class Storage {
    * Returns the number of identifiers with data in storage.
    *
    * ☡ This number may be smaller than the actual number of used
-   * identifiers, as deleted identifiers are *not* freed up for re·use.
+   * identifiers, as deleted identifiers are ⹐not⹑ freed up for re·use.
    */
   get size() {
     return this.#store.size;
This page took 0.19344 seconds and 4 git commands to generate.