diff options
Diffstat (limited to 'aoc2023/build/packages/gleam_stdlib/src')
54 files changed, 0 insertions, 19687 deletions
diff --git a/aoc2023/build/packages/gleam_stdlib/src/dict.mjs b/aoc2023/build/packages/gleam_stdlib/src/dict.mjs deleted file mode 100644 index a8309e0..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/dict.mjs +++ /dev/null @@ -1,957 +0,0 @@ -/** - * This file uses jsdoc to annotate types. - * These types can be checked using the typescript compiler with "checkjs" option. - */ - -import { isEqual } from "./gleam.mjs"; - -const referenceMap = new WeakMap(); -const tempDataView = new DataView(new ArrayBuffer(8)); -let referenceUID = 0; -/** - * hash the object by reference using a weak map and incrementing uid - * @param {any} o - * @returns {number} - */ -function hashByReference(o) { - const known = referenceMap.get(o); - if (known !== undefined) { - return known; - } - const hash = referenceUID++; - if (referenceUID === 0x7fffffff) { - referenceUID = 0; - } - referenceMap.set(o, hash); - return hash; -} -/** - * merge two hashes in an order sensitive way - * @param {number} a - * @param {number} b - * @returns {number} - */ -function hashMerge(a, b) { - return (a ^ (b + 0x9e3779b9 + (a << 6) + (a >> 2))) | 0; -} -/** - * standard string hash popularised by java - * @param {string} s - * @returns {number} - */ -function hashString(s) { - let hash = 0; - const len = s.length; - for (let i = 0; i < len; i++) { - hash = (Math.imul(31, hash) + s.charCodeAt(i)) | 0; - } - return hash; -} -/** - * hash a number by converting to two integers and do some jumbling - * @param {number} n - * @returns {number} - */ -function hashNumber(n) { - tempDataView.setFloat64(0, n); - const i = tempDataView.getInt32(0); - const j = tempDataView.getInt32(4); - return Math.imul(0x45d9f3b, (i >> 16) ^ i) ^ j; -} -/** - * hash a BigInt by converting it to a string and hashing that - * @param {BigInt} n - * @returns {number} - */ -function hashBigInt(n) { - return hashString(n.toString()); -} -/** - * hash any js object - * @param {any} o - * @returns {number} - */ -function hashObject(o) { - const proto = Object.getPrototypeOf(o); - if (proto !== null && typeof proto.hashCode === "function") { - try { - const code = o.hashCode(o); - if (typeof code === "number") { - return code; - } - } catch {} - } - if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { - return hashByReference(o); - } - if (o instanceof Date) { - return hashNumber(o.getTime()); - } - let h = 0; - if (o instanceof ArrayBuffer) { - o = new Uint8Array(o); - } - if (Array.isArray(o) || o instanceof Uint8Array) { - for (let i = 0; i < o.length; i++) { - h = (Math.imul(31, h) + getHash(o[i])) | 0; - } - } else if (o instanceof Set) { - o.forEach((v) => { - h = (h + getHash(v)) | 0; - }); - } else if (o instanceof Map) { - o.forEach((v, k) => { - h = (h + hashMerge(getHash(v), getHash(k))) | 0; - }); - } else { - const keys = Object.keys(o); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - const v = o[k]; - h = (h + hashMerge(getHash(v), hashString(k))) | 0; - } - } - return h; -} -/** - * hash any js value - * @param {any} u - * @returns {number} - */ -export function getHash(u) { - if (u === null) return 0x42108422; - if (u === undefined) return 0x42108423; - if (u === true) return 0x42108421; - if (u === false) return 0x42108420; - switch (typeof u) { - case "number": - return hashNumber(u); - case "string": - return hashString(u); - case "bigint": - return hashBigInt(u); - case "object": - return hashObject(u); - case "symbol": - return hashByReference(u); - case "function": - return hashByReference(u); - default: - return 0; // should be unreachable - } -} -/** - * @template K,V - * @typedef {ArrayNode<K,V> | IndexNode<K,V> | CollisionNode<K,V>} Node - */ -/** - * @template K,V - * @typedef {{ type: typeof ENTRY, k: K, v: V }} Entry - */ -/** - * @template K,V - * @typedef {{ type: typeof ARRAY_NODE, size: number, array: (undefined | Entry<K,V> | Node<K,V>)[] }} ArrayNode - */ -/** - * @template K,V - * @typedef {{ type: typeof INDEX_NODE, bitmap: number, array: (Entry<K,V> | Node<K,V>)[] }} IndexNode - */ -/** - * @template K,V - * @typedef {{ type: typeof COLLISION_NODE, hash: number, array: Entry<K, V>[] }} CollisionNode - */ -/** - * @typedef {{ val: boolean }} Flag - */ -const SHIFT = 5; // number of bits you need to shift by to get the next bucket -const BUCKET_SIZE = Math.pow(2, SHIFT); -const MASK = BUCKET_SIZE - 1; // used to zero out all bits not in the bucket -const MAX_INDEX_NODE = BUCKET_SIZE / 2; // when does index node grow into array node -const MIN_ARRAY_NODE = BUCKET_SIZE / 4; // when does array node shrink to index node -const ENTRY = 0; -const ARRAY_NODE = 1; -const INDEX_NODE = 2; -const COLLISION_NODE = 3; -/** @type {IndexNode<any,any>} */ -const EMPTY = { - type: INDEX_NODE, - bitmap: 0, - array: [], -}; -/** - * Mask the hash to get only the bucket corresponding to shift - * @param {number} hash - * @param {number} shift - * @returns {number} - */ -function mask(hash, shift) { - return (hash >>> shift) & MASK; -} -/** - * Set only the Nth bit where N is the masked hash - * @param {number} hash - * @param {number} shift - * @returns {number} - */ -function bitpos(hash, shift) { - return 1 << mask(hash, shift); -} -/** - * Count the number of 1 bits in a number - * @param {number} x - * @returns {number} - */ -function bitcount(x) { - x -= (x >> 1) & 0x55555555; - x = (x & 0x33333333) + ((x >> 2) & 0x33333333); - x = (x + (x >> 4)) & 0x0f0f0f0f; - x += x >> 8; - x += x >> 16; - return x & 0x7f; -} -/** - * Calculate the array index of an item in a bitmap index node - * @param {number} bitmap - * @param {number} bit - * @returns {number} - */ -function index(bitmap, bit) { - return bitcount(bitmap & (bit - 1)); -} -/** - * Efficiently copy an array and set one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @param {T} val - * @returns {T[]} - */ -function cloneAndSet(arr, at, val) { - const len = arr.length; - const out = new Array(len); - for (let i = 0; i < len; ++i) { - out[i] = arr[i]; - } - out[at] = val; - return out; -} -/** - * Efficiently copy an array and insert one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @param {T} val - * @returns {T[]} - */ -function spliceIn(arr, at, val) { - const len = arr.length; - const out = new Array(len + 1); - let i = 0; - let g = 0; - while (i < at) { - out[g++] = arr[i++]; - } - out[g++] = val; - while (i < len) { - out[g++] = arr[i++]; - } - return out; -} -/** - * Efficiently copy an array and remove one value at an index - * @template T - * @param {T[]} arr - * @param {number} at - * @returns {T[]} - */ -function spliceOut(arr, at) { - const len = arr.length; - const out = new Array(len - 1); - let i = 0; - let g = 0; - while (i < at) { - out[g++] = arr[i++]; - } - ++i; - while (i < len) { - out[g++] = arr[i++]; - } - return out; -} -/** - * Create a new node containing two entries - * @template K,V - * @param {number} shift - * @param {K} key1 - * @param {V} val1 - * @param {number} key2hash - * @param {K} key2 - * @param {V} val2 - * @returns {Node<K,V>} - */ -function createNode(shift, key1, val1, key2hash, key2, val2) { - const key1hash = getHash(key1); - if (key1hash === key2hash) { - return { - type: COLLISION_NODE, - hash: key1hash, - array: [ - { type: ENTRY, k: key1, v: val1 }, - { type: ENTRY, k: key2, v: val2 }, - ], - }; - } - const addedLeaf = { val: false }; - return assoc( - assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), - shift, - key2hash, - key2, - val2, - addedLeaf - ); -} -/** - * @template T,K,V - * @callback AssocFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @param {V} val - * @param {Flag} addedLeaf - * @returns {Node<K,V>} - */ -/** - * Associate a node with a new entry, creating a new node - * @template T,K,V - * @type {AssocFunction<Node<K,V>,K,V>} - */ -function assoc(root, shift, hash, key, val, addedLeaf) { - switch (root.type) { - case ARRAY_NODE: - return assocArray(root, shift, hash, key, val, addedLeaf); - case INDEX_NODE: - return assocIndex(root, shift, hash, key, val, addedLeaf); - case COLLISION_NODE: - return assocCollision(root, shift, hash, key, val, addedLeaf); - } -} -/** - * @template T,K,V - * @type {AssocFunction<ArrayNode<K,V>,K,V>} - */ -function assocArray(root, shift, hash, key, val, addedLeaf) { - const idx = mask(hash, shift); - const node = root.array[idx]; - // if the corresponding index is empty set the index to a newly created node - if (node === undefined) { - addedLeaf.val = true; - return { - type: ARRAY_NODE, - size: root.size + 1, - array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }), - }; - } - if (node.type === ENTRY) { - // if keys are equal replace the entry - if (isEqual(key, node.k)) { - if (val === node.v) { - return root; - } - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }), - }; - } - // otherwise upgrade the entry to a node and insert - addedLeaf.val = true; - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet( - root.array, - idx, - createNode(shift + SHIFT, node.k, node.v, hash, key, val) - ), - }; - } - // otherwise call assoc on the child node - const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); - // if the child node hasn't changed just return the old root - if (n === node) { - return root; - } - // otherwise set the index to the new node - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, n), - }; -} -/** - * @template T,K,V - * @type {AssocFunction<IndexNode<K,V>,K,V>} - */ -function assocIndex(root, shift, hash, key, val, addedLeaf) { - const bit = bitpos(hash, shift); - const idx = index(root.bitmap, bit); - // if there is already a item at this hash index.. - if ((root.bitmap & bit) !== 0) { - // if there is a node at the index (not an entry), call assoc on the child node - const node = root.array[idx]; - if (node.type !== ENTRY) { - const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); - if (n === node) { - return root; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, n), - }; - } - // otherwise there is an entry at the index - // if the keys are equal replace the entry with the updated value - const nodeKey = node.k; - if (isEqual(key, nodeKey)) { - if (val === node.v) { - return root; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }), - }; - } - // if the keys are not equal, replace the entry with a new child node - addedLeaf.val = true; - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet( - root.array, - idx, - createNode(shift + SHIFT, nodeKey, node.v, hash, key, val) - ), - }; - } else { - // else there is currently no item at the hash index - const n = root.array.length; - // if the number of nodes is at the maximum, expand this node into an array node - if (n >= MAX_INDEX_NODE) { - // create a 32 length array for the new array node (one for each bit in the hash) - const nodes = new Array(32); - // create and insert a node for the new entry - const jdx = mask(hash, shift); - nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); - let j = 0; - let bitmap = root.bitmap; - // place each item in the index node into the correct spot in the array node - // loop through all 32 bits / array positions - for (let i = 0; i < 32; i++) { - if ((bitmap & 1) !== 0) { - const node = root.array[j++]; - nodes[i] = node; - } - // shift the bitmap to process the next bit - bitmap = bitmap >>> 1; - } - return { - type: ARRAY_NODE, - size: n + 1, - array: nodes, - }; - } else { - // else there is still space in this index node - // simply insert a new entry at the hash index - const newArray = spliceIn(root.array, idx, { - type: ENTRY, - k: key, - v: val, - }); - addedLeaf.val = true; - return { - type: INDEX_NODE, - bitmap: root.bitmap | bit, - array: newArray, - }; - } - } -} -/** - * @template T,K,V - * @type {AssocFunction<CollisionNode<K,V>,K,V>} - */ -function assocCollision(root, shift, hash, key, val, addedLeaf) { - // if there is a hash collision - if (hash === root.hash) { - const idx = collisionIndexOf(root, key); - // if this key already exists replace the entry with the new value - if (idx !== -1) { - const entry = root.array[idx]; - if (entry.v === val) { - return root; - } - return { - type: COLLISION_NODE, - hash: hash, - array: cloneAndSet(root.array, idx, { type: ENTRY, k: key, v: val }), - }; - } - // otherwise insert the entry at the end of the array - const size = root.array.length; - addedLeaf.val = true; - return { - type: COLLISION_NODE, - hash: hash, - array: cloneAndSet(root.array, size, { type: ENTRY, k: key, v: val }), - }; - } - // if there is no hash collision, upgrade to an index node - return assoc( - { - type: INDEX_NODE, - bitmap: bitpos(root.hash, shift), - array: [root], - }, - shift, - hash, - key, - val, - addedLeaf - ); -} -/** - * Find the index of a key in the collision node's array - * @template K,V - * @param {CollisionNode<K,V>} root - * @param {K} key - * @returns {number} - */ -function collisionIndexOf(root, key) { - const size = root.array.length; - for (let i = 0; i < size; i++) { - if (isEqual(key, root.array[i].k)) { - return i; - } - } - return -1; -} -/** - * @template T,K,V - * @callback FindFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @returns {undefined | Entry<K,V>} - */ -/** - * Return the found entry or undefined if not present in the root - * @template K,V - * @type {FindFunction<Node<K,V>,K,V>} - */ -function find(root, shift, hash, key) { - switch (root.type) { - case ARRAY_NODE: - return findArray(root, shift, hash, key); - case INDEX_NODE: - return findIndex(root, shift, hash, key); - case COLLISION_NODE: - return findCollision(root, key); - } -} -/** - * @template K,V - * @type {FindFunction<ArrayNode<K,V>,K,V>} - */ -function findArray(root, shift, hash, key) { - const idx = mask(hash, shift); - const node = root.array[idx]; - if (node === undefined) { - return undefined; - } - if (node.type !== ENTRY) { - return find(node, shift + SHIFT, hash, key); - } - if (isEqual(key, node.k)) { - return node; - } - return undefined; -} -/** - * @template K,V - * @type {FindFunction<IndexNode<K,V>,K,V>} - */ -function findIndex(root, shift, hash, key) { - const bit = bitpos(hash, shift); - if ((root.bitmap & bit) === 0) { - return undefined; - } - const idx = index(root.bitmap, bit); - const node = root.array[idx]; - if (node.type !== ENTRY) { - return find(node, shift + SHIFT, hash, key); - } - if (isEqual(key, node.k)) { - return node; - } - return undefined; -} -/** - * @template K,V - * @param {CollisionNode<K,V>} root - * @param {K} key - * @returns {undefined | Entry<K,V>} - */ -function findCollision(root, key) { - const idx = collisionIndexOf(root, key); - if (idx < 0) { - return undefined; - } - return root.array[idx]; -} -/** - * @template T,K,V - * @callback WithoutFunction - * @param {T} root - * @param {number} shift - * @param {number} hash - * @param {K} key - * @returns {undefined | Node<K,V>} - */ -/** - * Remove an entry from the root, returning the updated root. - * Returns undefined if the node should be removed from the parent. - * @template K,V - * @type {WithoutFunction<Node<K,V>,K,V>} - * */ -function without(root, shift, hash, key) { - switch (root.type) { - case ARRAY_NODE: - return withoutArray(root, shift, hash, key); - case INDEX_NODE: - return withoutIndex(root, shift, hash, key); - case COLLISION_NODE: - return withoutCollision(root, key); - } -} -/** - * @template K,V - * @type {WithoutFunction<ArrayNode<K,V>,K,V>} - */ -function withoutArray(root, shift, hash, key) { - const idx = mask(hash, shift); - const node = root.array[idx]; - if (node === undefined) { - return root; // already empty - } - let n = undefined; - // if node is an entry and the keys are not equal there is nothing to remove - // if node is not an entry do a recursive call - if (node.type === ENTRY) { - if (!isEqual(node.k, key)) { - return root; // no changes - } - } else { - n = without(node, shift + SHIFT, hash, key); - if (n === node) { - return root; // no changes - } - } - // if the recursive call returned undefined the node should be removed - if (n === undefined) { - // if the number of child nodes is at the minimum, pack into an index node - if (root.size <= MIN_ARRAY_NODE) { - const arr = root.array; - const out = new Array(root.size - 1); - let i = 0; - let j = 0; - let bitmap = 0; - while (i < idx) { - const nv = arr[i]; - if (nv !== undefined) { - out[j] = nv; - bitmap |= 1 << i; - ++j; - } - ++i; - } - ++i; // skip copying the removed node - while (i < arr.length) { - const nv = arr[i]; - if (nv !== undefined) { - out[j] = nv; - bitmap |= 1 << i; - ++j; - } - ++i; - } - return { - type: INDEX_NODE, - bitmap: bitmap, - array: out, - }; - } - return { - type: ARRAY_NODE, - size: root.size - 1, - array: cloneAndSet(root.array, idx, n), - }; - } - return { - type: ARRAY_NODE, - size: root.size, - array: cloneAndSet(root.array, idx, n), - }; -} -/** - * @template K,V - * @type {WithoutFunction<IndexNode<K,V>,K,V>} - */ -function withoutIndex(root, shift, hash, key) { - const bit = bitpos(hash, shift); - if ((root.bitmap & bit) === 0) { - return root; // already empty - } - const idx = index(root.bitmap, bit); - const node = root.array[idx]; - // if the item is not an entry - if (node.type !== ENTRY) { - const n = without(node, shift + SHIFT, hash, key); - if (n === node) { - return root; // no changes - } - // if not undefined, the child node still has items, so update it - if (n !== undefined) { - return { - type: INDEX_NODE, - bitmap: root.bitmap, - array: cloneAndSet(root.array, idx, n), - }; - } - // otherwise the child node should be removed - // if it was the only child node, remove this node from the parent - if (root.bitmap === bit) { - return undefined; - } - // otherwise just remove the child node - return { - type: INDEX_NODE, - bitmap: root.bitmap ^ bit, - array: spliceOut(root.array, idx), - }; - } - // otherwise the item is an entry, remove it if the key matches - if (isEqual(key, node.k)) { - if (root.bitmap === bit) { - return undefined; - } - return { - type: INDEX_NODE, - bitmap: root.bitmap ^ bit, - array: spliceOut(root.array, idx), - }; - } - return root; -} -/** - * @template K,V - * @param {CollisionNode<K,V>} root - * @param {K} key - * @returns {undefined | Node<K,V>} - */ -function withoutCollision(root, key) { - const idx = collisionIndexOf(root, key); - // if the key not found, no changes - if (idx < 0) { - return root; - } - // otherwise the entry was found, remove it - // if it was the only entry in this node, remove the whole node - if (root.array.length === 1) { - return undefined; - } - // otherwise just remove the entry - return { - type: COLLISION_NODE, - hash: root.hash, - array: spliceOut(root.array, idx), - }; -} -/** - * @template K,V - * @param {undefined | Node<K,V>} root - * @param {(value:V,key:K)=>void} fn - * @returns {void} - */ -function forEach(root, fn) { - if (root === undefined) { - return; - } - const items = root.array; - const size = items.length; - for (let i = 0; i < size; i++) { - const item = items[i]; - if (item === undefined) { - continue; - } - if (item.type === ENTRY) { - fn(item.v, item.k); - continue; - } - forEach(item, fn); - } -} -/** - * Extra wrapper to keep track of Dict size and clean up the API - * @template K,V - */ -export default class Dict { - /** - * @template V - * @param {Record<string,V>} o - * @returns {Dict<string,V>} - */ - static fromObject(o) { - const keys = Object.keys(o); - /** @type Dict<string,V> */ - let m = Dict.new(); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - m = m.set(k, o[k]); - } - return m; - } - /** - * @template K,V - * @param {Map<K,V>} o - * @returns {Dict<K,V>} - */ - static fromMap(o) { - /** @type Dict<K,V> */ - let m = Dict.new(); - o.forEach((v, k) => { - m = m.set(k, v); - }); - return m; - } - static new() { - return new Dict(undefined, 0); - } - /** - * @param {undefined | Node<K,V>} root - * @param {number} size - */ - constructor(root, size) { - this.root = root; - this.size = size; - } - /** - * @template NotFound - * @param {K} key - * @param {NotFound} notFound - * @returns {NotFound | V} - */ - get(key, notFound) { - if (this.root === undefined) { - return notFound; - } - const found = find(this.root, 0, getHash(key), key); - if (found === undefined) { - return notFound; - } - return found.v; - } - /** - * @param {K} key - * @param {V} val - * @returns {Dict<K,V>} - */ - set(key, val) { - const addedLeaf = { val: false }; - const root = this.root === undefined ? EMPTY : this.root; - const newRoot = assoc(root, 0, getHash(key), key, val, addedLeaf); - if (newRoot === this.root) { - return this; - } - return new Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); - } - /** - * @param {K} key - * @returns {Dict<K,V>} - */ - delete(key) { - if (this.root === undefined) { - return this; - } - const newRoot = without(this.root, 0, getHash(key), key); - if (newRoot === this.root) { - return this; - } - if (newRoot === undefined) { - return Dict.new(); - } - return new Dict(newRoot, this.size - 1); - } - /** - * @param {K} key - * @returns {boolean} - */ - has(key) { - if (this.root === undefined) { - return false; - } - return find(this.root, 0, getHash(key), key) !== undefined; - } - /** - * @returns {[K,V][]} - */ - entries() { - if (this.root === undefined) { - return []; - } - /** @type [K,V][] */ - const result = []; - this.forEach((v, k) => result.push([k, v])); - return result; - } - /** - * - * @param {(val:V,key:K)=>void} fn - */ - forEach(fn) { - forEach(this.root, fn); - } - hashCode() { - let h = 0; - this.forEach((v, k) => { - h = (h + hashMerge(getHash(v), getHash(k))) | 0; - }); - return h; - } - /** - * @param {unknown} o - * @returns {boolean} - */ - equals(o) { - if (!(o instanceof Dict) || this.size !== o.size) { - return false; - } - let equal = true; - this.forEach((v, k) => { - equal = equal && isEqual(o.get(k, !v), v); - }); - return equal; - } -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/base.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/base.gleam deleted file mode 100644 index eab2f0b..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/base.gleam +++ /dev/null @@ -1,21 +0,0 @@ -import gleam/bit_array - -@deprecated("Please use `base64_encode` in the `gleam/bit_array` module instead.") -pub fn encode64(input: BitArray, padding: Bool) -> String { - bit_array.base64_encode(input, padding) -} - -@deprecated("Please use `base64_decode` in the `gleam/bit_array` module instead.") -pub fn decode64(encoded: String) -> Result(BitArray, Nil) { - bit_array.base64_decode(encoded) -} - -@deprecated("Please use `base64_url_encode` in the `gleam/bit_array` module instead.") -pub fn url_encode64(input: BitArray, padding: Bool) -> String { - bit_array.base64_url_encode(input, padding) -} - -@deprecated("Please use `base64_url_decode` in the `gleam/bit_array` module instead.") -pub fn url_decode64(encoded: String) -> Result(BitArray, Nil) { - bit_array.base64_url_decode(encoded) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_array.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_array.gleam deleted file mode 100644 index 79860e9..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_array.gleam +++ /dev/null @@ -1,157 +0,0 @@ -//// BitArrays are a sequence of binary data of any length. - -import gleam/string - -/// Converts a UTF-8 `String` type into a `BitArray`. -/// -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_from_string") -pub fn from_string(x: String) -> BitArray - -/// Returns an integer which is the number of bytes in the bit array. -/// -@external(erlang, "erlang", "byte_size") -@external(javascript, "../gleam_stdlib.mjs", "length") -pub fn byte_size(x: BitArray) -> Int - -/// Creates a new bit array by joining two bit arrays. -/// -/// ## Examples -/// -/// ```gleam -/// > append(to: from_string("butter"), suffix: from_string("fly")) -/// from_string("butterfly") -/// ``` -/// -pub fn append(to first: BitArray, suffix second: BitArray) -> BitArray { - concat([first, second]) -} - -/// Extracts a sub-section of a bit array. -/// -/// The slice will start at given position and continue up to specified -/// length. -/// A negative length can be used to extract bytes at the end of a bit array. -/// -/// This function runs in constant time. -/// -@external(erlang, "gleam_stdlib", "bit_array_slice") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_slice") -pub fn slice( - from string: BitArray, - at position: Int, - take length: Int, -) -> Result(BitArray, Nil) - -/// Tests to see whether a bit array is valid UTF-8. -/// -pub fn is_utf8(bits: BitArray) -> Bool { - do_is_utf8(bits) -} - -@target(erlang) -fn do_is_utf8(bits: BitArray) -> Bool { - case bits { - <<>> -> True - <<_:utf8, rest:bytes>> -> do_is_utf8(rest) - _ -> False - } -} - -@target(javascript) -fn do_is_utf8(bits: BitArray) -> Bool { - case to_string(bits) { - Ok(_) -> True - _ -> False - } -} - -/// Converts a bit array to a string. -/// -/// Returns an error if the bit array is invalid UTF-8 data. -/// -pub fn to_string(bits: BitArray) -> Result(String, Nil) { - do_to_string(bits) -} - -@target(erlang) -@external(erlang, "gleam_stdlib", "identity") -fn unsafe_to_string(a: BitArray) -> String - -@target(erlang) -fn do_to_string(bits: BitArray) -> Result(String, Nil) { - case is_utf8(bits) { - True -> Ok(unsafe_to_string(bits)) - False -> Error(Nil) - } -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "bit_array_to_string") -fn do_to_string(a: BitArray) -> Result(String, Nil) - -/// Creates a new bit array by joining multiple binaries. -/// -/// ## Examples -/// -/// ```gleam -/// > concat([from_string("butter"), from_string("fly")]) -/// from_string("butterfly") -/// ``` -/// -@external(erlang, "gleam_stdlib", "bit_array_concat") -@external(javascript, "../gleam_stdlib.mjs", "bit_array_concat") -pub fn concat(bit_arrays: List(BitArray)) -> BitArray - -/// Encodes a BitArray into a base 64 encoded string. -/// -pub fn base64_encode(input: BitArray, padding: Bool) -> String { - let encoded = encode64(input) - case padding { - True -> encoded - False -> string.replace(encoded, "=", "") - } -} - -@external(erlang, "base64", "encode") -@external(javascript, "../gleam_stdlib.mjs", "encode64") -fn encode64(a: BitArray) -> String - -/// Decodes a base 64 encoded string into a `BitArray`. -/// -pub fn base64_decode(encoded: String) -> Result(BitArray, Nil) { - let padded = case byte_size(from_string(encoded)) % 4 { - 0 -> encoded - n -> string.append(encoded, string.repeat("=", 4 - n)) - } - decode64(padded) -} - -@external(erlang, "gleam_stdlib", "base_decode64") -@external(javascript, "../gleam_stdlib.mjs", "decode64") -fn decode64(a: String) -> Result(BitArray, Nil) - -/// Encodes a `BitArray` into a base 64 encoded string with URL and filename safe alphabet. -/// -pub fn base64_url_encode(input: BitArray, padding: Bool) -> String { - base64_encode(input, padding) - |> string.replace("+", "-") - |> string.replace("/", "_") -} - -/// Decodes a base 64 encoded string with URL and filename safe alphabet into a `BitArray`. -/// -pub fn base64_url_decode(encoded: String) -> Result(BitArray, Nil) { - encoded - |> string.replace("-", "+") - |> string.replace("_", "/") - |> base64_decode() -} - -@external(erlang, "binary", "encode_hex") -@external(javascript, "../gleam_stdlib.mjs", "base16_encode") -pub fn base16_encode(input: BitArray) -> String - -@external(erlang, "gleam_stdlib", "base16_decode") -@external(javascript, "../gleam_stdlib.mjs", "base16_decode") -pub fn base16_decode(input: String) -> Result(BitArray, Nil) diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_builder.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_builder.gleam deleted file mode 100644 index ce6fe52..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_builder.gleam +++ /dev/null @@ -1,80 +0,0 @@ -//// This module has been deprecated in favour of `gleam/bytes_builder`. - -import gleam/bytes_builder -import gleam/string_builder.{type StringBuilder} - -pub type BitBuilder = - bytes_builder.BytesBuilder - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn new() -> BitBuilder { - bytes_builder.new() -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn prepend(to: BitBuilder, prefix: BitArray) -> BitBuilder { - bytes_builder.prepend(to, prefix) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn append(to: BitBuilder, suffix: BitArray) -> BitBuilder { - bytes_builder.append(to, suffix) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn prepend_builder(to: BitBuilder, prefix: BitBuilder) -> BitBuilder { - bytes_builder.prepend_builder(to, prefix) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn append_builder( - to first: BitBuilder, - suffix second: BitBuilder, -) -> BitBuilder { - bytes_builder.append_builder(first, second) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn prepend_string(to: BitBuilder, prefix: String) -> BitBuilder { - bytes_builder.prepend_string(to, prefix) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn append_string(to: BitBuilder, suffix: String) -> BitBuilder { - bytes_builder.append_string(to, suffix) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn concat(builders: List(BitBuilder)) -> BitBuilder { - bytes_builder.concat(builders) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn concat_bit_strings(bits: List(BitArray)) -> BitBuilder { - bytes_builder.concat_bit_arrays(bits) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn from_string(string: String) -> BitBuilder { - bytes_builder.from_string(string) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn from_string_builder(builder: StringBuilder) -> BitBuilder { - bytes_builder.from_string_builder(builder) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn from_bit_string(bits: BitArray) -> BitBuilder { - bytes_builder.from_bit_array(bits) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn to_bit_string(builder: BitBuilder) -> BitArray { - bytes_builder.to_bit_array(builder) -} - -@deprecated("Please use the `gleam/bytes_builder` module instead.") -pub fn byte_size(builder: BitBuilder) -> Int { - bytes_builder.byte_size(builder) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_string.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_string.gleam deleted file mode 100644 index b703da0..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/bit_string.gleam +++ /dev/null @@ -1,43 +0,0 @@ -//// This module has been deprecated. Please use the `gleam/bit_array` module -//// instead. - -import gleam/bit_array - -@deprecated("Please use the `gleam/bit_array` module instead.") -pub fn from_string(x: String) -> BitArray { - bit_array.from_string(x) -} - -@deprecated("Please use the `gleam/bit_array` module instead.") -pub fn byte_size(x: BitArray) -> Int { - bit_array.byte_size(x) -} - -@deprecated("Please use the `gleam/bit_array` module instead.") -pub fn append(to first: BitArray, suffix second: BitArray) -> BitArray { - bit_array.append(first, second) -} - -@deprecated("Please use the `gleam/bit_array` module instead.") -pub fn slice( - from string: BitArray, - at position: Int, - take length: Int, -) -> Result(BitArray, Nil) { - bit_array.slice(string, position, length) -} - -@deprecated("Please use the `gleam/bit_array` module instead.") -pub fn is_utf8(bits: BitArray) -> Bool { - bit_array.is_utf8(bits) -} - -@deprecated("Please use the `gleam/bit_array` module instead.") -pub fn to_string(bits: BitArray) -> Result(String, Nil) { - bit_array.to_string(bits) -} - -@deprecated("Please use the `gleam/bit_array` module instead.") -pub fn concat(bit_strings: List(BitArray)) -> BitArray { - bit_array.concat(bit_strings) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/bool.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/bool.gleam deleted file mode 100644 index 91bd6b7..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/bool.gleam +++ /dev/null @@ -1,428 +0,0 @@ -//// A type with two possible values, `True` and `False`. Used to indicate whether -//// things are... true or false! -//// -//// Often is it clearer and offers more type safety to define a custom type -//// than to use `Bool`. For example, rather than having a `is_teacher: Bool` -//// field consider having a `role: SchoolRole` field where `SchoolRole` is a custom -//// type that can be either `Student` or `Teacher`. - -import gleam/order.{type Order} - -/// Returns the and of two bools, but it evaluates both arguments. -/// -/// It's the function equivalent of the `&&` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > and(True, True) -/// True -/// ``` -/// -/// ```gleam -/// > and(False, True) -/// False -/// ``` -/// -/// ```gleam -/// > False |> and(True) -/// False -/// ``` -/// -pub fn and(a: Bool, b: Bool) -> Bool { - a && b -} - -/// Returns the or of two bools, but it evaluates both arguments. -/// -/// It's the function equivalent of the `||` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > or(True, True) -/// True -/// ``` -/// -/// ```gleam -/// > or(False, True) -/// True -/// ``` -/// -/// ```gleam -/// > False |> or(True) -/// True -/// ``` -/// -pub fn or(a: Bool, b: Bool) -> Bool { - a || b -} - -/// Returns the opposite bool value. -/// -/// This is the same as the `!` or `not` operators in some other languages. -/// -/// ## Examples -/// -/// ```gleam -/// > negate(True) -/// False -/// ``` -/// -/// ```gleam -/// > negate(False) -/// True -/// ``` -/// -pub fn negate(bool: Bool) -> Bool { - case bool { - True -> False - False -> True - } -} - -/// Returns the nor of two bools. -/// -/// ## Examples -/// -/// ```gleam -/// > nor(False, False) -/// True -/// ``` -/// -/// ```gleam -/// > nor(False, True) -/// False -/// ``` -/// -/// ```gleam -/// > nor(True, False) -/// False -/// ``` -/// -/// ```gleam -/// > nor(True, True) -/// False -/// ``` -/// -pub fn nor(a: Bool, b: Bool) -> Bool { - case a, b { - False, False -> True - False, True -> False - True, False -> False - True, True -> False - } -} - -/// Returns the nand of two bools. -/// -/// ## Examples -/// -/// ```gleam -/// > nand(False, False) -/// True -/// ``` -/// -/// ```gleam -/// > nand(False, True) -/// True -/// ``` -/// -/// ```gleam -/// > nand(True, False) -/// True -/// ``` -/// -/// ```gleam -/// > nand(True, True) -/// False -/// ``` -/// -pub fn nand(a: Bool, b: Bool) -> Bool { - case a, b { - False, False -> True - False, True -> True - True, False -> True - True, True -> False - } -} - -/// Returns the exclusive or of two bools. -/// -/// ## Examples -/// -/// ```gleam -/// > exclusive_or(False, False) -/// False -/// ``` -/// -/// ```gleam -/// > exclusive_or(False, True) -/// True -/// ``` -/// -/// ```gleam -/// > exclusive_or(True, False) -/// True -/// ``` -/// -/// ```gleam -/// > exclusive_or(True, True) -/// False -/// ``` -/// -pub fn exclusive_or(a: Bool, b: Bool) -> Bool { - case a, b { - False, False -> False - False, True -> True - True, False -> True - True, True -> False - } -} - -/// Returns the exclusive nor of two bools. -/// -/// ## Examples -/// -/// ```gleam -/// > exclusive_nor(False, False) -/// True -/// ``` -/// -/// ```gleam -/// > exclusive_nor(False, True) -/// False -/// ``` -/// -/// ```gleam -/// > exclusive_nor(True, False) -/// False -/// ``` -/// -/// ```gleam -/// > exclusive_nor(True, True) -/// True -/// ``` -/// -pub fn exclusive_nor(a: Bool, b: Bool) -> Bool { - case a, b { - False, False -> True - False, True -> False - True, False -> False - True, True -> True - } -} - -/// Compares two bools and returns the first value's `Order` to the second. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/order -/// > compare(True, False) -/// order.Gt -/// ``` -/// -pub fn compare(a: Bool, with b: Bool) -> Order { - case a, b { - True, True -> order.Eq - True, False -> order.Gt - False, False -> order.Eq - False, True -> order.Lt - } -} - -/// Returns `True` if either argument's value is `True`. -/// -/// ## Examples -/// -/// ```gleam -/// > max(True, False) -/// True -/// ``` -/// -/// ```gleam -/// > max(False, True) -/// True -/// ``` -/// -/// ```gleam -/// > max(False, False) -/// False -/// ``` -/// -pub fn max(a: Bool, b: Bool) -> Bool { - case a { - True -> True - False -> b - } -} - -/// Returns `False` if either bool value is `False`. -/// -/// ## Examples -/// -/// ```gleam -/// > min(True, False) -/// False -/// ``` -/// -/// ```gleam -/// > min(False, True) -/// False -/// -/// > min(False, False) -/// False -/// ``` -/// -pub fn min(a: Bool, b: Bool) -> Bool { - case a { - False -> False - True -> b - } -} - -/// Returns a numeric representation of the given bool. -/// -/// ## Examples -/// -/// ```gleam -/// > to_int(True) -/// 1 -/// -/// > to_int(False) -/// 0 -/// ``` -/// -pub fn to_int(bool: Bool) -> Int { - case bool { - False -> 0 - True -> 1 - } -} - -/// Returns a string representation of the given bool. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(True) -/// "True" -/// ``` -/// -/// ```gleam -/// > to_string(False) -/// "False" -/// ``` -/// -pub fn to_string(bool: Bool) -> String { - case bool { - False -> "False" - True -> "True" - } -} - -/// Run a callback function if the given bool is `False`, otherwise return a -/// default value. -/// -/// With a `use` expression this function can simulate the early-return pattern -/// found in some other programming languages. -/// -/// In a procedural language: -/// -/// ```js -/// if (predicate) return value; -/// // ... -/// ``` -/// -/// In Gleam with a `use` expression: -/// -/// ```gleam -/// use <- guard(when: predicate, return: value) -/// // ... -/// ``` -/// -/// Like everything in Gleam `use` is an expression, so it short circuits the -/// current block, not the entire function. As a result you can assign the value -/// to a variable: -/// -/// ```gleam -/// let x = { -/// use <- guard(when: predicate, return: value) -/// // ... -/// } -/// ``` -/// -/// Note that unlike in procedural languages the `return` value is evaluated -/// even when the predicate is `False`, so it is advisable not to perform -/// expensive computation there. -/// -/// -/// ## Examples -/// -/// ```gleam -/// > let name = "" -/// > use <- guard(when: name == "", return: "Welcome!") -/// > "Hello, " <> name -/// "Welcome!" -/// ``` -/// -/// ```gleam -/// > let name = "Kamaka" -/// > use <- guard(when: name == "", return: "Welcome!") -/// > "Hello, " <> name -/// "Hello, Kamaka" -/// ``` -/// -pub fn guard( - when requirement: Bool, - return consequence: t, - otherwise alternative: fn() -> t, -) -> t { - case requirement { - True -> consequence - False -> alternative() - } -} - -/// Runs a callback function if the given bool is `True`, otherwise runs an -/// alternative callback function. -/// -/// Useful when further computation should be delayed regardless of the given -/// bool's value. -/// -/// See [`guard`](#guard) for more info. -/// -/// ## Examples -/// -/// ```gleam -/// > let name = "Kamaka" -/// > let inquiry = fn() { "How may we address you?" } -/// > use <- lazy_guard(when: name == "", return: inquiry) -/// > "Hello, " <> name -/// "Hello, Kamaka" -/// ``` -/// -/// ```gleam -/// > import gleam/int -/// > let name = "" -/// > let greeting = fn() { "Hello, " <> name } -/// > use <- lazy_guard(when: name == "", otherwise: greeting) -/// > let number = int.random(1, 99) -/// > let name = "User " <> int.to_string(number) -/// > "Welcome, " <> name -/// "Welcome, User 54" -/// ``` -/// -pub fn lazy_guard( - when requirement: Bool, - return consequence: fn() -> a, - otherwise alternative: fn() -> a, -) -> a { - case requirement { - True -> consequence() - False -> alternative() - } -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/bytes_builder.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/bytes_builder.gleam deleted file mode 100644 index 20c145d..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/bytes_builder.gleam +++ /dev/null @@ -1,197 +0,0 @@ -//// BytesBuilder is a type used for efficiently concatenating bytes together -//// without copying. -//// -//// If we append one bit array to another the bit arrays must be copied to a -//// new location in memory so that they can sit together. This behaviour -//// enables efficient reading of the string but copying can be expensive, -//// especially if we want to join many bit arrays together. -//// -//// BytesBuilder is different in that it can be joined together in constant -//// time using minimal memory, and then can be efficiently converted to a -//// bit array using the `to_bit_array` function. -//// -//// Byte builders are always byte aligned, so that a number of bits that is not -//// divisible by 8 will be padded with 0s. -//// -//// On Erlang this type is compatible with Erlang's iolists. - -// TODO: pad bit arrays to byte boundaries when adding to a builder. -import gleam/string_builder.{type StringBuilder} -import gleam/list -import gleam/bit_array - -pub opaque type BytesBuilder { - Bytes(BitArray) - Text(StringBuilder) - Many(List(BytesBuilder)) -} - -/// Create an empty `BytesBuilder`. Useful as the start of a pipe chaining many -/// builders together. -/// -pub fn new() -> BytesBuilder { - concat([]) -} - -/// Prepends a bit array to the start of a builder. -/// -/// Runs in constant time. -/// -pub fn prepend(to second: BytesBuilder, prefix first: BitArray) -> BytesBuilder { - append_builder(from_bit_array(first), second) -} - -/// Appends a bit array to the end of a builder. -/// -/// Runs in constant time. -/// -pub fn append(to first: BytesBuilder, suffix second: BitArray) -> BytesBuilder { - append_builder(first, from_bit_array(second)) -} - -/// Prepends a builder onto the start of another. -/// -/// Runs in constant time. -/// -pub fn prepend_builder( - to second: BytesBuilder, - prefix first: BytesBuilder, -) -> BytesBuilder { - append_builder(first, second) -} - -/// Appends a builder onto the end of another. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "iodata_append") -pub fn append_builder( - to first: BytesBuilder, - suffix second: BytesBuilder, -) -> BytesBuilder { - case second { - Many(builders) -> Many([first, ..builders]) - _ -> Many([first, second]) - } -} - -/// Prepends a string onto the start of a builder. -/// -/// Runs in constant time when running on Erlang. -/// Runs in linear time with the length of the string otherwise. -/// -pub fn prepend_string( - to second: BytesBuilder, - prefix first: String, -) -> BytesBuilder { - append_builder(from_string(first), second) -} - -/// Appends a string onto the end of a builder. -/// -/// Runs in constant time when running on Erlang. -/// Runs in linear time with the length of the string otherwise. -/// -pub fn append_string( - to first: BytesBuilder, - suffix second: String, -) -> BytesBuilder { - append_builder(first, from_string(second)) -} - -/// Joins a list of builders into a single builder. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "identity") -pub fn concat(builders: List(BytesBuilder)) -> BytesBuilder { - Many(builders) -} - -/// Joins a list of bit arrays into a single builder. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "identity") -pub fn concat_bit_arrays(bits: List(BitArray)) -> BytesBuilder { - bits - |> list.map(fn(b) { from_bit_array(b) }) - |> concat() -} - -/// Creates a new builder from a string. -/// -/// Runs in constant time when running on Erlang. -/// Runs in linear time otherwise. -/// -@external(erlang, "gleam_stdlib", "wrap_list") -pub fn from_string(string: String) -> BytesBuilder { - Text(string_builder.from_string(string)) -} - -/// Creates a new builder from a string builder. -/// -/// Runs in constant time when running on Erlang. -/// Runs in linear time otherwise. -/// -@external(erlang, "gleam_stdlib", "wrap_list") -pub fn from_string_builder(builder: StringBuilder) -> BytesBuilder { - Text(builder) -} - -/// Creates a new builder from a bit array. -/// -/// Runs in constant time. -/// -@external(erlang, "gleam_stdlib", "wrap_list") -pub fn from_bit_array(bits: BitArray) -> BytesBuilder { - Bytes(bits) -} - -/// Turns an builder into a bit array. -/// -/// Runs in linear time. -/// -/// When running on Erlang this function is implemented natively by the -/// virtual machine and is highly optimised. -/// -@external(erlang, "erlang", "list_to_bitstring") -pub fn to_bit_array(builder: BytesBuilder) -> BitArray { - [[builder]] - |> to_list([]) - |> list.reverse - |> bit_array.concat -} - -fn to_list( - stack: List(List(BytesBuilder)), - acc: List(BitArray), -) -> List(BitArray) { - case stack { - [] -> acc - - [[], ..remaining_stack] -> to_list(remaining_stack, acc) - - [[Bytes(bits), ..rest], ..remaining_stack] -> - to_list([rest, ..remaining_stack], [bits, ..acc]) - - [[Text(builder), ..rest], ..remaining_stack] -> { - let bits = bit_array.from_string(string_builder.to_string(builder)) - to_list([rest, ..remaining_stack], [bits, ..acc]) - } - - [[Many(builders), ..rest], ..remaining_stack] -> - to_list([builders, rest, ..remaining_stack], acc) - } -} - -/// Returns the size of the builder's content in bytes. -/// -/// Runs in linear time. -/// -@external(erlang, "erlang", "iolist_size") -pub fn byte_size(builder: BytesBuilder) -> Int { - [[builder]] - |> to_list([]) - |> list.fold(0, fn(acc, builder) { bit_array.byte_size(builder) + acc }) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/dict.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/dict.gleam deleted file mode 100644 index 280bf9d..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/dict.gleam +++ /dev/null @@ -1,544 +0,0 @@ -import gleam/option.{type Option} - -/// A dictionary of keys and values. -/// -/// Any type can be used for the keys and values of a dict, but all the keys -/// must be of the same type and all the values must be of the same type. -/// -/// Each key can only be present in a dict once. -/// -/// Dicts are not ordered in any way, and any unintentional ordering is not to -/// be relied upon in your code as it may change in future versions of Erlang -/// or Gleam. -/// -/// See [the Erlang map module](https://erlang.org/doc/man/maps.html) for more -/// information. -/// -pub type Dict(key, value) - -/// Determines the number of key-value pairs in the dict. -/// This function runs in constant time and does not need to iterate the dict. -/// -/// ## Examples -/// -/// ```gleam -/// > new() |> size() -/// 0 -/// ``` -/// -/// ```gleam -/// > new() |> insert("key", "value") |> size() -/// 1 -/// ``` -/// -pub fn size(dict: Dict(k, v)) -> Int { - do_size(dict) -} - -@external(erlang, "maps", "size") -@external(javascript, "../gleam_stdlib.mjs", "map_size") -fn do_size(a: Dict(k, v)) -> Int - -/// Converts the dict to a list of 2-element tuples `#(key, value)`, one for -/// each key-value pair in the dict. -/// -/// The tuples in the list have no specific order. -/// -/// ## Examples -/// -/// ```gleam -/// > new() |> to_list() -/// [] -/// ``` -/// -/// ```gleam -/// > new() |> insert("key", 0) |> to_list() -/// [#("key", 0)] -/// ``` -/// -pub fn to_list(dict: Dict(key, value)) -> List(#(key, value)) { - do_to_list(dict) -} - -@external(erlang, "maps", "to_list") -@external(javascript, "../gleam_stdlib.mjs", "map_to_list") -fn do_to_list(a: Dict(key, value)) -> List(#(key, value)) - -/// Converts a list of 2-element tuples `#(key, value)` to a dict. -/// -/// If two tuples have the same key the last one in the list will be the one -/// that is present in the dict. -/// -pub fn from_list(list: List(#(k, v))) -> Dict(k, v) { - do_from_list(list) -} - -@target(erlang) -@external(erlang, "maps", "from_list") -fn do_from_list(a: List(#(key, value))) -> Dict(key, value) - -@target(javascript) -fn fold_list_of_pair( - over list: List(#(k, v)), - from initial: Dict(k, v), -) -> Dict(k, v) { - case list { - [] -> initial - [x, ..rest] -> fold_list_of_pair(rest, insert(initial, x.0, x.1)) - } -} - -@target(javascript) -fn do_from_list(list: List(#(k, v))) -> Dict(k, v) { - fold_list_of_pair(list, new()) -} - -/// Determines whether or not a value present in the dict for a given key. -/// -/// ## Examples -/// -/// ```gleam -/// > new() |> insert("a", 0) |> has_key("a") -/// True -/// ``` -/// -/// ```gleam -/// > new() |> insert("a", 0) |> has_key("b") -/// False -/// ``` -/// -pub fn has_key(dict: Dict(k, v), key: k) -> Bool { - do_has_key(key, dict) -} - -@target(erlang) -@external(erlang, "maps", "is_key") -fn do_has_key(a: key, b: Dict(key, v)) -> Bool - -@target(javascript) -fn do_has_key(key: k, dict: Dict(k, v)) -> Bool { - get(dict, key) != Error(Nil) -} - -/// Creates a fresh dict that contains no values. -/// -pub fn new() -> Dict(key, value) { - do_new() -} - -@external(erlang, "maps", "new") -@external(javascript, "../gleam_stdlib.mjs", "new_map") -fn do_new() -> Dict(key, value) - -/// Fetches a value from a dict for a given key. -/// -/// The dict may not have a value for the key, so the value is wrapped in a -/// `Result`. -/// -/// ## Examples -/// -/// ```gleam -/// > new() |> insert("a", 0) |> get("a") -/// Ok(0) -/// ``` -/// -/// ```gleam -/// > new() |> insert("a", 0) |> get("b") -/// Error(Nil) -/// ``` -/// -pub fn get(from: Dict(key, value), get: key) -> Result(value, Nil) { - do_get(from, get) -} - -@external(erlang, "gleam_stdlib", "map_get") -@external(javascript, "../gleam_stdlib.mjs", "map_get") -fn do_get(a: Dict(key, value), b: key) -> Result(value, Nil) - -/// Inserts a value into the dict with the given key. -/// -/// If the dict already has a value for the given key then the value is -/// replaced with the new value. -/// -/// ## Examples -/// -/// ```gleam -/// > new() |> insert("a", 0) |> to_list -/// [#("a", 0)] -/// ``` -/// -/// ```gleam -/// > new() |> insert("a", 0) |> insert("a", 5) |> to_list -/// [#("a", 5)] -/// ``` -/// -pub fn insert(into dict: Dict(k, v), for key: k, insert value: v) -> Dict(k, v) { - do_insert(key, value, dict) -} - -@external(erlang, "maps", "put") -@external(javascript, "../gleam_stdlib.mjs", "map_insert") -fn do_insert(a: key, b: value, c: Dict(key, value)) -> Dict(key, value) - -/// Updates all values in a given dict by calling a given function on each key -/// and value. -/// -/// ## Examples -/// -/// ```gleam -/// > [#(3, 3), #(2, 4)] -/// > |> from_list -/// > |> map_values(fn(key, value) { key * value }) -/// [#(3, 9), #(2, 8)] -/// ``` -/// -pub fn map_values(in dict: Dict(k, v), with fun: fn(k, v) -> w) -> Dict(k, w) { - do_map_values(fun, dict) -} - -@target(erlang) -@external(erlang, "maps", "map") -fn do_map_values(a: fn(key, value) -> b, b: Dict(key, value)) -> Dict(key, b) - -@target(javascript) -fn do_map_values(f: fn(key, value) -> b, dict: Dict(key, value)) -> Dict(key, b) { - let f = fn(dict, k, v) { insert(dict, k, f(k, v)) } - dict - |> fold(from: new(), with: f) -} - -/// Gets a list of all keys in a given dict. -/// -/// Dicts are not ordered so the keys are not returned in any specific order. Do -/// not write code that relies on the order keys are returned by this function -/// as it may change in later versions of Gleam or Erlang. -/// -/// ## Examples -/// -/// ```gleam -/// > keys([#("a", 0), #("b", 1)]) -/// ["a", "b"] -/// ``` -/// -pub fn keys(dict: Dict(keys, v)) -> List(keys) { - do_keys(dict) -} - -@target(erlang) -@external(erlang, "maps", "keys") -fn do_keys(a: Dict(keys, v)) -> List(keys) - -@target(javascript) -fn reverse_and_concat(remaining, accumulator) { - case remaining { - [] -> accumulator - [item, ..rest] -> reverse_and_concat(rest, [item, ..accumulator]) - } -} - -@target(javascript) -fn do_keys_acc(list: List(#(k, v)), acc: List(k)) -> List(k) { - case list { - [] -> reverse_and_concat(acc, []) - [x, ..xs] -> do_keys_acc(xs, [x.0, ..acc]) - } -} - -@target(javascript) -fn do_keys(dict: Dict(k, v)) -> List(k) { - let list_of_pairs = to_list(dict) - do_keys_acc(list_of_pairs, []) -} - -/// Gets a list of all values in a given dict. -/// -/// Dicts are not ordered so the values are not returned in any specific order. Do -/// not write code that relies on the order values are returned by this function -/// as it may change in later versions of Gleam or Erlang. -/// -/// ## Examples -/// -/// ```gleam -/// > values(from_list([#("a", 0), #("b", 1)])) -/// [0, 1] -/// ``` -/// -pub fn values(dict: Dict(k, values)) -> List(values) { - do_values(dict) -} - -@target(erlang) -@external(erlang, "maps", "values") -fn do_values(a: Dict(k, values)) -> List(values) - -@target(javascript) -fn do_values_acc(list: List(#(k, v)), acc: List(v)) -> List(v) { - case list { - [] -> reverse_and_concat(acc, []) - [x, ..xs] -> do_values_acc(xs, [x.1, ..acc]) - } -} - -@target(javascript) -fn do_values(dict: Dict(k, v)) -> List(v) { - let list_of_pairs = to_list(dict) - do_values_acc(list_of_pairs, []) -} - -/// Creates a new dict from a given dict, minus any entries that a given function -/// returns `False` for. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([#("a", 0), #("b", 1)]) -/// > |> filter(fn(key, value) { value != 0 }) -/// from_list([#("b", 1)]) -/// ``` -/// -/// ```gleam -/// > from_list([#("a", 0), #("b", 1)]) -/// > |> filter(fn(key, value) { True }) -/// from_list([#("a", 0), #("b", 1)]) -/// ``` -/// -pub fn filter( - in dict: Dict(k, v), - keeping predicate: fn(k, v) -> Bool, -) -> Dict(k, v) { - do_filter(predicate, dict) -} - -@target(erlang) -@external(erlang, "maps", "filter") -fn do_filter(a: fn(key, value) -> Bool, b: Dict(key, value)) -> Dict(key, value) - -@target(javascript) -fn do_filter( - f: fn(key, value) -> Bool, - dict: Dict(key, value), -) -> Dict(key, value) { - let insert = fn(dict, k, v) { - case f(k, v) { - True -> insert(dict, k, v) - _ -> dict - } - } - dict - |> fold(from: new(), with: insert) -} - -/// Creates a new dict from a given dict, only including any entries for which the -/// keys are in a given list. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([#("a", 0), #("b", 1)]) -/// > |> take(["b"]) -/// from_list([#("b", 1)]) -/// ``` -/// -/// ```gleam -/// > from_list([#("a", 0), #("b", 1)]) -/// > |> take(["a", "b", "c"]) -/// from_list([#("a", 0), #("b", 1)]) -/// ``` -/// -pub fn take(from dict: Dict(k, v), keeping desired_keys: List(k)) -> Dict(k, v) { - do_take(desired_keys, dict) -} - -@target(erlang) -@external(erlang, "maps", "with") -fn do_take(a: List(k), b: Dict(k, v)) -> Dict(k, v) - -@target(javascript) -fn insert_taken( - dict: Dict(k, v), - desired_keys: List(k), - acc: Dict(k, v), -) -> Dict(k, v) { - let insert = fn(taken, key) { - case get(dict, key) { - Ok(value) -> insert(taken, key, value) - _ -> taken - } - } - case desired_keys { - [] -> acc - [x, ..xs] -> insert_taken(dict, xs, insert(acc, x)) - } -} - -@target(javascript) -fn do_take(desired_keys: List(k), dict: Dict(k, v)) -> Dict(k, v) { - insert_taken(dict, desired_keys, new()) -} - -/// Creates a new dict from a pair of given dicts by combining their entries. -/// -/// If there are entries with the same keys in both dicts the entry from the -/// second dict takes precedence. -/// -/// ## Examples -/// -/// ```gleam -/// > let a = from_list([#("a", 0), #("b", 1)]) -/// > let b = from_list([#("b", 2), #("c", 3)]) -/// > merge(a, b) -/// from_list([#("a", 0), #("b", 2), #("c", 3)]) -/// ``` -/// -pub fn merge(into dict: Dict(k, v), from new_entries: Dict(k, v)) -> Dict(k, v) { - do_merge(dict, new_entries) -} - -@target(erlang) -@external(erlang, "maps", "merge") -fn do_merge(a: Dict(k, v), b: Dict(k, v)) -> Dict(k, v) - -@target(javascript) -fn insert_pair(dict: Dict(k, v), pair: #(k, v)) -> Dict(k, v) { - insert(dict, pair.0, pair.1) -} - -@target(javascript) -fn fold_inserts(new_entries: List(#(k, v)), dict: Dict(k, v)) -> Dict(k, v) { - case new_entries { - [] -> dict - [x, ..xs] -> fold_inserts(xs, insert_pair(dict, x)) - } -} - -@target(javascript) -fn do_merge(dict: Dict(k, v), new_entries: Dict(k, v)) -> Dict(k, v) { - new_entries - |> to_list - |> fold_inserts(dict) -} - -/// Creates a new dict from a given dict with all the same entries except for the -/// one with a given key, if it exists. -/// -/// ## Examples -/// -/// ```gleam -/// > delete([#("a", 0), #("b", 1)], "a") -/// from_list([#("b", 1)]) -/// ``` -/// -/// ```gleam -/// > delete([#("a", 0), #("b", 1)], "c") -/// from_list([#("a", 0), #("b", 1)]) -/// ``` -/// -pub fn delete(from dict: Dict(k, v), delete key: k) -> Dict(k, v) { - do_delete(key, dict) -} - -@external(erlang, "maps", "remove") -@external(javascript, "../gleam_stdlib.mjs", "map_remove") -fn do_delete(a: k, b: Dict(k, v)) -> Dict(k, v) - -/// Creates a new dict from a given dict with all the same entries except any with -/// keys found in a given list. -/// -/// ## Examples -/// -/// ```gleam -/// > drop([#("a", 0), #("b", 1)], ["a"]) -/// from_list([#("b", 2)]) -/// ``` -/// -/// ```gleam -/// > delete([#("a", 0), #("b", 1)], ["c"]) -/// from_list([#("a", 0), #("b", 1)]) -/// ``` -/// -/// ```gleam -/// > drop([#("a", 0), #("b", 1)], ["a", "b", "c"]) -/// from_list([]) -/// ``` -/// -pub fn drop(from dict: Dict(k, v), drop disallowed_keys: List(k)) -> Dict(k, v) { - case disallowed_keys { - [] -> dict - [x, ..xs] -> drop(delete(dict, x), xs) - } -} - -/// Creates a new dict with one entry updated using a given function. -/// -/// If there was not an entry in the dict for the given key then the function -/// gets `None` as its argument, otherwise it gets `Some(value)`. -/// -/// ## Example -/// -/// ```gleam -/// > let increment = fn(x) { -/// > case x { -/// > Some(i) -> i + 1 -/// > None -> 0 -/// > } -/// > } -/// > let dict = from_list([#("a", 0)]) -/// > -/// > update(dict, "a", increment) -/// from_list([#("a", 1)]) -/// ``` -/// -/// ```gleam -/// > update(dict, "b", increment) -/// from_list([#("a", 0), #("b", 0)]) -/// ``` -/// -pub fn update( - in dict: Dict(k, v), - update key: k, - with fun: fn(Option(v)) -> v, -) -> Dict(k, v) { - dict - |> get(key) - |> option.from_result - |> fun - |> insert(dict, key, _) -} - -fn do_fold(list: List(#(k, v)), initial: acc, fun: fn(acc, k, v) -> acc) -> acc { - case list { - [] -> initial - [#(k, v), ..rest] -> do_fold(rest, fun(initial, k, v), fun) - } -} - -/// Combines all entries into a single value by calling a given function on each -/// one. -/// -/// Dicts are not ordered so the values are not returned in any specific order. Do -/// not write code that relies on the order entries are used by this function -/// as it may change in later versions of Gleam or Erlang. -/// -/// # Examples -/// -/// ```gleam -/// > let dict = from_list([#("a", 1), #("b", 3), #("c", 9)]) -/// > fold(dict, 0, fn(accumulator, key, value) { accumulator + value }) -/// 13 -/// ``` -/// -/// ```gleam -/// > import gleam/string.{append} -/// > fold(dict, "", fn(accumulator, key, value) { append(accumulator, key) }) -/// "abc" -/// ``` -/// -pub fn fold( - over dict: Dict(k, v), - from initial: acc, - with fun: fn(acc, k, v) -> acc, -) -> acc { - dict - |> to_list - |> do_fold(initial, fun) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/dynamic.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/dynamic.gleam deleted file mode 100644 index c71c6f3..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/dynamic.gleam +++ /dev/null @@ -1,1508 +0,0 @@ -import gleam/int -import gleam/list -import gleam/dict.{type Dict} -import gleam/option.{type Option} -import gleam/result -import gleam/string_builder -@target(erlang) -import gleam/bit_array - -/// `Dynamic` data is data that we don't know the type of yet. -/// We likely get data like this from interop with Erlang, or from -/// IO with the outside world. -/// -pub type Dynamic - -/// Error returned when unexpected data is encountered -/// -pub type DecodeError { - DecodeError(expected: String, found: String, path: List(String)) -} - -pub type DecodeErrors = - List(DecodeError) - -pub type Decoder(t) = - fn(Dynamic) -> Result(t, DecodeErrors) - -/// Converts any Gleam data into `Dynamic` data. -/// -pub fn from(a) -> Dynamic { - do_from(a) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -fn do_from(a: anything) -> Dynamic - -/// Unsafely casts a Dynamic value into any other type. -/// -/// This is an escape hatch for the type system that may be useful when wrapping -/// native Erlang APIs. It is to be used as a last measure only! -/// -/// If you can avoid using this function, do! -/// -pub fn unsafe_coerce(a: Dynamic) -> anything { - do_unsafe_coerce(a) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -fn do_unsafe_coerce(a: Dynamic) -> a - -/// Decodes a `Dynamic` value from a `Dynamic` value. -/// -/// This function doesn't seem very useful at first, but it can be convenient -/// when you need to give a decoder function but you don't actually care what -/// the to-decode value is. -/// -pub fn dynamic(value: Dynamic) -> Result(Dynamic, List(DecodeError)) { - Ok(value) -} - -/// Checks to see whether a `Dynamic` value is a bit array, and returns that bit -/// array if it is. -/// -/// ## Examples -/// -/// ```gleam -/// > bit_array(from("Hello")) == bit_array.from_string("Hello") -/// True -/// ``` -/// -/// ```gleam -/// > bit_array(from(123)) -/// Error([DecodeError(expected: "BitArray", found: "Int", path: [])]) -/// ``` -/// -pub fn bit_array(from data: Dynamic) -> Result(BitArray, DecodeErrors) { - decode_bit_array(data) -} - -@deprecated("Please use `bit_array` instead") -pub fn bit_string(from data: Dynamic) -> Result(BitArray, DecodeErrors) { - bit_array(data) -} - -@external(erlang, "gleam_stdlib", "decode_bit_array") -@external(javascript, "../gleam_stdlib.mjs", "decode_bit_array") -fn decode_bit_array(a: Dynamic) -> Result(BitArray, DecodeErrors) - -/// Checks to see whether a `Dynamic` value is a string, and returns that string if -/// it is. -/// -/// ## Examples -/// -/// ```gleam -/// > string(from("Hello")) -/// Ok("Hello") -/// ``` -/// -/// ```gleam -/// > string(from(123)) -/// Error([DecodeError(expected: "String", found: "Int", path: [])]) -/// ``` -/// -pub fn string(from data: Dynamic) -> Result(String, DecodeErrors) { - decode_string(data) -} - -fn map_errors( - result: Result(t, DecodeErrors), - f: fn(DecodeError) -> DecodeError, -) -> Result(t, DecodeErrors) { - result.map_error(result, list.map(_, f)) -} - -@target(erlang) -fn decode_string(data: Dynamic) -> Result(String, DecodeErrors) { - bit_array(data) - |> map_errors(put_expected(_, "String")) - |> result.try(fn(raw) { - case bit_array.to_string(raw) { - Ok(string) -> Ok(string) - Error(Nil) -> - Error([DecodeError(expected: "String", found: "BitArray", path: [])]) - } - }) -} - -@target(erlang) -fn put_expected(error: DecodeError, expected: String) -> DecodeError { - DecodeError(..error, expected: expected) -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "decode_string") -fn decode_string(a: Dynamic) -> Result(String, DecodeErrors) - -/// Return a string indicating the type of the dynamic value. -/// -/// ```gleam -/// > classify(from("Hello")) -/// "String" -/// ``` -/// -pub fn classify(data: Dynamic) -> String { - do_classify(data) -} - -@external(erlang, "gleam_stdlib", "classify_dynamic") -@external(javascript, "../gleam_stdlib.mjs", "classify_dynamic") -fn do_classify(a: Dynamic) -> String - -/// Checks to see whether a `Dynamic` value is an int, and returns that int if it -/// is. -/// -/// ## Examples -/// -/// ```gleam -/// > int(from(123)) -/// Ok(123) -/// ``` -/// -/// ```gleam -/// > int(from("Hello")) -/// Error([DecodeError(expected: "Int", found: "String", path: [])]) -/// ``` -/// -pub fn int(from data: Dynamic) -> Result(Int, DecodeErrors) { - decode_int(data) -} - -@external(erlang, "gleam_stdlib", "decode_int") -@external(javascript, "../gleam_stdlib.mjs", "decode_int") -fn decode_int(a: Dynamic) -> Result(Int, DecodeErrors) - -/// Checks to see whether a `Dynamic` value is a float, and returns that float if -/// it is. -/// -/// ## Examples -/// -/// ```gleam -/// > float(from(2.0)) -/// Ok(2.0) -/// ``` -/// -/// ```gleam -/// > float(from(123)) -/// Error([DecodeError(expected: "Float", found: "Int", path: [])]) -/// ``` -/// -pub fn float(from data: Dynamic) -> Result(Float, DecodeErrors) { - decode_float(data) -} - -@external(erlang, "gleam_stdlib", "decode_float") -@external(javascript, "../gleam_stdlib.mjs", "decode_float") -fn decode_float(a: Dynamic) -> Result(Float, DecodeErrors) - -/// Checks to see whether a `Dynamic` value is a bool, and returns that bool if -/// it is. -/// -/// ## Examples -/// -/// ```gleam -/// > bool(from(True)) -/// Ok(True) -/// ``` -/// -/// ```gleam -/// > bool(from(123)) -/// Error([DecodeError(expected: "Bool", found: "Int", path: [])]) -/// ``` -/// -pub fn bool(from data: Dynamic) -> Result(Bool, DecodeErrors) { - decode_bool(data) -} - -@external(erlang, "gleam_stdlib", "decode_bool") -@external(javascript, "../gleam_stdlib.mjs", "decode_bool") -fn decode_bool(a: Dynamic) -> Result(Bool, DecodeErrors) - -/// Checks to see whether a `Dynamic` value is a list, and returns that list if it -/// is. The types of the elements are not checked. -/// -/// If you wish to decode all the elements in the list use the `list` function -/// instead. -/// -/// ## Examples -/// -/// ```gleam -/// > shallow_list(from(["a", "b", "c"])) -/// Ok([from("a"), from("b"), from("c")]) -/// ``` -/// -/// ```gleam -/// > shallow_list(1) -/// Error([DecodeError(expected: "List", found: "Int", path: [])]) -/// ``` -/// -pub fn shallow_list(from value: Dynamic) -> Result(List(Dynamic), DecodeErrors) { - decode_list(value) -} - -@external(erlang, "gleam_stdlib", "decode_list") -@external(javascript, "../gleam_stdlib.mjs", "decode_list") -fn decode_list(a: Dynamic) -> Result(List(Dynamic), DecodeErrors) - -@external(erlang, "gleam_stdlib", "decode_result") -@external(javascript, "../gleam_stdlib.mjs", "decode_result") -fn decode_result(a: Dynamic) -> Result(Result(a, e), DecodeErrors) - -/// Checks to see whether a `Dynamic` value is a result of a particular type, and -/// returns that result if it is. -/// -/// The `ok` and `error` arguments are decoders for decoding the `Ok` and -/// `Error` values of the result. -/// -/// ## Examples -/// -/// ```gleam -/// > from(Ok(1)) -/// > |> result(ok: int, error: string) -/// Ok(Ok(1)) -/// ``` -/// -/// ```gleam -/// > from(Error("boom")) -/// > |> result(ok: int, error: string) -/// Ok(Error("boom")) -/// ``` -/// -/// ```gleam -/// > from(123) -/// > |> result(ok: int, error: string) -/// Error([DecodeError(expected: "Result", found: "Int", path: [])]) -/// ``` -/// -pub fn result( - ok decode_ok: Decoder(a), - error decode_error: Decoder(e), -) -> Decoder(Result(a, e)) { - fn(value) { - use inner_result <- result.try(decode_result(value)) - - case inner_result { - Ok(raw) -> { - use value <- result.try( - decode_ok(raw) - |> map_errors(push_path(_, "ok")), - ) - Ok(Ok(value)) - } - Error(raw) -> { - use value <- result.try( - decode_error(raw) - |> map_errors(push_path(_, "error")), - ) - Ok(Error(value)) - } - } - } -} - -/// Checks to see whether a `Dynamic` value is a list of a particular type, and -/// returns that list if it is. -/// -/// The second argument is a decoder function used to decode the elements of -/// the list. The list is only decoded if all elements in the list can be -/// successfully decoded using this function. -/// -/// If you do not wish to decode all the elements in the list use the `shallow_list` -/// function instead. -/// -/// ## Examples -/// -/// ```gleam -/// > from(["a", "b", "c"]) -/// > |> list(of: string) -/// Ok(["a", "b", "c"]) -/// ``` -/// -/// ```gleam -/// > from([1, 2, 3]) -/// > |> list(of: string) -/// Error([DecodeError(expected: "String", found: "Int", path: ["*"])]) -/// ``` -/// -/// ```gleam -/// > from("ok") -/// > |> list(of: string) -/// Error([DecodeError(expected: "List", found: "String", path: [])]) -/// ``` -/// -pub fn list( - of decoder_type: fn(Dynamic) -> Result(inner, DecodeErrors), -) -> Decoder(List(inner)) { - fn(dynamic) { - use list <- result.try(shallow_list(dynamic)) - list - |> list.try_map(decoder_type) - |> map_errors(push_path(_, "*")) - } -} - -/// Checks to see if a `Dynamic` value is a nullable version of a particular -/// type, and returns a corresponding `Option` if it is. -/// -/// ## Examples -/// -/// ```gleam -/// > from("Hello") -/// > |> optional(string) -/// Ok(Some("Hello")) -/// ``` -/// -/// ```gleam -/// > from("Hello") -/// > |> optional(string) -/// Ok(Some("Hello")) -/// ``` -/// -/// ```gleam -/// > from(atom.from_string("null")) -/// > |> optional(string) -/// Ok(None) -/// ``` -/// -/// ```gleam -/// > from(atom.from_string("nil")) -/// > |> optional(string) -/// Ok(None) -/// ``` -/// -/// ```gleam -/// > from(atom.from_string("undefined")) -/// > |> optional(string) -/// Ok(None) -/// ``` -/// -/// ```gleam -/// > from(123) -/// > |> optional(string) -/// Error([DecodeError(expected: "String", found: "Int", path: [])]) -/// ``` -/// -pub fn optional(of decode: Decoder(inner)) -> Decoder(Option(inner)) { - fn(value) { decode_optional(value, decode) } -} - -@external(erlang, "gleam_stdlib", "decode_option") -@external(javascript, "../gleam_stdlib.mjs", "decode_option") -fn decode_optional(a: Dynamic, b: Decoder(a)) -> Result(Option(a), DecodeErrors) - -/// Checks to see if a `Dynamic` value is a map with a specific field, and returns -/// the value of that field if it is. -/// -/// This will not succeed on a record. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/dict -/// > dict.new() -/// > |> dict.insert("Hello", "World") -/// > |> from -/// > |> field(named: "Hello", of: string) -/// Ok("World") -/// ``` -/// -/// ```gleam -/// > from(123) -/// > |> field("Hello", string) -/// Error([DecodeError(expected: "Map", found: "Int", path: [])]) -/// ``` -/// -pub fn field(named name: a, of inner_type: Decoder(t)) -> Decoder(t) { - fn(value) { - let missing_field_error = - DecodeError(expected: "field", found: "nothing", path: []) - - use maybe_inner <- result.try(decode_field(value, name)) - maybe_inner - |> option.to_result([missing_field_error]) - |> result.try(inner_type) - |> map_errors(push_path(_, name)) - } -} - -/// Checks to see if a `Dynamic` value is a map with a specific field. -/// If the map does not have the specified field, returns an `Ok(None)` instead of failing; otherwise, -/// returns the decoded field wrapped in `Some(_)`. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/dict -/// > dict.new() -/// > |> dict.insert("Hello", "World") -/// > |> from -/// > |> field(named: "Hello", of: string) -/// Ok(Some("World")) -/// ``` -/// -/// ```gleam -/// > import gleam/dict -/// > dict.new() -/// > |> from -/// > |> field(named: "Hello", of: string) -/// Ok(None) -/// ``` -/// -/// ```gleam -/// > from(123) -/// > |> field("Hello", string) -/// Error([DecodeError(expected: "Map", found: "Int", path: [])]) -/// ``` -/// -pub fn optional_field( - named name: a, - of inner_type: Decoder(t), -) -> Decoder(Option(t)) { - fn(value) { - use maybe_inner <- result.try(decode_field(value, name)) - case maybe_inner { - option.None -> Ok(option.None) - option.Some(dynamic_inner) -> - dynamic_inner - |> decode_optional(inner_type) - |> map_errors(push_path(_, name)) - } - } -} - -@external(erlang, "gleam_stdlib", "decode_field") -@external(javascript, "../gleam_stdlib.mjs", "decode_field") -fn decode_field(a: Dynamic, b: name) -> Result(Option(Dynamic), DecodeErrors) - -/// Checks to see if a `Dynamic` value is a tuple large enough to have a certain -/// index, and returns the value of that index if it is. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2)) -/// > |> element(0, int) -/// Ok(from(1)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2)) -/// > |> element(2, int) -/// Error([ -/// DecodeError( -/// expected: "Tuple of at least 3 elements", -/// found: "Tuple of 2 elements", -/// path: [], -/// ), -/// ]) -/// ``` -/// -pub fn element(at index: Int, of inner_type: Decoder(t)) -> Decoder(t) { - fn(data: Dynamic) { - use tuple <- result.try(decode_tuple(data)) - let size = tuple_size(tuple) - use data <- result.try(case index >= 0 { - True -> - case index < size { - True -> tuple_get(tuple, index) - False -> at_least_decode_tuple_error(index + 1, data) - } - False -> - case int.absolute_value(index) <= size { - True -> tuple_get(tuple, size + index) - False -> at_least_decode_tuple_error(int.absolute_value(index), data) - } - }) - inner_type(data) - |> map_errors(push_path(_, index)) - } -} - -fn at_least_decode_tuple_error( - size: Int, - data: Dynamic, -) -> Result(a, DecodeErrors) { - let s = case size { - 1 -> "" - _ -> "s" - } - let error = - ["Tuple of at least ", int.to_string(size), " element", s] - |> string_builder.from_strings - |> string_builder.to_string - |> DecodeError(found: classify(data), path: []) - Error([error]) -} - -// A tuple of unknown size -type UnknownTuple - -@external(erlang, "gleam_stdlib", "decode_tuple") -@external(javascript, "../gleam_stdlib.mjs", "decode_tuple") -fn decode_tuple(a: Dynamic) -> Result(UnknownTuple, DecodeErrors) - -@external(erlang, "gleam_stdlib", "decode_tuple2") -@external(javascript, "../gleam_stdlib.mjs", "decode_tuple2") -fn decode_tuple2(a: Dynamic) -> Result(#(Dynamic, Dynamic), DecodeErrors) - -@external(erlang, "gleam_stdlib", "decode_tuple3") -@external(javascript, "../gleam_stdlib.mjs", "decode_tuple3") -fn decode_tuple3( - a: Dynamic, -) -> Result(#(Dynamic, Dynamic, Dynamic), DecodeErrors) - -@external(erlang, "gleam_stdlib", "decode_tuple4") -@external(javascript, "../gleam_stdlib.mjs", "decode_tuple4") -fn decode_tuple4( - a: Dynamic, -) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic), DecodeErrors) - -@external(erlang, "gleam_stdlib", "decode_tuple5") -@external(javascript, "../gleam_stdlib.mjs", "decode_tuple5") -fn decode_tuple5( - a: Dynamic, -) -> Result(#(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic), DecodeErrors) - -@external(erlang, "gleam_stdlib", "decode_tuple6") -@external(javascript, "../gleam_stdlib.mjs", "decode_tuple6") -fn decode_tuple6( - a: Dynamic, -) -> Result( - #(Dynamic, Dynamic, Dynamic, Dynamic, Dynamic, Dynamic), - DecodeErrors, -) - -@external(erlang, "gleam_stdlib", "tuple_get") -@external(javascript, "../gleam_stdlib.mjs", "tuple_get") -fn tuple_get(a: UnknownTuple, b: Int) -> Result(Dynamic, DecodeErrors) - -@external(erlang, "gleam_stdlib", "size_of_tuple") -@external(javascript, "../gleam_stdlib.mjs", "length") -fn tuple_size(a: UnknownTuple) -> Int - -fn tuple_errors( - result: Result(a, List(DecodeError)), - name: String, -) -> List(DecodeError) { - case result { - Ok(_) -> [] - Error(errors) -> list.map(errors, push_path(_, name)) - } -} - -fn push_path(error: DecodeError, name: t) -> DecodeError { - let name = from(name) - let decoder = any([string, fn(x) { result.map(int(x), int.to_string) }]) - let name = case decoder(name) { - Ok(name) -> name - Error(_) -> - ["<", classify(name), ">"] - |> string_builder.from_strings - |> string_builder.to_string - } - DecodeError(..error, path: [name, ..error.path]) -} - -/// Checks to see if a `Dynamic` value is a 2-element tuple, list or array containing -/// specifically typed elements. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2)) -/// > |> tuple2(int, int) -/// Ok(#(1, 2)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2.0)) -/// > |> tuple2(int, float) -/// Ok(#(1, 2.0)) -/// ``` -/// -/// ```gleam -/// > from([1, 2]) -/// > |> tuple2(int, int) -/// Ok(#(1, 2)) -/// ``` -/// -/// ```gleam -/// > from([from(1), from(2.0)]) -/// > |> tuple2(int, float) -/// Ok(#(1, 2.0)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2, 3)) -/// > |> tuple2(int, float) -/// Error([ -/// DecodeError(expected: "Tuple of 2 elements", found: "Tuple of 3 elements", path: []), -/// ]) -/// ``` -/// -/// ```gleam -/// > from("") -/// > |> tuple2(int, float) -/// Error([DecodeError(expected: "Tuple of 2 elements", found: "String", path: [])]) -/// ``` -/// -pub fn tuple2( - first decode1: Decoder(a), - second decode2: Decoder(b), -) -> Decoder(#(a, b)) { - fn(value) { - use #(a, b) <- result.try(decode_tuple2(value)) - case decode1(a), decode2(b) { - Ok(a), Ok(b) -> Ok(#(a, b)) - a, b -> - tuple_errors(a, "0") - |> list.append(tuple_errors(b, "1")) - |> Error - } - } -} - -/// Checks to see if a `Dynamic` value is a 3-element tuple, list or array containing -/// specifically typed elements. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2, 3)) -/// > |> tuple3(int, int, int) -/// Ok(#(1, 2, 3)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2.0, "3")) -/// > |> tuple3(int, float, string) -/// Ok(#(1, 2.0, "3")) -/// ``` -/// -/// ```gleam -/// > from([1, 2, 3]) -/// > |> tuple3(int, int, int) -/// Ok(#(1, 2, 3)) -/// ``` -/// -/// ```gleam -/// > from([from(1), from(2.0), from("3")]) -/// > |> tuple3(int, float, string) -/// Ok(#(1, 2.0, "3")) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2)) -/// > |> tuple3(int, float, string) -/// Error([ -/// DecodeError(expected: "Tuple of 3 elements", found: "Tuple of 2 elements", path: [])), -/// ]) -/// ``` -/// -/// ```gleam -/// > from("") -/// > |> tuple3(int, float, string) -/// Error([ -/// DecodeError(expected: "Tuple of 3 elements", found: "String", path: []), -/// ]) -/// ``` -/// -pub fn tuple3( - first decode1: Decoder(a), - second decode2: Decoder(b), - third decode3: Decoder(c), -) -> Decoder(#(a, b, c)) { - fn(value) { - use #(a, b, c) <- result.try(decode_tuple3(value)) - case decode1(a), decode2(b), decode3(c) { - Ok(a), Ok(b), Ok(c) -> Ok(#(a, b, c)) - a, b, c -> - tuple_errors(a, "0") - |> list.append(tuple_errors(b, "1")) - |> list.append(tuple_errors(c, "2")) - |> Error - } - } -} - -/// Checks to see if a `Dynamic` value is a 4-element tuple, list or array containing -/// specifically typed elements. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2, 3, 4)) -/// > |> tuple4(int, int, int, int) -/// Ok(#(1, 2, 3, 4)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2.0, "3", 4)) -/// > |> tuple4(int, float, string, int) -/// Ok(#(1, 2.0, "3", 4)) -/// ``` -/// -/// ```gleam -/// > from([1, 2, 3, 4]) -/// > |> tuple4(int, int, int, int) -/// Ok(#(1, 2, 3, 4)) -/// ``` -/// -/// ```gleam -/// > from([from(1), from(2.0), from("3"), from(4)]) -/// > |> tuple4(int, float, string, int) -/// Ok(#(1, 2.0, "3", 4)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2)) -/// > |> tuple4(int, float, string, int) -/// Error([ -/// DecodeError(expected: "Tuple of 4 elements", found: "Tuple of 2 elements", path: []), -/// ]) -/// ``` -/// -/// ```gleam -/// > from("") -/// > |> tuple4(int, float, string, int) -/// Error([ -/// DecodeError(expected: "Tuple of 4 elements", found: "String", path: []), -/// ]) -/// ``` -/// -pub fn tuple4( - first decode1: Decoder(a), - second decode2: Decoder(b), - third decode3: Decoder(c), - fourth decode4: Decoder(d), -) -> Decoder(#(a, b, c, d)) { - fn(value) { - use #(a, b, c, d) <- result.try(decode_tuple4(value)) - case decode1(a), decode2(b), decode3(c), decode4(d) { - Ok(a), Ok(b), Ok(c), Ok(d) -> Ok(#(a, b, c, d)) - a, b, c, d -> - tuple_errors(a, "0") - |> list.append(tuple_errors(b, "1")) - |> list.append(tuple_errors(c, "2")) - |> list.append(tuple_errors(d, "3")) - |> Error - } - } -} - -/// Checks to see if a `Dynamic` value is a 5-element tuple, list or array containing -/// specifically typed elements. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2, 3, 4, 5)) -/// > |> tuple5(int, int, int, int, int) -/// Ok(#(1, 2, 3, 4, 5)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2.0, "3", 4, 5)) -/// > |> tuple5(int, float, string, int, int) -/// Ok(#(1, 2.0, "3", 4, 5)) -/// ``` -/// -/// ```gleam -/// > from([1, 2, 3, 4, 5]) -/// > |> tuple5(int, int, int, int, int) -/// Ok(#(1, 2, 3, 4, 5)) -/// ``` -/// -/// ```gleam -/// > from([from(1), from(2.0), from("3"), from(4), from(True)]) -/// > |> tuple5(int, float, string, int, bool) -/// Ok(#(1, 2.0, "3", 4, True)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2)) -/// > |> tuple5(int, float, string, int, int) -/// Error([ -/// DecodeError(expected: "Tuple of 5 elements", found: "Tuple of 2 elements", path: [])), -/// ]) -/// ``` -/// -/// ```gleam -/// > from("") -/// > |> tuple5(int, float, string, int, int) -/// Error([DecodeError(expected: "Tuple of 5 elements", found: "String", path: [])]) -/// ``` -/// -pub fn tuple5( - first decode1: Decoder(a), - second decode2: Decoder(b), - third decode3: Decoder(c), - fourth decode4: Decoder(d), - fifth decode5: Decoder(e), -) -> Decoder(#(a, b, c, d, e)) { - fn(value) { - use #(a, b, c, d, e) <- result.try(decode_tuple5(value)) - case decode1(a), decode2(b), decode3(c), decode4(d), decode5(e) { - Ok(a), Ok(b), Ok(c), Ok(d), Ok(e) -> Ok(#(a, b, c, d, e)) - a, b, c, d, e -> - tuple_errors(a, "0") - |> list.append(tuple_errors(b, "1")) - |> list.append(tuple_errors(c, "2")) - |> list.append(tuple_errors(d, "3")) - |> list.append(tuple_errors(e, "4")) - |> Error - } - } -} - -/// Checks to see if a `Dynamic` value is a 6-element tuple, list or array containing -/// specifically typed elements. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2, 3, 4, 5, 6)) -/// > |> tuple6(int, int, int, int, int, int) -/// Ok(#(1, 2, 3, 4, 5, 6)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2.0, "3", 4, 5, 6)) -/// > |> tuple6(int, float, string, int, int, int) -/// Ok(#(1, 2.0, "3", 4, 5, 6)) -/// ``` -/// -/// ```gleam -/// > from([1, 2, 3, 4, 5, 6]) -/// > |> tuple6(int, int, int, int, int, int) -/// Ok(#(1, 2, 3, 4, 5, 6)) -/// ``` -/// -/// ```gleam -/// > from([from(1), from(2.0), from("3"), from(4), from(True), from(False)]) -/// > |> tuple6(int, float, string, int, bool, bool) -/// Ok(#(1, 2.0, "3", 4, True, False)) -/// ``` -/// -/// ```gleam -/// > from(#(1, 2)) -/// > |> tuple6(int, float, string, int, int, int) -/// Error([ -/// DecodeError(expected: "Tuple of 6 elements", found: "Tuple of 2 elements", path: []), -/// ]) -/// ``` -/// -/// ```gleam -/// > from("") -/// > |> tuple6(int, float, string, int, int, int) -/// Error([DecodeError(expected: "Tuple of 6 elements", found: "String", path: [])]) -/// ``` -/// -pub fn tuple6( - first decode1: Decoder(a), - second decode2: Decoder(b), - third decode3: Decoder(c), - fourth decode4: Decoder(d), - fifth decode5: Decoder(e), - sixth decode6: Decoder(f), -) -> Decoder(#(a, b, c, d, e, f)) { - fn(value) { - use #(a, b, c, d, e, f) <- result.try(decode_tuple6(value)) - case - decode1(a), - decode2(b), - decode3(c), - decode4(d), - decode5(e), - decode6(f) - { - Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f) -> Ok(#(a, b, c, d, e, f)) - a, b, c, d, e, f -> - tuple_errors(a, "0") - |> list.append(tuple_errors(b, "1")) - |> list.append(tuple_errors(c, "2")) - |> list.append(tuple_errors(d, "3")) - |> list.append(tuple_errors(e, "4")) - |> list.append(tuple_errors(f, "5")) - |> Error - } - } -} - -/// Checks to see if a `Dynamic` value is a dict. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/dict -/// > dict.new() |> from |> map(string, int) -/// Ok(dict.new()) -/// ``` -/// -/// ```gleam -/// > from(1) |> map(string, int) -/// Error(DecodeError(expected: "Map", found: "Int", path: [])) -/// ``` -/// -/// ```gleam -/// > from("") |> map(string, int) -/// Error(DecodeError(expected: "Map", found: "String", path: [])) -/// ``` -/// -pub fn dict( - of key_type: Decoder(k), - to value_type: Decoder(v), -) -> Decoder(Dict(k, v)) { - fn(value) { - use map <- result.try(decode_map(value)) - use pairs <- result.try( - map - |> dict.to_list - |> list.try_map(fn(pair) { - let #(k, v) = pair - use k <- result.try( - key_type(k) - |> map_errors(push_path(_, "keys")), - ) - use v <- result.try( - value_type(v) - |> map_errors(push_path(_, "values")), - ) - Ok(#(k, v)) - }), - ) - Ok(dict.from_list(pairs)) - } -} - -@deprecated("Use `dict` instead") -pub fn map( - of key_type: Decoder(k), - to value_type: Decoder(v), -) -> Decoder(Dict(k, v)) { - dict(key_type, value_type) -} - -@external(erlang, "gleam_stdlib", "decode_map") -@external(javascript, "../gleam_stdlib.mjs", "decode_map") -fn decode_map(a: Dynamic) -> Result(Dict(Dynamic, Dynamic), DecodeErrors) - -/// Joins multiple decoders into one. When run they will each be tried in turn -/// until one succeeds, or they all fail. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/result -/// > let bool_or_string = any(of: [ -/// > string, -/// > fn(x) { result.map(bool(x), fn(_) { "a bool" }) } -/// > ]) -/// > bool_or_string(from("ok")) -/// Ok("ok") -/// ``` -/// -/// ```gleam -/// > bool_or_string(from(True)) -/// Ok("a bool") -/// ``` -/// -/// ```gleam -/// > bool_or_string(from(1)) -/// Error(DecodeError(expected: "another type", found: "Int", path: [])) -/// ``` -/// -pub fn any(of decoders: List(Decoder(t))) -> Decoder(t) { - fn(data) { - case decoders { - [] -> - Error([ - DecodeError(found: classify(data), expected: "another type", path: []), - ]) - - [decoder, ..decoders] -> - case decoder(data) { - Ok(decoded) -> Ok(decoded) - Error(_) -> any(decoders)(data) - } - } - } -} - -/// Decode 1 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.0, "3")) -/// > |> decode1(MyRecord, element(0, int)) -/// Ok(MyRecord(1)) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "")) -/// > |> decode1(MyRecord, element(0, int)) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// ]) -/// ``` -/// -pub fn decode1(constructor: fn(t1) -> t, t1: Decoder(t1)) -> Decoder(t) { - fn(value) { - case t1(value) { - Ok(a) -> Ok(constructor(a)) - a -> Error(all_errors(a)) - } - } -} - -/// Decode 2 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.0, "3")) -/// > |> decode2(MyRecord, element(0, int), element(1, float)) -/// Ok(MyRecord(1, 2.0)) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "")) -/// > |> decode2(MyRecord, element(0, int), element(1, float)) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode2( - constructor: fn(t1, t2) -> t, - t1: Decoder(t1), - t2: Decoder(t2), -) -> Decoder(t) { - fn(value) { - case t1(value), t2(value) { - Ok(a), Ok(b) -> Ok(constructor(a, b)) - a, b -> Error(list.concat([all_errors(a), all_errors(b)])) - } - } -} - -/// Decode 3 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.0, "3")) -/// > |> decode3(MyRecord, element(0, int), element(1, float), element(2, string)) -/// Ok(MyRecord(1, 2.0, "3")) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "")) -/// > |> decode3(MyRecord, element(0, int), element(1, float), element(2, string)) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode3( - constructor: fn(t1, t2, t3) -> t, - t1: Decoder(t1), - t2: Decoder(t2), - t3: Decoder(t3), -) -> Decoder(t) { - fn(value) { - case t1(value), t2(value), t3(value) { - Ok(a), Ok(b), Ok(c) -> Ok(constructor(a, b, c)) - a, b, c -> - Error(list.concat([all_errors(a), all_errors(b), all_errors(c)])) - } - } -} - -/// Decode 4 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.1, "3", "4")) -/// > |> decode4( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > ) -/// Ok(MyRecord(1, 2.1, "3", "4")) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "", "")) -/// > |> decode4( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > ) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode4( - constructor: fn(t1, t2, t3, t4) -> t, - t1: Decoder(t1), - t2: Decoder(t2), - t3: Decoder(t3), - t4: Decoder(t4), -) -> Decoder(t) { - fn(x: Dynamic) { - case t1(x), t2(x), t3(x), t4(x) { - Ok(a), Ok(b), Ok(c), Ok(d) -> Ok(constructor(a, b, c, d)) - a, b, c, d -> - Error(list.concat([ - all_errors(a), - all_errors(b), - all_errors(c), - all_errors(d), - ])) - } - } -} - -/// Decode 5 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.1, "3", "4", "5")) -/// > |> decode5( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > ) -/// Ok(MyRecord(1, 2.1, "3", "4", "5")) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "", "", "")) -/// > |> decode5( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > ) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode5( - constructor: fn(t1, t2, t3, t4, t5) -> t, - t1: Decoder(t1), - t2: Decoder(t2), - t3: Decoder(t3), - t4: Decoder(t4), - t5: Decoder(t5), -) -> Decoder(t) { - fn(x: Dynamic) { - case t1(x), t2(x), t3(x), t4(x), t5(x) { - Ok(a), Ok(b), Ok(c), Ok(d), Ok(e) -> Ok(constructor(a, b, c, d, e)) - a, b, c, d, e -> - Error(list.concat([ - all_errors(a), - all_errors(b), - all_errors(c), - all_errors(d), - all_errors(e), - ])) - } - } -} - -/// Decode 6 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.1, "3", "4", "5", "6")) -/// > |> decode6( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > ) -/// Ok(MyRecord(1, 2.1, "3", "4", "5", "6")) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "", "", "", "")) -/// > |> decode6( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > ) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode6( - constructor: fn(t1, t2, t3, t4, t5, t6) -> t, - t1: Decoder(t1), - t2: Decoder(t2), - t3: Decoder(t3), - t4: Decoder(t4), - t5: Decoder(t5), - t6: Decoder(t6), -) -> Decoder(t) { - fn(x: Dynamic) { - case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x) { - Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f) -> - Ok(constructor(a, b, c, d, e, f)) - a, b, c, d, e, f -> - Error(list.concat([ - all_errors(a), - all_errors(b), - all_errors(c), - all_errors(d), - all_errors(e), - all_errors(f), - ])) - } - } -} - -/// Decode 7 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.1, "3", "4", "5", "6")) -/// > |> decode7( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > element(6, string), -/// > ) -/// Ok(MyRecord(1, 2.1, "3", "4", "5", "6", "7")) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "", "", "", "", "")) -/// > |> decode7( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > element(6, string), -/// > ) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode7( - constructor: fn(t1, t2, t3, t4, t5, t6, t7) -> t, - t1: Decoder(t1), - t2: Decoder(t2), - t3: Decoder(t3), - t4: Decoder(t4), - t5: Decoder(t5), - t6: Decoder(t6), - t7: Decoder(t7), -) -> Decoder(t) { - fn(x: Dynamic) { - case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x), t7(x) { - Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f), Ok(g) -> - Ok(constructor(a, b, c, d, e, f, g)) - a, b, c, d, e, f, g -> - Error(list.concat([ - all_errors(a), - all_errors(b), - all_errors(c), - all_errors(d), - all_errors(e), - all_errors(f), - all_errors(g), - ])) - } - } -} - -/// Decode 8 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.1, "3", "4", "5", "6", "7", "8")) -/// > |> decode8( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > element(6, string), -/// > element(7, string), -/// > ) -/// Ok(MyRecord(1, 2.1, "3", "4", "5", "6", "7", "8")) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "", "", "", "", "", "")) -/// > |> decode8( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > element(6, string), -/// > element(7, string), -/// > ) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode8( - constructor: fn(t1, t2, t3, t4, t5, t6, t7, t8) -> t, - t1: Decoder(t1), - t2: Decoder(t2), - t3: Decoder(t3), - t4: Decoder(t4), - t5: Decoder(t5), - t6: Decoder(t6), - t7: Decoder(t7), - t8: Decoder(t8), -) -> Decoder(t) { - fn(x: Dynamic) { - case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x), t7(x), t8(x) { - Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f), Ok(g), Ok(h) -> - Ok(constructor(a, b, c, d, e, f, g, h)) - a, b, c, d, e, f, g, h -> - Error(list.concat([ - all_errors(a), - all_errors(b), - all_errors(c), - all_errors(d), - all_errors(e), - all_errors(f), - all_errors(g), - all_errors(h), - ])) - } - } -} - -/// Decode 9 values from a `Dynamic` value. -/// -/// ## Examples -/// -/// ```gleam -/// > from(#(1, 2.1, "3", "4", "5", "6", "7", "8", "9")) -/// > |> decode9( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > element(6, string), -/// > element(7, string), -/// > element(8, string), -/// > ) -/// Ok(MyRecord(1, 2.1, "3", "4", "5", "6", "7", "8", "9")) -/// ``` -/// -/// ```gleam -/// > from(#("", "", "", "", "", "", "", "", "")) -/// > |> decode9( -/// > MyRecord, -/// > element(0, int), -/// > element(1, float), -/// > element(2, string), -/// > element(3, string), -/// > element(4, string), -/// > element(5, string), -/// > element(6, string), -/// > element(7, string), -/// > element(8, string), -/// > ) -/// Error([ -/// DecodeError(expected: "Int", found: "String", path: ["0"]), -/// DecodeError(expected: "Float", found: "String", path: ["1"]), -/// ]) -/// ``` -/// -pub fn decode9( - constructor: fn(t1, t2, t3, t4, t5, t6, t7, t8, t9) -> t, - t1: Decoder(t1), - t2: Decoder(t2), - t3: Decoder(t3), - t4: Decoder(t4), - t5: Decoder(t5), - t6: Decoder(t6), - t7: Decoder(t7), - t8: Decoder(t8), - t9: Decoder(t9), -) -> Decoder(t) { - fn(x: Dynamic) { - case t1(x), t2(x), t3(x), t4(x), t5(x), t6(x), t7(x), t8(x), t9(x) { - Ok(a), Ok(b), Ok(c), Ok(d), Ok(e), Ok(f), Ok(g), Ok(h), Ok(i) -> - Ok(constructor(a, b, c, d, e, f, g, h, i)) - a, b, c, d, e, f, g, h, i -> - Error(list.concat([ - all_errors(a), - all_errors(b), - all_errors(c), - all_errors(d), - all_errors(e), - all_errors(f), - all_errors(g), - all_errors(h), - all_errors(i), - ])) - } - } -} - -fn all_errors(result: Result(a, List(DecodeError))) -> List(DecodeError) { - case result { - Ok(_) -> [] - Error(errors) -> errors - } -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam deleted file mode 100644 index 5d62419..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/float.gleam +++ /dev/null @@ -1,546 +0,0 @@ -//// Functions for working with floats. -//// -//// ## Division by zero -//// -//// Gleam runs on the Erlang virtual machine, which does not follow the IEEE -//// 754 standard for floating point arithmetic and does not have an `Infinity` -//// value. In Erlang division by zero results in a crash, however Gleam does -//// not have partial functions and operators in core so instead division by zero -//// returns zero, a behaviour taken from Pony, Coq, and Lean. -//// -//// This may seem unexpected at first, but it is no less mathematically valid -//// than crashing or returning a special value. Division by zero is undefined -//// in mathematics. - -import gleam/order.{type Order} - -/// Attempts to parse a string as a `Float`, returning `Error(Nil)` if it was -/// not possible. -/// -/// ## Examples -/// -/// ```gleam -/// > parse("2.3") -/// Ok(2.3) -/// ``` -/// -/// ```gleam -/// > parse("ABC") -/// Error(Nil) -/// ``` -/// -pub fn parse(string: String) -> Result(Float, Nil) { - do_parse(string) -} - -@external(erlang, "gleam_stdlib", "parse_float") -@external(javascript, "../gleam_stdlib.mjs", "parse_float") -fn do_parse(a: String) -> Result(Float, Nil) - -/// Returns the string representation of the provided `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(2.3) -/// "2.3" -/// ``` -/// -pub fn to_string(x: Float) -> String { - do_to_string(x) -} - -@external(erlang, "gleam_stdlib", "float_to_string") -@external(javascript, "../gleam_stdlib.mjs", "float_to_string") -fn do_to_string(a: Float) -> String - -/// Restricts a `Float` between a lower and upper bound. -/// -/// ## Examples -/// -/// ```gleam -/// > clamp(1.2, min: 1.4, max: 1.6) -/// 1.4 -/// ``` -/// -pub fn clamp(x: Float, min min_bound: Float, max max_bound: Float) -> Float { - x - |> min(max_bound) - |> max(min_bound) -} - -/// Compares two `Float`s, returning an `Order`: -/// `Lt` for lower than, `Eq` for equals, or `Gt` for greater than. -/// -/// ## Examples -/// -/// ```gleam -/// > compare(2.0, 2.3) -/// Lt -/// ``` -/// -/// To handle -/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) -/// you may use [`loosely_compare`](#loosely_compare) instead. -/// -pub fn compare(a: Float, with b: Float) -> Order { - case a == b { - True -> order.Eq - False -> - case a <. b { - True -> order.Lt - False -> order.Gt - } - } -} - -/// Compares two `Float`s within a tolerance, returning an `Order`: -/// `Lt` for lower than, `Eq` for equals, or `Gt` for greater than. -/// -/// This function allows Float comparison while handling -/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems). -/// -/// Notice: For `Float`s the tolerance won't be exact: -/// `5.3 - 5.0` is not exactly `0.3`. -/// -/// ## Examples -/// -/// ```gleam -/// > loosely_compare(5.0, with: 5.3, tolerating: 0.5) -/// Eq -/// ``` -/// -/// If you want to check only for equality you may use -/// [`loosely_equals`](#loosely_equals) instead. -/// -pub fn loosely_compare( - a: Float, - with b: Float, - tolerating tolerance: Float, -) -> Order { - let difference = absolute_value(a -. b) - case difference <=. tolerance { - True -> order.Eq - False -> compare(a, b) - } -} - -/// Checks for equality of two `Float`s within a tolerance, -/// returning an `Bool`. -/// -/// This function allows Float comparison while handling -/// [Floating Point Imprecision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems). -/// -/// Notice: For `Float`s the tolerance won't be exact: -/// `5.3 - 5.0` is not exactly `0.3`. -/// -/// ## Examples -/// -/// ```gleam -/// > loosely_equals(5.0, with: 5.3, tolerating: 0.5) -/// True -/// ``` -/// -/// ```gleam -/// > loosely_equals(5.0, with: 5.1, tolerating: 0.1) -/// False -/// ``` -/// -pub fn loosely_equals( - a: Float, - with b: Float, - tolerating tolerance: Float, -) -> Bool { - let difference = absolute_value(a -. b) - difference <=. tolerance -} - -/// Compares two `Float`s, returning the smaller of the two. -/// -/// ## Examples -/// -/// ```gleam -/// > min(2.0, 2.3) -/// 2.0 -/// ``` -/// -pub fn min(a: Float, b: Float) -> Float { - case a <. b { - True -> a - False -> b - } -} - -/// Compares two `Float`s, returning the larger of the two. -/// -/// ## Examples -/// -/// ```gleam -/// > max(2.0, 2.3) -/// 2.3 -/// ``` -/// -pub fn max(a: Float, b: Float) -> Float { - case a >. b { - True -> a - False -> b - } -} - -/// Rounds the value to the next highest whole number as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > ceiling(2.3) -/// 3.0 -/// ``` -/// -pub fn ceiling(x: Float) -> Float { - do_ceiling(x) -} - -@external(erlang, "math", "ceil") -@external(javascript, "../gleam_stdlib.mjs", "ceiling") -fn do_ceiling(a: Float) -> Float - -/// Rounds the value to the next lowest whole number as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > floor(2.3) -/// 2.0 -/// ``` -/// -pub fn floor(x: Float) -> Float { - do_floor(x) -} - -@external(erlang, "math", "floor") -@external(javascript, "../gleam_stdlib.mjs", "floor") -fn do_floor(a: Float) -> Float - -/// Rounds the value to the nearest whole number as an `Int`. -/// -/// ## Examples -/// -/// ```gleam -/// > round(2.3) -/// 2 -/// ``` -/// -/// ```gleam -/// > round(2.5) -/// 3 -/// ``` -/// -pub fn round(x: Float) -> Int { - do_round(x) -} - -@target(erlang) -@external(erlang, "erlang", "round") -fn do_round(a: Float) -> Int - -@target(javascript) -fn do_round(x: Float) -> Int { - case x >=. 0.0 { - True -> js_round(x) - _ -> 0 - js_round(negate(x)) - } -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "round") -fn js_round(a: Float) -> Int - -/// Returns the value as an `Int`, truncating all decimal digits. -/// -/// ## Examples -/// -/// ```gleam -/// > truncate(2.4343434847383438) -/// 2 -/// ``` -/// -pub fn truncate(x: Float) -> Int { - do_truncate(x) -} - -@external(erlang, "erlang", "trunc") -@external(javascript, "../gleam_stdlib.mjs", "truncate") -fn do_truncate(a: Float) -> Int - -/// Returns the absolute value of the input as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > absolute_value(-12.5) -/// 12.5 -/// ``` -/// -/// ```gleam -/// > absolute_value(10.2) -/// 10.2 -/// ``` -/// -pub fn absolute_value(x: Float) -> Float { - case x >=. 0.0 { - True -> x - _ -> 0.0 -. x - } -} - -/// Returns the results of the base being raised to the power of the -/// exponent, as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > power(2.0, -1.0) -/// Ok(0.5) -/// ``` -/// -/// ```gleam -/// > power(2.0, 2.0) -/// Ok(4.0) -/// ``` -/// -/// ```gleam -/// > power(8.0, 1.5) -/// Ok(22.627416997969522) -/// ``` -/// -/// ```gleam -/// > 4.0 |> power(of: 2.0) -/// Ok(16.0) -/// ``` -/// -/// ```gleam -/// > power(-1.0, 0.5) -/// Error(Nil) -/// ``` -/// -pub fn power(base: Float, of exponent: Float) -> Result(Float, Nil) { - let fractional: Bool = ceiling(exponent) -. exponent >. 0.0 - // In the following check: - // 1. If the base is negative and the exponent is fractional then - // return an error as it will otherwise be an imaginary number - // 2. If the base is 0 and the exponent is negative then the expression - // is equivalent to the exponent divided by 0 and an error should be - // returned - case base <. 0.0 && fractional || base == 0.0 && exponent <. 0.0 { - True -> Error(Nil) - False -> Ok(do_power(base, exponent)) - } -} - -@external(erlang, "math", "pow") -@external(javascript, "../gleam_stdlib.mjs", "power") -fn do_power(a: Float, b: Float) -> Float - -/// Returns the square root of the input as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > square_root(4.0) -/// Ok(2.0) -/// ``` -/// -/// ```gleam -/// > square_root(-16.0) -/// Error(Nil) -/// ``` -/// -pub fn square_root(x: Float) -> Result(Float, Nil) { - power(x, 0.5) -} - -/// Returns the negative of the value provided. -/// -/// ## Examples -/// -/// ```gleam -/// > negate(1.0) -/// -1.0 -/// ``` -/// -pub fn negate(x: Float) -> Float { - -1.0 *. x -} - -/// Sums a list of `Float`s. -/// -/// ## Example -/// -/// ```gleam -/// > sum([1.0, 2.2, 3.3]) -/// 6.5 -/// ``` -/// -pub fn sum(numbers: List(Float)) -> Float { - numbers - |> do_sum(0.0) -} - -fn do_sum(numbers: List(Float), initial: Float) -> Float { - case numbers { - [] -> initial - [x, ..rest] -> do_sum(rest, x +. initial) - } -} - -/// Multiplies a list of `Float`s and returns the product. -/// -/// ## Example -/// -/// ```gleam -/// > product([2.5, 3.2, 4.2]) -/// 33.6 -/// ``` -/// -pub fn product(numbers: List(Float)) -> Float { - case numbers { - [] -> 1.0 - _ -> do_product(numbers, 1.0) - } -} - -fn do_product(numbers: List(Float), initial: Float) -> Float { - case numbers { - [] -> initial - [x, ..rest] -> do_product(rest, x *. initial) - } -} - -/// Generates a random float between the given minimum and maximum values. -/// -/// -/// ## Examples -/// -/// ```gleam -/// > random(1.0, 5.0) -/// 2.646355926896028 -/// ``` -/// -pub fn random(min: Float, max: Float) -> Float { - do_random_uniform() *. { max -. min } +. min -} - -/// Returns a random float uniformly distributed in the value range -/// 0.0 =< X < 1.0 and updates the state in the process dictionary. -/// See: <https://www.erlang.org/doc/man/rand.html#uniform-0> -/// -@external(erlang, "rand", "uniform") -@external(javascript, "../gleam_stdlib.mjs", "random_uniform") -fn do_random_uniform() -> Float - -/// Returns division of the inputs as a `Result`. -/// -/// ## Examples -/// -/// ```gleam -/// > divide(0.0, 1.0) -/// Ok(1.0) -/// ``` -/// -/// ```gleam -/// > divide(1.0, 0.0) -/// Error(Nil) -/// ``` -/// -pub fn divide(a: Float, by b: Float) -> Result(Float, Nil) { - case b { - 0.0 -> Error(Nil) - b -> Ok(a /. b) - } -} - -/// Adds two floats together. -/// -/// It's the function equivalent of the `+.` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > add(1.0, 2.0) -/// 3.0 -/// ``` -/// -/// ```gleam -/// > import gleam/list -/// > list.fold([1.0, 2.0, 3.0], 0.0, add) -/// 6.0 -/// ``` -/// -/// ```gleam -/// > 3.0 |> add(2.0) -/// 5.0 -/// ``` -/// -pub fn add(a: Float, b: Float) -> Float { - a +. b -} - -/// Multiplies two floats together. -/// -/// It's the function equivalent of the `*.` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > multiply(2.0, 4.0) -/// 8.0 -/// ``` -/// -/// ```gleam -/// import gleam/list -/// > list.fold([2.0, 3.0, 4.0], 1.0, multiply) -/// 24.0 -/// ``` -/// -/// ```gleam -/// > 3.0 |> multiply(2.0) -/// 6.0 -/// ``` -/// -pub fn multiply(a: Float, b: Float) -> Float { - a *. b -} - -/// Subtracts one float from another. -/// -/// It's the function equivalent of the `-.` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > subtract(3.0, 1.0) -/// 2.0 -/// ``` -/// -/// ```gleam -/// > import gleam/list -/// > list.fold([1.0, 2.0, 3.0], 10.0, subtract) -/// 4.0 -/// ``` -/// -/// ```gleam -/// > 3.0 |> subtract(_, 2.0) -/// 1.0 -/// ``` -/// -/// ```gleam -/// > 3.0 |> subtract(2.0, _) -/// -1.0 -/// ``` -/// -pub fn subtract(a: Float, b: Float) -> Float { - a -. b -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/function.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/function.gleam deleted file mode 100644 index daa997d..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/function.gleam +++ /dev/null @@ -1,162 +0,0 @@ -/// Takes two functions and chains them together to form one function that -/// takes the input from the first and returns the output of the second. -/// -pub fn compose(fun1: fn(a) -> b, fun2: fn(b) -> c) -> fn(a) -> c { - fn(a) { fun2(fun1(a)) } -} - -/// Takes a function with `2` arguments (an arity of `2`), and returns the -/// curried equivalent. -/// -/// `fn(a, b) -> c` becomes `fn(a) -> fn(b) -> c`. -/// -/// ## Examples -/// -/// *Currying* creates a new function that is identical to the given function -/// except that arguments must now be supplied one by one over several function -/// calls. It thus is the process of taking a function with `n` arguments -/// and producing a sequence of `n` single-argument functions. Given: -/// -/// ```gleam -/// > fn my_fun(i: Int, s: String) -> String { ... } -/// ``` -/// -/// …calling `curry2(my_fun)` would return the curried equivalent, like so: -/// -/// ```gleam -/// > curry2(my_fun) -/// fn(Int) -> fn(String) -> String -/// ``` -/// -/// Currying is useful when you want to partially apply a function with -/// some arguments and then pass it somewhere else, for example: -/// -/// ```gleam -/// > import gleam/list -/// > let multiply = curry2(fn(x, y) { x * y }) -/// > let doubles = list.map([1, 2, 3], multiply(2)) -/// [2, 4, 6] -/// ``` -/// -pub fn curry2(fun: fn(a, b) -> value) { - fn(a) { fn(b) { fun(a, b) } } -} - -/// Takes a function with `3` arguments (an arity of `3`), and returns the -/// curried equivalent. -/// -/// `fn(a, b, c) -> d` becomes `fn(a) -> fn(b) -> fn(c) -> d`. -/// -/// See [`curry2`](#curry2) for a detailed explanation. -/// -pub fn curry3(fun: fn(a, b, c) -> value) { - fn(a) { fn(b) { fn(c) { fun(a, b, c) } } } -} - -/// Takes a function with `4` arguments (an arity of `4`), and returns the -/// curried equivalent. -/// -/// `fn(a, b, c, d) -> e` becomes `fn(a) -> fn(b) -> fn(c) -> fn(d) -> e`. -/// -/// See [`curry2`](#curry2) for a detailed explanation. -/// -pub fn curry4(fun: fn(a, b, c, d) -> value) { - fn(a) { fn(b) { fn(c) { fn(d) { fun(a, b, c, d) } } } } -} - -/// Takes a function with `5` arguments (an arity of `5`), and returns the -/// curried equivalent. -/// -/// `fn(a, b, c, d, e) -> f` becomes -/// `fn(a) -> fn(b) -> fn(c) -> fn(d) -> fn(e) -> f`. -/// -/// See [`curry2`](#curry2) for a detailed explanation. -/// -pub fn curry5(fun: fn(a, b, c, d, e) -> value) { - fn(a) { fn(b) { fn(c) { fn(d) { fn(e) { fun(a, b, c, d, e) } } } } } -} - -/// Takes a function with `6` arguments (an arity of `6`), and returns the -/// curried equivalent. -/// -/// `fn(a, b, c, d, e, f) -> g` becomes -/// `fn(a) -> fn(b) -> fn(c) -> fn(d) -> fn(e) -> fn(f) -> g`. -/// -/// See [`curry2`](#curry2) for a detailed explanation. -/// -pub fn curry6(fun: fn(a, b, c, d, e, f) -> value) { - fn(a) { - fn(b) { fn(c) { fn(d) { fn(e) { fn(f) { fun(a, b, c, d, e, f) } } } } } - } -} - -/// Takes a function that takes two arguments and returns a new function that -/// takes the same two arguments, but in reverse order. -/// -pub fn flip(fun: fn(a, b) -> c) -> fn(b, a) -> c { - fn(b, a) { fun(a, b) } -} - -/// Takes a single argument and always returns its input value. -/// -pub fn identity(x: a) -> a { - x -} - -/// Takes a single argument and returns a new function that -/// ignores its argument and always returns the input value. -/// -pub fn constant(value: a) -> fn(b) -> a { - fn(_) { value } -} - -/// Takes an argument and a single function, -/// calls that function with that argument -/// and returns that argument instead of the function return value. -/// Useful for running synchronous side effects in a pipeline. -/// -pub fn tap(arg: a, effect: fn(a) -> b) -> a { - effect(arg) - arg -} - -/// Takes a function with arity one and an argument, -/// calls that function with the argument and returns the function return value. -/// -/// Useful for concisely calling functions returned as a part of a pipeline. -/// -/// ## Example -/// -/// ```gleam -/// > let doubler = fn() { -/// > fn(x: Int) { x * 2 } -/// > } -/// > -/// > doubler() -/// > |> apply1(2) -/// 4 -/// ``` -/// -pub fn apply1(fun: fn(a) -> value, arg1: a) -> value { - fun(arg1) -} - -/// Takes a function with arity two and two arguments, -/// calls that function with the arguments -/// and returns the function return value. -/// -/// See [`apply1`](#apply1) for more details. -/// -pub fn apply2(fun: fn(a, b) -> value, arg1: a, arg2: b) -> value { - fun(arg1, arg2) -} - -/// Takes a function with arity three and three arguments, -/// calls that function with the arguments -/// and returns the function return value. -/// -/// See [`apply1`](#apply1) for more details. -/// -pub fn apply3(fun: fn(a, b, c) -> value, arg1: a, arg2: b, arg3: c) -> value { - fun(arg1, arg2, arg3) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam deleted file mode 100644 index d93c16a..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/int.gleam +++ /dev/null @@ -1,874 +0,0 @@ -//// Functions for working with integers. -//// -//// ## Division by zero -//// -//// In Erlang division by zero results in a crash, however Gleam does not have -//// partial functions and operators in core so instead division by zero returns -//// zero, a behaviour taken from Pony, Coq, and Lean. -//// -//// This may seem unexpected at first, but it is no less mathematically valid -//// than crashing or returning a special value. Division by zero is undefined -//// in mathematics. - -import gleam/float -import gleam/order.{type Order} - -/// Returns the absolute value of the input. -/// -/// ## Examples -/// -/// ```gleam -/// > absolute_value(-12) -/// 12 -/// ``` -/// -/// ```gleam -/// > absolute_value(10) -/// 10 -/// ``` -/// -pub fn absolute_value(x: Int) -> Int { - case x >= 0 { - True -> x - False -> x * -1 - } -} - -/// Returns the results of the base being raised to the power of the -/// exponent, as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > power(2, -1.0) -/// Ok(0.5) -/// ``` -/// -/// ```gleam -/// > power(2, 2.0) -/// Ok(4.0) -/// ``` -/// -/// ```gleam -/// > power(8, 1.5) -/// Ok(22.627416997969522) -/// ``` -/// -/// ```gleam -/// > 4 |> power(of: 2.0) -/// Ok(16.0) -/// ``` -/// -/// ```gleam -/// > power(-1, 0.5) -/// Error(Nil) -/// ``` -/// -pub fn power(base: Int, of exponent: Float) -> Result(Float, Nil) { - base - |> to_float() - |> float.power(exponent) -} - -/// Returns the square root of the input as a `Float`. -/// -/// ## Examples -/// -/// ```gleam -/// > square_root(4) -/// Ok(2.0) -/// ``` -/// -/// ```gleam -/// > square_root(-16) -/// Error(Nil) -/// ``` -/// -pub fn square_root(x: Int) -> Result(Float, Nil) { - x - |> to_float() - |> float.square_root() -} - -/// Parses a given string as an int if possible. -/// -/// ## Examples -/// -/// ```gleam -/// > parse("2") -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > parse("ABC") -/// Error(Nil) -/// ``` -/// -pub fn parse(string: String) -> Result(Int, Nil) { - do_parse(string) -} - -@external(erlang, "gleam_stdlib", "parse_int") -@external(javascript, "../gleam_stdlib.mjs", "parse_int") -fn do_parse(a: String) -> Result(Int, Nil) - -/// Parses a given string as an int in a given base if possible. -/// Supports only bases 2 to 36, for values outside of which this function returns an `Error(Nil)`. -/// -/// ## Examples -/// -/// ```gleam -/// > base_parse("10", 2) -/// Ok(2) -/// -/// > base_parse("30", 16) -/// Ok(48) -/// -/// > base_parse("1C", 36) -/// Ok(48) -/// -/// > base_parse("48", 1) -/// Error(Nil) -/// -/// > base_parse("48", 37) -/// Error(Nil) -/// ``` -/// -pub fn base_parse(string: String, base: Int) -> Result(Int, Nil) { - case base >= 2 && base <= 36 { - True -> do_base_parse(string, base) - False -> Error(Nil) - } -} - -@external(erlang, "gleam_stdlib", "int_from_base_string") -@external(javascript, "../gleam_stdlib.mjs", "int_from_base_string") -fn do_base_parse(a: String, b: Int) -> Result(Int, Nil) - -/// Prints a given int to a string. -/// -/// ## Examples -/// -/// ```gleam -/// > to_string(2) -/// "2" -/// ``` -/// -pub fn to_string(x: Int) { - do_to_string(x) -} - -@external(erlang, "erlang", "integer_to_binary") -@external(javascript, "../gleam_stdlib.mjs", "to_string") -fn do_to_string(a: Int) -> String - -/// Error value when trying to operate with a base out of the allowed range. -/// -pub type InvalidBase { - InvalidBase -} - -/// Prints a given int to a string using the base number provided. -/// Supports only bases 2 to 36, for values outside of which this function returns an `Error(InvalidBase)`. -/// For common bases (2, 8, 16, 36), use the `to_baseN` functions. -/// -/// ## Examples -/// -/// ```gleam -/// > to_base_string(2, 2) -/// Ok("10") -/// ``` -/// -/// ```gleam -/// > to_base_string(48, 16) -/// Ok("30") -/// ``` -/// -/// ```gleam -/// > to_base_string(48, 36) -/// Ok("1C") -/// ``` -/// -/// ```gleam -/// > to_base_string(48, 1) -/// Error(InvalidBase) -/// ``` -/// -/// ```gleam -/// > to_base_string(48, 37) -/// Error(InvalidBase) -/// ``` -/// -pub fn to_base_string(x: Int, base: Int) -> Result(String, InvalidBase) { - case base >= 2 && base <= 36 { - True -> Ok(do_to_base_string(x, base)) - False -> Error(InvalidBase) - } -} - -@external(erlang, "erlang", "integer_to_binary") -@external(javascript, "../gleam_stdlib.mjs", "int_to_base_string") -fn do_to_base_string(a: Int, b: Int) -> String - -/// Prints a given int to a string using base-2. -/// -/// ## Examples -/// -/// ```gleam -/// > to_base2(2) -/// "10" -/// ``` -/// -pub fn to_base2(x: Int) -> String { - do_to_base_string(x, 2) -} - -/// Prints a given int to a string using base-8. -/// -/// ## Examples -/// -/// ```gleam -/// > to_base8(15) -/// "17" -/// ``` -/// -pub fn to_base8(x: Int) -> String { - do_to_base_string(x, 8) -} - -/// Prints a given int to a string using base-16. -/// -/// ## Examples -/// -/// ```gleam -/// > to_base16(48) -/// "30" -/// ``` -/// -pub fn to_base16(x: Int) -> String { - do_to_base_string(x, 16) -} - -/// Prints a given int to a string using base-36. -/// -/// ## Examples -/// -/// ```gleam -/// > to_base36(48) -/// "1C" -/// ``` -/// -pub fn to_base36(x: Int) -> String { - do_to_base_string(x, 36) -} - -/// Takes an int and returns its value as a float. -/// -/// ## Examples -/// -/// ```gleam -/// > to_float(5) -/// 5.0 -/// ``` -/// -/// ```gleam -/// > to_float(0) -/// 0.0 -/// ``` -/// -/// ```gleam -/// > to_float(-3) -/// -3.0 -/// ``` -/// -pub fn to_float(x: Int) -> Float { - do_to_float(x) -} - -@external(erlang, "erlang", "float") -@external(javascript, "../gleam_stdlib.mjs", "identity") -fn do_to_float(a: Int) -> Float - -/// Restricts an int between a lower and upper bound. -/// -/// ## Examples -/// -/// ```gleam -/// > clamp(40, min: 50, max: 60) -/// 50 -/// ``` -/// -pub fn clamp(x: Int, min min_bound: Int, max max_bound: Int) -> Int { - x - |> min(max_bound) - |> max(min_bound) -} - -/// Compares two ints, returning an order. -/// -/// ## Examples -/// -/// ```gleam -/// > compare(2, 3) -/// Lt -/// ``` -/// -/// ```gleam -/// > compare(4, 3) -/// Gt -/// ``` -/// -/// ```gleam -/// > compare(3, 3) -/// Eq -/// ``` -/// -pub fn compare(a: Int, with b: Int) -> Order { - case a == b { - True -> order.Eq - False -> - case a < b { - True -> order.Lt - False -> order.Gt - } - } -} - -/// Compares two ints, returning the smaller of the two. -/// -/// ## Examples -/// -/// ```gleam -/// > min(2, 3) -/// 2 -/// ``` -/// -pub fn min(a: Int, b: Int) -> Int { - case a < b { - True -> a - False -> b - } -} - -/// Compares two ints, returning the larger of the two. -/// -/// ## Examples -/// -/// ```gleam -/// > max(2, 3) -/// 3 -/// ``` -/// -pub fn max(a: Int, b: Int) -> Int { - case a > b { - True -> a - False -> b - } -} - -/// Returns whether the value provided is even. -/// -/// ## Examples -/// -/// ```gleam -/// > is_even(2) -/// True -/// ``` -/// -/// ```gleam -/// > is_even(3) -/// False -/// ``` -/// -pub fn is_even(x: Int) -> Bool { - x % 2 == 0 -} - -/// Returns whether the value provided is odd. -/// -/// ## Examples -/// -/// ```gleam -/// > is_odd(3) -/// True -/// ``` -/// -/// ```gleam -/// > is_odd(2) -/// False -/// ``` -/// -pub fn is_odd(x: Int) -> Bool { - x % 2 != 0 -} - -/// Returns the negative of the value provided. -/// -/// ## Examples -/// -/// ```gleam -/// > negate(1) -/// -1 -/// ``` -/// -pub fn negate(x: Int) -> Int { - -1 * x -} - -/// Sums a list of ints. -/// -/// ## Example -/// -/// ```gleam -/// > sum([1, 2, 3]) -/// 6 -/// ``` -/// -pub fn sum(numbers: List(Int)) -> Int { - numbers - |> do_sum(0) -} - -fn do_sum(numbers: List(Int), initial: Int) -> Int { - case numbers { - [] -> initial - [x, ..rest] -> do_sum(rest, x + initial) - } -} - -/// Multiplies a list of ints and returns the product. -/// -/// ## Example -/// -/// ```gleam -/// > product([2, 3, 4]) -/// 24 -/// ``` -/// -pub fn product(numbers: List(Int)) -> Int { - case numbers { - [] -> 1 - _ -> do_product(numbers, 1) - } -} - -fn do_product(numbers: List(Int), initial: Int) -> Int { - case numbers { - [] -> initial - [x, ..rest] -> do_product(rest, x * initial) - } -} - -/// Splits an integer into its digit representation in the specified base -/// -/// ## Examples -/// -/// ```gleam -/// > digits(234, 10) -/// Ok([2,3,4]) -/// ``` -/// -/// ```gleam -/// > digits(234, 1) -/// Error(InvalidBase) -/// ``` -/// -pub fn digits(x: Int, base: Int) -> Result(List(Int), InvalidBase) { - case base < 2 { - True -> Error(InvalidBase) - False -> Ok(do_digits(x, base, [])) - } -} - -fn do_digits(x: Int, base: Int, acc: List(Int)) -> List(Int) { - case absolute_value(x) < base { - True -> [x, ..acc] - False -> do_digits(x / base, base, [x % base, ..acc]) - } -} - -/// Joins a list of digits into a single value. -/// Returns an error if the base is less than 2 or if the list contains a digit greater than or equal to the specified base. -/// -/// ## Examples -/// -/// ```gleam -/// > undigits([2,3,4], 10) -/// Ok(234) -/// ``` -/// -/// ```gleam -/// > undigits([2,3,4], 1) -/// Error(InvalidBase) -/// ``` -/// -/// ```gleam -/// > undigits([2,3,4], 2) -/// Error(InvalidBase) -/// ``` -/// -pub fn undigits(numbers: List(Int), base: Int) -> Result(Int, InvalidBase) { - case base < 2 { - True -> Error(InvalidBase) - False -> do_undigits(numbers, base, 0) - } -} - -fn do_undigits( - numbers: List(Int), - base: Int, - acc: Int, -) -> Result(Int, InvalidBase) { - case numbers { - [] -> Ok(acc) - [digit, ..] if digit >= base -> Error(InvalidBase) - [digit, ..rest] -> do_undigits(rest, base, acc * base + digit) - } -} - -/// Generates a random int between the given minimum and maximum values. -/// -/// ## Examples -/// -/// ```gleam -/// > random(1, 5) -/// 2 -/// ``` -/// -pub fn random(min: Int, max: Int) -> Int { - float.random(to_float(min), to_float(max)) - |> float.floor() - |> float.round() -} - -/// Performs a truncated integer division. -/// -/// Returns division of the inputs as a `Result`: If the given divisor equals -/// `0`, this function returns an `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// > divide(0, 1) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > divide(1, 0) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > divide(5, 2) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > divide(-99, 2) -/// Ok(-49) -/// ``` -/// -pub fn divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - divisor -> Ok(dividend / divisor) - } -} - -/// Computes the remainder of an integer division of inputs as a `Result`. -/// -/// Returns division of the inputs as a `Result`: If the given divisor equals -/// `0`, this function returns an `Error`. -/// -/// Most the time you will want to use the `%` operator instead of this -/// function. -/// -/// ## Examples -/// -/// ```gleam -/// > remainder(3, 2) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > remainder(1, 0) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > remainder(10, -1) -/// Ok(0) -/// ``` -/// -/// ```gleam -/// > remainder(13, by: 3) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > remainder(-13, by: 3) -/// Ok(-1) -/// ``` -/// -/// ```gleam -/// > remainder(13, by: -3) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > remainder(-13, by: -3) -/// Ok(-1) -/// ``` -/// -pub fn remainder(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - divisor -> Ok(dividend % divisor) - } -} - -/// Computes the modulo of an integer division of inputs as a `Result`. -/// -/// Returns division of the inputs as a `Result`: If the given divisor equals -/// `0`, this function returns an `Error`. -/// -/// Most the time you will want to use the `%` operator instead of this -/// function. -/// -/// ## Examples -/// -/// ```gleam -/// > modulo(3, 2) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > modulo(1, 0) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > modulo(10, -1) -/// Ok(0) -/// ``` -/// -/// ```gleam -/// > modulo(13, by: 3) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > modulo(-13, by: 3) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > modulo(13, by: -3) -/// Ok(-2) -/// ``` -/// -/// ```gleam -/// > modulo(-13, by: -3) -/// Ok(-1) -/// ``` -/// -pub fn modulo(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - _ -> { - let remainder = dividend % divisor - case remainder * divisor < 0 { - True -> Ok(remainder + divisor) - False -> Ok(remainder) - } - } - } -} - -/// Performs a *floored* integer division, which means that the result will -/// always be rounded towards negative infinity. -/// -/// If you want to perform truncated integer division (rounding towards zero), -/// use `int.divide()` or the `/` operator instead. -/// -/// Returns division of the inputs as a `Result`: If the given divisor equals -/// `0`, this function returns an `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// > floor_divide(1, 0) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > floor_divide(5, 2) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > floor_divide(6, -4) -/// Ok(-2) -/// ``` -/// -/// ```gleam -/// > floor_divide(-99, 2) -/// Ok(-50) -/// ``` -/// -pub fn floor_divide(dividend: Int, by divisor: Int) -> Result(Int, Nil) { - case divisor { - 0 -> Error(Nil) - divisor -> - case dividend * divisor < 0 && dividend % divisor != 0 { - True -> Ok(dividend / divisor - 1) - False -> Ok(dividend / divisor) - } - } -} - -/// Adds two integers together. -/// -/// It's the function equivalent of the `+` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > add(1, 2) -/// 3 -/// ``` -/// -/// ```gleam -/// import gleam/list -/// > list.fold([1, 2, 3], 0, add) -/// 6 -/// ``` -/// -/// ```gleam -/// > 3 |> add(2) -/// 5 -/// ``` -/// -pub fn add(a: Int, b: Int) -> Int { - a + b -} - -/// Multiplies two integers together. -/// -/// It's the function equivalent of the `*` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > multiply(2, 4) -/// 8 -/// ``` -/// -/// ```gleam -/// import gleam/list -/// > list.fold([2, 3, 4], 1, multiply) -/// 24 -/// ``` -/// -/// ```gleam -/// > 3 |> multiply(2) -/// 6 -/// ``` -/// -pub fn multiply(a: Int, b: Int) -> Int { - a * b -} - -/// Subtracts one int from another. -/// -/// It's the function equivalent of the `-` operator. -/// This function is useful in higher order functions or pipes. -/// -/// ## Examples -/// -/// ```gleam -/// > subtract(3, 1) -/// 2.0 -/// ``` -/// -/// ```gleam -/// import gleam/list -/// > list.fold([1, 2, 3], 10, subtract) -/// 4 -/// ``` -/// -/// ```gleam -/// > 3 |> subtract(2) -/// 1 -/// ``` -/// -/// ```gleam -/// > 3 |> subtract(2, _) -/// -1 -/// ``` -/// -pub fn subtract(a: Int, b: Int) -> Int { - a - b -} - -/// Calculates the bitwise AND of its arguments. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "band") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_and") -pub fn bitwise_and(x: Int, y: Int) -> Int - -/// Calculates the bitwise NOT of its argument. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bnot") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_not") -pub fn bitwise_not(x: Int) -> Int - -/// Calculates the bitwise OR of its arguments. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bor") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_or") -pub fn bitwise_or(x: Int, y: Int) -> Int - -/// Calculates the bitwise XOR of its arguments. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bxor") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_exclusive_or") -pub fn bitwise_exclusive_or(x: Int, y: Int) -> Int - -/// Calculates the result of an arithmetic left bitshift. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bsl") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_left") -pub fn bitwise_shift_left(x: Int, y: Int) -> Int - -/// Calculates the result of an arithmetic right bitshift. -/// -/// The exact behaviour of this function depends on the target platform. -/// On Erlang it is equivalent to bitwise operations on ints, on JavaScript it -/// is equivalent to bitwise operations on big-ints. -/// -@external(erlang, "erlang", "bsr") -@external(javascript, "../gleam_stdlib.mjs", "bitwise_shift_right") -pub fn bitwise_shift_right(x: Int, y: Int) -> Int diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/io.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/io.gleam deleted file mode 100644 index 0c0a3ee..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/io.gleam +++ /dev/null @@ -1,117 +0,0 @@ -import gleam/string - -/// Writes a string to standard output. -/// -/// If you want your output to be printed on its own line see `println`. -/// -/// ## Example -/// -/// ```gleam -/// > io.print("Hi mum") -/// // -> Hi mum -/// Nil -/// ``` -/// -pub fn print(string: String) -> Nil { - do_print(string) -} - -@external(erlang, "gleam_stdlib", "print") -@external(javascript, "../gleam_stdlib.mjs", "print") -fn do_print(string string: String) -> Nil - -/// Writes a string to standard error. -/// -/// If you want your output to be printed on its own line see `println_error`. -/// -/// ## Example -/// -/// ``` -/// > io.print_error("Hi pop") -/// // -> Hi pop -/// Nil -/// ``` -/// -pub fn print_error(string: String) -> Nil { - do_print_error(string) -} - -@external(erlang, "gleam_stdlib", "print_error") -@external(javascript, "../gleam_stdlib.mjs", "print_error") -fn do_print_error(string string: String) -> Nil - -/// Writes a string to standard output, appending a newline to the end. -/// -/// ## Example -/// -/// ```gleam -/// > io.println("Hi mum") -/// // -> Hi mum -/// Nil -/// ``` -/// -pub fn println(string: String) -> Nil { - do_println(string) -} - -@external(erlang, "gleam_stdlib", "println") -@external(javascript, "../gleam_stdlib.mjs", "console_log") -fn do_println(string string: String) -> Nil - -/// Writes a string to standard error, appending a newline to the end. -/// -/// ## Example -/// -/// ```gleam -/// > io.println_error("Hi pop") -/// // -> Hi mum -/// Nil -/// ``` -/// -pub fn println_error(string: String) -> Nil { - do_println_error(string) -} - -@external(erlang, "gleam_stdlib", "println_error") -@external(javascript, "../gleam_stdlib.mjs", "console_error") -fn do_println_error(string string: String) -> Nil - -/// Prints a value to standard error (stderr) yielding Gleam syntax. -/// -/// The value is returned after being printed so it can be used in pipelines. -/// -/// ## Example -/// -/// ```gleam -/// > debug("Hi mum") -/// // -> <<"Hi mum">> -/// "Hi mum" -/// ``` -/// -/// ```gleam -/// > debug(Ok(1)) -/// // -> {ok, 1} -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > import list -/// > [1, 2] -/// > |> list.map(fn(x) { x + 1 }) -/// > |> debug -/// > |> list.map(fn(x) { x * 2 }) -/// // -> [2, 3] -/// [4, 6] -/// ``` -/// -pub fn debug(term: anything) -> anything { - term - |> string.inspect - |> do_debug_println - - term -} - -@external(erlang, "gleam_stdlib", "println_error") -@external(javascript, "../gleam_stdlib.mjs", "print_debug") -fn do_debug_println(string string: String) -> Nil diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/iterator.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/iterator.gleam deleted file mode 100644 index c57e7fd..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/iterator.gleam +++ /dev/null @@ -1,1530 +0,0 @@ -import gleam/result -import gleam/int -import gleam/list -import gleam/dict.{type Dict} -import gleam/option.{type Option, None, Some} -import gleam/order - -// Internal private representation of an Iterator -type Action(element) { - // Dedicated to Electric Six - // https://youtu.be/_30t2dzEgiw?t=162 - Stop - Continue(element, fn() -> Action(element)) -} - -/// An iterator is a lazily evaluated sequence of element. -/// -/// Iterators are useful when working with collections that are too large to -/// fit in memory (or those that are infinite in size) as they only require the -/// elements currently being processed to be in memory. -/// -/// As a lazy data structure no work is done when an iterator is filters, -/// mapped, etc, instead a new iterator is returned with these transformations -/// applied to the stream. Once the stream has all the required transformations -/// applied it can be evaluated using functions such as `fold` and `to_list`. -/// -pub opaque type Iterator(element) { - Iterator(continuation: fn() -> Action(element)) -} - -// Public API for iteration -pub type Step(element, accumulator) { - Next(element: element, accumulator: accumulator) - Done -} - -// Shortcut for an empty iterator. -fn stop() -> Action(element) { - Stop -} - -// Creating Iterators -fn do_unfold( - initial: acc, - f: fn(acc) -> Step(element, acc), -) -> fn() -> Action(element) { - fn() { - case f(initial) { - Next(x, acc) -> Continue(x, do_unfold(acc, f)) - Done -> Stop - } - } -} - -/// Creates an iterator from a given function and accumulator. -/// -/// The function is called on the accumulator and returns either `Done`, -/// indicating the iterator has no more elements, or `Next` which contains a -/// new element and accumulator. The element is yielded by the iterator and the -/// new accumulator is used with the function to compute the next element in -/// the sequence. -/// -/// ## Examples -/// -/// ```gleam -/// > unfold(from: 5, with: fn(n) { -/// > case n { -/// > 0 -> Done -/// > n -> Next(element: n, accumulator: n - 1) -/// > } -/// > }) -/// > |> to_list -/// [5, 4, 3, 2, 1] -/// ``` -/// -pub fn unfold( - from initial: acc, - with f: fn(acc) -> Step(element, acc), -) -> Iterator(element) { - initial - |> do_unfold(f) - |> Iterator -} - -// TODO: test -/// Creates an iterator that yields values created by calling a given function -/// repeatedly. -/// -pub fn repeatedly(f: fn() -> element) -> Iterator(element) { - unfold(Nil, fn(_) { Next(f(), Nil) }) -} - -/// Creates an iterator that returns the same value infinitely. -/// -/// ## Examples -/// -/// ```gleam -/// > repeat(10) -/// > |> take(4) -/// > |> to_list -/// [10, 10, 10, 10] -/// ``` -/// -pub fn repeat(x: element) -> Iterator(element) { - repeatedly(fn() { x }) -} - -/// Creates an iterator that yields each element from the given list. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3, 4]) -/// > |> to_list -/// [1, 2, 3, 4] -/// ``` -/// -pub fn from_list(list: List(element)) -> Iterator(element) { - let yield = fn(acc) { - case acc { - [] -> Done - [head, ..tail] -> Next(head, tail) - } - } - unfold(list, yield) -} - -// Consuming Iterators -fn do_transform( - continuation: fn() -> Action(a), - state: acc, - f: fn(acc, a) -> Step(b, acc), -) -> fn() -> Action(b) { - fn() { - case continuation() { - Stop -> Stop - Continue(el, next) -> - case f(state, el) { - Done -> Stop - Next(yield, next_state) -> - Continue(yield, do_transform(next, next_state, f)) - } - } - } -} - -/// Creates an iterator from an existing iterator -/// and a stateful function that may short-circuit. -/// -/// `f` takes arguments `acc` for current state and `el` for current element from underlying iterator, -/// and returns either `Next` with yielded element and new state value, or `Done` to halt the iterator. -/// -/// ## Examples -/// -/// Approximate implementation of `index` in terms of `transform`: -/// -/// ```gleam -/// > from_list(["a", "b", "c"]) -/// > |> transform(0, fn(i, el) { Next(#(i, el), i + 1) }) -/// > |> to_list -/// [#(0, "a"), #(1, "b"), #(2, "c")] -/// ``` -pub fn transform( - over iterator: Iterator(a), - from initial: acc, - with f: fn(acc, a) -> Step(b, acc), -) -> Iterator(b) { - do_transform(iterator.continuation, initial, f) - |> Iterator -} - -fn do_fold( - continuation: fn() -> Action(e), - f: fn(acc, e) -> acc, - accumulator: acc, -) -> acc { - case continuation() { - Continue(elem, next) -> do_fold(next, f, f(accumulator, elem)) - Stop -> accumulator - } -} - -/// Reduces an iterator of elements into a single value by calling a given -/// function on each element in turn. -/// -/// If called on an iterator of infinite length then this function will never -/// return. -/// -/// If you do not care about the end value and only wish to evaluate the -/// iterator for side effects consider using the `run` function instead. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3, 4] -/// > |> from_list -/// > |> fold(from: 0, with: fn(acc, element) { element + acc }) -/// 10 -/// ``` -/// -pub fn fold( - over iterator: Iterator(e), - from initial: acc, - with f: fn(acc, e) -> acc, -) -> acc { - iterator.continuation - |> do_fold(f, initial) -} - -// TODO: test -/// Evaluates all elements emitted by the given iterator. This function is useful for when -/// you wish to trigger any side effects that would occur when evaluating -/// the iterator. -/// -pub fn run(iterator: Iterator(e)) -> Nil { - fold(iterator, Nil, fn(_, _) { Nil }) -} - -/// Evaluates an iterator and returns all the elements as a list. -/// -/// If called on an iterator of infinite length then this function will never -/// return. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3] -/// > |> from_list -/// > |> map(fn(x) { x * 2 }) -/// > |> to_list -/// [2, 4, 6] -/// ``` -/// -pub fn to_list(iterator: Iterator(element)) -> List(element) { - iterator - |> fold([], fn(acc, e) { [e, ..acc] }) - |> list.reverse -} - -/// Eagerly accesses the first value of an iterator, returning a `Next` -/// that contains the first value and the rest of the iterator. -/// -/// If called on an empty iterator, `Done` is returned. -/// -/// ## Examples -/// -/// ```gleam -/// > let assert Next(first, rest) = [1, 2, 3, 4] -/// > |> from_list -/// > |> step -/// > first -/// 1 -/// ``` -/// -/// ```gleam -/// > rest |> to_list -/// [2, 3, 4] -/// ``` -/// -/// ```gleam -/// > empty() |> step -/// Done -/// ``` -/// -pub fn step(iterator: Iterator(e)) -> Step(e, Iterator(e)) { - case iterator.continuation() { - Stop -> Done - Continue(e, a) -> Next(e, Iterator(a)) - } -} - -fn do_take(continuation: fn() -> Action(e), desired: Int) -> fn() -> Action(e) { - fn() { - case desired > 0 { - False -> Stop - True -> - case continuation() { - Stop -> Stop - Continue(e, next) -> Continue(e, do_take(next, desired - 1)) - } - } - } -} - -/// Creates an iterator that only yields the first `desired` elements. -/// -/// If the iterator does not have enough elements all of them are yielded. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3, 4, 5] -/// > |> from_list -/// > |> take(up_to: 3) -/// > |> to_list -/// [1, 2, 3] -/// ``` -/// -/// ```gleam -/// > [1, 2] -/// > |> from_list -/// > |> take(up_to: 3) -/// > |> to_list -/// [1, 2] -/// ``` -/// -pub fn take(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) { - iterator.continuation - |> do_take(desired) - |> Iterator -} - -fn do_drop(continuation: fn() -> Action(e), desired: Int) -> Action(e) { - case continuation() { - Stop -> Stop - Continue(e, next) -> - case desired > 0 { - True -> do_drop(next, desired - 1) - False -> Continue(e, next) - } - } -} - -/// Evaluates and discards the first N elements in an iterator, returning a new -/// iterator. -/// -/// If the iterator does not have enough elements an empty iterator is -/// returned. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3, 4, 5] -/// > |> from_list -/// > |> drop(up_to: 3) -/// > |> to_list -/// [4, 5] -/// ``` -/// -/// ```gleam -/// > [1, 2] -/// > |> from_list -/// > |> drop(up_to: 3) -/// > |> to_list -/// [] -/// ``` -/// -pub fn drop(from iterator: Iterator(e), up_to desired: Int) -> Iterator(e) { - fn() { do_drop(iterator.continuation, desired) } - |> Iterator -} - -fn do_map(continuation: fn() -> Action(a), f: fn(a) -> b) -> fn() -> Action(b) { - fn() { - case continuation() { - Stop -> Stop - Continue(e, continuation) -> Continue(f(e), do_map(continuation, f)) - } - } -} - -/// Creates an iterator from an existing iterator and a transformation function. -/// -/// Each element in the new iterator will be the result of calling the given -/// function on the elements in the given iterator. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3] -/// > |> from_list -/// > |> map(fn(x) { x * 2 }) -/// > |> to_list -/// [2, 4, 6] -/// ``` -/// -pub fn map(over iterator: Iterator(a), with f: fn(a) -> b) -> Iterator(b) { - iterator.continuation - |> do_map(f) - |> Iterator -} - -fn do_map2( - continuation1: fn() -> Action(a), - continuation2: fn() -> Action(b), - with fun: fn(a, b) -> c, -) -> fn() -> Action(c) { - fn() { - case continuation1() { - Stop -> Stop - Continue(a, next_a) -> - case continuation2() { - Stop -> Stop - Continue(b, next_b) -> - Continue(fun(a, b), do_map2(next_a, next_b, fun)) - } - } - } -} - -/// Combines two interators into a single one using the given function. -/// -/// If an iterator is longer than the other the extra elements are dropped. -/// -/// This function does not evaluate the elements of the two iterators, the -/// computation is performed when the resulting iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// let first = from_list([1, 2, 3]) -/// let second = from_list([4, 5, 6]) -/// map2(first, second, fn(x, y) { x + y }) |> to_list -/// // -> [5, 7, 9] -/// ``` -/// -/// ```gleam -/// let first = from_list([1, 2]) -/// let second = from_list(["a", "b", "c"]) -/// map2(first, second, fn(i, x) { #(i, x) }) |> to_list -/// // -> [#(1, "a"), #(2, "b")] -/// ``` -/// -pub fn map2( - iterator1: Iterator(a), - iterator2: Iterator(b), - with fun: fn(a, b) -> c, -) -> Iterator(c) { - do_map2(iterator1.continuation, iterator2.continuation, fun) - |> Iterator -} - -fn do_append(first: fn() -> Action(a), second: fn() -> Action(a)) -> Action(a) { - case first() { - Continue(e, first) -> Continue(e, fn() { do_append(first, second) }) - Stop -> second() - } -} - -/// Appends two iterators, producing a new iterator. -/// -/// This function does not evaluate the elements of the iterators, the -/// computation is performed when the resulting iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2] -/// > |> from_list -/// > |> append([3, 4] |> from_list) -/// > |> to_list -/// [1, 2, 3, 4] -/// ``` -/// -pub fn append(to first: Iterator(a), suffix second: Iterator(a)) -> Iterator(a) { - fn() { do_append(first.continuation, second.continuation) } - |> Iterator -} - -fn do_flatten(flattened: fn() -> Action(Iterator(a))) -> Action(a) { - case flattened() { - Stop -> Stop - Continue(it, next_iterator) -> - do_append(it.continuation, fn() { do_flatten(next_iterator) }) - } -} - -/// Flattens an iterator of iterators, creating a new iterator. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([[1, 2], [3, 4]]) -/// > |> map(from_list) -/// > |> flatten -/// > |> to_list -/// [1, 2, 3, 4] -/// ``` -/// -pub fn flatten(iterator: Iterator(Iterator(a))) -> Iterator(a) { - fn() { do_flatten(iterator.continuation) } - |> Iterator -} - -/// Joins a list of iterators into a single iterator. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// > [[1, 2], [3, 4]] -/// > |> map(from_list) -/// > |> concat -/// > |> to_list -/// [1, 2, 3, 4] -/// ``` -/// -pub fn concat(iterators: List(Iterator(a))) -> Iterator(a) { - flatten(from_list(iterators)) -} - -/// Creates an iterator from an existing iterator and a transformation function. -/// -/// Each element in the new iterator will be the result of calling the given -/// function on the elements in the given iterator and then flattening the -/// results. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2] -/// > |> from_list -/// > |> flat_map(fn(x) { from_list([x, x + 1]) }) -/// > |> to_list -/// [1, 2, 2, 3] -/// ``` -/// -pub fn flat_map( - over iterator: Iterator(a), - with f: fn(a) -> Iterator(b), -) -> Iterator(b) { - iterator - |> map(f) - |> flatten -} - -fn do_filter( - continuation: fn() -> Action(e), - predicate: fn(e) -> Bool, -) -> Action(e) { - case continuation() { - Stop -> Stop - Continue(e, iterator) -> - case predicate(e) { - True -> Continue(e, fn() { do_filter(iterator, predicate) }) - False -> do_filter(iterator, predicate) - } - } -} - -/// Creates an iterator from an existing iterator and a predicate function. -/// -/// The new iterator will contain elements from the first iterator for which -/// the given function returns `True`. -/// -/// This function does not evaluate the elements of the iterator, the -/// computation is performed when the iterator is later run. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/int -/// > [1, 2, 3, 4] -/// > |> from_list -/// > |> filter(int.is_even) -/// > |> to_list -/// [2, 4] -/// ``` -/// -pub fn filter( - iterator: Iterator(a), - keeping predicate: fn(a) -> Bool, -) -> Iterator(a) { - fn() { do_filter(iterator.continuation, predicate) } - |> Iterator -} - -/// Creates an iterator that repeats a given iterator infinitely. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2] -/// > |> from_list -/// > |> cycle -/// > |> take(6) -/// > |> to_list -/// [1, 2, 1, 2, 1, 2] -/// ``` -/// -pub fn cycle(iterator: Iterator(a)) -> Iterator(a) { - repeat(iterator) - |> flatten -} - -/// Creates an iterator of ints, starting at a given start int and stepping by -/// one to a given end int. -/// -/// ## Examples -/// -/// ```gleam -/// > range(from: 1, to: 5) |> to_list -/// [1, 2, 3, 4, 5] -/// ``` -/// -/// ```gleam -/// > range(from: 1, to: -2) |> to_list -/// [1, 0, -1, -2] -/// ``` -/// -/// ```gleam -/// > range(from: 0, to: 0) |> to_list -/// [0] -/// ``` -/// -pub fn range(from start: Int, to stop: Int) -> Iterator(Int) { - case int.compare(start, stop) { - order.Eq -> once(fn() { start }) - order.Gt -> - unfold( - from: start, - with: fn(current) { - case current < stop { - False -> Next(current, current - 1) - True -> Done - } - }, - ) - - order.Lt -> - unfold( - from: start, - with: fn(current) { - case current > stop { - False -> Next(current, current + 1) - True -> Done - } - }, - ) - } -} - -fn do_find(continuation: fn() -> Action(a), f: fn(a) -> Bool) -> Result(a, Nil) { - case continuation() { - Stop -> Error(Nil) - Continue(e, next) -> - case f(e) { - True -> Ok(e) - False -> do_find(next, f) - } - } -} - -/// Finds the first element in a given iterator for which the given function returns -/// `True`. -/// -/// Returns `Error(Nil)` if the function does not return `True` for any of the -/// elements. -/// -/// ## Examples -/// -/// ```gleam -/// > find(from_list([1, 2, 3]), fn(x) { x > 2 }) -/// Ok(3) -/// ``` -/// -/// ```gleam -/// > find(from_list([1, 2, 3]), fn(x) { x > 4 }) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > find(empty(), fn(_) { True }) -/// Error(Nil) -/// ``` -/// -pub fn find( - in haystack: Iterator(a), - one_that is_desired: fn(a) -> Bool, -) -> Result(a, Nil) { - haystack.continuation - |> do_find(is_desired) -} - -fn do_index( - continuation: fn() -> Action(element), - next: Int, -) -> fn() -> Action(#(Int, element)) { - fn() { - case continuation() { - Stop -> Stop - Continue(e, continuation) -> - Continue(#(next, e), do_index(continuation, next + 1)) - } - } -} - -/// Wraps values yielded from an iterator with indices, starting from 0. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list(["a", "b", "c"]) |> index |> to_list -/// [#(0, "a"), #(1, "b"), #(2, "c")] -/// ``` -/// -pub fn index(over iterator: Iterator(element)) -> Iterator(#(Int, element)) { - iterator.continuation - |> do_index(0) - |> Iterator -} - -/// Creates an iterator that inifinitely applies a function to a value. -/// -/// ## Examples -/// -/// ```gleam -/// > iterate(1, fn(n) { n * 3 }) |> take(5) |> to_list -/// [1, 3, 9, 27, 81] -/// ``` -/// -pub fn iterate( - from initial: element, - with f: fn(element) -> element, -) -> Iterator(element) { - unfold(initial, fn(element) { Next(element, f(element)) }) -} - -fn do_take_while( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> fn() -> Action(element) { - fn() { - case continuation() { - Stop -> Stop - Continue(e, next) -> - case predicate(e) { - False -> Stop - True -> Continue(e, do_take_while(next, predicate)) - } - } - } -} - -/// Creates an iterator that yields elements while the predicate returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3, 2, 4]) -/// > |> take_while(satisfying: fn(x) { x < 3 }) -/// > |> to_list -/// [1, 2] -/// ``` -/// -pub fn take_while( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Iterator(element) { - iterator.continuation - |> do_take_while(predicate) - |> Iterator -} - -fn do_drop_while( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> Action(element) { - case continuation() { - Stop -> Stop - Continue(e, next) -> - case predicate(e) { - False -> Continue(e, next) - True -> do_drop_while(next, predicate) - } - } -} - -/// Creates an iterator that drops elements while the predicate returns `True`, -/// and then yields the remaining elements. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3, 4, 2, 5]) -/// > |> drop_while(satisfying: fn(x) { x < 4 }) -/// > |> to_list -/// [4, 2, 5] -/// ``` -/// -pub fn drop_while( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Iterator(element) { - fn() { do_drop_while(iterator.continuation, predicate) } - |> Iterator -} - -fn do_scan( - continuation: fn() -> Action(element), - f: fn(acc, element) -> acc, - accumulator: acc, -) -> fn() -> Action(acc) { - fn() { - case continuation() { - Stop -> Stop - Continue(el, next) -> { - let accumulated = f(accumulator, el) - Continue(accumulated, do_scan(next, f, accumulated)) - } - } - } -} - -/// Creates an iterator from an existing iterator and a stateful function. -/// -/// Specifically, this behaves like `fold`, but yields intermediate results. -/// -/// ## Examples -/// -/// ```gleam -/// // Generate a sequence of partial sums -/// > from_list([1, 2, 3, 4, 5]) -/// > |> scan(from: 0, with: fn(acc, el) { acc + el }) -/// > |> to_list -/// [1, 3, 6, 10, 15] -/// ``` -/// -pub fn scan( - over iterator: Iterator(element), - from initial: acc, - with f: fn(acc, element) -> acc, -) -> Iterator(acc) { - iterator.continuation - |> do_scan(f, initial) - |> Iterator -} - -fn do_zip( - left: fn() -> Action(a), - right: fn() -> Action(b), -) -> fn() -> Action(#(a, b)) { - fn() { - case left() { - Stop -> Stop - Continue(el_left, next_left) -> - case right() { - Stop -> Stop - Continue(el_right, next_right) -> - Continue(#(el_left, el_right), do_zip(next_left, next_right)) - } - } - } -} - -/// Zips two iterators together, emitting values from both -/// until the shorter one runs out. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list(["a", "b", "c"]) -/// > |> zip(range(20, 30)) -/// > |> to_list -/// [#("a", 20), #("b", 21), #("c", 22)] -/// ``` -/// -pub fn zip(left: Iterator(a), right: Iterator(b)) -> Iterator(#(a, b)) { - do_zip(left.continuation, right.continuation) - |> Iterator -} - -// Result of collecting a single chunk by key -type Chunk(element, key) { - AnotherBy(List(element), key, element, fn() -> Action(element)) - LastBy(List(element)) -} - -fn next_chunk( - continuation: fn() -> Action(element), - f: fn(element) -> key, - previous_key: key, - current_chunk: List(element), -) -> Chunk(element, key) { - case continuation() { - Stop -> LastBy(list.reverse(current_chunk)) - Continue(e, next) -> { - let key = f(e) - case key == previous_key { - True -> next_chunk(next, f, key, [e, ..current_chunk]) - False -> AnotherBy(list.reverse(current_chunk), key, e, next) - } - } - } -} - -fn do_chunk( - continuation: fn() -> Action(element), - f: fn(element) -> key, - previous_key: key, - previous_element: element, -) -> Action(List(element)) { - case next_chunk(continuation, f, previous_key, [previous_element]) { - LastBy(chunk) -> Continue(chunk, stop) - AnotherBy(chunk, key, el, next) -> - Continue(chunk, fn() { do_chunk(next, f, key, el) }) - } -} - -/// Creates an iterator that emits chunks of elements -/// for which `f` returns the same value. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 2, 3, 4, 4, 6, 7, 7]) -/// > |> chunk(by: fn(n) { n % 2 }) -/// > |> to_list -/// [[1], [2, 2], [3], [4, 4, 6], [7, 7]] -/// ``` -/// -pub fn chunk( - over iterator: Iterator(element), - by f: fn(element) -> key, -) -> Iterator(List(element)) { - fn() { - case iterator.continuation() { - Stop -> Stop - Continue(e, next) -> do_chunk(next, f, f(e), e) - } - } - |> Iterator -} - -// Result of collecting a single sized chunk -type SizedChunk(element) { - Another(List(element), fn() -> Action(element)) - Last(List(element)) - NoMore -} - -fn next_sized_chunk( - continuation: fn() -> Action(element), - left: Int, - current_chunk: List(element), -) -> SizedChunk(element) { - case continuation() { - Stop -> - case current_chunk { - [] -> NoMore - remaining -> Last(list.reverse(remaining)) - } - Continue(e, next) -> { - let chunk = [e, ..current_chunk] - case left > 1 { - False -> Another(list.reverse(chunk), next) - True -> next_sized_chunk(next, left - 1, chunk) - } - } - } -} - -fn do_sized_chunk( - continuation: fn() -> Action(element), - count: Int, -) -> fn() -> Action(List(element)) { - fn() { - case next_sized_chunk(continuation, count, []) { - NoMore -> Stop - Last(chunk) -> Continue(chunk, stop) - Another(chunk, next_element) -> - Continue(chunk, do_sized_chunk(next_element, count)) - } - } -} - -/// Creates an iterator that emits chunks of given size. -/// -/// If the last chunk does not have `count` elements, it is yielded -/// as a partial chunk, with less than `count` elements. -/// -/// For any `count` less than 1 this function behaves as if it was set to 1. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3, 4, 5, 6]) -/// > |> sized_chunk(into: 2) -/// > |> to_list -/// [[1, 2], [3, 4], [5, 6]] -/// ``` -/// -/// ```gleam -/// > from_list([1, 2, 3, 4, 5, 6, 7, 8]) -/// > |> sized_chunk(into: 3) -/// > |> to_list -/// [[1, 2, 3], [4, 5, 6], [7, 8]] -/// ``` -/// -pub fn sized_chunk( - over iterator: Iterator(element), - into count: Int, -) -> Iterator(List(element)) { - iterator.continuation - |> do_sized_chunk(count) - |> Iterator -} - -fn do_intersperse( - continuation: fn() -> Action(element), - separator: element, -) -> Action(element) { - case continuation() { - Stop -> Stop - Continue(e, next) -> { - let next_interspersed = fn() { do_intersperse(next, separator) } - Continue(separator, fn() { Continue(e, next_interspersed) }) - } - } -} - -/// Creates an iterator that yields the given `elem` element -/// between elements emitted by the underlying iterator. -/// -/// ## Examples -/// -/// ```gleam -/// > empty() -/// > |> intersperse(with: 0) -/// > |> to_list -/// [] -/// -/// > from_list([1]) -/// > |> intersperse(with: 0) -/// > |> to_list -/// [1] -/// -/// > from_list([1, 2, 3, 4, 5]) -/// > |> intersperse(with: 0) -/// > |> to_list -/// [1, 0, 2, 0, 3, 0, 4, 0, 5] -/// ``` -/// -pub fn intersperse( - over iterator: Iterator(element), - with elem: element, -) -> Iterator(element) { - fn() { - case iterator.continuation() { - Stop -> Stop - Continue(e, next) -> Continue(e, fn() { do_intersperse(next, elem) }) - } - } - |> Iterator -} - -fn do_any( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> Bool { - case continuation() { - Stop -> False - Continue(e, next) -> - case predicate(e) { - True -> True - False -> do_any(next, predicate) - } - } -} - -/// Returns `True` if any element emitted by the iterator satisfies the given predicate, -/// `False` otherwise. -/// -/// This function short-circuits once it finds a satisfying element. -/// -/// An empty iterator results in `False`. -/// -/// ## Examples -/// -/// ```gleam -/// > empty() |> any(fn(n) { n % 2 == 0 }) -/// False -/// ``` -/// -/// ```gleam -/// > from_list([1, 2, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 }) -/// True -/// ``` -/// -/// ```gleam -/// > from_list([1, 3, 5, 7, 9]) |> any(fn(n) { n % 2 == 0 }) -/// False -/// ``` -/// -pub fn any( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Bool { - iterator.continuation - |> do_any(predicate) -} - -fn do_all( - continuation: fn() -> Action(element), - predicate: fn(element) -> Bool, -) -> Bool { - case continuation() { - Stop -> True - Continue(e, next) -> - case predicate(e) { - True -> do_all(next, predicate) - False -> False - } - } -} - -/// Returns `True` if all elements emitted by the iterator satisfy the given predicate, -/// `False` otherwise. -/// -/// This function short-circuits once it finds a non-satisfying element. -/// -/// An empty iterator results in `True`. -/// -/// ## Examples -/// -/// ```gleam -/// > empty() |> all(fn(n) { n % 2 == 0 }) -/// True -/// ``` -/// -/// ```gleam -/// > from_list([2, 4, 6, 8]) |> all(fn(n) { n % 2 == 0 }) -/// True -/// ``` -/// -/// ```gleam -/// > from_list([2, 4, 5, 8]) |> all(fn(n) { n % 2 == 0 }) -/// False -/// ``` -/// -pub fn all( - in iterator: Iterator(element), - satisfying predicate: fn(element) -> Bool, -) -> Bool { - iterator.continuation - |> do_all(predicate) -} - -fn update_group_with(el: element) -> fn(Option(List(element))) -> List(element) { - fn(maybe_group) { - case maybe_group { - Some(group) -> [el, ..group] - None -> [el] - } - } -} - -fn group_updater( - f: fn(element) -> key, -) -> fn(Dict(key, List(element)), element) -> Dict(key, List(element)) { - fn(groups, elem) { - groups - |> dict.update(f(elem), update_group_with(elem)) - } -} - -/// Returns a `Dict(k, List(element))` of elements from the given iterator -/// grouped with the given key function. -/// -/// The order within each group is preserved from the iterator. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3, 4, 5, 6]) |> group(by: fn(n) { n % 3 }) -/// dict.from_list([#(0, [3, 6]), #(1, [1, 4]), #(2, [2, 5])]) -/// ``` -/// -pub fn group( - in iterator: Iterator(element), - by key: fn(element) -> key, -) -> Dict(key, List(element)) { - iterator - |> fold(dict.new(), group_updater(key)) - |> dict.map_values(fn(_, group) { list.reverse(group) }) -} - -/// This function acts similar to fold, but does not take an initial state. -/// Instead, it starts from the first yielded element -/// and combines it with each subsequent element in turn using the given function. -/// The function is called as `f(accumulator, current_element)`. -/// -/// Returns `Ok` to indicate a successful run, and `Error` if called on an empty iterator. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([]) |> reduce(fn(acc, x) { acc + x }) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > from_list([1, 2, 3, 4, 5]) |> reduce(fn(acc, x) { acc + x }) -/// Ok(15) -/// ``` -/// -pub fn reduce( - over iterator: Iterator(e), - with f: fn(e, e) -> e, -) -> Result(e, Nil) { - case iterator.continuation() { - Stop -> Error(Nil) - Continue(e, next) -> - do_fold(next, f, e) - |> Ok - } -} - -/// Returns the last element in the given iterator. -/// -/// Returns `Error(Nil)` if the iterator is empty. -/// -/// This function runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// > empty() |> last -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > range(1, 10) |> last -/// Ok(9) -/// ``` -/// -pub fn last(iterator: Iterator(element)) -> Result(element, Nil) { - iterator - |> reduce(fn(_, elem) { elem }) -} - -/// Creates an iterator that yields no elements. -/// -/// ## Examples -/// -/// ```gleam -/// > empty() |> to_list -/// [] -/// ``` -/// -pub fn empty() -> Iterator(element) { - Iterator(stop) -} - -/// Creates an iterator that yields exactly one element provided by calling the given function. -/// -/// ## Examples -/// -/// ```gleam -/// > once(fn() { 1 }) |> to_list -/// [1] -/// ``` -/// -pub fn once(f: fn() -> element) -> Iterator(element) { - fn() { Continue(f(), stop) } - |> Iterator -} - -/// Creates an iterator that yields the given element exactly once. -/// -/// ## Examples -/// -/// ```gleam -/// > single(1) |> to_list -/// [1] -/// ``` -/// -pub fn single(elem: element) -> Iterator(element) { - once(fn() { elem }) -} - -fn do_interleave( - current: fn() -> Action(element), - next: fn() -> Action(element), -) -> Action(element) { - case current() { - Stop -> next() - Continue(e, next_other) -> - Continue(e, fn() { do_interleave(next, next_other) }) - } -} - -/// Creates an iterator that alternates between the two given iterators -/// until both have run out. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3, 4]) |> interleave(from_list([11, 12, 13, 14])) |> to_list -/// [1, 11, 2, 12, 3, 13, 4, 14] -/// ``` -/// -/// ```gleam -/// > from_list([1, 2, 3, 4]) |> interleave(from_list([100])) |> to_list -/// [1, 100, 2, 3, 4] -/// ``` -/// -pub fn interleave( - left: Iterator(element), - with right: Iterator(element), -) -> Iterator(element) { - fn() { do_interleave(left.continuation, right.continuation) } - |> Iterator -} - -fn do_fold_until( - continuation: fn() -> Action(e), - f: fn(acc, e) -> list.ContinueOrStop(acc), - accumulator: acc, -) -> acc { - case continuation() { - Stop -> accumulator - Continue(elem, next) -> - case f(accumulator, elem) { - list.Continue(accumulator) -> do_fold_until(next, f, accumulator) - list.Stop(accumulator) -> accumulator - } - } -} - -/// Like `fold`, `fold_until` reduces an iterator of elements into a single value by calling a given -/// function on each element in turn, but uses `list.ContinueOrStop` to determine -/// whether or not to keep iterating. -/// -/// If called on an iterator of infinite length then this function will only ever -/// return if the function returns `list.Stop`. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/list -/// > let f = fn(acc, e) { -/// > case e { -/// > _ if e < 4 -> list.Continue(e + acc) -/// > _ -> list.Stop(acc) -/// > } -/// > } -/// > -/// > [1, 2, 3, 4] -/// > |> from_list -/// > |> fold_until(from: acc, with: f) -/// 6 -/// ``` -/// -pub fn fold_until( - over iterator: Iterator(e), - from initial: acc, - with f: fn(acc, e) -> list.ContinueOrStop(acc), -) -> acc { - iterator.continuation - |> do_fold_until(f, initial) -} - -fn do_try_fold( - over continuation: fn() -> Action(a), - with f: fn(acc, a) -> Result(acc, err), - from accumulator: acc, -) -> Result(acc, err) { - case continuation() { - Stop -> Ok(accumulator) - Continue(elem, next) -> { - use accumulator <- result.try(f(accumulator, elem)) - do_try_fold(next, f, accumulator) - } - } -} - -/// A variant of fold that might fail. -/// -/// The folding function should return `Result(accumulator, error)`. -/// If the returned value is `Ok(accumulator)` try_fold will try the next value in the iterator. -/// If the returned value is `Error(error)` try_fold will stop and return that error. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3, 4] -/// > |> iterator.from_list() -/// > |> try_fold(0, fn(acc, i) { -/// > case i < 3 { -/// > True -> Ok(acc + i) -/// > False -> Error(Nil) -/// > } -/// > }) -/// Error(Nil) -/// ``` -/// -pub fn try_fold( - over iterator: Iterator(e), - from initial: acc, - with f: fn(acc, e) -> Result(acc, err), -) -> Result(acc, err) { - iterator.continuation - |> do_try_fold(f, initial) -} - -/// Returns the first element yielded by the given iterator, if it exists, -/// or `Error(Nil)` otherwise. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3]) |> first -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > empty() |> first -/// Error(Nil) -/// ``` -pub fn first(from iterator: Iterator(e)) -> Result(e, Nil) { - case iterator.continuation() { - Stop -> Error(Nil) - Continue(e, _) -> Ok(e) - } -} - -/// Returns nth element yielded by the given iterator, where `0` means the first element. -/// -/// If there are not enough elements in the iterator, `Error(Nil)` is returned. -/// -/// For any `index` less than `0` this function behaves as if it was set to `0`. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3, 4]) |> at(2) -/// Ok(3) -/// ``` -/// -/// ```gleam -/// > from_list([1, 2, 3, 4]) |> at(4) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > empty() |> at(0) -/// Error(Nil) -/// ``` -/// -pub fn at(in iterator: Iterator(e), get index: Int) -> Result(e, Nil) { - iterator - |> drop(index) - |> first -} - -fn do_length(over continuation: fn() -> Action(e), with length: Int) -> Int { - case continuation() { - Stop -> length - Continue(_, next) -> do_length(next, length + 1) - } -} - -/// Counts the number of elements in the given iterator. -/// -/// This function has to traverse the entire iterator to count its elements, -/// so it runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// > empty() |> length -/// 0 -/// ``` -/// -/// ```gleam -/// > from_list([1, 2, 3, 4]) |> length -/// 4 -/// ``` -/// -pub fn length(over iterator: Iterator(e)) -> Int { - iterator.continuation - |> do_length(0) -} - -/// Traverse an iterator, calling a function on each element. -/// -/// ## Examples -/// -/// ```gleam -/// > empty() |> each(io.println) -/// Nil -/// ``` -/// -/// ```gleam -/// > from_list(["Tom", "Malory", "Louis"]) |> each(io.println) -/// // -> Tom -/// // -> Malory -/// // -> Louis -/// Nil -/// ``` -/// -pub fn each(over iterator: Iterator(a), with f: fn(a) -> b) -> Nil { - iterator - |> map(f) - |> run -} - -/// Add a new element to the start of an iterator. -/// -/// This function is for use with `use` expressions, to replicate the behaviour -/// of the `yield` keyword found in other languages. -/// -/// ## Examples -/// -/// ```gleam -/// > use <- iterator.yield(1) -/// > use <- iterator.yield(2) -/// > use <- iterator.yield(3) -/// > iterator.empty() -/// iterator.from_list([1, 2, 3]) -/// ``` -/// -pub fn yield(element: a, next: fn() -> Iterator(a)) -> Iterator(a) { - Iterator(fn() { Continue(element, next().continuation) }) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/list.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/list.gleam deleted file mode 100644 index a5cffa9..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/list.gleam +++ /dev/null @@ -1,2154 +0,0 @@ -//// Lists are an ordered sequence of elements and are one of the most common -//// data types in Gleam. -//// -//// New elements can be added and removed from the front of a list in -//// constant time, while adding and removing from the end requires traversing -//// the copying the whole list, so keep this in mind when designing your -//// programs. -//// -//// There is a dedicated syntax for prefixing to a list: -//// -//// ```gleam -//// let new_list = [1, 2, ..existing_list] -//// ``` -//// -//// And a matching syntax for getting the first elements of a list: -//// -//// ```gleam -//// case list { -//// [first_element, ..rest] -> first_element -//// _ -> "this pattern matches when the list is empty" -//// } -//// ``` -//// - -import gleam/int -import gleam/float -import gleam/order.{type Order} -import gleam/pair -import gleam/dict.{type Dict} - -/// An error value returned by the `strict_zip` function. -/// -pub type LengthMismatch { - LengthMismatch -} - -/// Counts the number of elements in a given list. -/// -/// This function has to traverse the list to determine the number of elements, -/// so it runs in linear time. -/// -/// This function is natively implemented by the virtual machine and is highly -/// optimised. -/// -/// ## Examples -/// -/// ```gleam -/// > length([]) -/// 0 -/// ``` -/// -/// ```gleam -/// > length([1]) -/// 1 -/// ``` -/// -/// ```gleam -/// > length([1, 2]) -/// 2 -/// ``` -/// -pub fn length(of list: List(a)) -> Int { - do_length(list) -} - -@target(erlang) -@external(erlang, "erlang", "length") -fn do_length(a: List(a)) -> Int - -@target(javascript) -fn do_length(list: List(a)) -> Int { - do_length_acc(list, 0) -} - -@target(javascript) -fn do_length_acc(list: List(a), count: Int) -> Int { - case list { - [_, ..list] -> do_length_acc(list, count + 1) - _ -> count - } -} - -/// Creates a new list from a given list containing the same elements but in the -/// opposite order. -/// -/// This function has to traverse the list to create the new reversed list, so -/// it runs in linear time. -/// -/// This function is natively implemented by the virtual machine and is highly -/// optimised. -/// -/// ## Examples -/// -/// ```gleam -/// > reverse([]) -/// [] -/// ``` -/// -/// ```gleam -/// > reverse([1]) -/// [1] -/// ``` -/// -/// ```gleam -/// > reverse([1, 2]) -/// [2, 1] -/// ``` -/// -pub fn reverse(xs: List(a)) -> List(a) { - do_reverse(xs) -} - -@target(erlang) -@external(erlang, "lists", "reverse") -fn do_reverse(a: List(a)) -> List(a) - -@target(javascript) -fn do_reverse(list) { - do_reverse_acc(list, []) -} - -@target(javascript) -fn do_reverse_acc(remaining, accumulator) { - case remaining { - [] -> accumulator - [item, ..rest] -> do_reverse_acc(rest, [item, ..accumulator]) - } -} - -/// Determines whether or not the list is empty. -/// -/// This function runs in constant time. -/// -/// ## Examples -/// -/// ```gleam -/// > is_empty([]) -/// True -/// ``` -/// -/// ```gleam -/// > is_empty([1]) -/// False -/// ``` -/// -/// ```gleam -/// > is_empty([1, 1]) -/// False -/// ``` -/// -pub fn is_empty(list: List(a)) -> Bool { - list == [] -} - -/// Determines whether or not a given element exists within a given list. -/// -/// This function traverses the list to find the element, so it runs in linear -/// time. -/// -/// ## Examples -/// -/// ```gleam -/// > [] |> contains(any: 0) -/// False -/// ``` -/// -/// ```gleam -/// > [0] |> contains(any: 0) -/// True -/// ``` -/// -/// ```gleam -/// > [1] |> contains(any: 0) -/// False -/// ``` -/// -/// ```gleam -/// > [1, 1] |> contains(any: 0) -/// False -/// ``` -/// -/// ```gleam -/// > [1, 0] |> contains(any: 0) -/// True -/// ``` -/// -pub fn contains(list: List(a), any elem: a) -> Bool { - case list { - [] -> False - [first, ..] if first == elem -> True - [_, ..rest] -> contains(rest, elem) - } -} - -/// Gets the first element from the start of the list, if there is one. -/// -/// ## Examples -/// -/// ```gleam -/// > first([]) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > first([0]) -/// Ok(0) -/// ``` -/// -/// ```gleam -/// > first([1, 2]) -/// Ok(1) -/// ``` -/// -pub fn first(list: List(a)) -> Result(a, Nil) { - case list { - [] -> Error(Nil) - [x, ..] -> Ok(x) - } -} - -/// Returns the list minus the first element. If the list is empty, `Error(Nil)` is -/// returned. -/// -/// This function runs in constant time and does not make a copy of the list. -/// -/// ## Examples -/// -/// ```gleam -/// > rest([]) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > rest([0]) -/// Ok([]) -/// ``` -/// -/// ```gleam -/// > rest([1, 2]) -/// Ok([2]) -/// ``` -/// -pub fn rest(list: List(a)) -> Result(List(a), Nil) { - case list { - [] -> Error(Nil) - [_, ..xs] -> Ok(xs) - } -} - -fn update_group( - f: fn(element) -> key, -) -> fn(Dict(key, List(element)), element) -> Dict(key, List(element)) { - fn(groups, elem) { - case dict.get(groups, f(elem)) { - Ok(existing) -> dict.insert(groups, f(elem), [elem, ..existing]) - Error(_) -> dict.insert(groups, f(elem), [elem]) - } - } -} - -/// Takes a list and groups the values by a key -/// which is built from a key function. -/// -/// Does not preserve the initial value order. -/// -/// ## Examples -/// -/// ```gleam -/// > [Ok(3), Error("Wrong"), Ok(200), Ok(73)] -/// |> group(by: fn(i) { -/// case i { -/// Ok(_) -> "Successful" -/// Error(_) -> "Failed" -/// } -/// }) -/// |> dict.to_list -/// -/// [ -/// #("Failed", [Error("Wrong")]), -/// #("Successful", [Ok(73), Ok(200), Ok(3)]) -/// ] -/// -/// > group([1,2,3,4,5], by: fn(i) { i - i / 3 * 3 }) -/// |> dict.to_list -/// [#(0, [3]), #(1, [4, 1]), #(2, [5, 2])] -/// ``` -/// -pub fn group(list: List(v), by key: fn(v) -> k) -> Dict(k, List(v)) { - fold(list, dict.new(), update_group(key)) -} - -fn do_filter(list: List(a), fun: fn(a) -> Bool, acc: List(a)) -> List(a) { - case list { - [] -> reverse(acc) - [x, ..xs] -> { - let new_acc = case fun(x) { - True -> [x, ..acc] - False -> acc - } - do_filter(xs, fun, new_acc) - } - } -} - -/// Returns a new list containing only the elements from the first list for -/// which the given functions returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// > filter([2, 4, 6, 1], fn(x) { x > 2 }) -/// [4, 6] -/// ``` -/// -/// ```gleam -/// > filter([2, 4, 6, 1], fn(x) { x > 6 }) -/// [] -/// ``` -/// -pub fn filter(list: List(a), keeping predicate: fn(a) -> Bool) -> List(a) { - do_filter(list, predicate, []) -} - -fn do_filter_map( - list: List(a), - fun: fn(a) -> Result(b, e), - acc: List(b), -) -> List(b) { - case list { - [] -> reverse(acc) - [x, ..xs] -> { - let new_acc = case fun(x) { - Ok(x) -> [x, ..acc] - Error(_) -> acc - } - do_filter_map(xs, fun, new_acc) - } - } -} - -/// Returns a new list containing only the elements from the first list for -/// which the given functions returns `Ok(_)`. -/// -/// ## Examples -/// -/// ```gleam -/// > filter_map([2, 4, 6, 1], Error) -/// [] -/// ``` -/// -/// ```gleam -/// > filter_map([2, 4, 6, 1], fn(x) { Ok(x + 1) }) -/// [3, 5, 7, 2] -/// ``` -/// -pub fn filter_map(list: List(a), with fun: fn(a) -> Result(b, e)) -> List(b) { - do_filter_map(list, fun, []) -} - -fn do_map(list: List(a), fun: fn(a) -> b, acc: List(b)) -> List(b) { - case list { - [] -> reverse(acc) - [x, ..xs] -> do_map(xs, fun, [fun(x), ..acc]) - } -} - -/// Returns a new list containing only the elements of the first list after the -/// function has been applied to each one. -/// -/// ## Examples -/// -/// ```gleam -/// > map([2, 4, 6], fn(x) { x * 2 }) -/// [4, 8, 12] -/// ``` -/// -pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { - do_map(list, fun, []) -} - -/// Combines two lists into a single list using the given function. -/// -/// If a list is longer than the other the extra elements are dropped. -/// -/// ## Examples -/// -/// ```gleam -/// > map2([1, 2, 3], [4, 5, 6], fn(x, y) { x + y }) -/// [5, 7, 9] -/// ``` -/// -/// ```gleam -/// > map2([1, 2], ["a", "b", "c"], fn(i, x) { #(i, x) }) -/// [#(1, "a"), #(2, "b")] -/// ``` -/// -pub fn map2(list1: List(a), list2: List(b), with fun: fn(a, b) -> c) -> List(c) { - do_map2(list1, list2, fun, []) -} - -fn do_map2( - list1: List(a), - list2: List(b), - fun: fn(a, b) -> c, - acc: List(c), -) -> List(c) { - case list1, list2 { - [], _ | _, [] -> reverse(acc) - [a, ..as_], [b, ..bs] -> do_map2(as_, bs, fun, [fun(a, b), ..acc]) - } -} - -/// Similar to `map` but also lets you pass around an accumulated value. -/// -/// ## Examples -/// -/// ```gleam -/// > map_fold( -/// over: [1, 2, 3], -/// from: 100, -/// with: fn(memo, i) { #(memo + i, i * 2) } -/// ) -/// #(106, [2, 4, 6]) -/// ``` -/// -pub fn map_fold( - over list: List(a), - from acc: acc, - with fun: fn(acc, a) -> #(acc, b), -) -> #(acc, List(b)) { - fold( - over: list, - from: #(acc, []), - with: fn(acc, item) { - let #(current_acc, items) = acc - let #(next_acc, next_item) = fun(current_acc, item) - #(next_acc, [next_item, ..items]) - }, - ) - |> pair.map_second(reverse) -} - -fn do_index_map( - list: List(a), - fun: fn(Int, a) -> b, - index: Int, - acc: List(b), -) -> List(b) { - case list { - [] -> reverse(acc) - [x, ..xs] -> { - let acc = [fun(index, x), ..acc] - do_index_map(xs, fun, index + 1, acc) - } - } -} - -/// Returns a new list containing only the elements of the first list after the -/// function has been applied to each one and their index. -/// -/// The index starts at 0, so the first element is 0, the second is 1, and so -/// on. -/// -/// ## Examples -/// -/// ```gleam -/// > index_map(["a", "b"], fn(i, x) { #(i, x) }) -/// [#(0, "a"), #(1, "b")] -/// ``` -/// -pub fn index_map(list: List(a), with fun: fn(Int, a) -> b) -> List(b) { - do_index_map(list, fun, 0, []) -} - -fn do_try_map( - list: List(a), - fun: fn(a) -> Result(b, e), - acc: List(b), -) -> Result(List(b), e) { - case list { - [] -> Ok(reverse(acc)) - [x, ..xs] -> - case fun(x) { - Ok(y) -> do_try_map(xs, fun, [y, ..acc]) - Error(error) -> Error(error) - } - } -} - -/// Takes a function that returns a `Result` and applies it to each element in a -/// given list in turn. -/// -/// If the function returns `Ok(new_value)` for all elements in the list then a -/// list of the new values is returned. -/// -/// If the function returns `Error(reason)` for any of the elements then it is -/// returned immediately. None of the elements in the list are processed after -/// one returns an `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// > try_map([1, 2, 3], fn(x) { Ok(x + 2) }) -/// Ok([3, 4, 5]) -/// ``` -/// -/// ```gleam -/// > try_map([1, 2, 3], fn(_) { Error(0) }) -/// Error(0) -/// ``` -/// -/// ```gleam -/// > try_map([[1], [2, 3]], first) -/// Ok([1, 2]) -/// ``` -/// -/// ```gleam -/// > try_map([[1], [], [2]], first) -/// Error(Nil) -/// ``` -/// -pub fn try_map( - over list: List(a), - with fun: fn(a) -> Result(b, e), -) -> Result(List(b), e) { - do_try_map(list, fun, []) -} - -/// Returns a list that is the given list with up to the given number of -/// elements removed from the front of the list. -/// -/// If the element has less than the number of elements an empty list is -/// returned. -/// -/// This function runs in linear time but does not copy the list. -/// -/// ## Examples -/// -/// ```gleam -/// > drop([1, 2, 3, 4], 2) -/// [3, 4] -/// ``` -/// -/// ```gleam -/// > drop([1, 2, 3, 4], 9) -/// [] -/// ``` -/// -pub fn drop(from list: List(a), up_to n: Int) -> List(a) { - case n <= 0 { - True -> list - False -> - case list { - [] -> [] - [_, ..xs] -> drop(xs, n - 1) - } - } -} - -fn do_take(list: List(a), n: Int, acc: List(a)) -> List(a) { - case n <= 0 { - True -> reverse(acc) - False -> - case list { - [] -> reverse(acc) - [x, ..xs] -> do_take(xs, n - 1, [x, ..acc]) - } - } -} - -/// Returns a list containing the first given number of elements from the given -/// list. -/// -/// If the element has less than the number of elements then the full list is -/// returned. -/// -/// This function runs in linear time but does not copy the list. -/// -/// ## Examples -/// -/// ```gleam -/// > take([1, 2, 3, 4], 2) -/// [1, 2] -/// ``` -/// -/// ```gleam -/// > take([1, 2, 3, 4], 9) -/// [1, 2, 3, 4] -/// ``` -/// -pub fn take(from list: List(a), up_to n: Int) -> List(a) { - do_take(list, n, []) -} - -/// Returns a new empty list. -/// -/// ## Examples -/// -/// ```gleam -/// > new() -/// [] -/// ``` -/// -pub fn new() -> List(a) { - [] -} - -/// Joins one list onto the end of another. -/// -/// This function runs in linear time, and it traverses and copies the first -/// list. -/// -/// ## Examples -/// -/// ```gleam -/// > append([1, 2], [3]) -/// [1, 2, 3] -/// ``` -/// -pub fn append(first: List(a), second: List(a)) -> List(a) { - do_append(first, second) -} - -@target(erlang) -@external(erlang, "lists", "append") -fn do_append(a: List(a), b: List(a)) -> List(a) - -@target(javascript) -fn do_append(first: List(a), second: List(a)) -> List(a) { - do_append_acc(reverse(first), second) -} - -@target(javascript) -fn do_append_acc(first: List(a), second: List(a)) -> List(a) { - case first { - [] -> second - [item, ..rest] -> do_append_acc(rest, [item, ..second]) - } -} - -/// Prefixes an item to a list. This can also be done using the dedicated -/// syntax instead -/// -/// ```gleam -/// let new_list = [1, ..existing_list] -/// ``` -/// -pub fn prepend(to list: List(a), this item: a) -> List(a) { - [item, ..list] -} - -// Reverses a list and prepends it to another list -fn reverse_and_prepend(list prefix: List(a), to suffix: List(a)) -> List(a) { - case prefix { - [] -> suffix - [first, ..rest] -> reverse_and_prepend(list: rest, to: [first, ..suffix]) - } -} - -fn do_concat(lists: List(List(a)), acc: List(a)) -> List(a) { - case lists { - [] -> reverse(acc) - [list, ..further_lists] -> - do_concat(further_lists, reverse_and_prepend(list: list, to: acc)) - } -} - -/// Joins a list of lists into a single list. -/// -/// This function traverses all elements twice. -/// -/// ## Examples -/// -/// ```gleam -/// > concat([[1], [2, 3], []]) -/// [1, 2, 3] -/// ``` -/// -pub fn concat(lists: List(List(a))) -> List(a) { - do_concat(lists, []) -} - -/// This is the same as `concat`: it joins a list of lists into a single -/// list. -/// -/// This function traverses all elements twice. -/// -/// ## Examples -/// -/// ```gleam -/// > flatten([[1], [2, 3], []]) -/// [1, 2, 3] -/// ``` -/// -pub fn flatten(lists: List(List(a))) -> List(a) { - do_concat(lists, []) -} - -/// Maps the list with the given function into a list of lists, and then flattens it. -/// -/// ## Examples -/// -/// ```gleam -/// > flat_map([2, 4, 6], fn(x) { [x, x + 1] }) -/// [2, 3, 4, 5, 6, 7] -/// ``` -/// -pub fn flat_map(over list: List(a), with fun: fn(a) -> List(b)) -> List(b) { - map(list, fun) - |> concat -} - -/// Reduces a list of elements into a single value by calling a given function -/// on each element, going from left to right. -/// -/// `fold([1, 2, 3], 0, add)` is the equivalent of -/// `add(add(add(0, 1), 2), 3)`. -/// -/// This function runs in linear time. -/// -pub fn fold( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> acc, -) -> acc { - case list { - [] -> initial - [x, ..rest] -> fold(rest, fun(initial, x), fun) - } -} - -/// Reduces a list of elements into a single value by calling a given function -/// on each element, going from right to left. -/// -/// `fold_right([1, 2, 3], 0, add)` is the equivalent of -/// `add(add(add(0, 3), 2), 1)`. -/// -/// This function runs in linear time. -/// -/// Unlike `fold` this function is not tail recursive. Where possible use -/// `fold` instead as it will use less memory. -/// -pub fn fold_right( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> acc, -) -> acc { - case list { - [] -> initial - [x, ..rest] -> fun(fold_right(rest, initial, fun), x) - } -} - -fn do_index_fold( - over: List(a), - acc: acc, - with: fn(acc, a, Int) -> acc, - index: Int, -) -> acc { - case over { - [] -> acc - [first, ..rest] -> - do_index_fold(rest, with(acc, first, index), with, index + 1) - } -} - -/// Like fold but the folding function also receives the index of the current element. -/// -/// ## Examples -/// -/// ```gleam -/// ["a", "b", "c"] -/// |> index_fold([], fn(acc, item, index) { ... }) -/// ``` -/// -pub fn index_fold( - over over: List(a), - from initial: acc, - with fun: fn(acc, a, Int) -> acc, -) -> acc { - do_index_fold(over, initial, fun, 0) -} - -/// A variant of fold that might fail. -/// -/// The folding function should return `Result(accumulator, error)`. -/// If the returned value is `Ok(accumulator)` try_fold will try the next value in the list. -/// If the returned value is `Error(error)` try_fold will stop and return that error. -/// -/// ## Examples -/// -/// ```gleam -/// [1, 2, 3, 4] -/// |> try_fold(0, fn(acc, i) { -/// case i < 3 { -/// True -> Ok(acc + i) -/// False -> Error(Nil) -/// } -/// }) -/// ``` -/// -pub fn try_fold( - over collection: List(a), - from accumulator: acc, - with fun: fn(acc, a) -> Result(acc, e), -) -> Result(acc, e) { - case collection { - [] -> Ok(accumulator) - [first, ..rest] -> - case fun(accumulator, first) { - Ok(result) -> try_fold(rest, result, fun) - Error(_) as error -> error - } - } -} - -pub type ContinueOrStop(a) { - Continue(a) - Stop(a) -} - -/// A variant of fold that allows to stop folding earlier. -/// -/// The folding function should return `ContinueOrStop(accumulator)`. -/// If the returned value is `Continue(accumulator)` fold_until will try the next value in the list. -/// If the returned value is `Stop(accumulator)` fold_until will stop and return that accumulator. -/// -/// ## Examples -/// -/// ```gleam -/// [1, 2, 3, 4] -/// |> fold_until(0, fn(acc, i) { -/// case i < 3 { -/// True -> Continue(acc + i) -/// False -> Stop(acc) -/// } -/// }) -/// ``` -/// -pub fn fold_until( - over collection: List(a), - from accumulator: acc, - with fun: fn(acc, a) -> ContinueOrStop(acc), -) -> acc { - case collection { - [] -> accumulator - [first, ..rest] -> - case fun(accumulator, first) { - Continue(next_accumulator) -> fold_until(rest, next_accumulator, fun) - Stop(b) -> b - } - } -} - -/// Finds the first element in a given list for which the given function returns -/// `True`. -/// -/// Returns `Error(Nil)` if no such element is found. -/// -/// ## Examples -/// -/// ```gleam -/// > find([1, 2, 3], fn(x) { x > 2 }) -/// Ok(3) -/// ``` -/// -/// ```gleam -/// > find([1, 2, 3], fn(x) { x > 4 }) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > find([], fn(_) { True }) -/// Error(Nil) -/// ``` -/// -pub fn find( - in haystack: List(a), - one_that is_desired: fn(a) -> Bool, -) -> Result(a, Nil) { - case haystack { - [] -> Error(Nil) - [x, ..rest] -> - case is_desired(x) { - True -> Ok(x) - _ -> find(in: rest, one_that: is_desired) - } - } -} - -/// Finds the first element in a given list for which the given function returns -/// `Ok(new_value)`, then returns the wrapped `new_value`. -/// -/// Returns `Error(Nil)` if no such element is found. -/// -/// ## Examples -/// -/// ```gleam -/// > find_map([[], [2], [3]], first) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > find_map([[], []], first) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > find_map([], first) -/// Error(Nil) -/// ``` -/// -pub fn find_map( - in haystack: List(a), - with fun: fn(a) -> Result(b, c), -) -> Result(b, Nil) { - case haystack { - [] -> Error(Nil) - [x, ..rest] -> - case fun(x) { - Ok(x) -> Ok(x) - _ -> find_map(in: rest, with: fun) - } - } -} - -/// Returns `True` if the given function returns `True` for all the elements in -/// the given list. If the function returns `False` for any of the elements it -/// immediately returns `False` without checking the rest of the list. -/// -/// ## Examples -/// -/// ```gleam -/// > all([], fn(x) { x > 3 }) -/// True -/// ``` -/// -/// ```gleam -/// > all([4, 5], fn(x) { x > 3 }) -/// True -/// ``` -/// -/// ```gleam -/// > all([4, 3], fn(x) { x > 3 }) -/// False -/// ``` -/// -pub fn all(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool { - case list { - [] -> True - [first, ..rest] -> - case predicate(first) { - True -> all(rest, predicate) - False -> False - } - } -} - -/// Returns `True` if the given function returns `True` for any the elements in -/// the given list. If the function returns `True` for any of the elements it -/// immediately returns `True` without checking the rest of the list. -/// -/// ## Examples -/// -/// ```gleam -/// > any([], fn(x) { x > 3 }) -/// False -/// ``` -/// -/// ```gleam -/// > any([4, 5], fn(x) { x > 3 }) -/// True -/// ``` -/// -/// ```gleam -/// > any([4, 3], fn(x) { x > 4 }) -/// False -/// ``` -/// -/// ```gleam -/// > any([3, 4], fn(x) { x > 3 }) -/// True -/// ``` -/// -pub fn any(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool { - case list { - [] -> False - [first, ..rest] -> - case predicate(first) { - True -> True - False -> any(rest, predicate) - } - } -} - -fn do_zip(xs: List(a), ys: List(b), acc: List(#(a, b))) -> List(#(a, b)) { - case xs, ys { - [x, ..xs], [y, ..ys] -> do_zip(xs, ys, [#(x, y), ..acc]) - _, _ -> reverse(acc) - } -} - -/// Takes two lists and returns a single list of 2-element tuples. -/// -/// If one of the lists is longer than the other, the remaining elements from -/// the longer list are not used. -/// -/// ## Examples -/// -/// ```gleam -/// > zip([], []) -/// [] -/// ``` -/// -/// ```gleam -/// > zip([1, 2], [3]) -/// [#(1, 3)] -/// ``` -/// -/// ```gleam -/// > zip([1], [3, 4]) -/// [#(1, 3)] -/// ``` -/// -/// ```gleam -/// > zip([1, 2], [3, 4]) -/// [#(1, 3), #(2, 4)] -/// ``` -/// -pub fn zip(list: List(a), with other: List(b)) -> List(#(a, b)) { - do_zip(list, other, []) -} - -/// Takes two lists and returns a single list of 2-element tuples. -/// -/// If one of the lists is longer than the other, an `Error` is returned. -/// -/// ## Examples -/// -/// ```gleam -/// > strict_zip([], []) -/// Ok([]) -/// ``` -/// -/// ```gleam -/// > strict_zip([1, 2], [3]) -/// Error(LengthMismatch) -/// ``` -/// -/// ```gleam -/// > strict_zip([1], [3, 4]) -/// Error(LengthMismatch) -/// ``` -/// -/// ```gleam -/// > strict_zip([1, 2], [3, 4]) -/// Ok([#(1, 3), #(2, 4)]) -/// ``` -/// -pub fn strict_zip( - list: List(a), - with other: List(b), -) -> Result(List(#(a, b)), LengthMismatch) { - case length(of: list) == length(of: other) { - True -> Ok(zip(list, other)) - False -> Error(LengthMismatch) - } -} - -fn do_unzip(input, xs, ys) { - case input { - [] -> #(reverse(xs), reverse(ys)) - [#(x, y), ..rest] -> do_unzip(rest, [x, ..xs], [y, ..ys]) - } -} - -/// Takes a single list of 2-element tuples and returns two lists. -/// -/// ## Examples -/// -/// ```gleam -/// > unzip([#(1, 2), #(3, 4)]) -/// #([1, 3], [2, 4]) -/// ``` -/// -/// ```gleam -/// > unzip([]) -/// #([], []) -/// ``` -/// -pub fn unzip(input: List(#(a, b))) -> #(List(a), List(b)) { - do_unzip(input, [], []) -} - -fn do_intersperse(list: List(a), separator: a, acc: List(a)) -> List(a) { - case list { - [] -> reverse(acc) - [x, ..rest] -> do_intersperse(rest, separator, [x, separator, ..acc]) - } -} - -/// Inserts a given value between each existing element in a given list. -/// -/// This function runs in linear time and copies the list. -/// -/// ## Examples -/// -/// ```gleam -/// > intersperse([1, 1, 1], 2) -/// [1, 2, 1, 2, 1] -/// ``` -/// -/// ```gleam -/// > intersperse([], 2) -/// [] -/// ``` -/// -pub fn intersperse(list: List(a), with elem: a) -> List(a) { - case list { - [] | [_] -> list - [x, ..rest] -> do_intersperse(rest, elem, [x]) - } -} - -/// Returns the element in the Nth position in the list, with 0 being the first -/// position. -/// -/// `Error(Nil)` is returned if the list is not long enough for the given index -/// or if the index is less than 0. -/// -/// ## Examples -/// -/// ```gleam -/// > at([1, 2, 3], 1) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > at([1, 2, 3], 5) -/// Error(Nil) -/// ``` -/// -pub fn at(in list: List(a), get index: Int) -> Result(a, Nil) { - case index >= 0 { - True -> - list - |> drop(index) - |> first - False -> Error(Nil) - } -} - -/// Removes any duplicate elements from a given list. -/// -/// This function returns in loglinear time. -/// -/// ## Examples -/// -/// ```gleam -/// > unique([1, 1, 1, 4, 7, 3, 3, 4]) -/// [1, 4, 7, 3] -/// ``` -/// -pub fn unique(list: List(a)) -> List(a) { - case list { - [] -> [] - [x, ..rest] -> [x, ..unique(filter(rest, fn(y) { y != x }))] - } -} - -/// Merge lists `a` and `b` in ascending order -/// but only up to `na` and `nb` number of items respectively. -/// -fn merge_up( - na: Int, - nb: Int, - a: List(a), - b: List(a), - acc: List(a), - compare: fn(a, a) -> Order, -) { - case na, nb, a, b { - 0, 0, _, _ -> acc - _, 0, [ax, ..ar], _ -> merge_up(na - 1, nb, ar, b, [ax, ..acc], compare) - 0, _, _, [bx, ..br] -> merge_up(na, nb - 1, a, br, [bx, ..acc], compare) - _, _, [ax, ..ar], [bx, ..br] -> - case compare(ax, bx) { - order.Gt -> merge_up(na, nb - 1, a, br, [bx, ..acc], compare) - _ -> merge_up(na - 1, nb, ar, b, [ax, ..acc], compare) - } - _, _, _, _ -> acc - } -} - -/// Merge lists `a` and `b` in descending order -/// but only up to `na` and `nb` number of items respectively. -/// -fn merge_down( - na: Int, - nb: Int, - a: List(a), - b: List(a), - acc: List(a), - compare: fn(a, a) -> Order, -) { - case na, nb, a, b { - 0, 0, _, _ -> acc - _, 0, [ax, ..ar], _ -> merge_down(na - 1, nb, ar, b, [ax, ..acc], compare) - 0, _, _, [bx, ..br] -> merge_down(na, nb - 1, a, br, [bx, ..acc], compare) - _, _, [ax, ..ar], [bx, ..br] -> - case compare(bx, ax) { - order.Lt -> merge_down(na - 1, nb, ar, b, [ax, ..acc], compare) - _ -> merge_down(na, nb - 1, a, br, [bx, ..acc], compare) - } - _, _, _, _ -> acc - } -} - -/// Merge sort that alternates merging in ascending and descending order -/// because the merge process also reverses the list. -/// -/// Some copying is avoided by merging only a subset of the lists -/// instead of creating and merging new smaller lists. -/// -fn merge_sort( - l: List(a), - ln: Int, - compare: fn(a, a) -> Order, - down: Bool, -) -> List(a) { - let n = ln / 2 - let a = l - let b = drop(l, n) - case ln < 3 { - True -> - case down { - True -> merge_down(n, ln - n, a, b, [], compare) - False -> merge_up(n, ln - n, a, b, [], compare) - } - False -> - case down { - True -> - merge_down( - n, - ln - n, - merge_sort(a, n, compare, False), - merge_sort(b, ln - n, compare, False), - [], - compare, - ) - False -> - merge_up( - n, - ln - n, - merge_sort(a, n, compare, True), - merge_sort(b, ln - n, compare, True), - [], - compare, - ) - } - } -} - -/// Sorts from smallest to largest based upon the ordering specified by a given -/// function. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/int -/// > list.sort([4, 3, 6, 5, 4, 1, 2], by: int.compare) -/// [1, 2, 3, 4, 4, 5, 6] -/// ``` -/// -pub fn sort(list: List(a), by compare: fn(a, a) -> Order) -> List(a) { - merge_sort(list, length(list), compare, True) -} - -/// Creates a list of ints ranging from a given start and finish. -/// -/// ## Examples -/// -/// ```gleam -/// > range(0, 0) -/// [0] -/// ``` -/// -/// ```gleam -/// > range(0, 5) -/// [0, 1, 2, 3, 4, 5] -/// ``` -/// -/// ```gleam -/// > range(1, -5) -/// [1, 0, -1, -2, -3, -4, -5] -/// ``` -/// -pub fn range(from start: Int, to stop: Int) -> List(Int) { - tail_recursive_range(start, stop, []) -} - -fn tail_recursive_range(start: Int, stop: Int, acc: List(Int)) -> List(Int) { - case int.compare(start, stop) { - order.Eq -> [stop, ..acc] - order.Gt -> tail_recursive_range(start, stop + 1, [stop, ..acc]) - order.Lt -> tail_recursive_range(start, stop - 1, [stop, ..acc]) - } -} - -fn do_repeat(a: a, times: Int, acc: List(a)) -> List(a) { - case times <= 0 { - True -> acc - False -> do_repeat(a, times - 1, [a, ..acc]) - } -} - -/// Builds a list of a given value a given number of times. -/// -/// ## Examples -/// -/// ```gleam -/// > repeat("a", times: 0) -/// [] -/// ``` -/// -/// ```gleam -/// > repeat("a", times: 5) -/// ["a", "a", "a", "a", "a"] -/// ``` -/// -pub fn repeat(item a: a, times times: Int) -> List(a) { - do_repeat(a, times, []) -} - -fn do_split(list: List(a), n: Int, taken: List(a)) -> #(List(a), List(a)) { - case n <= 0 { - True -> #(reverse(taken), list) - False -> - case list { - [] -> #(reverse(taken), []) - [x, ..xs] -> do_split(xs, n - 1, [x, ..taken]) - } - } -} - -/// Splits a list in two before the given index. -/// -/// If the list is not long enough to have the given index the before list will -/// be the input list, and the after list will be empty. -/// -/// ## Examples -/// -/// ```gleam -/// > split([6, 7, 8, 9], 0) -/// #([], [6, 7, 8, 9]) -/// ``` -/// -/// ```gleam -/// > split([6, 7, 8, 9], 2) -/// #([6, 7], [8, 9]) -/// ``` -/// -/// ```gleam -/// > split([6, 7, 8, 9], 4) -/// #([6, 7, 8, 9], []) -/// ``` -/// -pub fn split(list list: List(a), at index: Int) -> #(List(a), List(a)) { - do_split(list, index, []) -} - -fn do_split_while( - list: List(a), - f: fn(a) -> Bool, - acc: List(a), -) -> #(List(a), List(a)) { - case list { - [] -> #(reverse(acc), []) - [x, ..xs] -> - case f(x) { - False -> #(reverse(acc), list) - _ -> do_split_while(xs, f, [x, ..acc]) - } - } -} - -/// Splits a list in two before the first element that a given function returns -/// `False` for. -/// -/// If the function returns `True` for all elements the first list will be the -/// input list, and the second list will be empty. -/// -/// ## Examples -/// -/// ```gleam -/// > split_while([1, 2, 3, 4, 5], fn(x) { x <= 3 }) -/// #([1, 2, 3], [4, 5]) -/// ``` -/// -/// ```gleam -/// > split_while([1, 2, 3, 4, 5], fn(x) { x <= 5 }) -/// #([1, 2, 3, 4, 5], []) -/// ``` -/// -pub fn split_while( - list list: List(a), - satisfying predicate: fn(a) -> Bool, -) -> #(List(a), List(a)) { - do_split_while(list, predicate, []) -} - -/// Given a list of 2-element tuples, finds the first tuple that has a given -/// key as the first element and returns the second element. -/// -/// If no tuple is found with the given key then `Error(Nil)` is returned. -/// -/// This function may be useful for interacting with Erlang code where lists of -/// tuples are common. -/// -/// ## Examples -/// -/// ```gleam -/// > key_find([#("a", 0), #("b", 1)], "a") -/// Ok(0) -/// ``` -/// -/// ```gleam -/// > key_find([#("a", 0), #("b", 1)], "b") -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > key_find([#("a", 0), #("b", 1)], "c") -/// Error(Nil) -/// ``` -/// -pub fn key_find( - in keyword_list: List(#(k, v)), - find desired_key: k, -) -> Result(v, Nil) { - find_map( - keyword_list, - fn(keyword) { - let #(key, value) = keyword - case key == desired_key { - True -> Ok(value) - False -> Error(Nil) - } - }, - ) -} - -/// Given a list of 2-element tuples, finds all tuples that have a given -/// key as the first element and returns the second element. -/// -/// This function may be useful for interacting with Erlang code where lists of -/// tuples are common. -/// -/// ## Examples -/// -/// ```gleam -/// > key_filter([#("a", 0), #("b", 1), #("a", 2)], "a") -/// [0, 2] -/// ``` -/// -/// ```gleam -/// > key_filter([#("a", 0), #("b", 1)], "c") -/// [] -/// ``` -/// -pub fn key_filter( - in keyword_list: List(#(k, v)), - find desired_key: k, -) -> List(v) { - filter_map( - keyword_list, - fn(keyword) { - let #(key, value) = keyword - case key == desired_key { - True -> Ok(value) - False -> Error(Nil) - } - }, - ) -} - -fn do_pop(haystack, predicate, checked) { - case haystack { - [] -> Error(Nil) - [x, ..rest] -> - case predicate(x) { - True -> Ok(#(x, append(reverse(checked), rest))) - False -> do_pop(rest, predicate, [x, ..checked]) - } - } -} - -/// Removes the first element in a given list for which the predicate function returns `True`. -/// -/// Returns `Error(Nil)` if no such element is found. -/// -/// ## Examples -/// -/// ```gleam -/// > pop([1, 2, 3], fn(x) { x > 2 }) -/// Ok(#(3, [1, 2])) -/// ``` -/// -/// ```gleam -/// > pop([1, 2, 3], fn(x) { x > 4 }) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > pop([], fn(_) { True }) -/// Error(Nil) -/// ``` -/// -pub fn pop( - in haystack: List(a), - one_that is_desired: fn(a) -> Bool, -) -> Result(#(a, List(a)), Nil) { - do_pop(haystack, is_desired, []) -} - -fn do_pop_map(haystack, mapper, checked) { - case haystack { - [] -> Error(Nil) - [x, ..rest] -> - case mapper(x) { - Ok(y) -> Ok(#(y, append(reverse(checked), rest))) - Error(_) -> do_pop_map(rest, mapper, [x, ..checked]) - } - } -} - -/// Removes the first element in a given list for which the given function returns -/// `Ok(new_value)`, then returns the wrapped `new_value` as well as list with the value removed. -/// -/// Returns `Error(Nil)` if no such element is found. -/// -/// ## Examples -/// -/// ```gleam -/// > pop_map([[], [2], [3]], first) -/// Ok(#(2, [[], [3]])) -/// ``` -/// -/// ```gleam -/// > pop_map([[], []], first) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > pop_map([], first) -/// Error(Nil) -/// ``` -/// -pub fn pop_map( - in haystack: List(a), - one_that is_desired: fn(a) -> Result(b, c), -) -> Result(#(b, List(a)), Nil) { - do_pop_map(haystack, is_desired, []) -} - -/// Given a list of 2-element tuples, finds the first tuple that has a given -/// key as the first element. This function will return the second element -/// of the found tuple and list with tuple removed. -/// -/// If no tuple is found with the given key then `Error(Nil)` is returned. -/// -/// ## Examples -/// -/// ```gleam -/// > key_pop([#("a", 0), #("b", 1)], "a") -/// Ok(#(0, [#("b", 1)])) -/// ``` -/// -/// ```gleam -/// > key_pop([#("a", 0), #("b", 1)], "b") -/// Ok(#(1, [#("a", 0)])) -/// ``` -/// -/// ```gleam -/// > key_pop([#("a", 0), #("b", 1)], "c") -/// Error(Nil) -/// ``` -/// -pub fn key_pop( - haystack: List(#(k, v)), - key: k, -) -> Result(#(v, List(#(k, v))), Nil) { - pop_map( - haystack, - fn(entry) { - let #(k, v) = entry - case k { - k if k == key -> Ok(v) - _ -> Error(Nil) - } - }, - ) -} - -/// Given a list of 2-element tuples, inserts a key and value into the list. -/// -/// If there was already a tuple with the key then it is replaced, otherwise it -/// is added to the end of the list. -/// -/// ## Examples -/// -/// ```gleam -/// > key_set([#(5, 0), #(4, 1)], 4, 100) -/// [#(5, 0), #(4, 100)] -/// ``` -/// -/// ```gleam -/// > key_set([#(5, 0), #(4, 1)], 1, 100) -/// [#(5, 0), #(4, 1), #(1, 100)] -/// ``` -/// -pub fn key_set(list: List(#(a, b)), key: a, value: b) -> List(#(a, b)) { - case list { - [] -> [#(key, value)] - [#(k, _), ..rest] if k == key -> [#(key, value), ..rest] - [first, ..rest] -> [first, ..key_set(rest, key, value)] - } -} - -/// Calls a function for each element in a list, discarding the return value. -/// -/// Useful for calling a side effect for every item of a list. -/// -/// ```gleam -/// > list.each([1, 2, 3], io.println) -/// Nil -/// ``` -/// -pub fn each(list: List(a), f: fn(a) -> b) -> Nil { - case list { - [] -> Nil - [x, ..xs] -> { - f(x) - each(xs, f) - } - } -} - -/// Calls a `Result` returning function for each element in a list, discarding -/// the return value. If the function returns `Error` then the iteration is -/// stopped and the error is returned. -/// -/// Useful for calling a side effect for every item of a list. -/// -/// ## Examples -/// -/// ```gleam -/// > try_each( -/// > over: [1, 2, 3], -/// > with: function_that_might_fail, -/// > ) -/// Ok(Nil) -/// ``` -/// -pub fn try_each( - over list: List(a), - with fun: fn(a) -> Result(b, e), -) -> Result(Nil, e) { - case list { - [] -> Ok(Nil) - [x, ..xs] -> - case fun(x) { - Ok(_) -> try_each(over: xs, with: fun) - Error(e) -> Error(e) - } - } -} - -fn do_partition(list, categorise, trues, falses) { - case list { - [] -> #(reverse(trues), reverse(falses)) - [x, ..xs] -> - case categorise(x) { - True -> do_partition(xs, categorise, [x, ..trues], falses) - False -> do_partition(xs, categorise, trues, [x, ..falses]) - } - } -} - -/// Partitions a list into a tuple/pair of lists -/// by a given categorisation function. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3, 4, 5] |> list.partition(int.is_odd) -/// #([1, 3, 5], [2, 4]) -/// ``` -/// -pub fn partition( - list: List(a), - with categorise: fn(a) -> Bool, -) -> #(List(a), List(a)) { - do_partition(list, categorise, [], []) -} - -/// Returns all the permutations of a list. -/// -/// ## Examples -/// -/// ```gleam -/// > permutations([1, 2]) -/// [[1, 2], [2, 1]] -/// ``` -/// -pub fn permutations(l: List(a)) -> List(List(a)) { - case l { - [] -> [[]] - _ -> - l - |> index_map(fn(i_idx, i) { - l - |> index_fold( - [], - fn(acc, j, j_idx) { - case i_idx == j_idx { - True -> acc - False -> [j, ..acc] - } - }, - ) - |> reverse - |> permutations - |> map(fn(permutation) { [i, ..permutation] }) - }) - |> concat - } -} - -fn do_window(acc: List(List(a)), l: List(a), n: Int) -> List(List(a)) { - let window = take(l, n) - - case length(window) == n { - True -> do_window([window, ..acc], drop(l, 1), n) - False -> acc - } -} - -/// Returns a list of sliding windows. -/// -/// ## Examples -/// -/// ```gleam -/// > window([1,2,3,4,5], 3) -/// [[1, 2, 3], [2, 3, 4], [3, 4, 5]] -/// ``` -/// -/// ```gleam -/// > window([1, 2], 4) -/// [] -/// ``` -/// -pub fn window(l: List(a), by n: Int) -> List(List(a)) { - do_window([], l, n) - |> reverse -} - -/// Returns a list of tuples containing two contiguous elements. -/// -/// ## Examples -/// -/// ```gleam -/// > window_by_2([1,2,3,4]) -/// [#(1, 2), #(2, 3), #(3, 4)] -/// ``` -/// -/// ```gleam -/// > window_by_2([1]) -/// [] -/// ``` -/// -pub fn window_by_2(l: List(a)) -> List(#(a, a)) { - zip(l, drop(l, 1)) -} - -/// Drops the first elements in a given list for which the predicate function returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// > drop_while([1, 2, 3, 4], fn (x) { x < 3 }) -/// [3, 4] -/// ``` -/// -pub fn drop_while( - in list: List(a), - satisfying predicate: fn(a) -> Bool, -) -> List(a) { - case list { - [] -> [] - [x, ..xs] -> - case predicate(x) { - True -> drop_while(xs, predicate) - False -> [x, ..xs] - } - } -} - -fn do_take_while( - list: List(a), - predicate: fn(a) -> Bool, - acc: List(a), -) -> List(a) { - case list { - [] -> reverse(acc) - [first, ..rest] -> - case predicate(first) { - True -> do_take_while(rest, predicate, [first, ..acc]) - False -> reverse(acc) - } - } -} - -/// Takes the first elements in a given list for which the predicate function returns `True`. -/// -/// ## Examples -/// -/// ```gleam -/// > take_while([1, 2, 3, 2, 4], fn (x) { x < 3 }) -/// [1, 2] -/// ``` -/// -pub fn take_while( - in list: List(a), - satisfying predicate: fn(a) -> Bool, -) -> List(a) { - do_take_while(list, predicate, []) -} - -fn do_chunk( - list: List(a), - f: fn(a) -> key, - previous_key: key, - current_chunk: List(a), - acc: List(List(a)), -) -> List(List(a)) { - case list { - [first, ..rest] -> { - let key = f(first) - case key == previous_key { - False -> { - let new_acc = [reverse(current_chunk), ..acc] - do_chunk(rest, f, key, [first], new_acc) - } - _true -> do_chunk(rest, f, key, [first, ..current_chunk], acc) - } - } - _empty -> reverse([reverse(current_chunk), ..acc]) - } -} - -/// Returns a list of chunks in which -/// the return value of calling `f` on each element is the same. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 2, 3, 4, 4, 6, 7, 7] |> chunk(by: fn(n) { n % 2 }) -/// [[1], [2, 2], [3], [4, 4, 6], [7, 7]] -/// ``` -/// -pub fn chunk(in list: List(a), by f: fn(a) -> key) -> List(List(a)) { - case list { - [] -> [] - [first, ..rest] -> do_chunk(rest, f, f(first), [first], []) - } -} - -fn do_sized_chunk( - list: List(a), - count: Int, - left: Int, - current_chunk: List(a), - acc: List(List(a)), -) -> List(List(a)) { - case list { - [] -> - case current_chunk { - [] -> reverse(acc) - remaining -> reverse([reverse(remaining), ..acc]) - } - [first, ..rest] -> { - let chunk = [first, ..current_chunk] - case left > 1 { - False -> do_sized_chunk(rest, count, count, [], [reverse(chunk), ..acc]) - True -> do_sized_chunk(rest, count, left - 1, chunk, acc) - } - } - } -} - -/// Returns a list of chunks containing `count` elements each. -/// -/// If the last chunk does not have `count` elements, it is instead -/// a partial chunk, with less than `count` elements. -/// -/// For any `count` less than 1 this function behaves as if it was set to 1. -/// -/// ## Examples -/// -/// ```gleam -/// > [1, 2, 3, 4, 5, 6] |> sized_chunk(into: 2) -/// [[1, 2], [3, 4], [5, 6]] -/// ``` -/// -/// ```gleam -/// > [1, 2, 3, 4, 5, 6, 7, 8] |> sized_chunk(into: 3) -/// [[1, 2, 3], [4, 5, 6], [7, 8]] -/// ``` -/// -pub fn sized_chunk(in list: List(a), into count: Int) -> List(List(a)) { - do_sized_chunk(list, count, count, [], []) -} - -/// This function acts similar to fold, but does not take an initial state. -/// Instead, it starts from the first element in the list -/// and combines it with each subsequent element in turn using the given -/// function. The function is called as `fun(accumulator, current_element)`. -/// -/// Returns `Ok` to indicate a successful run, and `Error` if called on an -/// empty list. -/// -/// ## Examples -/// -/// ```gleam -/// > [] |> reduce(fn(acc, x) { acc + x }) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > [1, 2, 3, 4, 5] |> reduce(fn(acc, x) { acc + x }) -/// Ok(15) -/// ``` -/// -pub fn reduce(over list: List(a), with fun: fn(a, a) -> a) -> Result(a, Nil) { - case list { - [] -> Error(Nil) - [first, ..rest] -> Ok(fold(rest, first, fun)) - } -} - -fn do_scan( - list: List(a), - accumulator: acc, - accumulated: List(acc), - fun: fn(acc, a) -> acc, -) -> List(acc) { - case list { - [] -> reverse(accumulated) - [x, ..xs] -> { - let next = fun(accumulator, x) - do_scan(xs, next, [next, ..accumulated], fun) - } - } -} - -/// Similar to `fold`, but yields the state of the accumulator at each stage. -/// -/// ## Examples -/// -/// ```gleam -/// > scan(over: [1, 2, 3], from: 100, with: fn(acc, i) { acc + i }) -/// [101, 103, 106] -/// ``` -/// -pub fn scan( - over list: List(a), - from initial: acc, - with fun: fn(acc, a) -> acc, -) -> List(acc) { - do_scan(list, initial, [], fun) -} - -/// Returns the last element in the given list. -/// -/// Returns `Error(Nil)` if the list is empty. -/// -/// This function runs in linear time. -/// For a collection oriented around performant access at either end, -/// see `gleam/queue.Queue`. -/// -/// ## Examples -/// -/// ```gleam -/// > last([]) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > last([1, 2, 3, 4, 5]) -/// Ok(5) -/// ``` -/// -pub fn last(list: List(a)) -> Result(a, Nil) { - list - |> reduce(fn(_, elem) { elem }) -} - -/// Return unique combinations of elements in the list. -/// -/// ## Examples -/// -/// ```gleam -/// > combinations([1, 2, 3], 2) -/// [[1, 2], [1, 3], [2, 3]] -/// ``` -/// -/// ```gleam -/// > combinations([1, 2, 3, 4], 3) -/// [[1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4]] -/// ``` -/// -pub fn combinations(items: List(a), by n: Int) -> List(List(a)) { - case n { - 0 -> [[]] - _ -> - case items { - [] -> [] - [x, ..xs] -> { - let first_combinations = - map(combinations(xs, n - 1), with: fn(com) { [x, ..com] }) - |> reverse - fold( - first_combinations, - combinations(xs, n), - fn(acc, c) { [c, ..acc] }, - ) - } - } - } -} - -fn do_combination_pairs(items: List(a)) -> List(List(#(a, a))) { - case items { - [] -> [] - [x, ..xs] -> { - let first_combinations = map(xs, with: fn(other) { #(x, other) }) - [first_combinations, ..do_combination_pairs(xs)] - } - } -} - -/// Return unique pair combinations of elements in the list -/// -/// ## Examples -/// -/// ```gleam -/// > combination_pairs([1, 2, 3]) -/// [#(1, 2), #(1, 3), #(2, 3)] -/// ``` -/// -pub fn combination_pairs(items: List(a)) -> List(#(a, a)) { - do_combination_pairs(items) - |> concat -} - -/// Make a list alternating the elements from the given lists -/// -/// ## Examples -/// -/// ```gleam -/// > list.interleave([[1, 2], [101, 102], [201, 202]]) -/// [1, 101, 201, 2, 102, 202] -/// ``` -/// -pub fn interleave(list: List(List(a))) -> List(a) { - transpose(list) - |> concat -} - -/// Transpose rows and columns of the list of lists. -/// -/// Notice: This function is not tail recursive, -/// and thus may exceed stack size if called, -/// with large lists (on target JavaScript). -/// -/// ## Examples -/// -/// ```gleam -/// > transpose([[1, 2, 3], [101, 102, 103]]) -/// [[1, 101], [2, 102], [3, 103]] -/// ``` -/// -pub fn transpose(list_of_list: List(List(a))) -> List(List(a)) { - let take_first = fn(list) { - case list { - [] -> [] - [f] -> [f] - [f, ..] -> [f] - } - } - - case list_of_list { - [] -> [] - [[], ..xss] -> transpose(xss) - rows -> { - let firsts = - rows - |> map(take_first) - |> concat - let rest = transpose(map(rows, drop(_, 1))) - [firsts, ..rest] - } - } -} - -fn do_shuffle_pair_unwrap(list: List(#(Float, a)), acc: List(a)) -> List(a) { - case list { - [] -> acc - [elem_pair, ..enumerable] -> - do_shuffle_pair_unwrap(enumerable, [elem_pair.1, ..acc]) - } -} - -fn do_shuffle_by_pair_indexes( - list_of_pairs: List(#(Float, a)), -) -> List(#(Float, a)) { - sort( - list_of_pairs, - fn(a_pair: #(Float, a), b_pair: #(Float, a)) -> Order { - float.compare(a_pair.0, b_pair.0) - }, - ) -} - -/// Takes a list, randomly sorts all items and returns the shuffled list. -/// -/// This function uses Erlang's `:rand` module or Javascript's -/// `Math.random()` to calculate the index shuffling. -/// -/// ## Example -/// -/// ```gleam -/// > range(1, 10) -/// > |> shuffle() -/// [1, 6, 9, 10, 3, 8, 4, 2, 7, 5] -/// ``` -/// -pub fn shuffle(list: List(a)) -> List(a) { - list - |> fold(from: [], with: fn(acc, a) { [#(float.random(0.0, 1.0), a), ..acc] }) - |> do_shuffle_by_pair_indexes() - |> do_shuffle_pair_unwrap([]) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/map.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/map.gleam deleted file mode 100644 index 1f8b228..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/map.gleam +++ /dev/null @@ -1,127 +0,0 @@ -import gleam/option.{type Option} -import gleam/dict - -@deprecated("Please use the `gleam/dict` module instead") -pub type Map(key, value) = - dict.Dict(key, value) - -@deprecated("Please use the `gleam/dict` module instead") -pub fn size(map) -> Int { - dict.size(map) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn to_list(map) -> List(#(key, value)) { - dict.to_list(map) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn from_list(list: List(#(k, v))) { - dict.from_list(list) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn has_key(map, key: k) -> Bool { - dict.has_key(map, key) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn new() { - dict.new() -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn get(from, get: key) -> Result(value, Nil) { - dict.get(from, get) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn insert(into map, for key: k, insert value: v) { - dict.insert(map, key, value) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn map_values(in map, with fun: fn(k, v) -> w) { - dict.map_values(map, fun) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn keys(map) -> List(keys) { - dict.keys(map) -} - -@target(javascript) -fn reverse_and_concat(remaining, accumulator) { - case remaining { - [] -> accumulator - [item, ..rest] -> reverse_and_concat(rest, [item, ..accumulator]) - } -} - -@target(javascript) -fn do_keys_acc(list: List(#(k, v)), acc: List(k)) -> List(k) { - case list { - [] -> reverse_and_concat(acc, []) - [x, ..xs] -> do_keys_acc(xs, [x.0, ..acc]) - } -} - -@target(javascript) -fn do_keys(map) -> List(k) { - let list_of_pairs = - map - |> to_list - do_keys_acc(list_of_pairs, []) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn values(map) -> List(values) { - dict.values(map) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn filter(in map, keeping predicate: fn(k, v) -> Bool) { - dict.filter(map, predicate) -} - -@target(javascript) -fn do_filter(f: fn(key, value) -> Bool, map) { - let insert = fn(map, k, v) { - case f(k, v) { - True -> insert(map, k, v) - _ -> map - } - } - map - |> fold(from: new(), with: insert) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn take(from map, keeping desired_keys: List(k)) { - dict.take(map, desired_keys) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn merge(into map, from new_entries) { - dict.merge(map, new_entries) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn delete(from map, delete key: k) { - dict.delete(map, key) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn drop(from map, drop disallowed_keys: List(k)) { - dict.drop(map, disallowed_keys) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn update(in map, update key: k, with fun: fn(Option(v)) -> v) { - dict.update(map, key, fun) -} - -@deprecated("Please use the `gleam/dict` module instead") -pub fn fold(over map, from initial: acc, with fun: fn(acc, k, v) -> acc) -> acc { - dict.fold(map, initial, fun) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/option.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/option.gleam deleted file mode 100644 index 6015c0f..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/option.gleam +++ /dev/null @@ -1,346 +0,0 @@ -/// `Option` represents a value that may be present or not. `Some` means the value is -/// present, `None` means the value is not. -/// -/// This is Gleam's alternative to having a value that could be Null, as is -/// possible in some other languages. -/// -pub type Option(a) { - Some(a) - None -} - -fn do_all(list: List(Option(a)), acc: List(a)) -> Option(List(a)) { - case list { - [] -> Some(acc) - [x, ..rest] -> { - let accumulate = fn(acc, item) { - case acc, item { - Some(values), Some(value) -> Some([value, ..values]) - _, _ -> None - } - } - accumulate(do_all(rest, acc), x) - } - } -} - -/// Combines a list of `Option`s into a single `Option`. -/// If all elements in the list are `Some` then returns a `Some` holding the list of values. -/// If any element is `None` then returns`None`. -/// -/// ## Examples -/// -/// ```gleam -/// > all([Some(1), Some(2)]) -/// Some([1, 2]) -/// ``` -/// -/// ```gleam -/// > all([Some(1), None]) -/// None -/// ``` -/// -pub fn all(list: List(Option(a))) -> Option(List(a)) { - do_all(list, []) -} - -/// Checks whether the `Option` is a `Some` value. -/// -/// ## Examples -/// -/// ```gleam -/// > is_some(Some(1)) -/// True -/// ``` -/// -/// ```gleam -/// > is_some(None) -/// False -/// ``` -/// -pub fn is_some(option: Option(a)) -> Bool { - option != None -} - -/// Checks whether the `Option` is a `None` value. -/// -/// ## Examples -/// -/// ```gleam -/// > is_none(Some(1)) -/// False -/// ``` -/// -/// ```gleam -/// > is_none(None) -/// True -/// ``` -/// -pub fn is_none(option: Option(a)) -> Bool { - option == None -} - -/// Converts an `Option` type to a `Result` type. -/// -/// ## Examples -/// -/// ```gleam -/// > to_result(Some(1), "some_error") -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > to_result(None, "some_error") -/// Error("some_error") -/// ``` -/// -pub fn to_result(option: Option(a), e) -> Result(a, e) { - case option { - Some(a) -> Ok(a) - _ -> Error(e) - } -} - -/// Converts a `Result` type to an `Option` type. -/// -/// ## Examples -/// -/// ```gleam -/// > from_result(Ok(1)) -/// Some(1) -/// ``` -/// -/// ```gleam -/// > from_result(Error("some_error")) -/// None -/// ``` -/// -pub fn from_result(result: Result(a, e)) -> Option(a) { - case result { - Ok(a) -> Some(a) - _ -> None - } -} - -/// Extracts the value from an `Option`, returning a default value if there is none. -/// -/// ## Examples -/// -/// ```gleam -/// > unwrap(Some(1), 0) -/// 1 -/// ``` -/// -/// ```gleam -/// > unwrap(None, 0) -/// 0 -/// ``` -/// -pub fn unwrap(option: Option(a), or default: a) -> a { - case option { - Some(x) -> x - None -> default - } -} - -/// Extracts the value from an `Option`, evaluating the default function if the option is `None`. -/// -/// ## Examples -/// -/// ```gleam -/// > lazy_unwrap(Some(1), fn() { 0 }) -/// 1 -/// ``` -/// -/// ```gleam -/// > lazy_unwrap(None, fn() { 0 }) -/// 0 -/// ``` -/// -pub fn lazy_unwrap(option: Option(a), or default: fn() -> a) -> a { - case option { - Some(x) -> x - None -> default() - } -} - -/// Updates a value held within the `Some` of an `Option` by calling a given function -/// on it. -/// -/// If the `Option` is a `None` rather than `Some`, the function is not called and the -/// `Option` stays the same. -/// -/// ## Examples -/// -/// ```gleam -/// > map(over: Some(1), with: fn(x) { x + 1 }) -/// Some(2) -/// ``` -/// -/// ```gleam -/// > map(over: None, with: fn(x) { x + 1 }) -/// None -/// ``` -/// -pub fn map(over option: Option(a), with fun: fn(a) -> b) -> Option(b) { - case option { - Some(x) -> Some(fun(x)) - None -> None - } -} - -/// Merges a nested `Option` into a single layer. -/// -/// ## Examples -/// -/// ```gleam -/// > flatten(Some(Some(1))) -/// Some(1) -/// ``` -/// -/// ```gleam -/// > flatten(Some(None)) -/// None -/// ``` -/// -/// ```gleam -/// > flatten(None) -/// None -/// ``` -/// -pub fn flatten(option: Option(Option(a))) -> Option(a) { - case option { - Some(x) -> x - None -> None - } -} - -/// Updates a value held within the `Some` of an `Option` by calling a given function -/// on it, where the given function also returns an `Option`. The two options are -/// then merged together into one `Option`. -/// -/// If the `Option` is a `None` rather than `Some` the function is not called and the -/// option stays the same. -/// -/// This function is the equivalent of calling `map` followed by `flatten`, and -/// it is useful for chaining together multiple functions that return `Option`. -/// -/// ## Examples -/// -/// ```gleam -/// > then(Some(1), fn(x) { Some(x + 1) }) -/// Some(2) -/// ``` -/// -/// ```gleam -/// > then(Some(1), fn(x) { Some(#("a", x)) }) -/// Some(#("a", 1)) -/// ``` -/// -/// ```gleam -/// > then(Some(1), fn(_) { None }) -/// None -/// ``` -/// -/// ```gleam -/// > then(None, fn(x) { Some(x + 1) }) -/// None -/// ``` -/// -pub fn then(option: Option(a), apply fun: fn(a) -> Option(b)) -> Option(b) { - case option { - Some(x) -> fun(x) - None -> None - } -} - -/// Returns the first value if it is `Some`, otherwise returns the second value. -/// -/// ## Examples -/// -/// ```gleam -/// > or(Some(1), Some(2)) -/// Some(1) -/// ``` -/// -/// ```gleam -/// > or(Some(1), None) -/// Some(1) -/// ``` -/// -/// ```gleam -/// > or(None, Some(2)) -/// Some(2) -/// ``` -/// -/// ```gleam -/// > or(None, None) -/// None -/// ``` -/// -pub fn or(first: Option(a), second: Option(a)) -> Option(a) { - case first { - Some(_) -> first - None -> second - } -} - -/// Returns the first value if it is `Some`, otherwise evaluates the given function for a fallback value. -/// -/// ## Examples -/// -/// ```gleam -/// > lazy_or(Some(1), fn() { Some(2) }) -/// Some(1) -/// ``` -/// -/// ```gleam -/// > lazy_or(Some(1), fn() { None }) -/// Some(1) -/// ``` -/// -/// ```gleam -/// > lazy_or(None, fn() { Some(2) }) -/// Some(2) -/// ``` -/// -/// ```gleam -/// > lazy_or(None, fn() { None }) -/// None -/// ``` -/// -pub fn lazy_or(first: Option(a), second: fn() -> Option(a)) -> Option(a) { - case first { - Some(_) -> first - None -> second() - } -} - -fn do_values(list: List(Option(a)), acc: List(a)) -> List(a) { - case list { - [] -> acc - [x, ..xs] -> { - let accumulate = fn(acc, item) { - case item { - Some(value) -> [value, ..acc] - None -> acc - } - } - accumulate(do_values(xs, acc), x) - } - } -} - -/// Given a list of `Option`s, -/// returns only the values inside `Some`. -/// -/// ## Examples -/// -/// ```gleam -/// > values([Some(1), None, Some(3)]) -/// [1, 3] -/// ``` -/// -pub fn values(options: List(Option(a))) -> List(a) { - do_values(options, []) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/order.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/order.gleam deleted file mode 100644 index 12ce011..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/order.gleam +++ /dev/null @@ -1,133 +0,0 @@ -/// Represents the result of a single comparison to determine the precise -/// ordering of two values. -/// -pub type Order { - /// Less-than - Lt - - /// Equal - Eq - - /// Greater than - Gt -} - -/// Inverts an order, so less-than becomes greater-than and greater-than -/// becomes less-than. -/// -/// ## Examples -/// -/// ```gleam -/// > negate(Lt) -/// Gt -/// ``` -/// -/// ```gleam -/// > negate(Eq) -/// Eq -/// ``` -/// -/// ```gleam -/// > negate(Lt) -/// Gt -/// ``` -/// -pub fn negate(order: Order) -> Order { - case order { - Lt -> Gt - Eq -> Eq - Gt -> Lt - } -} - -/// Produces a numeric representation of the order. -/// -/// ## Examples -/// -/// ```gleam -/// > to_int(Lt) -/// -1 -/// ``` -/// -/// ```gleam -/// > to_int(Eq) -/// 0 -/// ``` -/// -/// ```gleam -/// > to_int(Gt) -/// 1 -/// ``` -/// -pub fn to_int(order: Order) -> Int { - case order { - Lt -> -1 - Eq -> 0 - Gt -> 1 - } -} - -/// Compares two `Order` values to one another, producing a new `Order`. -/// -/// ## Examples -/// -/// ```gleam -/// > compare(Eq, with: Lt) -/// Gt -/// ``` -/// -pub fn compare(a: Order, with b: Order) -> Order { - case a, b { - x, y if x == y -> Eq - Lt, _ | Eq, Gt -> Lt - _, _ -> Gt - } -} - -/// Returns the largest of two orders given that `Gt > Eq > Lt`. -/// -/// ## Examples -/// -/// ```gleam -/// > max(Eq, Lt) -/// Eq -/// ``` -/// -pub fn max(a: Order, b: Order) -> Order { - case a, b { - Gt, _ -> Gt - Eq, Lt -> Eq - _, _ -> b - } -} - -/// Returns the smallest of two orders given that `Gt > Eq > Lt`. -/// -/// ## Examples -/// -/// ```gleam -/// > min(Eq, Lt) -/// Lt -/// ``` -/// -pub fn min(a: Order, b: Order) -> Order { - case a, b { - Lt, _ -> Lt - Eq, Gt -> Eq - _, _ -> b - } -} - -/// Inverts an ordering function, so less-than becomes greater-than and greater-than -/// becomes less-than. -/// -/// ## Examples -/// -/// ```gleam -/// > list.sort([1, 5, 4], by: reverse(int.compare)) -/// [5, 4, 1] -/// ``` -/// -pub fn reverse(orderer: fn(a, a) -> Order) -> fn(a, a) -> Order { - fn(a, b) { orderer(b, a) } -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/pair.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/pair.gleam deleted file mode 100644 index 894e6a8..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/pair.gleam +++ /dev/null @@ -1,85 +0,0 @@ -/// Returns the first element in a pair. -/// -/// ## Examples -/// -/// ```gleam -/// > first(#(1, 2)) -/// 1 -/// ``` -/// -pub fn first(pair: #(a, b)) -> a { - let #(a, _) = pair - a -} - -/// Returns the second element in a pair. -/// -/// ## Examples -/// -/// ```gleam -/// > second(#(1, 2)) -/// 2 -/// ``` -/// -pub fn second(pair: #(a, b)) -> b { - let #(_, a) = pair - a -} - -/// Returns a new pair with the elements swapped. -/// -/// ## Examples -/// -/// ```gleam -/// > swap(#(1, 2)) -/// #(2, 1) -/// ``` -/// -pub fn swap(pair: #(a, b)) -> #(b, a) { - let #(a, b) = pair - #(b, a) -} - -/// Returns a new pair with the first element having had `with` applied to -/// it. -/// -/// ## Examples -/// -/// ```gleam -/// > #(1, 2) |> map_first(fn(n) { n * 2 }) -/// #(2, 2) -/// ``` -/// -pub fn map_first(of pair: #(a, b), with fun: fn(a) -> c) -> #(c, b) { - let #(a, b) = pair - #(fun(a), b) -} - -/// Returns a new pair with the second element having had `with` applied to -/// it. -/// -/// ## Examples -/// -/// ```gleam -/// > #(1, 2) |> map_second(fn(n) { n * 2 }) -/// #(1, 4) -/// ``` -/// -pub fn map_second(of pair: #(a, b), with fun: fn(b) -> c) -> #(a, c) { - let #(a, b) = pair - #(a, fun(b)) -} - -/// Returns a new pair with the given elements. This can also be done using the dedicated -/// syntax instead: `new(1, 2) == #(1, 2)`. -/// -/// ## Examples -/// -/// ```gleam -/// > new(1, 2) -/// #(1, 2) -/// ``` -/// -pub fn new(first: a, second: b) -> #(a, b) { - #(first, second) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/queue.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/queue.gleam deleted file mode 100644 index 5bf60c8..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/queue.gleam +++ /dev/null @@ -1,292 +0,0 @@ -import gleam/list - -/// A queue is an ordered collection of elements. It is similar to a list, but -/// unlike a list elements can be added to or removed from either the front or -/// the back in a performant fashion. -/// -/// The internal representation may be different for two queues with the same -/// elements in the same order if the queues were constructed in different -/// ways. This is the price paid for a queue's fast access at both the front -/// and the back. -/// -/// Because of unpredictable internal representation the equality operator `==` -/// may return surprising results, and the `is_equal` and `is_logically_equal` -/// functions are the recommended way to test queues for equality. -/// -pub opaque type Queue(element) { - Queue(in: List(element), out: List(element)) -} - -/// Creates a fresh queue that contains no values. -/// -pub fn new() -> Queue(a) { - Queue(in: [], out: []) -} - -/// Converts a list of elements into a queue of the same elements in the same -/// order. The first element in the list becomes the front element in the queue. -/// -/// This function runs in constant time. -/// -/// # Examples -/// -/// ```gleam -/// > [1, 2, 3] |> from_list |> length -/// 3 -/// ``` -/// -pub fn from_list(list: List(a)) -> Queue(a) { - Queue(in: [], out: list) -} - -/// Converts a queue of elements into a list of the same elements in the same -/// order. The front element in the queue becomes the first element in the list. -/// -/// This function runs in linear time. -/// -/// # Examples -/// -/// ```gleam -/// > new() |> push_back(1) |> push_back(2) |> to_list -/// [1, 2] -/// ``` -/// -pub fn to_list(queue: Queue(a)) -> List(a) { - queue.out - |> list.append(list.reverse(queue.in)) -} - -/// Determines whether or not the queue is empty. -/// -/// This function runs in constant time. -/// -/// ## Examples -/// -/// ```gleam -/// > [] |> from_list |> is_empty -/// True -/// ``` -/// -/// ```gleam -/// > [1] |> from_list |> is_empty -/// False -/// ``` -/// -/// ```gleam -/// > [1, 2] |> from_list |> is_empty -/// False -/// ``` -/// -pub fn is_empty(queue: Queue(a)) -> Bool { - queue.in == [] && queue.out == [] -} - -/// Counts the number of elements in a given queue. -/// -/// This function has to traverse the queue to determine the number of elements, -/// so it runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// > length(from_list([])) -/// 0 -/// ``` -/// -/// ```gleam -/// > length(from_list([1])) -/// 1 -/// ``` -/// -/// ```gleam -/// > length(from_list([1, 2])) -/// 2 -/// ``` -/// -pub fn length(queue: Queue(a)) -> Int { - list.length(queue.in) + list.length(queue.out) -} - -/// Pushes an element onto the back of the queue. -/// -/// # Examples -/// -/// ```gleam -/// > [1, 2] |> from_list |> push_back(3) |> to_list -/// [1, 2, 3] -/// ``` -/// -pub fn push_back(onto queue: Queue(a), this item: a) -> Queue(a) { - Queue(in: [item, ..queue.in], out: queue.out) -} - -/// Pushes an element onto the front of the queue. -/// -/// # Examples -/// -/// ```gleam -/// > [0, 0] |> from_list |> push_front(1) |> to_list -/// [1, 0, 0] -/// ``` -/// -pub fn push_front(onto queue: Queue(a), this item: a) -> Queue(a) { - Queue(in: queue.in, out: [item, ..queue.out]) -} - -/// Gets the last element from the queue, returning the -/// element and a new queue without that element. -/// -/// This function typically runs in constant time, but will occasionally run in -/// linear time. -/// -/// # Examples -/// -/// ```gleam -/// > new() -/// > |> push_back(0) -/// > |> push_back(1) -/// > |> pop_back() -/// Ok(#(1, push_front(new(), 0))) -/// ``` -/// -/// ```gleam -/// > new() -/// > |> push_front(0) -/// > |> pop_back() -/// Ok(#(0, new())) -/// ``` -/// -/// ```gleam -/// > new() -/// > |> pop_back() -/// Error(Nil) -/// ``` -/// -pub fn pop_back(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) { - case queue { - Queue(in: [], out: []) -> Error(Nil) - Queue(in: [], out: out) -> pop_back(Queue(in: list.reverse(out), out: [])) - Queue(in: [first, ..rest], out: out) -> { - let queue = Queue(in: rest, out: out) - Ok(#(first, queue)) - } - } -} - -/// Gets the first element from the queue, returning the -/// element and a new queue without that element. -/// -/// This function typically runs in constant time, but will occasionally run in -/// linear time. -/// -/// # Examples -/// -/// ```gleam -/// > queue.new() -/// > |> queue.push_front(1) -/// > |> queue.push_front(0) -/// > |> queue.pop_front() -/// Ok(#(0, queue.push_back(queue.new(), 1))) -/// ``` -/// -/// ```gleam -/// > queue.new() -/// > |> queue.push_back(0) -/// > |> queue.pop_front() -/// Ok(#(0, queue.new())) -/// ``` -/// -/// ```gleam -/// > queue.new() -/// > |> queue.pop_back() -/// Error(Nil) -/// ``` -/// -pub fn pop_front(from queue: Queue(a)) -> Result(#(a, Queue(a)), Nil) { - case queue { - Queue(in: [], out: []) -> Error(Nil) - Queue(in: in, out: []) -> pop_front(Queue(in: [], out: list.reverse(in))) - Queue(in: in, out: [first, ..rest]) -> { - let queue = Queue(in: in, out: rest) - Ok(#(first, queue)) - } - } -} - -/// Creates a new queue from a given queue containing the same elements, but in -/// the opposite order. -/// -/// This function runs in constant time. -/// -/// ## Examples -/// -/// ```gleam -/// > [] |> from_list |> reverse |> to_list -/// [] -/// ``` -/// -/// ```gleam -/// > [1] |> from_list |> reverse |> to_list -/// [1] -/// ``` -/// -/// ```gleam -/// > [1, 2] |> from_list |> reverse |> to_list -/// [2, 1] -/// ``` -/// -pub fn reverse(queue: Queue(a)) -> Queue(a) { - Queue(in: queue.out, out: queue.in) -} - -fn check_equal( - xs: List(t), - x_tail: List(t), - ys: List(t), - y_tail: List(t), - eq: fn(t, t) -> Bool, -) -> Bool { - case xs, x_tail, ys, y_tail { - [], [], [], [] -> True - [x, ..xs], _, [y, ..ys], _ -> - case eq(x, y) { - False -> False - True -> check_equal(xs, x_tail, ys, y_tail, eq) - } - [], [_, ..], _, _ -> check_equal(list.reverse(x_tail), [], ys, y_tail, eq) - _, _, [], [_, ..] -> check_equal(xs, x_tail, list.reverse(y_tail), [], eq) - _, _, _, _ -> False - } -} - -/// Checks whether two queues have equal elements in the same order, where the -/// equality of elements is determined by a given equality checking function. -/// -/// This function is useful as the internal representation may be different for -/// two queues with the same elements in the same order depending on how they -/// were constructed, so the equality operator `==` may return surprising -/// results. -/// -/// This function runs in linear time multiplied by the time taken by the -/// element equality checking function. -/// -pub fn is_logically_equal( - a: Queue(t), - to b: Queue(t), - checking element_is_equal: fn(t, t) -> Bool, -) -> Bool { - check_equal(a.out, a.in, b.out, b.in, element_is_equal) -} - -/// Checks whether two queues have the same elements in the same order. -/// -/// This function is useful as the internal representation may be different for -/// two queues with the same elements in the same order depending on how they -/// were constructed, so the equality operator `==` may return surprising -/// results. -/// -/// This function runs in linear time. -/// -pub fn is_equal(a: Queue(t), to b: Queue(t)) -> Bool { - check_equal(a.out, a.in, b.out, b.in, fn(a, b) { a == b }) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/regex.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/regex.gleam deleted file mode 100644 index 9ffda78..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/regex.gleam +++ /dev/null @@ -1,214 +0,0 @@ -//// This module contains regular expression matching functions for strings. -//// The matching algorithms of the library are based on the PCRE library, but not -//// all of the PCRE library is interfaced and some parts of the library go beyond -//// what PCRE offers. Currently PCRE version 8.40 (release date 2017-01-11) is used. - -import gleam/option.{type Option} - -pub type Regex - -/// The details about a particular match: -/// -pub type Match { - Match( - /// The full string of the match. - content: String, - /// A `Regex` can have subpatterns, sup-parts that are in parentheses. - submatches: List(Option(String)), - ) -} - -/// When a regular expression fails to compile: -/// -pub type CompileError { - CompileError( - /// The problem encountered that caused the compilation to fail - error: String, - /// The byte index into the string to where the problem was found - /// This value may not be correct in JavaScript environments. - byte_index: Int, - ) -} - -pub type Options { - Options(case_insensitive: Bool, multi_line: Bool) -} - -/// Creates a `Regex` with some additional options. -/// -/// ## Examples -/// -/// ```gleam -/// > let options = Options(case_insensitive: False, multi_line: True) -/// > let assert Ok(re) = compile("^[0-9]", with: options) -/// > check(re, "abc\n123") -/// True -/// ``` -/// -/// ```gleam -/// > let options = Options(case_insensitive: True, multi_line: False) -/// > let assert Ok(re) = compile("[A-Z]", with: options) -/// > check(re, "abc123") -/// True -/// ``` -/// -pub fn compile( - pattern: String, - with options: Options, -) -> Result(Regex, CompileError) { - do_compile(pattern, options) -} - -@external(erlang, "gleam_stdlib", "compile_regex") -@external(javascript, "../gleam_stdlib.mjs", "compile_regex") -fn do_compile(a: String, with with: Options) -> Result(Regex, CompileError) - -/// Creates a new `Regex`. -/// -/// ## Examples -/// -/// ```gleam -/// > let assert Ok(re) = from_string("[0-9]") -/// > check(re, "abc123") -/// True -/// ``` -/// -/// ```gleam -/// > check(re, "abcxyz") -/// False -/// ``` -/// -/// ```gleam -/// > from_string("[0-9") -/// Error( -/// CompileError( -/// error: "missing terminating ] for character class", -/// byte_index: 4 -/// ) -/// ) -/// ``` -/// -pub fn from_string(pattern: String) -> Result(Regex, CompileError) { - compile(pattern, Options(case_insensitive: False, multi_line: False)) -} - -/// Returns a boolean indicating whether there was a match or not. -/// -/// ## Examples -/// -/// ```gleam -/// > let assert Ok(re) = from_string("^f.o.?") -/// > check(with: re, content: "foo") -/// True -/// ``` -/// -/// ```gleam -/// > check(with: re, content: "boo") -/// False -/// ``` -/// -pub fn check(with regex: Regex, content content: String) -> Bool { - do_check(regex, content) -} - -@external(erlang, "gleam_stdlib", "regex_check") -@external(javascript, "../gleam_stdlib.mjs", "regex_check") -fn do_check(a: Regex, b: String) -> Bool - -/// Splits a string. -/// -/// ## Examples -/// -/// ```gleam -/// > let assert Ok(re) = from_string(" *, *") -/// > split(with: re, content: "foo,32, 4, 9 ,0") -/// ["foo", "32", "4", "9", "0"] -/// ``` -/// -pub fn split(with regex: Regex, content string: String) -> List(String) { - do_split(regex, string) -} - -@target(erlang) -@external(erlang, "gleam_stdlib", "regex_split") -fn do_split(a: Regex, b: String) -> List(String) - -@target(javascript) -fn do_split(regex, string) -> List(String) { - js_split(string, regex) -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "split") -fn js_split(a: String, b: Regex) -> List(String) - -/// Collects all matches of the regular expression. -/// -/// ## Examples -/// -/// ```gleam -/// > let assert Ok(re) = from_string("[oi]n a (\\w+)") -/// > scan(with: re, content: "I am on a boat in a lake.") -/// [ -/// Match( -/// content: "on a boat", -/// submatches: [Some("boat")] -/// ), -/// Match( -/// content: "in a lake", -/// submatches: [Some("lake")] -/// ) -/// ] -/// ``` -/// -/// ```gleam -/// > let assert Ok(re) = regex.from_string("([+|\\-])?(\\d+)(\\w+)?") -/// > scan(with: re, content: "-36") -/// [ -/// Match( -/// content: "-36", -/// submatches: [Some("-"), Some("36")] -/// ) -/// ] -/// -/// > scan(with: re, content: "36") -/// [ -/// Match( -/// content: "36", -/// submatches: [None, Some("36")] -/// ) -/// ] -/// ``` -/// -/// ```gleam -/// > let assert Ok(re) = regex.from_string("var\\s*(\\w+)\\s*(int|string)?\\s*=\\s*(.*)") -/// > scan(with: re, content: "var age = 32") -/// [ -/// Match( -/// content: "var age = 32", -/// submatches: [Some("age"), None, Some("32")] -/// ) -/// ] -/// ``` -/// -/// ```gleam -/// > let assert Ok(re) = regex.from_string("let (\\w+) = (\\w+)") -/// > scan(with: re, content: "let age = 32") -/// [ -/// Match( -/// content: "let age = 32", -/// submatches: [Some("age"), Some("32")] -/// ) -/// ] -/// -/// > scan(with: re, content: "const age = 32") -/// [] -/// ``` -/// -pub fn scan(with regex: Regex, content string: String) -> List(Match) { - do_scan(regex, string) -} - -@external(erlang, "gleam_stdlib", "regex_scan") -@external(javascript, "../gleam_stdlib.mjs", "regex_scan") -fn do_scan(a: Regex, b: String) -> List(Match) diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/result.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/result.gleam deleted file mode 100644 index fb6dddb..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/result.gleam +++ /dev/null @@ -1,482 +0,0 @@ -//// Result represents the result of something that may succeed or not. -//// `Ok` means it was successful, `Error` means it was not successful. - -import gleam/list - -/// Checks whether the result is an `Ok` value. -/// -/// ## Examples -/// -/// ```gleam -/// > is_ok(Ok(1)) -/// True -/// ``` -/// -/// ```gleam -/// > is_ok(Error(Nil)) -/// False -/// ``` -/// -pub fn is_ok(result: Result(a, e)) -> Bool { - case result { - Error(_) -> False - Ok(_) -> True - } -} - -/// Checks whether the result is an `Error` value. -/// -/// ## Examples -/// -/// ```gleam -/// > is_error(Ok(1)) -/// False -/// ``` -/// -/// ```gleam -/// > is_error(Error(Nil)) -/// True -/// ``` -/// -pub fn is_error(result: Result(a, e)) -> Bool { - case result { - Ok(_) -> False - Error(_) -> True - } -} - -/// Updates a value held within the `Ok` of a result by calling a given function -/// on it. -/// -/// If the result is an `Error` rather than `Ok` the function is not called and the -/// result stays the same. -/// -/// ## Examples -/// -/// ```gleam -/// > map(over: Ok(1), with: fn(x) { x + 1 }) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > map(over: Error(1), with: fn(x) { x + 1 }) -/// Error(1) -/// ``` -/// -pub fn map(over result: Result(a, e), with fun: fn(a) -> b) -> Result(b, e) { - case result { - Ok(x) -> Ok(fun(x)) - Error(e) -> Error(e) - } -} - -/// Updates a value held within the `Error` of a result by calling a given function -/// on it. -/// -/// If the result is `Ok` rather than `Error` the function is not called and the -/// result stays the same. -/// -/// ## Examples -/// -/// ```gleam -/// > map_error(over: Error(1), with: fn(x) { x + 1 }) -/// Error(2) -/// ``` -/// -/// ```gleam -/// > map_error(over: Ok(1), with: fn(x) { x + 1 }) -/// Ok(1) -/// ``` -/// -pub fn map_error( - over result: Result(a, e), - with fun: fn(e) -> f, -) -> Result(a, f) { - case result { - Ok(x) -> Ok(x) - Error(error) -> Error(fun(error)) - } -} - -/// Merges a nested `Result` into a single layer. -/// -/// ## Examples -/// -/// ```gleam -/// > flatten(Ok(Ok(1))) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > flatten(Ok(Error(""))) -/// Error("") -/// ``` -/// -/// ```gleam -/// > flatten(Error(Nil)) -/// Error(Nil) -/// ``` -/// -pub fn flatten(result: Result(Result(a, e), e)) -> Result(a, e) { - case result { - Ok(x) -> x - Error(error) -> Error(error) - } -} - -/// "Updates" an `Ok` result by passing its value to a function that yields a result, -/// and returning the yielded result. (This may "replace" the `Ok` with an `Error`.) -/// -/// If the input is an `Error` rather than an `Ok`, the function is not called and -/// the original `Error` is returned. -/// -/// This function is the equivalent of calling `map` followed by `flatten`, and -/// it is useful for chaining together multiple functions that may fail. -/// -/// ## Examples -/// -/// ```gleam -/// > try(Ok(1), fn(x) { Ok(x + 1) }) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > try(Ok(1), fn(x) { Ok(#("a", x)) }) -/// Ok(#("a", 1)) -/// ``` -/// -/// ```gleam -/// > try(Ok(1), fn(_) { Error("Oh no") }) -/// Error("Oh no") -/// ``` -/// -/// ```gleam -/// > try(Error(Nil), fn(x) { Ok(x + 1) }) -/// Error(Nil) -/// ``` -/// -pub fn try( - result: Result(a, e), - apply fun: fn(a) -> Result(b, e), -) -> Result(b, e) { - case result { - Ok(x) -> fun(x) - Error(e) -> Error(e) - } -} - -/// An alias for `try`. See the documentation for that function for more information. -/// -pub fn then( - result: Result(a, e), - apply fun: fn(a) -> Result(b, e), -) -> Result(b, e) { - try(result, fun) -} - -/// Extracts the `Ok` value from a result, returning a default value if the result -/// is an `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// > unwrap(Ok(1), 0) -/// 1 -/// ``` -/// -/// ```gleam -/// > unwrap(Error(""), 0) -/// 0 -/// ``` -/// -pub fn unwrap(result: Result(a, e), or default: a) -> a { - case result { - Ok(v) -> v - Error(_) -> default - } -} - -/// Extracts the `Ok` value from a result, evaluating the default function if the result -/// is an `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// > lazy_unwrap(Ok(1), fn() { 0 }) -/// 1 -/// ``` -/// -/// ```gleam -/// > lazy_unwrap(Error(""), fn() { 0 }) -/// 0 -/// ``` -/// -pub fn lazy_unwrap(result: Result(a, e), or default: fn() -> a) -> a { - case result { - Ok(v) -> v - Error(_) -> default() - } -} - -/// Extracts the `Error` value from a result, returning a default value if the result -/// is an `Ok`. -/// -/// ## Examples -/// -/// ```gleam -/// > unwrap_error(Error(1), 0) -/// 1 -/// ``` -/// -/// ```gleam -/// > unwrap_error(Ok(""), 0) -/// 0 -/// ``` -/// -pub fn unwrap_error(result: Result(a, e), or default: e) -> e { - case result { - Ok(_) -> default - Error(e) -> e - } -} - -/// Extracts the inner value from a result. Both the value and error must be of -/// the same type. -/// -/// ## Examples -/// -/// ```gleam -/// > unwrap_both(Error(1)) -/// 1 -/// ``` -/// -/// ```gleam -/// > unwrap_both(Ok(2)) -/// 2 -/// ``` -/// -pub fn unwrap_both(result: Result(a, a)) -> a { - case result { - Ok(a) -> a - Error(a) -> a - } -} - -/// Transforms any error into `Error(Nil)`. -/// -/// ## Examples -/// -/// ```gleam -/// > nil_error(Error(1)) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > nil_error(Ok(1)) -/// Ok(1) -/// ``` -/// -pub fn nil_error(result: Result(a, e)) -> Result(a, Nil) { - map_error(result, fn(_) { Nil }) -} - -/// Returns the first value if it is `Ok`, otherwise returns the second value. -/// -/// ## Examples -/// -/// ```gleam -/// > or(Ok(1), Ok(2)) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > or(Ok(1), Error("Error 2")) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > or(Error("Error 1"), Ok(2)) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > or(Error("Error 1"), Error("Error 2")) -/// Error("Error 2") -/// ``` -/// -pub fn or(first: Result(a, e), second: Result(a, e)) -> Result(a, e) { - case first { - Ok(_) -> first - Error(_) -> second - } -} - -/// Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value. -/// -/// ## Examples -/// -/// ```gleam -/// > lazy_or(Ok(1), fn() { Ok(2) }) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > lazy_or(Ok(1), fn() { Error("Error 2") }) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > lazy_or(Error("Error 1"), fn() { Ok(2) }) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > lazy_or(Error("Error 1"), fn() { Error("Error 2") }) -/// Error("Error 2") -/// ``` -/// -pub fn lazy_or( - first: Result(a, e), - second: fn() -> Result(a, e), -) -> Result(a, e) { - case first { - Ok(_) -> first - Error(_) -> second() - } -} - -/// Combines a list of results into a single result. -/// If all elements in the list are `Ok` then returns an `Ok` holding the list of values. -/// If any element is `Error` then returns the first error. -/// -/// ## Examples -/// -/// ```gleam -/// > all([Ok(1), Ok(2)]) -/// Ok([1, 2]) -/// ``` -/// -/// ```gleam -/// > all([Ok(1), Error("e")]) -/// Error("e") -/// ``` -/// -pub fn all(results: List(Result(a, e))) -> Result(List(a), e) { - list.try_map(results, fn(x) { x }) -} - -/// Given a list of results, returns a pair where the first element is a list -/// of all the values inside `Ok` and the second element is a list with all the -/// values inside `Error`. The values in both lists appear in reverse order with -/// respect to their position in the original list of results. -/// -/// ## Examples -/// -/// ```gleam -/// > partition([Ok(1), Error("a"), Error("b"), Ok(2)]) -/// #([2, 1], ["b", "a"]) -/// ``` -/// -pub fn partition(results: List(Result(a, e))) -> #(List(a), List(e)) { - do_partition(results, [], []) -} - -fn do_partition(results: List(Result(a, e)), oks: List(a), errors: List(e)) { - case results { - [] -> #(oks, errors) - [Ok(a), ..rest] -> do_partition(rest, [a, ..oks], errors) - [Error(e), ..rest] -> do_partition(rest, oks, [e, ..errors]) - } -} - -/// Replace the value within a result -/// -/// ## Examples -/// -/// ```gleam -/// > replace(Ok(1), Nil) -/// Ok(Nil) -/// ``` -/// -/// ```gleam -/// > replace(Error(1), Nil) -/// Error(1) -/// ``` -/// -pub fn replace(result: Result(a, e), value: b) -> Result(b, e) { - case result { - Ok(_) -> Ok(value) - Error(error) -> Error(error) - } -} - -/// Replace the error within a result -/// -/// ## Examples -/// -/// ```gleam -/// > replace_error(Error(1), Nil) -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > replace_error(Ok(1), Nil) -/// Ok(1) -/// ``` -/// -pub fn replace_error(result: Result(a, e1), error: e2) -> Result(a, e2) { - case result { - Ok(x) -> Ok(x) - Error(_) -> Error(error) - } -} - -/// Given a list of results, returns only the values inside `Ok`. -/// -/// ## Examples -/// -/// ```gleam -/// > values([Ok(1), Error("a"), Ok(3)]) -/// [1, 3] -/// ``` -/// -pub fn values(results: List(Result(a, e))) -> List(a) { - list.filter_map(results, fn(r) { r }) -} - -/// Updates a value held within the `Error` of a result by calling a given function -/// on it, where the given function also returns a result. The two results are -/// then merged together into one result. -/// -/// If the result is an `Ok` rather than `Error` the function is not called and the -/// result stays the same. -/// -/// This function is useful for chaining together computations that may fail -/// and trying to recover from possible errors. -/// -/// ## Examples -/// -/// ```gleam -/// > Ok(1) |> try_recover(with: fn(_) { Error("failed to recover") }) -/// Ok(1) -/// ``` -/// -/// ```gleam -/// > Error(1) |> try_recover(with: fn(error) { Ok(error + 1) }) -/// Ok(2) -/// ``` -/// -/// ```gleam -/// > Error(1) |> try_recover(with: fn(error) { Error("failed to recover") }) -/// Error("failed to recover") -/// ``` -/// -pub fn try_recover( - result: Result(a, e), - with fun: fn(e) -> Result(a, f), -) -> Result(a, f) { - case result { - Ok(value) -> Ok(value) - Error(error) -> fun(error) - } -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/set.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/set.gleam deleted file mode 100644 index df8d500..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/set.gleam +++ /dev/null @@ -1,264 +0,0 @@ -import gleam/list -import gleam/dict.{type Dict} -import gleam/result - -// A list is used as the map value as an empty list has the smallest -// representation in Erlang's binary format -@target(erlang) -type Token = - List(Nil) - -@target(erlang) -const token = [] - -@target(javascript) -type Token = - Nil - -@target(javascript) -const token = Nil - -/// A set is a collection of unique members of the same type. -/// -/// It is implemented using the `gleam/map` module, so inserts and lookups have -/// logarithmic time complexity. -/// -pub opaque type Set(member) { - Set(map: Dict(member, Token)) -} - -/// Creates a new empty set. -/// -pub fn new() -> Set(member) { - Set(dict.new()) -} - -/// Gets the number of members in a set. -/// -/// This function runs in constant time. -/// -/// ## Examples -/// -/// ```gleam -/// > new() -/// > |> insert(1) -/// > |> insert(2) -/// > |> size -/// 2 -/// ``` -/// -pub fn size(set: Set(member)) -> Int { - dict.size(set.map) -} - -/// Inserts an member into the set. -/// -/// This function runs in logarithmic time. -/// -/// ## Examples -/// -/// ```gleam -/// > new() -/// > |> insert(1) -/// > |> insert(2) -/// > |> size -/// 2 -/// ``` -/// -pub fn insert(into set: Set(member), this member: member) -> Set(member) { - Set(map: dict.insert(set.map, member, token)) -} - -/// Checks whether a set contains a given member. -/// -/// This function runs in logarithmic time. -/// -/// ## Examples -/// -/// ```gleam -/// > new() -/// > |> insert(2) -/// > |> contains(2) -/// True -/// ``` -/// -/// ```gleam -/// > new() -/// > |> insert(2) -/// > |> contains(1) -/// False -/// ``` -/// -pub fn contains(in set: Set(member), this member: member) -> Bool { - set.map - |> dict.get(member) - |> result.is_ok -} - -/// Removes a member from a set. If the set does not contain the member then -/// the set is returned unchanged. -/// -/// This function runs in logarithmic time. -/// -/// ## Examples -/// -/// ```gleam -/// > new() -/// > |> insert(2) -/// > |> delete(2) -/// > |> contains(1) -/// False -/// ``` -/// -pub fn delete(from set: Set(member), this member: member) -> Set(member) { - Set(map: dict.delete(set.map, member)) -} - -/// Converts the set into a list of the contained members. -/// -/// The list has no specific ordering, any unintentional ordering may change in -/// future versions of Gleam or Erlang. -/// -/// This function runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// > new() |> insert(2) |> to_list -/// [2] -/// ``` -/// -pub fn to_list(set: Set(member)) -> List(member) { - dict.keys(set.map) -} - -/// Creates a new set of the members in a given list. -/// -/// This function runs in loglinear time. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/list -/// > [1, 1, 2, 4, 3, 2] |> from_list |> to_list |> list.sort -/// [1, 3, 3, 4] -/// ``` -/// -pub fn from_list(members: List(member)) -> Set(member) { - let map = - list.fold( - over: members, - from: dict.new(), - with: fn(m, k) { dict.insert(m, k, token) }, - ) - Set(map) -} - -/// Combines all entries into a single value by calling a given function on each -/// one. -/// -/// Sets are not ordered so the values are not returned in any specific order. -/// Do not write code that relies on the order entries are used by this -/// function as it may change in later versions of Gleam or Erlang. -/// -/// # Examples -/// -/// ```gleam -/// > from_list([1, 3, 9]) -/// > |> fold(0, fn(member, accumulator) { accumulator + member }) -/// 13 -/// ``` -/// -pub fn fold( - over set: Set(member), - from initial: acc, - with reducer: fn(acc, member) -> acc, -) -> acc { - dict.fold(over: set.map, from: initial, with: fn(a, k, _) { reducer(a, k) }) -} - -/// Creates a new set from an existing set, minus any members that a given -/// function returns `False` for. -/// -/// This function runs in loglinear time. -/// -/// ## Examples -/// -/// ```gleam -/// > import gleam/int -/// > from_list([1, 4, 6, 3, 675, 44, 67]) -/// > |> filter(for: int.is_even) -/// > |> to_list -/// [4, 6, 44] -/// ``` -/// -pub fn filter( - in set: Set(member), - keeping predicate: fn(member) -> Bool, -) -> Set(member) { - Set(dict.filter(in: set.map, keeping: fn(m, _) { predicate(m) })) -} - -pub fn drop(from set: Set(member), drop disallowed: List(member)) -> Set(member) { - list.fold(over: disallowed, from: set, with: delete) -} - -/// Creates a new map from a given map, only including any members which are in -/// a given list. -/// -/// This function runs in loglinear time. -/// -/// ## Examples -/// -/// ```gleam -/// > from_list([1, 2, 3]) -/// > |> take([1, 3, 5]) -/// > |> to_list -/// [1, 3] -/// ``` -/// -pub fn take(from set: Set(member), keeping desired: List(member)) -> Set(member) { - Set(dict.take(from: set.map, keeping: desired)) -} - -fn order(first: Set(member), second: Set(member)) -> #(Set(member), Set(member)) { - case dict.size(first.map) > dict.size(second.map) { - True -> #(first, second) - False -> #(second, first) - } -} - -/// Creates a new set that contains all members of both given sets. -/// -/// This function runs in loglinear time. -/// -/// ## Examples -/// -/// ```gleam -/// > union(from_list([1, 2]), from_list([2, 3])) |> to_list -/// [1, 2, 3] -/// ``` -/// -pub fn union(of first: Set(member), and second: Set(member)) -> Set(member) { - let #(larger, smaller) = order(first, second) - fold(over: smaller, from: larger, with: insert) -} - -/// Creates a new set that contains members that are present in both given sets. -/// -/// This function runs in loglinear time. -/// -/// ## Examples -/// -/// ```gleam -/// > intersection(from_list([1, 2]), from_list([2, 3])) |> to_list -/// [2] -/// ``` -/// -pub fn intersection( - of first: Set(member), - and second: Set(member), -) -> Set(member) { - let #(larger, smaller) = order(first, second) - take(from: larger, keeping: to_list(smaller)) -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/string.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/string.gleam deleted file mode 100644 index d4496f3..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/string.gleam +++ /dev/null @@ -1,906 +0,0 @@ -//// Strings in Gleam are UTF-8 binaries. They can be written in your code as -//// text surrounded by `"double quotes"`. - -import gleam/iterator.{type Iterator} -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/order -import gleam/string_builder.{type StringBuilder} - -/// Determines if a `String` is empty. -/// -/// ## Examples -/// -/// ```gleam -/// > is_empty("") -/// True -/// ``` -/// -/// ```gleam -/// > is_empty("the world") -/// False -/// ``` -/// -pub fn is_empty(str: String) -> Bool { - str == "" -} - -/// Gets the number of grapheme clusters in a given `String`. -/// -/// This function has to iterate across the whole string to count the number of -/// graphemes, so it runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// > length("Gleam") -/// 5 -/// ``` -/// -/// ```gleam -/// > length("ß↑e̊") -/// 3 -/// ``` -/// -/// ```gleam -/// > length("") -/// 0 -/// ``` -/// -pub fn length(string: String) -> Int { - do_length(string) -} - -@external(erlang, "string", "length") -@external(javascript, "../gleam_stdlib.mjs", "string_length") -fn do_length(a: String) -> Int - -/// Reverses a `String`. -/// -/// This function has to iterate across the whole `String` so it runs in linear -/// time. -/// -/// ## Examples -/// -/// ```gleam -/// > reverse("stressed") -/// "desserts" -/// ``` -/// -pub fn reverse(string: String) -> String { - do_reverse(string) -} - -@target(erlang) -fn do_reverse(string: String) -> String { - string - |> string_builder.from_string - |> string_builder.reverse - |> string_builder.to_string -} - -@target(javascript) -fn do_reverse(string: String) -> String { - string - |> to_graphemes - |> list.reverse - |> concat -} - -/// Creates a new `String` by replacing all occurrences of a given substring. -/// -/// ## Examples -/// -/// ```gleam -/// > replace("www.example.com", each: ".", with: "-") -/// "www-example-com" -/// ``` -/// -/// ```gleam -/// > replace("a,b,c,d,e", each: ",", with: "/") -/// "a/b/c/d/e" -/// ``` -/// -pub fn replace( - in string: String, - each pattern: String, - with substitute: String, -) -> String { - string - |> string_builder.from_string - |> string_builder.replace(each: pattern, with: substitute) - |> string_builder.to_string -} - -/// Creates a new `String` with all the graphemes in the input `String` converted to -/// lowercase. -/// -/// Useful for case-insensitive comparisons. -/// -/// ## Examples -/// -/// ```gleam -/// > lowercase("X-FILES") -/// "x-files" -/// ``` -/// -pub fn lowercase(string: String) -> String { - do_lowercase(string) -} - -@external(erlang, "string", "lowercase") -@external(javascript, "../gleam_stdlib.mjs", "lowercase") -fn do_lowercase(a: String) -> String - -/// Creates a new `String` with all the graphemes in the input `String` converted to -/// uppercase. -/// -/// Useful for case-insensitive comparisons and VIRTUAL YELLING. -/// -/// ## Examples -/// -/// ```gleam -/// > uppercase("skinner") -/// "SKINNER" -/// ``` -/// -pub fn uppercase(string: String) -> String { - do_uppercase(string) -} - -@external(erlang, "string", "uppercase") -@external(javascript, "../gleam_stdlib.mjs", "uppercase") -fn do_uppercase(a: String) -> String - -/// Compares two `String`s to see which is "larger" by comparing their graphemes. -/// -/// This does not compare the size or length of the given `String`s. -/// -/// ## Examples -/// -/// ```gleam -/// > compare("Anthony", "Anthony") -/// order.Eq -/// ``` -/// -/// ```gleam -/// > compare("A", "B") -/// order.Lt -/// ``` -/// -pub fn compare(a: String, b: String) -> order.Order { - case a == b { - True -> order.Eq - _ -> - case less_than(a, b) { - True -> order.Lt - _ -> order.Gt - } - } -} - -@external(erlang, "gleam_stdlib", "less_than") -@external(javascript, "../gleam_stdlib.mjs", "less_than") -fn less_than(a: String, b: String) -> Bool - -/// Takes a substring given a start grapheme index and a length. Negative indexes -/// are taken starting from the *end* of the list. -/// -/// ## Examples -/// -/// ```gleam -/// > slice(from: "gleam", at_index: 1, length: 2) -/// "le" -/// ``` -/// -/// ```gleam -/// > slice(from: "gleam", at_index: 1, length: 10) -/// "leam" -/// ``` -/// -/// ```gleam -/// > slice(from: "gleam", at_index: 10, length: 3) -/// "" -/// ``` -/// -/// ```gleam -/// > slice(from: "gleam", at_index: -2, length: 2) -/// "am" -/// ``` -/// -/// ```gleam -/// > slice(from: "gleam", at_index: -12, length: 2) -/// "" -/// ``` -/// -pub fn slice(from string: String, at_index idx: Int, length len: Int) -> String { - case len < 0 { - True -> "" - False -> - case idx < 0 { - True -> { - let translated_idx = length(string) + idx - case translated_idx < 0 { - True -> "" - False -> do_slice(string, translated_idx, len) - } - } - False -> do_slice(string, idx, len) - } - } -} - -@target(erlang) -@external(erlang, "string", "slice") -fn do_slice(a: String, b: Int, c: Int) -> String - -@target(javascript) -fn do_slice(string: String, idx: Int, len: Int) -> String { - string - |> to_graphemes - |> list.drop(idx) - |> list.take(len) - |> concat -} - -/// Drops contents of the first `String` that occur before the second `String`. -/// If the `from` string does not contain the `before` string, `from` is returned unchanged. -/// -/// ## Examples -/// -/// ```gleam -/// > crop(from: "The Lone Gunmen", before: "Lone") -/// "Lone Gunmen" -/// ``` -/// -@external(erlang, "gleam_stdlib", "crop_string") -@external(javascript, "../gleam_stdlib.mjs", "crop_string") -pub fn crop(from string: String, before substring: String) -> String - -/// Drops *n* graphemes from the left side of a `String`. -/// -/// ## Examples -/// -/// ```gleam -/// > drop_left(from: "The Lone Gunmen", up_to: 2) -/// "e Lone Gunmen" -/// ``` -/// -pub fn drop_left(from string: String, up_to num_graphemes: Int) -> String { - case num_graphemes < 0 { - True -> string - False -> slice(string, num_graphemes, length(string) - num_graphemes) - } -} - -/// Drops *n* graphemes from the right side of a `String`. -/// -/// ## Examples -/// -/// ```gleam -/// > drop_right(from: "Cigarette Smoking Man", up_to: 2) -/// "Cigarette Smoking M" -/// ``` -/// -pub fn drop_right(from string: String, up_to num_graphemes: Int) -> String { - case num_graphemes < 0 { - True -> string - False -> slice(string, 0, length(string) - num_graphemes) - } -} - -/// Checks if the first `String` contains the second. -/// -/// ## Examples -/// -/// ```gleam -/// > contains(does: "theory", contain: "ory") -/// True -/// ``` -/// -/// ```gleam -/// > contains(does: "theory", contain: "the") -/// True -/// ``` -/// -/// ```gleam -/// > contains(does: "theory", contain: "THE") -/// False -/// ``` -/// -@external(erlang, "gleam_stdlib", "contains_string") -@external(javascript, "../gleam_stdlib.mjs", "contains_string") -pub fn contains(does haystack: String, contain needle: String) -> Bool - -/// Checks whether the first `String` starts with the second one. -/// -/// ## Examples -/// -/// ```gleam -/// > starts_with("theory", "ory") -/// False -/// ``` -/// -pub fn starts_with(string: String, prefix: String) -> Bool { - do_starts_with(string, prefix) -} - -@external(erlang, "gleam_stdlib", "string_starts_with") -@external(javascript, "../gleam_stdlib.mjs", "starts_with") -fn do_starts_with(a: String, b: String) -> Bool - -/// Checks whether the first `String` ends with the second one. -/// -/// ## Examples -/// -/// ```gleam -/// > ends_with("theory", "ory") -/// True -/// ``` -/// -pub fn ends_with(string: String, suffix: String) -> Bool { - do_ends_with(string, suffix) -} - -@external(erlang, "gleam_stdlib", "string_ends_with") -@external(javascript, "../gleam_stdlib.mjs", "ends_with") -fn do_ends_with(a: String, b: String) -> Bool - -/// Creates a list of `String`s by splitting a given string on a given substring. -/// -/// ## Examples -/// -/// ```gleam -/// > split("home/gleam/desktop/", on: "/") -/// ["home", "gleam", "desktop", ""] -/// ``` -/// -pub fn split(x: String, on substring: String) -> List(String) { - case substring { - "" -> to_graphemes(x) - _ -> - x - |> string_builder.from_string - |> string_builder.split(on: substring) - |> list.map(with: string_builder.to_string) - } -} - -/// Splits a `String` a single time on the given substring. -/// -/// Returns an `Error` if substring not present. -/// -/// ## Examples -/// -/// ```gleam -/// > split_once("home/gleam/desktop/", on: "/") -/// Ok(#("home", "gleam/desktop/")) -/// ``` -/// -/// ```gleam -/// > split_once("home/gleam/desktop/", on: "?") -/// Error(Nil) -/// ``` -/// -pub fn split_once( - x: String, - on substring: String, -) -> Result(#(String, String), Nil) { - do_split_once(x, substring) -} - -@target(erlang) -@external(erlang, "string", "split") -fn erl_split(a: String, b: String) -> List(String) - -@target(erlang) -fn do_split_once(x: String, substring: String) -> Result(#(String, String), Nil) { - case erl_split(x, substring) { - [first, rest] -> Ok(#(first, rest)) - _ -> Error(Nil) - } -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "split_once") -fn do_split_once( - x x: String, - substring substring: String, -) -> Result(#(String, String), Nil) - -/// Creates a new `String` by joining two `String`s together. -/// -/// This function copies both `String`s and runs in linear time. If you find -/// yourself joining `String`s frequently consider using the [`string_builder`](../gleam/string_builder.html) -/// module as it can append `String`s much faster! -/// -/// ## Examples -/// -/// ```gleam -/// > append(to: "butter", suffix: "fly") -/// "butterfly" -/// ``` -/// -pub fn append(to first: String, suffix second: String) -> String { - first - |> string_builder.from_string - |> string_builder.append(second) - |> string_builder.to_string -} - -/// Creates a new `String` by joining many `String`s together. -/// -/// This function copies both `String`s and runs in linear time. If you find -/// yourself joining `String`s frequently consider using the [`string_builder`](../gleam/string_builder.html) -/// module as it can append `String`s much faster! -/// -/// ## Examples -/// -/// ```gleam -/// > concat(["never", "the", "less"]) -/// "nevertheless" -/// ``` -/// -pub fn concat(strings: List(String)) -> String { - strings - |> string_builder.from_strings - |> string_builder.to_string -} - -/// Creates a new `String` by repeating a `String` a given number of times. -/// -/// This function runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// > repeat("ha", times: 3) -/// "hahaha" -/// ``` -/// -pub fn repeat(string: String, times times: Int) -> String { - iterator.repeat(string) - |> iterator.take(times) - |> iterator.to_list - |> concat -} - -/// Joins many `String`s together with a given separator. -/// -/// This function runs in linear time. -/// -/// ## Examples -/// -/// ```gleam -/// > join(["home","evan","Desktop"], with: "/") -/// "home/evan/Desktop" -/// ``` -/// -pub fn join(strings: List(String), with separator: String) -> String { - do_join(strings, separator) -} - -@target(erlang) -fn do_join(strings: List(String), separator: String) -> String { - strings - |> list.intersperse(with: separator) - |> concat -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "join") -fn do_join(strings strings: List(String), string string: String) -> String - -/// Pads a `String` on the left until it has at least given number of graphemes. -/// -/// ## Examples -/// -/// ```gleam -/// > pad_left("121", to: 5, with: ".") -/// "..121" -/// ``` -/// -/// ```gleam -/// > pad_left("121", to: 3, with: ".") -/// "121" -/// ``` -/// -/// ```gleam -/// > pad_left("121", to: 2, with: ".") -/// "121" -/// ``` -/// -pub fn pad_left(string: String, to desired_length: Int, with pad_string: String) { - let current_length = length(string) - let to_pad_length = desired_length - current_length - padding(to_pad_length, pad_string) - |> iterator.append(iterator.single(string)) - |> iterator.to_list - |> concat -} - -/// Pads a `String` on the right until it has a given length. -/// -/// ## Examples -/// -/// ```gleam -/// > pad_right("123", to: 5, with: ".") -/// "123.." -/// ``` -/// -/// ```gleam -/// > pad_right("123", to: 3, with: ".") -/// "123" -/// ``` -/// -/// ```gleam -/// > pad_right("123", to: 2, with: ".") -/// "123" -/// ``` -/// -pub fn pad_right( - string: String, - to desired_length: Int, - with pad_string: String, -) { - let current_length = length(string) - let to_pad_length = desired_length - current_length - iterator.single(string) - |> iterator.append(padding(to_pad_length, pad_string)) - |> iterator.to_list - |> concat -} - -fn padding(size: Int, pad_string: String) -> Iterator(String) { - let pad_length = length(pad_string) - let num_pads = size / pad_length - let extra = size % pad_length - iterator.repeat(pad_string) - |> iterator.take(num_pads) - |> iterator.append(iterator.single(slice(pad_string, 0, extra))) -} - -/// Removes whitespace on both sides of a `String`. -/// -/// ## Examples -/// -/// ```gleam -/// > trim(" hats \n") -/// "hats" -/// ``` -/// -pub fn trim(string: String) -> String { - do_trim(string) -} - -@target(erlang) -fn do_trim(string: String) -> String { - erl_trim(string, Both) -} - -@target(erlang) -type Direction { - Leading - Trailing - Both -} - -@target(erlang) -@external(erlang, "string", "trim") -fn erl_trim(a: String, b: Direction) -> String - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "trim") -fn do_trim(string string: String) -> String - -/// Removes whitespace on the left of a `String`. -/// -/// ## Examples -/// -/// ```gleam -/// > trim_left(" hats \n") -/// "hats \n" -/// ``` -/// -pub fn trim_left(string: String) -> String { - do_trim_left(string) -} - -@target(erlang) -fn do_trim_left(string: String) -> String { - erl_trim(string, Leading) -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "trim_left") -fn do_trim_left(string string: String) -> String - -/// Removes whitespace on the right of a `String`. -/// -/// ## Examples -/// -/// ```gleam -/// > trim_right(" hats \n") -/// " hats" -/// ``` -/// -pub fn trim_right(string: String) -> String { - do_trim_right(string) -} - -@target(erlang) -fn do_trim_right(string: String) -> String { - erl_trim(string, Trailing) -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "trim_right") -fn do_trim_right(string string: String) -> String - -/// Splits a non-empty `String` into its first element (head) and rest (tail). -/// This lets you pattern match on `String`s exactly as you would with lists. -/// -/// Note on JavaScript using the function to iterate over a string will likely -/// be slower than using `to_graphemes` due to string slicing being more -/// expensive on JavaScript than Erlang. -/// -/// ## Examples -/// -/// ```gleam -/// > pop_grapheme("gleam") -/// Ok(#("g", "leam")) -/// ``` -/// -/// ```gleam -/// > pop_grapheme("") -/// Error(Nil) -/// ``` -/// -pub fn pop_grapheme(string: String) -> Result(#(String, String), Nil) { - do_pop_grapheme(string) -} - -@external(erlang, "gleam_stdlib", "string_pop_grapheme") -@external(javascript, "../gleam_stdlib.mjs", "pop_grapheme") -fn do_pop_grapheme(string string: String) -> Result(#(String, String), Nil) - -/// Converts a `String` to a list of -/// [graphemes](https://en.wikipedia.org/wiki/Grapheme). -/// -/// ```gleam -/// > to_graphemes("abc") -/// ["a", "b", "c"] -/// ``` -/// -@external(javascript, "../gleam_stdlib.mjs", "graphemes") -pub fn to_graphemes(string: String) -> List(String) { - do_to_graphemes(string, []) - |> list.reverse -} - -fn do_to_graphemes(string: String, acc: List(String)) -> List(String) { - case pop_grapheme(string) { - Ok(#(grapheme, rest)) -> do_to_graphemes(rest, [grapheme, ..acc]) - _ -> acc - } -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "codepoint") -fn unsafe_int_to_utf_codepoint(a: Int) -> UtfCodepoint - -/// Converts a `String` to a `List` of `UtfCodepoint`. -/// -/// See <https://en.wikipedia.org/wiki/Code_point> and -/// <https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points> for an -/// explanation on code points. -/// -/// ## Examples -/// -/// ```gleam -/// > "a" |> to_utf_codepoints -/// [UtfCodepoint(97)] -/// ``` -/// -/// ```gleam -/// // Semantically the same as: -/// // ["🏳", "️", "", "🌈"] or: -/// // [waving_white_flag, variant_selector_16, zero_width_joiner, rainbow] -/// > "🏳️🌈" |> to_utf_codepoints -/// [UtfCodepoint(127987), UtfCodepoint(65039), UtfCodepoint(8205), UtfCodepoint(127752)] -/// ``` -/// -pub fn to_utf_codepoints(string: String) -> List(UtfCodepoint) { - do_to_utf_codepoints(string) -} - -@target(erlang) -fn do_to_utf_codepoints(string: String) -> List(UtfCodepoint) { - do_to_utf_codepoints_impl(<<string:utf8>>, []) - |> list.reverse -} - -@target(erlang) -fn do_to_utf_codepoints_impl( - bit_array: BitArray, - acc: List(UtfCodepoint), -) -> List(UtfCodepoint) { - case bit_array { - <<first:utf8_codepoint, rest:bytes>> -> - do_to_utf_codepoints_impl(rest, [first, ..acc]) - _ -> acc - } -} - -@target(javascript) -fn do_to_utf_codepoints(string: String) -> List(UtfCodepoint) { - string - |> string_to_codepoint_integer_list - |> list.map(unsafe_int_to_utf_codepoint) -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "string_to_codepoint_integer_list") -fn string_to_codepoint_integer_list(a: String) -> List(Int) - -/// Converts a `List` of `UtfCodepoint`s to a `String`. -/// -/// See <https://en.wikipedia.org/wiki/Code_point> and -/// <https://en.wikipedia.org/wiki/Unicode#Codespace_and_Code_Points> for an -/// explanation on code points. -/// -/// ## Examples -/// -/// ```gleam -/// > { -/// > let assert #(Ok(a), Ok(b), Ok(c)) = #( -/// > utf_codepoint(97), -/// > utf_codepoint(98), -/// > utf_codepoint(99), -/// > ) -/// > [a, b, c] -/// > } -/// > |> from_utf_codepoints -/// "abc" -/// ``` -/// -@external(erlang, "gleam_stdlib", "utf_codepoint_list_to_string") -@external(javascript, "../gleam_stdlib.mjs", "utf_codepoint_list_to_string") -pub fn from_utf_codepoints(utf_codepoints: List(UtfCodepoint)) -> String - -/// Converts an integer to a `UtfCodepoint`. -/// -/// Returns an `Error` if the integer does not represent a valid UTF codepoint. -/// -pub fn utf_codepoint(value: Int) -> Result(UtfCodepoint, Nil) { - case value { - i if i > 1_114_111 -> Error(Nil) - 65_534 | 65_535 -> Error(Nil) - i if i >= 55_296 && i <= 57_343 -> Error(Nil) - i -> Ok(unsafe_int_to_utf_codepoint(i)) - } -} - -/// Converts an UtfCodepoint to its ordinal code point value. -/// -/// ## Examples -/// -/// ```gleam -/// > let assert [utf_codepoint, ..] = to_utf_codepoints("💜") -/// > utf_codepoint_to_int(utf_codepoint) -/// 128156 -/// ``` -/// -pub fn utf_codepoint_to_int(cp: UtfCodepoint) -> Int { - do_utf_codepoint_to_int(cp) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "utf_codepoint_to_int") -fn do_utf_codepoint_to_int(cp cp: UtfCodepoint) -> Int - -/// Converts a `String` into `Option(String)` where an empty `String` becomes -/// `None`. -/// -/// ## Examples -/// -/// ```gleam -/// > to_option("") -/// None -/// ``` -/// -/// ```gleam -/// > to_option("hats") -/// Some("hats") -/// ``` -/// -pub fn to_option(s: String) -> Option(String) { - case s { - "" -> None - _ -> Some(s) - } -} - -/// Returns the first grapheme cluster in a given `String` and wraps it in a -/// `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. -/// Otherwise, it returns `Ok(String)`. -/// -/// ## Examples -/// -/// ```gleam -/// > first("") -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > first("icecream") -/// Ok("i") -/// ``` -/// -pub fn first(s: String) -> Result(String, Nil) { - case pop_grapheme(s) { - Ok(#(first, _)) -> Ok(first) - Error(e) -> Error(e) - } -} - -/// Returns the last grapheme cluster in a given `String` and wraps it in a -/// `Result(String, Nil)`. If the `String` is empty, it returns `Error(Nil)`. -/// Otherwise, it returns `Ok(String)`. -/// -/// ## Examples -/// -/// ```gleam -/// > last("") -/// Error(Nil) -/// ``` -/// -/// ```gleam -/// > last("icecream") -/// Ok("m") -/// ``` -/// -pub fn last(s: String) -> Result(String, Nil) { - case pop_grapheme(s) { - Ok(#(first, "")) -> Ok(first) - Ok(#(_, rest)) -> Ok(slice(rest, -1, 1)) - Error(e) -> Error(e) - } -} - -/// Creates a new `String` with the first grapheme in the input `String` -/// converted to uppercase and the remaining graphemes to lowercase. -/// -/// ## Examples -/// -/// ```gleam -/// > capitalise("mamouna") -/// "Mamouna" -/// ``` -/// -pub fn capitalise(s: String) -> String { - case pop_grapheme(s) { - Ok(#(first, rest)) -> append(to: uppercase(first), suffix: lowercase(rest)) - _ -> "" - } -} - -/// Returns a `String` representation of a term in Gleam syntax. -/// -pub fn inspect(term: anything) -> String { - do_inspect(term) - |> string_builder.to_string -} - -@external(erlang, "gleam_stdlib", "inspect") -@external(javascript, "../gleam_stdlib.mjs", "inspect") -fn do_inspect(term term: anything) -> StringBuilder - -/// Returns the number of bytes in a `String`. -/// -/// This function runs in constant time on Erlang and in linear time on -/// JavaScript. -/// -@external(erlang, "erlang", "byte_size") -@external(javascript, "../gleam_stdlib.mjs", "byte_size") -pub fn byte_size(string: String) -> Int diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/string_builder.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/string_builder.gleam deleted file mode 100644 index 5792ca8..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/string_builder.gleam +++ /dev/null @@ -1,298 +0,0 @@ -import gleam/list - -/// `StringBuilder` is a type used for efficiently building strings. -/// -/// When we append one string to another the strings must be copied to a -/// new location in memory so that they can sit together. This behaviour -/// enables efficient reading of the string but copying can be expensive, -/// especially if we want to join many strings together. -/// -/// `StringBuilder` is different in that it can be joined together in constant time -/// using minimal memory, and then can be efficiently converted to a string -/// using the `to_string` function. -/// -/// On Erlang this type is compatible with Erlang's iodata. On JavaScript this -/// type is compatible with normal strings. -/// -pub type StringBuilder - -/// Create an empty `StringBuilder`. Useful as the start of a pipe chaining many -/// builders together. -/// -pub fn new() -> StringBuilder { - do_from_strings([]) -} - -/// Prepends a `String` onto the start of some `StringBuilder`. -/// -/// Runs in constant time. -/// -pub fn prepend( - to builder: StringBuilder, - prefix prefix: String, -) -> StringBuilder { - append_builder(from_string(prefix), builder) -} - -/// Appends a `String` onto the end of some `StringBuilder`. -/// -/// Runs in constant time. -/// -pub fn append(to builder: StringBuilder, suffix second: String) -> StringBuilder { - append_builder(builder, from_string(second)) -} - -/// Prepends some `StringBuilder` onto the start of another. -/// -/// Runs in constant time. -/// -pub fn prepend_builder( - to builder: StringBuilder, - prefix prefix: StringBuilder, -) -> StringBuilder { - do_append(prefix, builder) -} - -/// Appends some `StringBuilder` onto the end of another. -/// -/// Runs in constant time. -/// -pub fn append_builder( - to builder: StringBuilder, - suffix suffix: StringBuilder, -) -> StringBuilder { - do_append(builder, suffix) -} - -@external(erlang, "gleam_stdlib", "iodata_append") -@external(javascript, "../gleam_stdlib.mjs", "add") -fn do_append(a: StringBuilder, b: StringBuilder) -> StringBuilder - -/// Converts a list of strings into a builder. -/// -/// Runs in constant time. -/// -pub fn from_strings(strings: List(String)) -> StringBuilder { - do_from_strings(strings) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "concat") -fn do_from_strings(a: List(String)) -> StringBuilder - -/// Joins a list of builders into a single builder. -/// -/// Runs in constant time. -/// -pub fn concat(builders: List(StringBuilder)) -> StringBuilder { - do_concat(builders) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "concat") -fn do_concat(a: List(StringBuilder)) -> StringBuilder - -/// Converts a string into a builder. -/// -/// Runs in constant time. -/// -pub fn from_string(string: String) -> StringBuilder { - do_from_string(string) -} - -@external(erlang, "gleam_stdlib", "identity") -@external(javascript, "../gleam_stdlib.mjs", "identity") -fn do_from_string(a: String) -> StringBuilder - -/// Turns an `StringBuilder` into a `String` -/// -/// This function is implemented natively by the virtual machine and is highly -/// optimised. -/// -pub fn to_string(builder: StringBuilder) -> String { - do_to_string(builder) -} - -@external(erlang, "unicode", "characters_to_binary") -@external(javascript, "../gleam_stdlib.mjs", "identity") -fn do_to_string(a: StringBuilder) -> String - -/// Returns the size of the `StringBuilder` in bytes. -/// -pub fn byte_size(builder: StringBuilder) -> Int { - do_byte_size(builder) -} - -@external(erlang, "erlang", "iolist_size") -@external(javascript, "../gleam_stdlib.mjs", "length") -fn do_byte_size(a: StringBuilder) -> Int - -/// Joins the given builders into a new builder separated with the given string -/// -pub fn join(builders: List(StringBuilder), with sep: String) -> StringBuilder { - builders - |> list.intersperse(from_string(sep)) - |> concat -} - -/// Converts a builder to a new builder where the contents have been -/// lowercased. -/// -pub fn lowercase(builder: StringBuilder) -> StringBuilder { - do_lowercase(builder) -} - -@external(erlang, "string", "lowercase") -@external(javascript, "../gleam_stdlib.mjs", "lowercase") -fn do_lowercase(a: StringBuilder) -> StringBuilder - -/// Converts a builder to a new builder where the contents have been -/// uppercased. -/// -pub fn uppercase(builder: StringBuilder) -> StringBuilder { - do_uppercase(builder) -} - -@external(erlang, "string", "uppercase") -@external(javascript, "../gleam_stdlib.mjs", "uppercase") -fn do_uppercase(a: StringBuilder) -> StringBuilder - -/// Converts a builder to a new builder with the contents reversed. -/// -pub fn reverse(builder: StringBuilder) -> StringBuilder { - do_reverse(builder) -} - -@target(erlang) -@external(erlang, "string", "reverse") -fn do_reverse(a: StringBuilder) -> StringBuilder - -@target(javascript) -fn do_reverse(builder: StringBuilder) -> StringBuilder { - builder - |> to_string - |> do_to_graphemes - |> list.reverse - |> from_strings -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "graphemes") -fn do_to_graphemes(string string: String) -> List(String) - -/// Splits a builder on a given pattern into a list of builders. -/// -pub fn split(iodata: StringBuilder, on pattern: String) -> List(StringBuilder) { - do_split(iodata, pattern) -} - -@target(erlang) -type Direction { - All -} - -@target(erlang) -@external(erlang, "string", "split") -fn erl_split(a: StringBuilder, b: String, c: Direction) -> List(StringBuilder) - -@target(erlang) -fn do_split(iodata: StringBuilder, pattern: String) -> List(StringBuilder) { - erl_split(iodata, pattern, All) -} - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "split") -fn do_split( - builder builder: StringBuilder, - pattern pattern: String, -) -> List(StringBuilder) - -/// Replaces all instances of a pattern with a given string substitute. -/// -pub fn replace( - in builder: StringBuilder, - each pattern: String, - with substitute: String, -) -> StringBuilder { - do_replace(builder, pattern, substitute) -} - -@target(erlang) -fn do_replace( - iodata: StringBuilder, - pattern: String, - substitute: String, -) -> StringBuilder { - erl_replace(iodata, pattern, substitute, All) -} - -@target(erlang) -@external(erlang, "string", "replace") -fn erl_replace( - a: StringBuilder, - b: String, - c: String, - d: Direction, -) -> StringBuilder - -@target(javascript) -@external(javascript, "../gleam_stdlib.mjs", "string_replace") -fn do_replace(a: StringBuilder, b: String, c: String) -> StringBuilder - -/// Compares two builders to determine if they have the same textual content. -/// -/// Comparing two iodata using the `==` operator may return `False` even if they -/// have the same content as they may have been build in different ways, so -/// using this function is often preferred. -/// -/// ## Examples -/// -/// ```gleam -/// > from_strings(["a", "b"]) == from_string("ab") -/// False -/// ``` -/// -/// ```gleam -/// > is_equal(from_strings(["a", "b"]), from_string("ab")) -/// True -/// ``` -/// -pub fn is_equal(a: StringBuilder, b: StringBuilder) -> Bool { - do_is_equal(a, b) -} - -@external(erlang, "string", "equal") -@external(javascript, "../gleam_stdlib.mjs", "equal") -fn do_is_equal(a: StringBuilder, b: StringBuilder) -> Bool - -/// Inspects a builder to determine if it is equivalent to an empty string. -/// -/// ## Examples -/// -/// ```gleam -/// > from_string("ok") |> is_empty -/// False -/// ``` -/// -/// ```gleam -/// > from_string("") |> is_empty -/// True -/// ``` -/// -/// ```gleam -/// > from_strings([]) |> is_empty -/// True -/// ``` -/// -pub fn is_empty(builder: StringBuilder) -> Bool { - do_is_empty(builder) -} - -@target(erlang) -@external(erlang, "string", "is_empty") -fn do_is_empty(a: StringBuilder) -> Bool - -@target(javascript) -fn do_is_empty(builder: StringBuilder) -> Bool { - from_string("") == builder -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam/uri.gleam b/aoc2023/build/packages/gleam_stdlib/src/gleam/uri.gleam deleted file mode 100644 index 11f6ea6..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam/uri.gleam +++ /dev/null @@ -1,462 +0,0 @@ -//// Utilities for working with URIs -//// -//// This module provides functions for working with URIs (for example, parsing -//// URIs or encoding query strings). The functions in this module are implemented -//// according to [RFC 3986](https://tools.ietf.org/html/rfc3986). -//// -//// Query encoding (Form encoding) is defined in the -//// [W3C specification](https://www.w3.org/TR/html52/sec-forms.html#urlencoded-form-data). - -import gleam/int -import gleam/list -import gleam/option.{type Option, None, Some} -import gleam/string -import gleam/string_builder.{type StringBuilder} -@target(javascript) -import gleam/pair -@target(javascript) -import gleam/regex -@target(javascript) -import gleam/result - -/// Type representing holding the parsed components of an URI. -/// All components of a URI are optional, except the path. -/// -pub type Uri { - Uri( - scheme: Option(String), - userinfo: Option(String), - host: Option(String), - port: Option(Int), - path: String, - query: Option(String), - fragment: Option(String), - ) -} - -/// Parses a compliant URI string into the `Uri` Type. -/// If the string is not a valid URI string then an error is returned. -/// -/// The opposite operation is `uri.to_string`. -/// -/// ## Examples -/// -/// ```gleam -/// > parse("https://example.com:1234/a/b?query=true#fragment") -/// Ok( -/// Uri( -/// scheme: Some("https"), -/// userinfo: None, -/// host: Some("example.com"), -/// port: Some(1234), -/// path: "/a/b", -/// query: Some("query=true"), -/// fragment: Some("fragment") -/// ) -/// ) -/// ``` -/// -pub fn parse(uri_string: String) -> Result(Uri, Nil) { - do_parse(uri_string) -} - -@target(erlang) -@external(erlang, "gleam_stdlib", "uri_parse") -fn do_parse(a: String) -> Result(Uri, Nil) - -@target(javascript) -fn do_parse(uri_string: String) -> Result(Uri, Nil) { - // From https://tools.ietf.org/html/rfc3986#appendix-B - let pattern = - // 12 3 4 5 6 7 8 - "^(([a-z][a-z0-9\\+\\-\\.]*):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#.*)?" - let matches = - pattern - |> regex_submatches(uri_string) - |> pad_list(8) - - let #(scheme, authority, path, query, fragment) = case matches { - [ - _scheme_with_colon, - scheme, - authority_with_slashes, - _authority, - path, - query_with_question_mark, - _query, - fragment, - ] -> #( - scheme, - authority_with_slashes, - path, - query_with_question_mark, - fragment, - ) - _ -> #(None, None, None, None, None) - } - - let scheme = noneify_empty_string(scheme) - let path = option.unwrap(path, "") - let query = noneify_query(query) - let #(userinfo, host, port) = split_authority(authority) - let fragment = - fragment - |> option.to_result(Nil) - |> result.try(string.pop_grapheme) - |> result.map(pair.second) - |> option.from_result - let scheme = - scheme - |> noneify_empty_string - |> option.map(string.lowercase) - Ok(Uri( - scheme: scheme, - userinfo: userinfo, - host: host, - port: port, - path: path, - query: query, - fragment: fragment, - )) -} - -@target(javascript) -fn regex_submatches(pattern: String, string: String) -> List(Option(String)) { - pattern - |> regex.compile(regex.Options(case_insensitive: True, multi_line: False)) - |> result.nil_error - |> result.map(regex.scan(_, string)) - |> result.try(list.first) - |> result.map(fn(m: regex.Match) { m.submatches }) - |> result.unwrap([]) -} - -@target(javascript) -fn noneify_query(x: Option(String)) -> Option(String) { - case x { - None -> None - Some(x) -> - case string.pop_grapheme(x) { - Ok(#("?", query)) -> Some(query) - _ -> None - } - } -} - -@target(javascript) -fn noneify_empty_string(x: Option(String)) -> Option(String) { - case x { - Some("") | None -> None - Some(_) -> x - } -} - -// Split an authority into its userinfo, host and port parts. -@target(javascript) -fn split_authority( - authority: Option(String), -) -> #(Option(String), Option(String), Option(Int)) { - case option.unwrap(authority, "") { - "" -> #(None, None, None) - "//" -> #(None, Some(""), None) - authority -> { - let matches = - "^(//)?((.*)@)?(\\[[a-zA-Z0-9:.]*\\]|[^:]*)(:(\\d*))?" - |> regex_submatches(authority) - |> pad_list(6) - case matches { - [_, _, userinfo, host, _, port] -> { - let userinfo = noneify_empty_string(userinfo) - let host = noneify_empty_string(host) - let port = - port - |> option.unwrap("") - |> int.parse - |> option.from_result - #(userinfo, host, port) - } - _ -> #(None, None, None) - } - } - } -} - -@target(javascript) -fn pad_list(list: List(Option(a)), size: Int) -> List(Option(a)) { - list - |> list.append(list.repeat(None, extra_required(list, size))) -} - -@target(javascript) -fn extra_required(list: List(a), remaining: Int) -> Int { - case list { - _ if remaining == 0 -> 0 - [] -> remaining - [_, ..xs] -> extra_required(xs, remaining - 1) - } -} - -/// Parses an urlencoded query string into a list of key value pairs. -/// Returns an error for invalid encoding. -/// -/// The opposite operation is `uri.query_to_string`. -/// -/// ## Examples -/// -/// ```gleam -/// > parse_query("a=1&b=2") -/// Ok([#("a", "1"), #("b", "2")]) -/// ``` -/// -pub fn parse_query(query: String) -> Result(List(#(String, String)), Nil) { - do_parse_query(query) -} - -@external(erlang, "gleam_stdlib", "parse_query") -@external(javascript, "../gleam_stdlib.mjs", "parse_query") -fn do_parse_query(a: String) -> Result(List(#(String, String)), Nil) - -/// Encodes a list of key value pairs as a URI query string. -/// -/// The opposite operation is `uri.parse_query`. -/// -/// ## Examples -/// -/// ```gleam -/// > query_to_string([#("a", "1"), #("b", "2")]) -/// "a=1&b=2" -/// ``` -/// -pub fn query_to_string(query: List(#(String, String))) -> String { - query - |> list.map(query_pair) - |> list.intersperse(string_builder.from_string("&")) - |> string_builder.concat - |> string_builder.to_string -} - -fn query_pair(pair: #(String, String)) -> StringBuilder { - string_builder.from_strings([ - percent_encode(pair.0), - "=", - percent_encode(pair.1), - ]) -} - -/// Encodes a string into a percent encoded representation. -/// -/// ## Examples -/// -/// ```gleam -/// > percent_encode("100% great") -/// "100%25%20great" -/// ``` -/// -pub fn percent_encode(value: String) -> String { - do_percent_encode(value) -} - -@external(erlang, "gleam_stdlib", "percent_encode") -@external(javascript, "../gleam_stdlib.mjs", "percent_encode") -fn do_percent_encode(a: String) -> String - -/// Decodes a percent encoded string. -/// -/// ## Examples -/// -/// ```gleam -/// > percent_decode("100%25+great") -/// Ok("100% great") -/// ``` -/// -pub fn percent_decode(value: String) -> Result(String, Nil) { - do_percent_decode(value) -} - -@external(erlang, "gleam_stdlib", "percent_decode") -@external(javascript, "../gleam_stdlib.mjs", "percent_decode") -fn do_percent_decode(a: String) -> Result(String, Nil) - -fn do_remove_dot_segments( - input: List(String), - accumulator: List(String), -) -> List(String) { - case input { - [] -> list.reverse(accumulator) - [segment, ..rest] -> { - let accumulator = case segment, accumulator { - "", accumulator -> accumulator - ".", accumulator -> accumulator - "..", [] -> [] - "..", [_, ..accumulator] -> accumulator - segment, accumulator -> [segment, ..accumulator] - } - do_remove_dot_segments(rest, accumulator) - } - } -} - -fn remove_dot_segments(input: List(String)) -> List(String) { - do_remove_dot_segments(input, []) -} - -/// Splits the path section of a URI into it's constituent segments. -/// -/// Removes empty segments and resolves dot-segments as specified in -/// [section 5.2](https://www.ietf.org/rfc/rfc3986.html#section-5.2) of the RFC. -/// -/// ## Examples -/// -/// ```gleam -/// > path_segments("/users/1") -/// ["users" ,"1"] -/// ``` -/// -pub fn path_segments(path: String) -> List(String) { - remove_dot_segments(string.split(path, "/")) -} - -/// Encodes a `Uri` value as a URI string. -/// -/// The opposite operation is `uri.parse`. -/// -/// ## Examples -/// -/// ```gleam -/// > let uri = Uri(Some("http"), None, Some("example.com"), ...) -/// > to_string(uri) -/// "http://example.com" -/// ``` -/// -pub fn to_string(uri: Uri) -> String { - let parts = case uri.fragment { - Some(fragment) -> ["#", fragment] - _ -> [] - } - let parts = case uri.query { - Some(query) -> ["?", query, ..parts] - _ -> parts - } - let parts = [uri.path, ..parts] - let parts = case uri.host, string.starts_with(uri.path, "/") { - Some(host), False if host != "" -> ["/", ..parts] - _, _ -> parts - } - let parts = case uri.host, uri.port { - Some(_), Some(port) -> [":", int.to_string(port), ..parts] - _, _ -> parts - } - let parts = case uri.scheme, uri.userinfo, uri.host { - Some(s), Some(u), Some(h) -> [s, "://", u, "@", h, ..parts] - Some(s), None, Some(h) -> [s, "://", h, ..parts] - Some(s), Some(_), None | Some(s), None, None -> [s, ":", ..parts] - None, None, Some(h) -> ["//", h, ..parts] - _, _, _ -> parts - } - string.concat(parts) -} - -/// Fetches the origin of a URI. -/// -/// Returns the origin of a uri as defined in -/// [RFC 6454](https://tools.ietf.org/html/rfc6454) -/// -/// The supported URI schemes are `http` and `https`. -/// URLs without a scheme will return `Error`. -/// -/// ## Examples -/// -/// ```gleam -/// > let assert Ok(uri) = parse("http://example.com/path?foo#bar") -/// > origin(uri) -/// Ok("http://example.com") -/// ``` -/// -pub fn origin(uri: Uri) -> Result(String, Nil) { - let Uri(scheme: scheme, host: host, port: port, ..) = uri - case scheme { - Some("https") if port == Some(443) -> { - let origin = Uri(scheme, None, host, None, "", None, None) - Ok(to_string(origin)) - } - Some("http") if port == Some(80) -> { - let origin = Uri(scheme, None, host, None, "", None, None) - Ok(to_string(origin)) - } - Some(s) if s == "http" || s == "https" -> { - let origin = Uri(scheme, None, host, port, "", None, None) - Ok(to_string(origin)) - } - _ -> Error(Nil) - } -} - -fn drop_last(elements: List(a)) -> List(a) { - list.take(from: elements, up_to: list.length(elements) - 1) -} - -fn join_segments(segments: List(String)) -> String { - string.join(["", ..segments], "/") -} - -/// Resolves a URI with respect to the given base URI. -/// -/// The base URI must be an absolute URI or this function will return an error. -/// The algorithm for merging uris is described in -/// [RFC 3986](https://tools.ietf.org/html/rfc3986#section-5.2). -/// -pub fn merge(base: Uri, relative: Uri) -> Result(Uri, Nil) { - case base { - Uri(scheme: Some(_), host: Some(_), ..) -> - case relative { - Uri(host: Some(_), ..) -> { - let path = - string.split(relative.path, "/") - |> remove_dot_segments() - |> join_segments() - let resolved = - Uri( - option.or(relative.scheme, base.scheme), - None, - relative.host, - option.or(relative.port, base.port), - path, - relative.query, - relative.fragment, - ) - Ok(resolved) - } - _ -> { - let #(new_path, new_query) = case relative.path { - "" -> #(base.path, option.or(relative.query, base.query)) - _ -> { - let path_segments = case string.starts_with(relative.path, "/") { - True -> string.split(relative.path, "/") - False -> - string.split(base.path, "/") - |> drop_last() - |> list.append(string.split(relative.path, "/")) - } - let path = - path_segments - |> remove_dot_segments() - |> join_segments() - #(path, relative.query) - } - } - let resolved = - Uri( - base.scheme, - None, - base.host, - base.port, - new_path, - new_query, - relative.fragment, - ) - Ok(resolved) - } - } - _ -> Error(Nil) - } -} diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@base.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@base.erl deleted file mode 100644 index 65bc3f6..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@base.erl +++ /dev/null @@ -1,20 +0,0 @@ --module(gleam@base). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([encode64/2, decode64/1, url_encode64/2, url_decode64/1]). - --spec encode64(bitstring(), boolean()) -> binary(). -encode64(Input, Padding) -> - gleam@bit_array:base64_encode(Input, Padding). - --spec decode64(binary()) -> {ok, bitstring()} | {error, nil}. -decode64(Encoded) -> - gleam@bit_array:base64_decode(Encoded). - --spec url_encode64(bitstring(), boolean()) -> binary(). -url_encode64(Input, Padding) -> - gleam@bit_array:base64_url_encode(Input, Padding). - --spec url_decode64(binary()) -> {ok, bitstring()} | {error, nil}. -url_decode64(Encoded) -> - gleam@bit_array:base64_url_decode(Encoded). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_array.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_array.erl deleted file mode 100644 index ba18dfa..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_array.erl +++ /dev/null @@ -1,102 +0,0 @@ --module(gleam@bit_array). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([from_string/1, byte_size/1, slice/3, is_utf8/1, to_string/1, concat/1, append/2, base64_encode/2, base64_decode/1, base64_url_encode/2, base64_url_decode/1, base16_encode/1, base16_decode/1]). - --spec from_string(binary()) -> bitstring(). -from_string(X) -> - gleam_stdlib:identity(X). - --spec byte_size(bitstring()) -> integer(). -byte_size(X) -> - erlang:byte_size(X). - --spec slice(bitstring(), integer(), integer()) -> {ok, bitstring()} | - {error, nil}. -slice(String, Position, Length) -> - gleam_stdlib:bit_array_slice(String, Position, Length). - --spec do_is_utf8(bitstring()) -> boolean(). -do_is_utf8(Bits) -> - case Bits of - <<>> -> - true; - - <<_/utf8, Rest/binary>> -> - do_is_utf8(Rest); - - _ -> - false - end. - --spec is_utf8(bitstring()) -> boolean(). -is_utf8(Bits) -> - do_is_utf8(Bits). - --spec do_to_string(bitstring()) -> {ok, binary()} | {error, nil}. -do_to_string(Bits) -> - case is_utf8(Bits) of - true -> - {ok, gleam_stdlib:identity(Bits)}; - - false -> - {error, nil} - end. - --spec to_string(bitstring()) -> {ok, binary()} | {error, nil}. -to_string(Bits) -> - do_to_string(Bits). - --spec concat(list(bitstring())) -> bitstring(). -concat(Bit_arrays) -> - gleam_stdlib:bit_array_concat(Bit_arrays). - --spec append(bitstring(), bitstring()) -> bitstring(). -append(First, Second) -> - gleam_stdlib:bit_array_concat([First, Second]). - --spec base64_encode(bitstring(), boolean()) -> binary(). -base64_encode(Input, Padding) -> - Encoded = base64:encode(Input), - case Padding of - true -> - Encoded; - - false -> - gleam@string:replace(Encoded, <<"="/utf8>>, <<""/utf8>>) - end. - --spec base64_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base64_decode(Encoded) -> - Padded = case erlang:byte_size(gleam_stdlib:identity(Encoded)) rem 4 of - 0 -> - Encoded; - - N -> - gleam@string:append( - Encoded, - gleam@string:repeat(<<"="/utf8>>, 4 - N) - ) - end, - gleam_stdlib:base_decode64(Padded). - --spec base64_url_encode(bitstring(), boolean()) -> binary(). -base64_url_encode(Input, Padding) -> - _pipe = base64_encode(Input, Padding), - _pipe@1 = gleam@string:replace(_pipe, <<"+"/utf8>>, <<"-"/utf8>>), - gleam@string:replace(_pipe@1, <<"/"/utf8>>, <<"_"/utf8>>). - --spec base64_url_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base64_url_decode(Encoded) -> - _pipe = Encoded, - _pipe@1 = gleam@string:replace(_pipe, <<"-"/utf8>>, <<"+"/utf8>>), - _pipe@2 = gleam@string:replace(_pipe@1, <<"_"/utf8>>, <<"/"/utf8>>), - base64_decode(_pipe@2). - --spec base16_encode(bitstring()) -> binary(). -base16_encode(Input) -> - binary:encode_hex(Input). - --spec base16_decode(binary()) -> {ok, bitstring()} | {error, nil}. -base16_decode(Input) -> - gleam_stdlib:base16_decode(Input). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_builder.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_builder.erl deleted file mode 100644 index 284c6d4..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_builder.erl +++ /dev/null @@ -1,66 +0,0 @@ --module(gleam@bit_builder). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([new/0, prepend/2, append/2, prepend_builder/2, append_builder/2, prepend_string/2, append_string/2, concat/1, concat_bit_strings/1, from_string/1, from_string_builder/1, from_bit_string/1, to_bit_string/1, byte_size/1]). - --spec new() -> gleam@bytes_builder:bytes_builder(). -new() -> - gleam@bytes_builder:new(). - --spec prepend(gleam@bytes_builder:bytes_builder(), bitstring()) -> gleam@bytes_builder:bytes_builder(). -prepend(To, Prefix) -> - gleam@bytes_builder:prepend(To, Prefix). - --spec append(gleam@bytes_builder:bytes_builder(), bitstring()) -> gleam@bytes_builder:bytes_builder(). -append(To, Suffix) -> - gleam@bytes_builder:append(To, Suffix). - --spec prepend_builder( - gleam@bytes_builder:bytes_builder(), - gleam@bytes_builder:bytes_builder() -) -> gleam@bytes_builder:bytes_builder(). -prepend_builder(To, Prefix) -> - gleam@bytes_builder:prepend_builder(To, Prefix). - --spec append_builder( - gleam@bytes_builder:bytes_builder(), - gleam@bytes_builder:bytes_builder() -) -> gleam@bytes_builder:bytes_builder(). -append_builder(First, Second) -> - gleam_stdlib:iodata_append(First, Second). - --spec prepend_string(gleam@bytes_builder:bytes_builder(), binary()) -> gleam@bytes_builder:bytes_builder(). -prepend_string(To, Prefix) -> - gleam@bytes_builder:prepend_string(To, Prefix). - --spec append_string(gleam@bytes_builder:bytes_builder(), binary()) -> gleam@bytes_builder:bytes_builder(). -append_string(To, Suffix) -> - gleam@bytes_builder:append_string(To, Suffix). - --spec concat(list(gleam@bytes_builder:bytes_builder())) -> gleam@bytes_builder:bytes_builder(). -concat(Builders) -> - gleam_stdlib:identity(Builders). - --spec concat_bit_strings(list(bitstring())) -> gleam@bytes_builder:bytes_builder(). -concat_bit_strings(Bits) -> - gleam_stdlib:identity(Bits). - --spec from_string(binary()) -> gleam@bytes_builder:bytes_builder(). -from_string(String) -> - gleam_stdlib:wrap_list(String). - --spec from_string_builder(gleam@string_builder:string_builder()) -> gleam@bytes_builder:bytes_builder(). -from_string_builder(Builder) -> - gleam_stdlib:wrap_list(Builder). - --spec from_bit_string(bitstring()) -> gleam@bytes_builder:bytes_builder(). -from_bit_string(Bits) -> - gleam_stdlib:wrap_list(Bits). - --spec to_bit_string(gleam@bytes_builder:bytes_builder()) -> bitstring(). -to_bit_string(Builder) -> - erlang:list_to_bitstring(Builder). - --spec byte_size(gleam@bytes_builder:bytes_builder()) -> integer(). -byte_size(Builder) -> - erlang:iolist_size(Builder). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_string.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_string.erl deleted file mode 100644 index 7dabaa3..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@bit_string.erl +++ /dev/null @@ -1,33 +0,0 @@ --module(gleam@bit_string). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([from_string/1, byte_size/1, append/2, slice/3, is_utf8/1, to_string/1, concat/1]). - --spec from_string(binary()) -> bitstring(). -from_string(X) -> - gleam_stdlib:identity(X). - --spec byte_size(bitstring()) -> integer(). -byte_size(X) -> - erlang:byte_size(X). - --spec append(bitstring(), bitstring()) -> bitstring(). -append(First, Second) -> - gleam@bit_array:append(First, Second). - --spec slice(bitstring(), integer(), integer()) -> {ok, bitstring()} | - {error, nil}. -slice(String, Position, Length) -> - gleam_stdlib:bit_array_slice(String, Position, Length). - --spec is_utf8(bitstring()) -> boolean(). -is_utf8(Bits) -> - gleam@bit_array:is_utf8(Bits). - --spec to_string(bitstring()) -> {ok, binary()} | {error, nil}. -to_string(Bits) -> - gleam@bit_array:to_string(Bits). - --spec concat(list(bitstring())) -> bitstring(). -concat(Bit_strings) -> - gleam_stdlib:bit_array_concat(Bit_strings). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@bool.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@bool.erl deleted file mode 100644 index cd55358..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@bool.erl +++ /dev/null @@ -1,162 +0,0 @@ --module(gleam@bool). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export(['and'/2, 'or'/2, negate/1, nor/2, nand/2, exclusive_or/2, exclusive_nor/2, compare/2, max/2, min/2, to_int/1, to_string/1, guard/3, lazy_guard/3]). - --spec 'and'(boolean(), boolean()) -> boolean(). -'and'(A, B) -> - A andalso B. - --spec 'or'(boolean(), boolean()) -> boolean(). -'or'(A, B) -> - A orelse B. - --spec negate(boolean()) -> boolean(). -negate(Bool) -> - case Bool of - true -> - false; - - false -> - true - end. - --spec nor(boolean(), boolean()) -> boolean(). -nor(A, B) -> - case {A, B} of - {false, false} -> - true; - - {false, true} -> - false; - - {true, false} -> - false; - - {true, true} -> - false - end. - --spec nand(boolean(), boolean()) -> boolean(). -nand(A, B) -> - case {A, B} of - {false, false} -> - true; - - {false, true} -> - true; - - {true, false} -> - true; - - {true, true} -> - false - end. - --spec exclusive_or(boolean(), boolean()) -> boolean(). -exclusive_or(A, B) -> - case {A, B} of - {false, false} -> - false; - - {false, true} -> - true; - - {true, false} -> - true; - - {true, true} -> - false - end. - --spec exclusive_nor(boolean(), boolean()) -> boolean(). -exclusive_nor(A, B) -> - case {A, B} of - {false, false} -> - true; - - {false, true} -> - false; - - {true, false} -> - false; - - {true, true} -> - true - end. - --spec compare(boolean(), boolean()) -> gleam@order:order(). -compare(A, B) -> - case {A, B} of - {true, true} -> - eq; - - {true, false} -> - gt; - - {false, false} -> - eq; - - {false, true} -> - lt - end. - --spec max(boolean(), boolean()) -> boolean(). -max(A, B) -> - case A of - true -> - true; - - false -> - B - end. - --spec min(boolean(), boolean()) -> boolean(). -min(A, B) -> - case A of - false -> - false; - - true -> - B - end. - --spec to_int(boolean()) -> integer(). -to_int(Bool) -> - case Bool of - false -> - 0; - - true -> - 1 - end. - --spec to_string(boolean()) -> binary(). -to_string(Bool) -> - case Bool of - false -> - <<"False"/utf8>>; - - true -> - <<"True"/utf8>> - end. - --spec guard(boolean(), DDZ, fun(() -> DDZ)) -> DDZ. -guard(Requirement, Consequence, Alternative) -> - case Requirement of - true -> - Consequence; - - false -> - Alternative() - end. - --spec lazy_guard(boolean(), fun(() -> DEA), fun(() -> DEA)) -> DEA. -lazy_guard(Requirement, Consequence, Alternative) -> - case Requirement of - true -> - Consequence(); - - false -> - Alternative() - end. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@bytes_builder.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@bytes_builder.erl deleted file mode 100644 index 2f6dd93..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@bytes_builder.erl +++ /dev/null @@ -1,87 +0,0 @@ --module(gleam@bytes_builder). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([append_builder/2, prepend_builder/2, concat/1, new/0, from_string/1, prepend_string/2, append_string/2, from_string_builder/1, from_bit_array/1, prepend/2, append/2, concat_bit_arrays/1, to_bit_array/1, byte_size/1]). --export_type([bytes_builder/0]). - --opaque bytes_builder() :: {bytes, bitstring()} | - {text, gleam@string_builder:string_builder()} | - {many, list(bytes_builder())}. - --spec append_builder(bytes_builder(), bytes_builder()) -> bytes_builder(). -append_builder(First, Second) -> - gleam_stdlib:iodata_append(First, Second). - --spec prepend_builder(bytes_builder(), bytes_builder()) -> bytes_builder(). -prepend_builder(Second, First) -> - gleam_stdlib:iodata_append(First, Second). - --spec concat(list(bytes_builder())) -> bytes_builder(). -concat(Builders) -> - gleam_stdlib:identity(Builders). - --spec new() -> bytes_builder(). -new() -> - gleam_stdlib:identity([]). - --spec from_string(binary()) -> bytes_builder(). -from_string(String) -> - gleam_stdlib:wrap_list(String). - --spec prepend_string(bytes_builder(), binary()) -> bytes_builder(). -prepend_string(Second, First) -> - gleam_stdlib:iodata_append(gleam_stdlib:wrap_list(First), Second). - --spec append_string(bytes_builder(), binary()) -> bytes_builder(). -append_string(First, Second) -> - gleam_stdlib:iodata_append(First, gleam_stdlib:wrap_list(Second)). - --spec from_string_builder(gleam@string_builder:string_builder()) -> bytes_builder(). -from_string_builder(Builder) -> - gleam_stdlib:wrap_list(Builder). - --spec from_bit_array(bitstring()) -> bytes_builder(). -from_bit_array(Bits) -> - gleam_stdlib:wrap_list(Bits). - --spec prepend(bytes_builder(), bitstring()) -> bytes_builder(). -prepend(Second, First) -> - gleam_stdlib:iodata_append(gleam_stdlib:wrap_list(First), Second). - --spec append(bytes_builder(), bitstring()) -> bytes_builder(). -append(First, Second) -> - gleam_stdlib:iodata_append(First, gleam_stdlib:wrap_list(Second)). - --spec concat_bit_arrays(list(bitstring())) -> bytes_builder(). -concat_bit_arrays(Bits) -> - gleam_stdlib:identity(Bits). - --spec to_list(list(list(bytes_builder())), list(bitstring())) -> list(bitstring()). -to_list(Stack, Acc) -> - case Stack of - [] -> - Acc; - - [[] | Remaining_stack] -> - to_list(Remaining_stack, Acc); - - [[{bytes, Bits} | Rest] | Remaining_stack@1] -> - to_list([Rest | Remaining_stack@1], [Bits | Acc]); - - [[{text, Builder} | Rest@1] | Remaining_stack@2] -> - Bits@1 = gleam_stdlib:identity( - gleam@string_builder:to_string(Builder) - ), - to_list([Rest@1 | Remaining_stack@2], [Bits@1 | Acc]); - - [[{many, Builders} | Rest@2] | Remaining_stack@3] -> - to_list([Builders, Rest@2 | Remaining_stack@3], Acc) - end. - --spec to_bit_array(bytes_builder()) -> bitstring(). -to_bit_array(Builder) -> - erlang:list_to_bitstring(Builder). - --spec byte_size(bytes_builder()) -> integer(). -byte_size(Builder) -> - erlang:iolist_size(Builder). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@dict.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@dict.erl deleted file mode 100644 index 44b89ea..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@dict.erl +++ /dev/null @@ -1,97 +0,0 @@ --module(gleam@dict). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([size/1, to_list/1, from_list/1, has_key/2, new/0, get/2, insert/3, map_values/2, keys/1, values/1, filter/2, take/2, merge/2, delete/2, drop/2, update/3, fold/3]). --export_type([dict/2]). - --type dict(KS, KT) :: any() | {gleam_phantom, KS, KT}. - --spec size(dict(any(), any())) -> integer(). -size(Dict) -> - maps:size(Dict). - --spec to_list(dict(LC, LD)) -> list({LC, LD}). -to_list(Dict) -> - maps:to_list(Dict). - --spec from_list(list({LM, LN})) -> dict(LM, LN). -from_list(List) -> - maps:from_list(List). - --spec has_key(dict(LW, any()), LW) -> boolean(). -has_key(Dict, Key) -> - maps:is_key(Key, Dict). - --spec new() -> dict(any(), any()). -new() -> - maps:new(). - --spec get(dict(MM, MN), MM) -> {ok, MN} | {error, nil}. -get(From, Get) -> - gleam_stdlib:map_get(From, Get). - --spec insert(dict(MY, MZ), MY, MZ) -> dict(MY, MZ). -insert(Dict, Key, Value) -> - maps:put(Key, Value, Dict). - --spec map_values(dict(NK, NL), fun((NK, NL) -> NO)) -> dict(NK, NO). -map_values(Dict, Fun) -> - maps:map(Fun, Dict). - --spec keys(dict(NY, any())) -> list(NY). -keys(Dict) -> - maps:keys(Dict). - --spec values(dict(any(), OJ)) -> list(OJ). -values(Dict) -> - maps:values(Dict). - --spec filter(dict(OS, OT), fun((OS, OT) -> boolean())) -> dict(OS, OT). -filter(Dict, Predicate) -> - maps:filter(Predicate, Dict). - --spec take(dict(PE, PF), list(PE)) -> dict(PE, PF). -take(Dict, Desired_keys) -> - maps:with(Desired_keys, Dict). - --spec merge(dict(PS, PT), dict(PS, PT)) -> dict(PS, PT). -merge(Dict, New_entries) -> - maps:merge(Dict, New_entries). - --spec delete(dict(QI, QJ), QI) -> dict(QI, QJ). -delete(Dict, Key) -> - maps:remove(Key, Dict). - --spec drop(dict(QU, QV), list(QU)) -> dict(QU, QV). -drop(Dict, Disallowed_keys) -> - case Disallowed_keys of - [] -> - Dict; - - [X | Xs] -> - drop(delete(Dict, X), Xs) - end. - --spec update(dict(RB, RC), RB, fun((gleam@option:option(RC)) -> RC)) -> dict(RB, RC). -update(Dict, Key, Fun) -> - _pipe = Dict, - _pipe@1 = get(_pipe, Key), - _pipe@2 = gleam@option:from_result(_pipe@1), - _pipe@3 = Fun(_pipe@2), - insert(Dict, Key, _pipe@3). - --spec do_fold(list({RI, RJ}), RL, fun((RL, RI, RJ) -> RL)) -> RL. -do_fold(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [{K, V} | Rest] -> - do_fold(Rest, Fun(Initial, K, V), Fun) - end. - --spec fold(dict(RM, RN), RQ, fun((RQ, RM, RN) -> RQ)) -> RQ. -fold(Dict, Initial, Fun) -> - _pipe = Dict, - _pipe@1 = to_list(_pipe), - do_fold(_pipe@1, Initial, Fun). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@dynamic.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@dynamic.erl deleted file mode 100644 index 38f4b4e..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@dynamic.erl +++ /dev/null @@ -1,808 +0,0 @@ --module(gleam@dynamic). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([from/1, unsafe_coerce/1, dynamic/1, bit_array/1, bit_string/1, classify/1, int/1, float/1, bool/1, shallow_list/1, optional/1, any/1, decode1/2, result/2, list/1, string/1, field/2, optional_field/2, element/2, tuple2/2, tuple3/3, tuple4/4, tuple5/5, tuple6/6, dict/2, map/2, decode2/3, decode3/4, decode4/5, decode5/6, decode6/7, decode7/8, decode8/9, decode9/10]). --export_type([dynamic_/0, decode_error/0, unknown_tuple/0]). - --type dynamic_() :: any(). - --type decode_error() :: {decode_error, binary(), binary(), list(binary())}. - --type unknown_tuple() :: any(). - --spec from(any()) -> dynamic_(). -from(A) -> - gleam_stdlib:identity(A). - --spec unsafe_coerce(dynamic_()) -> any(). -unsafe_coerce(A) -> - gleam_stdlib:identity(A). - --spec dynamic(dynamic_()) -> {ok, dynamic_()} | {error, list(decode_error())}. -dynamic(Value) -> - {ok, Value}. - --spec bit_array(dynamic_()) -> {ok, bitstring()} | {error, list(decode_error())}. -bit_array(Data) -> - gleam_stdlib:decode_bit_array(Data). - --spec bit_string(dynamic_()) -> {ok, bitstring()} | - {error, list(decode_error())}. -bit_string(Data) -> - bit_array(Data). - --spec put_expected(decode_error(), binary()) -> decode_error(). -put_expected(Error, Expected) -> - erlang:setelement(2, Error, Expected). - --spec classify(dynamic_()) -> binary(). -classify(Data) -> - gleam_stdlib:classify_dynamic(Data). - --spec int(dynamic_()) -> {ok, integer()} | {error, list(decode_error())}. -int(Data) -> - gleam_stdlib:decode_int(Data). - --spec float(dynamic_()) -> {ok, float()} | {error, list(decode_error())}. -float(Data) -> - gleam_stdlib:decode_float(Data). - --spec bool(dynamic_()) -> {ok, boolean()} | {error, list(decode_error())}. -bool(Data) -> - gleam_stdlib:decode_bool(Data). - --spec shallow_list(dynamic_()) -> {ok, list(dynamic_())} | - {error, list(decode_error())}. -shallow_list(Value) -> - gleam_stdlib:decode_list(Value). - --spec optional(fun((dynamic_()) -> {ok, DZX} | {error, list(decode_error())})) -> fun((dynamic_()) -> {ok, - gleam@option:option(DZX)} | - {error, list(decode_error())}). -optional(Decode) -> - fun(Value) -> gleam_stdlib:decode_option(Value, Decode) end. - --spec at_least_decode_tuple_error(integer(), dynamic_()) -> {ok, any()} | - {error, list(decode_error())}. -at_least_decode_tuple_error(Size, Data) -> - S = case Size of - 1 -> - <<""/utf8>>; - - _ -> - <<"s"/utf8>> - end, - Error = begin - _pipe = [<<"Tuple of at least "/utf8>>, - gleam@int:to_string(Size), - <<" element"/utf8>>, - S], - _pipe@1 = gleam@string_builder:from_strings(_pipe), - _pipe@2 = gleam@string_builder:to_string(_pipe@1), - {decode_error, _pipe@2, classify(Data), []} - end, - {error, [Error]}. - --spec any(list(fun((dynamic_()) -> {ok, EEE} | {error, list(decode_error())}))) -> fun((dynamic_()) -> {ok, - EEE} | - {error, list(decode_error())}). -any(Decoders) -> - fun(Data) -> case Decoders of - [] -> - {error, - [{decode_error, <<"another type"/utf8>>, classify(Data), []}]}; - - [Decoder | Decoders@1] -> - case Decoder(Data) of - {ok, Decoded} -> - {ok, Decoded}; - - {error, _} -> - (any(Decoders@1))(Data) - end - end end. - --spec all_errors({ok, any()} | {error, list(decode_error())}) -> list(decode_error()). -all_errors(Result) -> - case Result of - {ok, _} -> - []; - - {error, Errors} -> - Errors - end. - --spec decode1( - fun((EEI) -> EEJ), - fun((dynamic_()) -> {ok, EEI} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EEJ} | {error, list(decode_error())}). -decode1(Constructor, T1) -> - fun(Value) -> case T1(Value) of - {ok, A} -> - {ok, Constructor(A)}; - - A@1 -> - {error, all_errors(A@1)} - end end. - --spec push_path(decode_error(), any()) -> decode_error(). -push_path(Error, Name) -> - Name@1 = from(Name), - Decoder = any( - [fun string/1, - fun(X) -> gleam@result:map(int(X), fun gleam@int:to_string/1) end] - ), - Name@3 = case Decoder(Name@1) of - {ok, Name@2} -> - Name@2; - - {error, _} -> - _pipe = [<<"<"/utf8>>, classify(Name@1), <<">"/utf8>>], - _pipe@1 = gleam@string_builder:from_strings(_pipe), - gleam@string_builder:to_string(_pipe@1) - end, - erlang:setelement(4, Error, [Name@3 | erlang:element(4, Error)]). - --spec result( - fun((dynamic_()) -> {ok, DZL} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, DZN} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, {ok, DZL} | {error, DZN}} | - {error, list(decode_error())}). -result(Decode_ok, Decode_error) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_result(Value), - fun(Inner_result) -> case Inner_result of - {ok, Raw} -> - gleam@result:'try'( - begin - _pipe = Decode_ok(Raw), - map_errors( - _pipe, - fun(_capture) -> - push_path(_capture, <<"ok"/utf8>>) - end - ) - end, - fun(Value@1) -> {ok, {ok, Value@1}} end - ); - - {error, Raw@1} -> - gleam@result:'try'( - begin - _pipe@1 = Decode_error(Raw@1), - map_errors( - _pipe@1, - fun(_capture@1) -> - push_path(_capture@1, <<"error"/utf8>>) - end - ) - end, - fun(Value@2) -> {ok, {error, Value@2}} end - ) - end end - ) - end. - --spec list(fun((dynamic_()) -> {ok, DZS} | {error, list(decode_error())})) -> fun((dynamic_()) -> {ok, - list(DZS)} | - {error, list(decode_error())}). -list(Decoder_type) -> - fun(Dynamic) -> - gleam@result:'try'(shallow_list(Dynamic), fun(List) -> _pipe = List, - _pipe@1 = gleam@list:try_map(_pipe, Decoder_type), - map_errors( - _pipe@1, - fun(_capture) -> push_path(_capture, <<"*"/utf8>>) end - ) end) - end. - --spec map_errors( - {ok, DYG} | {error, list(decode_error())}, - fun((decode_error()) -> decode_error()) -) -> {ok, DYG} | {error, list(decode_error())}. -map_errors(Result, F) -> - gleam@result:map_error( - Result, - fun(_capture) -> gleam@list:map(_capture, F) end - ). - --spec decode_string(dynamic_()) -> {ok, binary()} | - {error, list(decode_error())}. -decode_string(Data) -> - _pipe = bit_array(Data), - _pipe@1 = map_errors( - _pipe, - fun(_capture) -> put_expected(_capture, <<"String"/utf8>>) end - ), - gleam@result:'try'( - _pipe@1, - fun(Raw) -> case gleam@bit_array:to_string(Raw) of - {ok, String} -> - {ok, String}; - - {error, nil} -> - {error, - [{decode_error, - <<"String"/utf8>>, - <<"BitArray"/utf8>>, - []}]} - end end - ). - --spec string(dynamic_()) -> {ok, binary()} | {error, list(decode_error())}. -string(Data) -> - decode_string(Data). - --spec field( - any(), - fun((dynamic_()) -> {ok, EAH} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EAH} | {error, list(decode_error())}). -field(Name, Inner_type) -> - fun(Value) -> - Missing_field_error = {decode_error, - <<"field"/utf8>>, - <<"nothing"/utf8>>, - []}, - gleam@result:'try'( - gleam_stdlib:decode_field(Value, Name), - fun(Maybe_inner) -> _pipe = Maybe_inner, - _pipe@1 = gleam@option:to_result(_pipe, [Missing_field_error]), - _pipe@2 = gleam@result:'try'(_pipe@1, Inner_type), - map_errors( - _pipe@2, - fun(_capture) -> push_path(_capture, Name) end - ) end - ) - end. - --spec optional_field( - any(), - fun((dynamic_()) -> {ok, EAL} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, gleam@option:option(EAL)} | - {error, list(decode_error())}). -optional_field(Name, Inner_type) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_field(Value, Name), - fun(Maybe_inner) -> case Maybe_inner of - none -> - {ok, none}; - - {some, Dynamic_inner} -> - _pipe = Dynamic_inner, - _pipe@1 = gleam_stdlib:decode_option(_pipe, Inner_type), - map_errors( - _pipe@1, - fun(_capture) -> push_path(_capture, Name) end - ) - end end - ) - end. - --spec element( - integer(), - fun((dynamic_()) -> {ok, EAT} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EAT} | {error, list(decode_error())}). -element(Index, Inner_type) -> - fun(Data) -> - gleam@result:'try'( - gleam_stdlib:decode_tuple(Data), - fun(Tuple) -> - Size = gleam_stdlib:size_of_tuple(Tuple), - gleam@result:'try'(case Index >= 0 of - true -> - case Index < Size of - true -> - gleam_stdlib:tuple_get(Tuple, Index); - - false -> - at_least_decode_tuple_error(Index + 1, Data) - end; - - false -> - case gleam@int:absolute_value(Index) =< Size of - true -> - gleam_stdlib:tuple_get(Tuple, Size + Index); - - false -> - at_least_decode_tuple_error( - gleam@int:absolute_value(Index), - Data - ) - end - end, fun(Data@1) -> _pipe = Inner_type(Data@1), - map_errors( - _pipe, - fun(_capture) -> push_path(_capture, Index) end - ) end) - end - ) - end. - --spec tuple_errors({ok, any()} | {error, list(decode_error())}, binary()) -> list(decode_error()). -tuple_errors(Result, Name) -> - case Result of - {ok, _} -> - []; - - {error, Errors} -> - gleam@list:map( - Errors, - fun(_capture) -> push_path(_capture, Name) end - ) - end. - --spec tuple2( - fun((dynamic_()) -> {ok, EBT} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EBV} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, {EBT, EBV}} | {error, list(decode_error())}). -tuple2(Decode1, Decode2) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_tuple2(Value), - fun(_use0) -> - {A, B} = _use0, - case {Decode1(A), Decode2(B)} of - {{ok, A@1}, {ok, B@1}} -> - {ok, {A@1, B@1}}; - - {A@2, B@2} -> - _pipe = tuple_errors(A@2, <<"0"/utf8>>), - _pipe@1 = gleam@list:append( - _pipe, - tuple_errors(B@2, <<"1"/utf8>>) - ), - {error, _pipe@1} - end - end - ) - end. - --spec tuple3( - fun((dynamic_()) -> {ok, EBY} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECA} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECC} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, {EBY, ECA, ECC}} | {error, list(decode_error())}). -tuple3(Decode1, Decode2, Decode3) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_tuple3(Value), - fun(_use0) -> - {A, B, C} = _use0, - case {Decode1(A), Decode2(B), Decode3(C)} of - {{ok, A@1}, {ok, B@1}, {ok, C@1}} -> - {ok, {A@1, B@1, C@1}}; - - {A@2, B@2, C@2} -> - _pipe = tuple_errors(A@2, <<"0"/utf8>>), - _pipe@1 = gleam@list:append( - _pipe, - tuple_errors(B@2, <<"1"/utf8>>) - ), - _pipe@2 = gleam@list:append( - _pipe@1, - tuple_errors(C@2, <<"2"/utf8>>) - ), - {error, _pipe@2} - end - end - ) - end. - --spec tuple4( - fun((dynamic_()) -> {ok, ECF} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECH} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECJ} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECL} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, {ECF, ECH, ECJ, ECL}} | - {error, list(decode_error())}). -tuple4(Decode1, Decode2, Decode3, Decode4) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_tuple4(Value), - fun(_use0) -> - {A, B, C, D} = _use0, - case {Decode1(A), Decode2(B), Decode3(C), Decode4(D)} of - {{ok, A@1}, {ok, B@1}, {ok, C@1}, {ok, D@1}} -> - {ok, {A@1, B@1, C@1, D@1}}; - - {A@2, B@2, C@2, D@2} -> - _pipe = tuple_errors(A@2, <<"0"/utf8>>), - _pipe@1 = gleam@list:append( - _pipe, - tuple_errors(B@2, <<"1"/utf8>>) - ), - _pipe@2 = gleam@list:append( - _pipe@1, - tuple_errors(C@2, <<"2"/utf8>>) - ), - _pipe@3 = gleam@list:append( - _pipe@2, - tuple_errors(D@2, <<"3"/utf8>>) - ), - {error, _pipe@3} - end - end - ) - end. - --spec tuple5( - fun((dynamic_()) -> {ok, ECO} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECQ} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECS} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECU} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, ECW} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, {ECO, ECQ, ECS, ECU, ECW}} | - {error, list(decode_error())}). -tuple5(Decode1, Decode2, Decode3, Decode4, Decode5) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_tuple5(Value), - fun(_use0) -> - {A, B, C, D, E} = _use0, - case {Decode1(A), - Decode2(B), - Decode3(C), - Decode4(D), - Decode5(E)} of - {{ok, A@1}, {ok, B@1}, {ok, C@1}, {ok, D@1}, {ok, E@1}} -> - {ok, {A@1, B@1, C@1, D@1, E@1}}; - - {A@2, B@2, C@2, D@2, E@2} -> - _pipe = tuple_errors(A@2, <<"0"/utf8>>), - _pipe@1 = gleam@list:append( - _pipe, - tuple_errors(B@2, <<"1"/utf8>>) - ), - _pipe@2 = gleam@list:append( - _pipe@1, - tuple_errors(C@2, <<"2"/utf8>>) - ), - _pipe@3 = gleam@list:append( - _pipe@2, - tuple_errors(D@2, <<"3"/utf8>>) - ), - _pipe@4 = gleam@list:append( - _pipe@3, - tuple_errors(E@2, <<"4"/utf8>>) - ), - {error, _pipe@4} - end - end - ) - end. - --spec tuple6( - fun((dynamic_()) -> {ok, ECZ} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EDB} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EDD} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EDF} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EDH} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EDJ} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, {ECZ, EDB, EDD, EDF, EDH, EDJ}} | - {error, list(decode_error())}). -tuple6(Decode1, Decode2, Decode3, Decode4, Decode5, Decode6) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_tuple6(Value), - fun(_use0) -> - {A, B, C, D, E, F} = _use0, - case {Decode1(A), - Decode2(B), - Decode3(C), - Decode4(D), - Decode5(E), - Decode6(F)} of - {{ok, A@1}, - {ok, B@1}, - {ok, C@1}, - {ok, D@1}, - {ok, E@1}, - {ok, F@1}} -> - {ok, {A@1, B@1, C@1, D@1, E@1, F@1}}; - - {A@2, B@2, C@2, D@2, E@2, F@2} -> - _pipe = tuple_errors(A@2, <<"0"/utf8>>), - _pipe@1 = gleam@list:append( - _pipe, - tuple_errors(B@2, <<"1"/utf8>>) - ), - _pipe@2 = gleam@list:append( - _pipe@1, - tuple_errors(C@2, <<"2"/utf8>>) - ), - _pipe@3 = gleam@list:append( - _pipe@2, - tuple_errors(D@2, <<"3"/utf8>>) - ), - _pipe@4 = gleam@list:append( - _pipe@3, - tuple_errors(E@2, <<"4"/utf8>>) - ), - _pipe@5 = gleam@list:append( - _pipe@4, - tuple_errors(F@2, <<"5"/utf8>>) - ), - {error, _pipe@5} - end - end - ) - end. - --spec dict( - fun((dynamic_()) -> {ok, EDM} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EDO} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, gleam@dict:dict(EDM, EDO)} | - {error, list(decode_error())}). -dict(Key_type, Value_type) -> - fun(Value) -> - gleam@result:'try'( - gleam_stdlib:decode_map(Value), - fun(Map) -> - gleam@result:'try'( - begin - _pipe = Map, - _pipe@1 = gleam@dict:to_list(_pipe), - gleam@list:try_map( - _pipe@1, - fun(Pair) -> - {K, V} = Pair, - gleam@result:'try'( - begin - _pipe@2 = Key_type(K), - map_errors( - _pipe@2, - fun(_capture) -> - push_path( - _capture, - <<"keys"/utf8>> - ) - end - ) - end, - fun(K@1) -> - gleam@result:'try'( - begin - _pipe@3 = Value_type(V), - map_errors( - _pipe@3, - fun(_capture@1) -> - push_path( - _capture@1, - <<"values"/utf8>> - ) - end - ) - end, - fun(V@1) -> {ok, {K@1, V@1}} end - ) - end - ) - end - ) - end, - fun(Pairs) -> {ok, gleam@dict:from_list(Pairs)} end - ) - end - ) - end. - --spec map( - fun((dynamic_()) -> {ok, EDT} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EDV} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, gleam@dict:dict(EDT, EDV)} | - {error, list(decode_error())}). -map(Key_type, Value_type) -> - dict(Key_type, Value_type). - --spec decode2( - fun((EEM, EEN) -> EEO), - fun((dynamic_()) -> {ok, EEM} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EEN} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EEO} | {error, list(decode_error())}). -decode2(Constructor, T1, T2) -> - fun(Value) -> case {T1(Value), T2(Value)} of - {{ok, A}, {ok, B}} -> - {ok, Constructor(A, B)}; - - {A@1, B@1} -> - {error, gleam@list:concat([all_errors(A@1), all_errors(B@1)])} - end end. - --spec decode3( - fun((EES, EET, EEU) -> EEV), - fun((dynamic_()) -> {ok, EES} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EET} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EEU} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EEV} | {error, list(decode_error())}). -decode3(Constructor, T1, T2, T3) -> - fun(Value) -> case {T1(Value), T2(Value), T3(Value)} of - {{ok, A}, {ok, B}, {ok, C}} -> - {ok, Constructor(A, B, C)}; - - {A@1, B@1, C@1} -> - {error, - gleam@list:concat( - [all_errors(A@1), all_errors(B@1), all_errors(C@1)] - )} - end end. - --spec decode4( - fun((EFA, EFB, EFC, EFD) -> EFE), - fun((dynamic_()) -> {ok, EFA} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFB} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFC} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFD} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EFE} | {error, list(decode_error())}). -decode4(Constructor, T1, T2, T3, T4) -> - fun(X) -> case {T1(X), T2(X), T3(X), T4(X)} of - {{ok, A}, {ok, B}, {ok, C}, {ok, D}} -> - {ok, Constructor(A, B, C, D)}; - - {A@1, B@1, C@1, D@1} -> - {error, - gleam@list:concat( - [all_errors(A@1), - all_errors(B@1), - all_errors(C@1), - all_errors(D@1)] - )} - end end. - --spec decode5( - fun((EFK, EFL, EFM, EFN, EFO) -> EFP), - fun((dynamic_()) -> {ok, EFK} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFL} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFM} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFN} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFO} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EFP} | {error, list(decode_error())}). -decode5(Constructor, T1, T2, T3, T4, T5) -> - fun(X) -> case {T1(X), T2(X), T3(X), T4(X), T5(X)} of - {{ok, A}, {ok, B}, {ok, C}, {ok, D}, {ok, E}} -> - {ok, Constructor(A, B, C, D, E)}; - - {A@1, B@1, C@1, D@1, E@1} -> - {error, - gleam@list:concat( - [all_errors(A@1), - all_errors(B@1), - all_errors(C@1), - all_errors(D@1), - all_errors(E@1)] - )} - end end. - --spec decode6( - fun((EFW, EFX, EFY, EFZ, EGA, EGB) -> EGC), - fun((dynamic_()) -> {ok, EFW} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFX} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFY} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EFZ} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGA} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGB} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EGC} | {error, list(decode_error())}). -decode6(Constructor, T1, T2, T3, T4, T5, T6) -> - fun(X) -> case {T1(X), T2(X), T3(X), T4(X), T5(X), T6(X)} of - {{ok, A}, {ok, B}, {ok, C}, {ok, D}, {ok, E}, {ok, F}} -> - {ok, Constructor(A, B, C, D, E, F)}; - - {A@1, B@1, C@1, D@1, E@1, F@1} -> - {error, - gleam@list:concat( - [all_errors(A@1), - all_errors(B@1), - all_errors(C@1), - all_errors(D@1), - all_errors(E@1), - all_errors(F@1)] - )} - end end. - --spec decode7( - fun((EGK, EGL, EGM, EGN, EGO, EGP, EGQ) -> EGR), - fun((dynamic_()) -> {ok, EGK} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGL} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGM} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGN} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGO} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGP} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EGQ} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EGR} | {error, list(decode_error())}). -decode7(Constructor, T1, T2, T3, T4, T5, T6, T7) -> - fun(X) -> case {T1(X), T2(X), T3(X), T4(X), T5(X), T6(X), T7(X)} of - {{ok, A}, {ok, B}, {ok, C}, {ok, D}, {ok, E}, {ok, F}, {ok, G}} -> - {ok, Constructor(A, B, C, D, E, F, G)}; - - {A@1, B@1, C@1, D@1, E@1, F@1, G@1} -> - {error, - gleam@list:concat( - [all_errors(A@1), - all_errors(B@1), - all_errors(C@1), - all_errors(D@1), - all_errors(E@1), - all_errors(F@1), - all_errors(G@1)] - )} - end end. - --spec decode8( - fun((EHA, EHB, EHC, EHD, EHE, EHF, EHG, EHH) -> EHI), - fun((dynamic_()) -> {ok, EHA} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHB} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHC} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHD} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHE} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHF} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHG} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHH} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EHI} | {error, list(decode_error())}). -decode8(Constructor, T1, T2, T3, T4, T5, T6, T7, T8) -> - fun(X) -> case {T1(X), T2(X), T3(X), T4(X), T5(X), T6(X), T7(X), T8(X)} of - {{ok, A}, - {ok, B}, - {ok, C}, - {ok, D}, - {ok, E}, - {ok, F}, - {ok, G}, - {ok, H}} -> - {ok, Constructor(A, B, C, D, E, F, G, H)}; - - {A@1, B@1, C@1, D@1, E@1, F@1, G@1, H@1} -> - {error, - gleam@list:concat( - [all_errors(A@1), - all_errors(B@1), - all_errors(C@1), - all_errors(D@1), - all_errors(E@1), - all_errors(F@1), - all_errors(G@1), - all_errors(H@1)] - )} - end end. - --spec decode9( - fun((EHS, EHT, EHU, EHV, EHW, EHX, EHY, EHZ, EIA) -> EIB), - fun((dynamic_()) -> {ok, EHS} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHT} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHU} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHV} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHW} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHX} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHY} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EHZ} | {error, list(decode_error())}), - fun((dynamic_()) -> {ok, EIA} | {error, list(decode_error())}) -) -> fun((dynamic_()) -> {ok, EIB} | {error, list(decode_error())}). -decode9(Constructor, T1, T2, T3, T4, T5, T6, T7, T8, T9) -> - fun(X) -> - case {T1(X), T2(X), T3(X), T4(X), T5(X), T6(X), T7(X), T8(X), T9(X)} of - {{ok, A}, - {ok, B}, - {ok, C}, - {ok, D}, - {ok, E}, - {ok, F}, - {ok, G}, - {ok, H}, - {ok, I}} -> - {ok, Constructor(A, B, C, D, E, F, G, H, I)}; - - {A@1, B@1, C@1, D@1, E@1, F@1, G@1, H@1, I@1} -> - {error, - gleam@list:concat( - [all_errors(A@1), - all_errors(B@1), - all_errors(C@1), - all_errors(D@1), - all_errors(E@1), - all_errors(F@1), - all_errors(G@1), - all_errors(H@1), - all_errors(I@1)] - )} - end - end. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@float.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@float.erl deleted file mode 100644 index 33b3d4a..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@float.erl +++ /dev/null @@ -1,181 +0,0 @@ --module(gleam@float). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([parse/1, to_string/1, compare/2, min/2, max/2, clamp/3, ceiling/1, floor/1, round/1, truncate/1, absolute_value/1, loosely_compare/3, loosely_equals/3, power/2, square_root/1, negate/1, sum/1, product/1, random/2, divide/2, add/2, multiply/2, subtract/2]). - --spec parse(binary()) -> {ok, float()} | {error, nil}. -parse(String) -> - gleam_stdlib:parse_float(String). - --spec to_string(float()) -> binary(). -to_string(X) -> - gleam_stdlib:float_to_string(X). - --spec compare(float(), float()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - false -> - case A < B of - true -> - lt; - - false -> - gt - end - end. - --spec min(float(), float()) -> float(). -min(A, B) -> - case A < B of - true -> - A; - - false -> - B - end. - --spec max(float(), float()) -> float(). -max(A, B) -> - case A > B of - true -> - A; - - false -> - B - end. - --spec clamp(float(), float(), float()) -> float(). -clamp(X, Min_bound, Max_bound) -> - _pipe = X, - _pipe@1 = min(_pipe, Max_bound), - max(_pipe@1, Min_bound). - --spec ceiling(float()) -> float(). -ceiling(X) -> - math:ceil(X). - --spec floor(float()) -> float(). -floor(X) -> - math:floor(X). - --spec round(float()) -> integer(). -round(X) -> - erlang:round(X). - --spec truncate(float()) -> integer(). -truncate(X) -> - erlang:trunc(X). - --spec absolute_value(float()) -> float(). -absolute_value(X) -> - case X >= +0.0 of - true -> - X; - - _ -> - +0.0 - X - end. - --spec loosely_compare(float(), float(), float()) -> gleam@order:order(). -loosely_compare(A, B, Tolerance) -> - Difference = absolute_value(A - B), - case Difference =< Tolerance of - true -> - eq; - - false -> - compare(A, B) - end. - --spec loosely_equals(float(), float(), float()) -> boolean(). -loosely_equals(A, B, Tolerance) -> - Difference = absolute_value(A - B), - Difference =< Tolerance. - --spec power(float(), float()) -> {ok, float()} | {error, nil}. -power(Base, Exponent) -> - Fractional = (ceiling(Exponent) - Exponent) > +0.0, - case ((Base < +0.0) andalso Fractional) orelse ((Base =:= +0.0) andalso (Exponent - < +0.0)) of - true -> - {error, nil}; - - false -> - {ok, math:pow(Base, Exponent)} - end. - --spec square_root(float()) -> {ok, float()} | {error, nil}. -square_root(X) -> - power(X, 0.5). - --spec negate(float()) -> float(). -negate(X) -> - -1.0 * X. - --spec do_sum(list(float()), float()) -> float(). -do_sum(Numbers, Initial) -> - case Numbers of - [] -> - Initial; - - [X | Rest] -> - do_sum(Rest, X + Initial) - end. - --spec sum(list(float())) -> float(). -sum(Numbers) -> - _pipe = Numbers, - do_sum(_pipe, +0.0). - --spec do_product(list(float()), float()) -> float(). -do_product(Numbers, Initial) -> - case Numbers of - [] -> - Initial; - - [X | Rest] -> - do_product(Rest, X * Initial) - end. - --spec product(list(float())) -> float(). -product(Numbers) -> - case Numbers of - [] -> - 1.0; - - _ -> - do_product(Numbers, 1.0) - end. - --spec random(float(), float()) -> float(). -random(Min, Max) -> - (rand:uniform() * (Max - Min)) + Min. - --spec divide(float(), float()) -> {ok, float()} | {error, nil}. -divide(A, B) -> - case B of - +0.0 -> - {error, nil}; - - B@1 -> - {ok, case B@1 of - +0.0 -> +0.0; - -0.0 -> -0.0; - Gleam@denominator -> A / Gleam@denominator - end} - end. - --spec add(float(), float()) -> float(). -add(A, B) -> - A + B. - --spec multiply(float(), float()) -> float(). -multiply(A, B) -> - A * B. - --spec subtract(float(), float()) -> float(). -subtract(A, B) -> - A - B. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@function.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@function.erl deleted file mode 100644 index 3496318..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@function.erl +++ /dev/null @@ -1,67 +0,0 @@ --module(gleam@function). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([compose/2, curry2/1, curry3/1, curry4/1, curry5/1, curry6/1, flip/1, identity/1, constant/1, tap/2, apply1/2, apply2/3, apply3/4]). - --spec compose(fun((DOO) -> DOP), fun((DOP) -> DOQ)) -> fun((DOO) -> DOQ). -compose(Fun1, Fun2) -> - fun(A) -> Fun2(Fun1(A)) end. - --spec curry2(fun((DOR, DOS) -> DOT)) -> fun((DOR) -> fun((DOS) -> DOT)). -curry2(Fun) -> - fun(A) -> fun(B) -> Fun(A, B) end end. - --spec curry3(fun((DOV, DOW, DOX) -> DOY)) -> fun((DOV) -> fun((DOW) -> fun((DOX) -> DOY))). -curry3(Fun) -> - fun(A) -> fun(B) -> fun(C) -> Fun(A, B, C) end end end. - --spec curry4(fun((DPA, DPB, DPC, DPD) -> DPE)) -> fun((DPA) -> fun((DPB) -> fun((DPC) -> fun((DPD) -> DPE)))). -curry4(Fun) -> - fun(A) -> fun(B) -> fun(C) -> fun(D) -> Fun(A, B, C, D) end end end end. - --spec curry5(fun((DPG, DPH, DPI, DPJ, DPK) -> DPL)) -> fun((DPG) -> fun((DPH) -> fun((DPI) -> fun((DPJ) -> fun((DPK) -> DPL))))). -curry5(Fun) -> - fun(A) -> - fun(B) -> - fun(C) -> fun(D) -> fun(E) -> Fun(A, B, C, D, E) end end end - end - end. - --spec curry6(fun((DPN, DPO, DPP, DPQ, DPR, DPS) -> DPT)) -> fun((DPN) -> fun((DPO) -> fun((DPP) -> fun((DPQ) -> fun((DPR) -> fun((DPS) -> DPT)))))). -curry6(Fun) -> - fun(A) -> - fun(B) -> - fun(C) -> - fun(D) -> fun(E) -> fun(F) -> Fun(A, B, C, D, E, F) end end end - end - end - end. - --spec flip(fun((DPV, DPW) -> DPX)) -> fun((DPW, DPV) -> DPX). -flip(Fun) -> - fun(B, A) -> Fun(A, B) end. - --spec identity(DPY) -> DPY. -identity(X) -> - X. - --spec constant(DPZ) -> fun((any()) -> DPZ). -constant(Value) -> - fun(_) -> Value end. - --spec tap(DQB, fun((DQB) -> any())) -> DQB. -tap(Arg, Effect) -> - Effect(Arg), - Arg. - --spec apply1(fun((DQD) -> DQE), DQD) -> DQE. -apply1(Fun, Arg1) -> - Fun(Arg1). - --spec apply2(fun((DQF, DQG) -> DQH), DQF, DQG) -> DQH. -apply2(Fun, Arg1, Arg2) -> - Fun(Arg1, Arg2). - --spec apply3(fun((DQI, DQJ, DQK) -> DQL), DQI, DQJ, DQK) -> DQL. -apply3(Fun, Arg1, Arg2, Arg3) -> - Fun(Arg1, Arg2, Arg3). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@int.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@int.erl deleted file mode 100644 index 2a5dd2c..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@int.erl +++ /dev/null @@ -1,332 +0,0 @@ --module(gleam@int). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([absolute_value/1, parse/1, base_parse/2, to_string/1, to_base_string/2, to_base2/1, to_base8/1, to_base16/1, to_base36/1, to_float/1, power/2, square_root/1, compare/2, min/2, max/2, clamp/3, is_even/1, is_odd/1, negate/1, sum/1, product/1, digits/2, undigits/2, random/2, divide/2, remainder/2, modulo/2, floor_divide/2, add/2, multiply/2, subtract/2, bitwise_and/2, bitwise_not/1, bitwise_or/2, bitwise_exclusive_or/2, bitwise_shift_left/2, bitwise_shift_right/2]). --export_type([invalid_base/0]). - --type invalid_base() :: invalid_base. - --spec absolute_value(integer()) -> integer(). -absolute_value(X) -> - case X >= 0 of - true -> - X; - - false -> - X * -1 - end. - --spec parse(binary()) -> {ok, integer()} | {error, nil}. -parse(String) -> - gleam_stdlib:parse_int(String). - --spec base_parse(binary(), integer()) -> {ok, integer()} | {error, nil}. -base_parse(String, Base) -> - case (Base >= 2) andalso (Base =< 36) of - true -> - gleam_stdlib:int_from_base_string(String, Base); - - false -> - {error, nil} - end. - --spec to_string(integer()) -> binary(). -to_string(X) -> - erlang:integer_to_binary(X). - --spec to_base_string(integer(), integer()) -> {ok, binary()} | - {error, invalid_base()}. -to_base_string(X, Base) -> - case (Base >= 2) andalso (Base =< 36) of - true -> - {ok, erlang:integer_to_binary(X, Base)}; - - false -> - {error, invalid_base} - end. - --spec to_base2(integer()) -> binary(). -to_base2(X) -> - erlang:integer_to_binary(X, 2). - --spec to_base8(integer()) -> binary(). -to_base8(X) -> - erlang:integer_to_binary(X, 8). - --spec to_base16(integer()) -> binary(). -to_base16(X) -> - erlang:integer_to_binary(X, 16). - --spec to_base36(integer()) -> binary(). -to_base36(X) -> - erlang:integer_to_binary(X, 36). - --spec to_float(integer()) -> float(). -to_float(X) -> - erlang:float(X). - --spec power(integer(), float()) -> {ok, float()} | {error, nil}. -power(Base, Exponent) -> - _pipe = Base, - _pipe@1 = to_float(_pipe), - gleam@float:power(_pipe@1, Exponent). - --spec square_root(integer()) -> {ok, float()} | {error, nil}. -square_root(X) -> - _pipe = X, - _pipe@1 = to_float(_pipe), - gleam@float:square_root(_pipe@1). - --spec compare(integer(), integer()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - false -> - case A < B of - true -> - lt; - - false -> - gt - end - end. - --spec min(integer(), integer()) -> integer(). -min(A, B) -> - case A < B of - true -> - A; - - false -> - B - end. - --spec max(integer(), integer()) -> integer(). -max(A, B) -> - case A > B of - true -> - A; - - false -> - B - end. - --spec clamp(integer(), integer(), integer()) -> integer(). -clamp(X, Min_bound, Max_bound) -> - _pipe = X, - _pipe@1 = min(_pipe, Max_bound), - max(_pipe@1, Min_bound). - --spec is_even(integer()) -> boolean(). -is_even(X) -> - (X rem 2) =:= 0. - --spec is_odd(integer()) -> boolean(). -is_odd(X) -> - (X rem 2) /= 0. - --spec negate(integer()) -> integer(). -negate(X) -> - -1 * X. - --spec do_sum(list(integer()), integer()) -> integer(). -do_sum(Numbers, Initial) -> - case Numbers of - [] -> - Initial; - - [X | Rest] -> - do_sum(Rest, X + Initial) - end. - --spec sum(list(integer())) -> integer(). -sum(Numbers) -> - _pipe = Numbers, - do_sum(_pipe, 0). - --spec do_product(list(integer()), integer()) -> integer(). -do_product(Numbers, Initial) -> - case Numbers of - [] -> - Initial; - - [X | Rest] -> - do_product(Rest, X * Initial) - end. - --spec product(list(integer())) -> integer(). -product(Numbers) -> - case Numbers of - [] -> - 1; - - _ -> - do_product(Numbers, 1) - end. - --spec do_digits(integer(), integer(), list(integer())) -> list(integer()). -do_digits(X, Base, Acc) -> - case absolute_value(X) < Base of - true -> - [X | Acc]; - - false -> - do_digits(case Base of - 0 -> 0; - Gleam@denominator -> X div Gleam@denominator - end, Base, [case Base of - 0 -> 0; - Gleam@denominator@1 -> X rem Gleam@denominator@1 - end | Acc]) - end. - --spec digits(integer(), integer()) -> {ok, list(integer())} | - {error, invalid_base()}. -digits(X, Base) -> - case Base < 2 of - true -> - {error, invalid_base}; - - false -> - {ok, do_digits(X, Base, [])} - end. - --spec do_undigits(list(integer()), integer(), integer()) -> {ok, integer()} | - {error, invalid_base()}. -do_undigits(Numbers, Base, Acc) -> - case Numbers of - [] -> - {ok, Acc}; - - [Digit | _] when Digit >= Base -> - {error, invalid_base}; - - [Digit@1 | Rest] -> - do_undigits(Rest, Base, (Acc * Base) + Digit@1) - end. - --spec undigits(list(integer()), integer()) -> {ok, integer()} | - {error, invalid_base()}. -undigits(Numbers, Base) -> - case Base < 2 of - true -> - {error, invalid_base}; - - false -> - do_undigits(Numbers, Base, 0) - end. - --spec random(integer(), integer()) -> integer(). -random(Min, Max) -> - _pipe = gleam@float:random(to_float(Min), to_float(Max)), - _pipe@1 = gleam@float:floor(_pipe), - gleam@float:round(_pipe@1). - --spec divide(integer(), integer()) -> {ok, integer()} | {error, nil}. -divide(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend div Gleam@denominator - end} - end. - --spec remainder(integer(), integer()) -> {ok, integer()} | {error, nil}. -remainder(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end} - end. - --spec modulo(integer(), integer()) -> {ok, integer()} | {error, nil}. -modulo(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - _ -> - Remainder = case Divisor of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end, - case (Remainder * Divisor) < 0 of - true -> - {ok, Remainder + Divisor}; - - false -> - {ok, Remainder} - end - end. - --spec floor_divide(integer(), integer()) -> {ok, integer()} | {error, nil}. -floor_divide(Dividend, Divisor) -> - case Divisor of - 0 -> - {error, nil}; - - Divisor@1 -> - case ((Dividend * Divisor@1) < 0) andalso ((case Divisor@1 of - 0 -> 0; - Gleam@denominator -> Dividend rem Gleam@denominator - end) /= 0) of - true -> - {ok, (case Divisor@1 of - 0 -> 0; - Gleam@denominator@1 -> Dividend div Gleam@denominator@1 - end) - 1}; - - false -> - {ok, case Divisor@1 of - 0 -> 0; - Gleam@denominator@2 -> Dividend div Gleam@denominator@2 - end} - end - end. - --spec add(integer(), integer()) -> integer(). -add(A, B) -> - A + B. - --spec multiply(integer(), integer()) -> integer(). -multiply(A, B) -> - A * B. - --spec subtract(integer(), integer()) -> integer(). -subtract(A, B) -> - A - B. - --spec bitwise_and(integer(), integer()) -> integer(). -bitwise_and(X, Y) -> - erlang:'band'(X, Y). - --spec bitwise_not(integer()) -> integer(). -bitwise_not(X) -> - erlang:'bnot'(X). - --spec bitwise_or(integer(), integer()) -> integer(). -bitwise_or(X, Y) -> - erlang:'bor'(X, Y). - --spec bitwise_exclusive_or(integer(), integer()) -> integer(). -bitwise_exclusive_or(X, Y) -> - erlang:'bxor'(X, Y). - --spec bitwise_shift_left(integer(), integer()) -> integer(). -bitwise_shift_left(X, Y) -> - erlang:'bsl'(X, Y). - --spec bitwise_shift_right(integer(), integer()) -> integer(). -bitwise_shift_right(X, Y) -> - erlang:'bsr'(X, Y). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@io.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@io.erl deleted file mode 100644 index a46eae3..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@io.erl +++ /dev/null @@ -1,27 +0,0 @@ --module(gleam@io). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([print/1, print_error/1, println/1, println_error/1, debug/1]). - --spec print(binary()) -> nil. -print(String) -> - gleam_stdlib:print(String). - --spec print_error(binary()) -> nil. -print_error(String) -> - gleam_stdlib:print_error(String). - --spec println(binary()) -> nil. -println(String) -> - gleam_stdlib:println(String). - --spec println_error(binary()) -> nil. -println_error(String) -> - gleam_stdlib:println_error(String). - --spec debug(CZT) -> CZT. -debug(Term) -> - _pipe = Term, - _pipe@1 = gleam@string:inspect(_pipe), - gleam_stdlib:println_error(_pipe@1), - Term. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@iterator.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@iterator.erl deleted file mode 100644 index aa84139..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@iterator.erl +++ /dev/null @@ -1,744 +0,0 @@ --module(gleam@iterator). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([unfold/2, repeatedly/1, repeat/1, from_list/1, transform/3, fold/3, run/1, to_list/1, step/1, take/2, drop/2, map/2, map2/3, append/2, flatten/1, concat/1, flat_map/2, filter/2, cycle/1, find/2, index/1, iterate/2, take_while/2, drop_while/2, scan/3, zip/2, chunk/2, sized_chunk/2, intersperse/2, any/2, all/2, group/2, reduce/2, last/1, empty/0, once/1, range/2, single/1, interleave/2, fold_until/3, try_fold/3, first/1, at/2, length/1, each/2, yield/2]). --export_type([action/1, iterator/1, step/2, chunk/2, sized_chunk/1]). - --type action(BPF) :: stop | {continue, BPF, fun(() -> action(BPF))}. - --opaque iterator(BPG) :: {iterator, fun(() -> action(BPG))}. - --type step(BPH, BPI) :: {next, BPH, BPI} | done. - --type chunk(BPJ, BPK) :: {another_by, - list(BPJ), - BPK, - BPJ, - fun(() -> action(BPJ))} | - {last_by, list(BPJ)}. - --type sized_chunk(BPL) :: {another, list(BPL), fun(() -> action(BPL))} | - {last, list(BPL)} | - no_more. - --spec stop() -> action(any()). -stop() -> - stop. - --spec do_unfold(BPO, fun((BPO) -> step(BPP, BPO))) -> fun(() -> action(BPP)). -do_unfold(Initial, F) -> - fun() -> case F(Initial) of - {next, X, Acc} -> - {continue, X, do_unfold(Acc, F)}; - - done -> - stop - end end. - --spec unfold(BPT, fun((BPT) -> step(BPU, BPT))) -> iterator(BPU). -unfold(Initial, F) -> - _pipe = Initial, - _pipe@1 = do_unfold(_pipe, F), - {iterator, _pipe@1}. - --spec repeatedly(fun(() -> BPY)) -> iterator(BPY). -repeatedly(F) -> - unfold(nil, fun(_) -> {next, F(), nil} end). - --spec repeat(BQA) -> iterator(BQA). -repeat(X) -> - repeatedly(fun() -> X end). - --spec from_list(list(BQC)) -> iterator(BQC). -from_list(List) -> - Yield = fun(Acc) -> case Acc of - [] -> - done; - - [Head | Tail] -> - {next, Head, Tail} - end end, - unfold(List, Yield). - --spec do_transform( - fun(() -> action(BQF)), - BQH, - fun((BQH, BQF) -> step(BQI, BQH)) -) -> fun(() -> action(BQI)). -do_transform(Continuation, State, F) -> - fun() -> case Continuation() of - stop -> - stop; - - {continue, El, Next} -> - case F(State, El) of - done -> - stop; - - {next, Yield, Next_state} -> - {continue, Yield, do_transform(Next, Next_state, F)} - end - end end. - --spec transform(iterator(BQM), BQO, fun((BQO, BQM) -> step(BQP, BQO))) -> iterator(BQP). -transform(Iterator, Initial, F) -> - _pipe = do_transform(erlang:element(2, Iterator), Initial, F), - {iterator, _pipe}. - --spec do_fold(fun(() -> action(BQT)), fun((BQV, BQT) -> BQV), BQV) -> BQV. -do_fold(Continuation, F, Accumulator) -> - case Continuation() of - {continue, Elem, Next} -> - do_fold(Next, F, F(Accumulator, Elem)); - - stop -> - Accumulator - end. - --spec fold(iterator(BQW), BQY, fun((BQY, BQW) -> BQY)) -> BQY. -fold(Iterator, Initial, F) -> - _pipe = erlang:element(2, Iterator), - do_fold(_pipe, F, Initial). - --spec run(iterator(any())) -> nil. -run(Iterator) -> - fold(Iterator, nil, fun(_, _) -> nil end). - --spec to_list(iterator(BRB)) -> list(BRB). -to_list(Iterator) -> - _pipe = Iterator, - _pipe@1 = fold(_pipe, [], fun(Acc, E) -> [E | Acc] end), - gleam@list:reverse(_pipe@1). - --spec step(iterator(BRE)) -> step(BRE, iterator(BRE)). -step(Iterator) -> - case (erlang:element(2, Iterator))() of - stop -> - done; - - {continue, E, A} -> - {next, E, {iterator, A}} - end. - --spec do_take(fun(() -> action(BRJ)), integer()) -> fun(() -> action(BRJ)). -do_take(Continuation, Desired) -> - fun() -> case Desired > 0 of - false -> - stop; - - true -> - case Continuation() of - stop -> - stop; - - {continue, E, Next} -> - {continue, E, do_take(Next, Desired - 1)} - end - end end. - --spec take(iterator(BRM), integer()) -> iterator(BRM). -take(Iterator, Desired) -> - _pipe = erlang:element(2, Iterator), - _pipe@1 = do_take(_pipe, Desired), - {iterator, _pipe@1}. - --spec do_drop(fun(() -> action(BRP)), integer()) -> action(BRP). -do_drop(Continuation, Desired) -> - case Continuation() of - stop -> - stop; - - {continue, E, Next} -> - case Desired > 0 of - true -> - do_drop(Next, Desired - 1); - - false -> - {continue, E, Next} - end - end. - --spec drop(iterator(BRS), integer()) -> iterator(BRS). -drop(Iterator, Desired) -> - _pipe = fun() -> do_drop(erlang:element(2, Iterator), Desired) end, - {iterator, _pipe}. - --spec do_map(fun(() -> action(BRV)), fun((BRV) -> BRX)) -> fun(() -> action(BRX)). -do_map(Continuation, F) -> - fun() -> case Continuation() of - stop -> - stop; - - {continue, E, Continuation@1} -> - {continue, F(E), do_map(Continuation@1, F)} - end end. - --spec map(iterator(BRZ), fun((BRZ) -> BSB)) -> iterator(BSB). -map(Iterator, F) -> - _pipe = erlang:element(2, Iterator), - _pipe@1 = do_map(_pipe, F), - {iterator, _pipe@1}. - --spec do_map2( - fun(() -> action(BSD)), - fun(() -> action(BSF)), - fun((BSD, BSF) -> BSH) -) -> fun(() -> action(BSH)). -do_map2(Continuation1, Continuation2, Fun) -> - fun() -> case Continuation1() of - stop -> - stop; - - {continue, A, Next_a} -> - case Continuation2() of - stop -> - stop; - - {continue, B, Next_b} -> - {continue, Fun(A, B), do_map2(Next_a, Next_b, Fun)} - end - end end. - --spec map2(iterator(BSJ), iterator(BSL), fun((BSJ, BSL) -> BSN)) -> iterator(BSN). -map2(Iterator1, Iterator2, Fun) -> - _pipe = do_map2( - erlang:element(2, Iterator1), - erlang:element(2, Iterator2), - Fun - ), - {iterator, _pipe}. - --spec do_append(fun(() -> action(BSP)), fun(() -> action(BSP))) -> action(BSP). -do_append(First, Second) -> - case First() of - {continue, E, First@1} -> - {continue, E, fun() -> do_append(First@1, Second) end}; - - stop -> - Second() - end. - --spec append(iterator(BST), iterator(BST)) -> iterator(BST). -append(First, Second) -> - _pipe = fun() -> - do_append(erlang:element(2, First), erlang:element(2, Second)) - end, - {iterator, _pipe}. - --spec do_flatten(fun(() -> action(iterator(BSX)))) -> action(BSX). -do_flatten(Flattened) -> - case Flattened() of - stop -> - stop; - - {continue, It, Next_iterator} -> - do_append( - erlang:element(2, It), - fun() -> do_flatten(Next_iterator) end - ) - end. - --spec flatten(iterator(iterator(BTB))) -> iterator(BTB). -flatten(Iterator) -> - _pipe = fun() -> do_flatten(erlang:element(2, Iterator)) end, - {iterator, _pipe}. - --spec concat(list(iterator(BTF))) -> iterator(BTF). -concat(Iterators) -> - flatten(from_list(Iterators)). - --spec flat_map(iterator(BTJ), fun((BTJ) -> iterator(BTL))) -> iterator(BTL). -flat_map(Iterator, F) -> - _pipe = Iterator, - _pipe@1 = map(_pipe, F), - flatten(_pipe@1). - --spec do_filter(fun(() -> action(BTO)), fun((BTO) -> boolean())) -> action(BTO). -do_filter(Continuation, Predicate) -> - case Continuation() of - stop -> - stop; - - {continue, E, Iterator} -> - case Predicate(E) of - true -> - {continue, E, fun() -> do_filter(Iterator, Predicate) end}; - - false -> - do_filter(Iterator, Predicate) - end - end. - --spec filter(iterator(BTR), fun((BTR) -> boolean())) -> iterator(BTR). -filter(Iterator, Predicate) -> - _pipe = fun() -> do_filter(erlang:element(2, Iterator), Predicate) end, - {iterator, _pipe}. - --spec cycle(iterator(BTU)) -> iterator(BTU). -cycle(Iterator) -> - _pipe = repeat(Iterator), - flatten(_pipe). - --spec do_find(fun(() -> action(BTY)), fun((BTY) -> boolean())) -> {ok, BTY} | - {error, nil}. -do_find(Continuation, F) -> - case Continuation() of - stop -> - {error, nil}; - - {continue, E, Next} -> - case F(E) of - true -> - {ok, E}; - - false -> - do_find(Next, F) - end - end. - --spec find(iterator(BUC), fun((BUC) -> boolean())) -> {ok, BUC} | {error, nil}. -find(Haystack, Is_desired) -> - _pipe = erlang:element(2, Haystack), - do_find(_pipe, Is_desired). - --spec do_index(fun(() -> action(BUG)), integer()) -> fun(() -> action({integer(), - BUG})). -do_index(Continuation, Next) -> - fun() -> case Continuation() of - stop -> - stop; - - {continue, E, Continuation@1} -> - {continue, {Next, E}, do_index(Continuation@1, Next + 1)} - end end. - --spec index(iterator(BUJ)) -> iterator({integer(), BUJ}). -index(Iterator) -> - _pipe = erlang:element(2, Iterator), - _pipe@1 = do_index(_pipe, 0), - {iterator, _pipe@1}. - --spec iterate(BUM, fun((BUM) -> BUM)) -> iterator(BUM). -iterate(Initial, F) -> - unfold(Initial, fun(Element) -> {next, Element, F(Element)} end). - --spec do_take_while(fun(() -> action(BUO)), fun((BUO) -> boolean())) -> fun(() -> action(BUO)). -do_take_while(Continuation, Predicate) -> - fun() -> case Continuation() of - stop -> - stop; - - {continue, E, Next} -> - case Predicate(E) of - false -> - stop; - - true -> - {continue, E, do_take_while(Next, Predicate)} - end - end end. - --spec take_while(iterator(BUR), fun((BUR) -> boolean())) -> iterator(BUR). -take_while(Iterator, Predicate) -> - _pipe = erlang:element(2, Iterator), - _pipe@1 = do_take_while(_pipe, Predicate), - {iterator, _pipe@1}. - --spec do_drop_while(fun(() -> action(BUU)), fun((BUU) -> boolean())) -> action(BUU). -do_drop_while(Continuation, Predicate) -> - case Continuation() of - stop -> - stop; - - {continue, E, Next} -> - case Predicate(E) of - false -> - {continue, E, Next}; - - true -> - do_drop_while(Next, Predicate) - end - end. - --spec drop_while(iterator(BUX), fun((BUX) -> boolean())) -> iterator(BUX). -drop_while(Iterator, Predicate) -> - _pipe = fun() -> do_drop_while(erlang:element(2, Iterator), Predicate) end, - {iterator, _pipe}. - --spec do_scan(fun(() -> action(BVA)), fun((BVC, BVA) -> BVC), BVC) -> fun(() -> action(BVC)). -do_scan(Continuation, F, Accumulator) -> - fun() -> case Continuation() of - stop -> - stop; - - {continue, El, Next} -> - Accumulated = F(Accumulator, El), - {continue, Accumulated, do_scan(Next, F, Accumulated)} - end end. - --spec scan(iterator(BVE), BVG, fun((BVG, BVE) -> BVG)) -> iterator(BVG). -scan(Iterator, Initial, F) -> - _pipe = erlang:element(2, Iterator), - _pipe@1 = do_scan(_pipe, F, Initial), - {iterator, _pipe@1}. - --spec do_zip(fun(() -> action(BVI)), fun(() -> action(BVK))) -> fun(() -> action({BVI, - BVK})). -do_zip(Left, Right) -> - fun() -> case Left() of - stop -> - stop; - - {continue, El_left, Next_left} -> - case Right() of - stop -> - stop; - - {continue, El_right, Next_right} -> - {continue, - {El_left, El_right}, - do_zip(Next_left, Next_right)} - end - end end. - --spec zip(iterator(BVN), iterator(BVP)) -> iterator({BVN, BVP}). -zip(Left, Right) -> - _pipe = do_zip(erlang:element(2, Left), erlang:element(2, Right)), - {iterator, _pipe}. - --spec next_chunk(fun(() -> action(BVS)), fun((BVS) -> BVU), BVU, list(BVS)) -> chunk(BVS, BVU). -next_chunk(Continuation, F, Previous_key, Current_chunk) -> - case Continuation() of - stop -> - {last_by, gleam@list:reverse(Current_chunk)}; - - {continue, E, Next} -> - Key = F(E), - case Key =:= Previous_key of - true -> - next_chunk(Next, F, Key, [E | Current_chunk]); - - false -> - {another_by, - gleam@list:reverse(Current_chunk), - Key, - E, - Next} - end - end. - --spec do_chunk(fun(() -> action(BVY)), fun((BVY) -> BWA), BWA, BVY) -> action(list(BVY)). -do_chunk(Continuation, F, Previous_key, Previous_element) -> - case next_chunk(Continuation, F, Previous_key, [Previous_element]) of - {last_by, Chunk} -> - {continue, Chunk, fun stop/0}; - - {another_by, Chunk@1, Key, El, Next} -> - {continue, Chunk@1, fun() -> do_chunk(Next, F, Key, El) end} - end. - --spec chunk(iterator(BWD), fun((BWD) -> any())) -> iterator(list(BWD)). -chunk(Iterator, F) -> - _pipe = fun() -> case (erlang:element(2, Iterator))() of - stop -> - stop; - - {continue, E, Next} -> - do_chunk(Next, F, F(E), E) - end end, - {iterator, _pipe}. - --spec next_sized_chunk(fun(() -> action(BWI)), integer(), list(BWI)) -> sized_chunk(BWI). -next_sized_chunk(Continuation, Left, Current_chunk) -> - case Continuation() of - stop -> - case Current_chunk of - [] -> - no_more; - - Remaining -> - {last, gleam@list:reverse(Remaining)} - end; - - {continue, E, Next} -> - Chunk = [E | Current_chunk], - case Left > 1 of - false -> - {another, gleam@list:reverse(Chunk), Next}; - - true -> - next_sized_chunk(Next, Left - 1, Chunk) - end - end. - --spec do_sized_chunk(fun(() -> action(BWM)), integer()) -> fun(() -> action(list(BWM))). -do_sized_chunk(Continuation, Count) -> - fun() -> case next_sized_chunk(Continuation, Count, []) of - no_more -> - stop; - - {last, Chunk} -> - {continue, Chunk, fun stop/0}; - - {another, Chunk@1, Next_element} -> - {continue, Chunk@1, do_sized_chunk(Next_element, Count)} - end end. - --spec sized_chunk(iterator(BWQ), integer()) -> iterator(list(BWQ)). -sized_chunk(Iterator, Count) -> - _pipe = erlang:element(2, Iterator), - _pipe@1 = do_sized_chunk(_pipe, Count), - {iterator, _pipe@1}. - --spec do_intersperse(fun(() -> action(BWU)), BWU) -> action(BWU). -do_intersperse(Continuation, Separator) -> - case Continuation() of - stop -> - stop; - - {continue, E, Next} -> - Next_interspersed = fun() -> do_intersperse(Next, Separator) end, - {continue, Separator, fun() -> {continue, E, Next_interspersed} end} - end. - --spec intersperse(iterator(BWX), BWX) -> iterator(BWX). -intersperse(Iterator, Elem) -> - _pipe = fun() -> case (erlang:element(2, Iterator))() of - stop -> - stop; - - {continue, E, Next} -> - {continue, E, fun() -> do_intersperse(Next, Elem) end} - end end, - {iterator, _pipe}. - --spec do_any(fun(() -> action(BXA)), fun((BXA) -> boolean())) -> boolean(). -do_any(Continuation, Predicate) -> - case Continuation() of - stop -> - false; - - {continue, E, Next} -> - case Predicate(E) of - true -> - true; - - false -> - do_any(Next, Predicate) - end - end. - --spec any(iterator(BXC), fun((BXC) -> boolean())) -> boolean(). -any(Iterator, Predicate) -> - _pipe = erlang:element(2, Iterator), - do_any(_pipe, Predicate). - --spec do_all(fun(() -> action(BXE)), fun((BXE) -> boolean())) -> boolean(). -do_all(Continuation, Predicate) -> - case Continuation() of - stop -> - true; - - {continue, E, Next} -> - case Predicate(E) of - true -> - do_all(Next, Predicate); - - false -> - false - end - end. - --spec all(iterator(BXG), fun((BXG) -> boolean())) -> boolean(). -all(Iterator, Predicate) -> - _pipe = erlang:element(2, Iterator), - do_all(_pipe, Predicate). - --spec update_group_with(BXI) -> fun((gleam@option:option(list(BXI))) -> list(BXI)). -update_group_with(El) -> - fun(Maybe_group) -> case Maybe_group of - {some, Group} -> - [El | Group]; - - none -> - [El] - end end. - --spec group_updater(fun((BXM) -> BXN)) -> fun((gleam@dict:dict(BXN, list(BXM)), BXM) -> gleam@dict:dict(BXN, list(BXM))). -group_updater(F) -> - fun(Groups, Elem) -> _pipe = Groups, - gleam@dict:update(_pipe, F(Elem), update_group_with(Elem)) end. - --spec group(iterator(BXU), fun((BXU) -> BXW)) -> gleam@dict:dict(BXW, list(BXU)). -group(Iterator, Key) -> - _pipe = Iterator, - _pipe@1 = fold(_pipe, gleam@dict:new(), group_updater(Key)), - gleam@dict:map_values( - _pipe@1, - fun(_, Group) -> gleam@list:reverse(Group) end - ). - --spec reduce(iterator(BYA), fun((BYA, BYA) -> BYA)) -> {ok, BYA} | {error, nil}. -reduce(Iterator, F) -> - case (erlang:element(2, Iterator))() of - stop -> - {error, nil}; - - {continue, E, Next} -> - _pipe = do_fold(Next, F, E), - {ok, _pipe} - end. - --spec last(iterator(BYE)) -> {ok, BYE} | {error, nil}. -last(Iterator) -> - _pipe = Iterator, - reduce(_pipe, fun(_, Elem) -> Elem end). - --spec empty() -> iterator(any()). -empty() -> - {iterator, fun stop/0}. - --spec once(fun(() -> BYK)) -> iterator(BYK). -once(F) -> - _pipe = fun() -> {continue, F(), fun stop/0} end, - {iterator, _pipe}. - --spec range(integer(), integer()) -> iterator(integer()). -range(Start, Stop) -> - case gleam@int:compare(Start, Stop) of - eq -> - once(fun() -> Start end); - - gt -> - unfold(Start, fun(Current) -> case Current < Stop of - false -> - {next, Current, Current - 1}; - - true -> - done - end end); - - lt -> - unfold(Start, fun(Current@1) -> case Current@1 > Stop of - false -> - {next, Current@1, Current@1 + 1}; - - true -> - done - end end) - end. - --spec single(BYM) -> iterator(BYM). -single(Elem) -> - once(fun() -> Elem end). - --spec do_interleave(fun(() -> action(BYO)), fun(() -> action(BYO))) -> action(BYO). -do_interleave(Current, Next) -> - case Current() of - stop -> - Next(); - - {continue, E, Next_other} -> - {continue, E, fun() -> do_interleave(Next, Next_other) end} - end. - --spec interleave(iterator(BYS), iterator(BYS)) -> iterator(BYS). -interleave(Left, Right) -> - _pipe = fun() -> - do_interleave(erlang:element(2, Left), erlang:element(2, Right)) - end, - {iterator, _pipe}. - --spec do_fold_until( - fun(() -> action(BYW)), - fun((BYY, BYW) -> gleam@list:continue_or_stop(BYY)), - BYY -) -> BYY. -do_fold_until(Continuation, F, Accumulator) -> - case Continuation() of - stop -> - Accumulator; - - {continue, Elem, Next} -> - case F(Accumulator, Elem) of - {continue, Accumulator@1} -> - do_fold_until(Next, F, Accumulator@1); - - {stop, Accumulator@2} -> - Accumulator@2 - end - end. - --spec fold_until( - iterator(BZA), - BZC, - fun((BZC, BZA) -> gleam@list:continue_or_stop(BZC)) -) -> BZC. -fold_until(Iterator, Initial, F) -> - _pipe = erlang:element(2, Iterator), - do_fold_until(_pipe, F, Initial). - --spec do_try_fold( - fun(() -> action(BZE)), - fun((BZG, BZE) -> {ok, BZG} | {error, BZH}), - BZG -) -> {ok, BZG} | {error, BZH}. -do_try_fold(Continuation, F, Accumulator) -> - case Continuation() of - stop -> - {ok, Accumulator}; - - {continue, Elem, Next} -> - gleam@result:'try'( - F(Accumulator, Elem), - fun(Accumulator@1) -> do_try_fold(Next, F, Accumulator@1) end - ) - end. - --spec try_fold(iterator(BZM), BZO, fun((BZO, BZM) -> {ok, BZO} | {error, BZP})) -> {ok, - BZO} | - {error, BZP}. -try_fold(Iterator, Initial, F) -> - _pipe = erlang:element(2, Iterator), - do_try_fold(_pipe, F, Initial). - --spec first(iterator(BZU)) -> {ok, BZU} | {error, nil}. -first(Iterator) -> - case (erlang:element(2, Iterator))() of - stop -> - {error, nil}; - - {continue, E, _} -> - {ok, E} - end. - --spec at(iterator(BZY), integer()) -> {ok, BZY} | {error, nil}. -at(Iterator, Index) -> - _pipe = Iterator, - _pipe@1 = drop(_pipe, Index), - first(_pipe@1). - --spec do_length(fun(() -> action(any())), integer()) -> integer(). -do_length(Continuation, Length) -> - case Continuation() of - stop -> - Length; - - {continue, _, Next} -> - do_length(Next, Length + 1) - end. - --spec length(iterator(any())) -> integer(). -length(Iterator) -> - _pipe = erlang:element(2, Iterator), - do_length(_pipe, 0). - --spec each(iterator(CAG), fun((CAG) -> any())) -> nil. -each(Iterator, F) -> - _pipe = Iterator, - _pipe@1 = map(_pipe, F), - run(_pipe@1). - --spec yield(CAJ, fun(() -> iterator(CAJ))) -> iterator(CAJ). -yield(Element, Next) -> - {iterator, fun() -> {continue, Element, erlang:element(2, Next())} end}. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@list.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@list.erl deleted file mode 100644 index 6c2e684..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@list.erl +++ /dev/null @@ -1,1129 +0,0 @@ --module(gleam@list). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([length/1, reverse/1, is_empty/1, contains/2, first/1, rest/1, filter/2, filter_map/2, map/2, map2/3, index_map/2, try_map/2, drop/2, take/2, new/0, append/2, prepend/2, concat/1, flatten/1, flat_map/2, fold/3, group/2, map_fold/3, fold_right/3, index_fold/3, try_fold/3, fold_until/3, find/2, find_map/2, all/2, any/2, zip/2, strict_zip/2, unzip/1, intersperse/2, at/2, unique/1, sort/2, range/2, repeat/2, split/2, split_while/2, key_find/2, key_filter/2, pop/2, pop_map/2, key_pop/2, key_set/3, each/2, try_each/2, partition/2, permutations/1, window/2, window_by_2/1, drop_while/2, take_while/2, chunk/2, sized_chunk/2, reduce/2, scan/3, last/1, combinations/2, combination_pairs/1, transpose/1, interleave/1, shuffle/1]). --export_type([length_mismatch/0, continue_or_stop/1]). - --type length_mismatch() :: length_mismatch. - --type continue_or_stop(UD) :: {continue, UD} | {stop, UD}. - --spec length(list(any())) -> integer(). -length(List) -> - erlang:length(List). - --spec reverse(list(UI)) -> list(UI). -reverse(Xs) -> - lists:reverse(Xs). - --spec is_empty(list(any())) -> boolean(). -is_empty(List) -> - List =:= []. - --spec contains(list(UQ), UQ) -> boolean(). -contains(List, Elem) -> - case List of - [] -> - false; - - [First | _] when First =:= Elem -> - true; - - [_ | Rest] -> - contains(Rest, Elem) - end. - --spec first(list(US)) -> {ok, US} | {error, nil}. -first(List) -> - case List of - [] -> - {error, nil}; - - [X | _] -> - {ok, X} - end. - --spec rest(list(UW)) -> {ok, list(UW)} | {error, nil}. -rest(List) -> - case List of - [] -> - {error, nil}; - - [_ | Xs] -> - {ok, Xs} - end. - --spec update_group(fun((VB) -> VC)) -> fun((gleam@dict:dict(VC, list(VB)), VB) -> gleam@dict:dict(VC, list(VB))). -update_group(F) -> - fun(Groups, Elem) -> case gleam@dict:get(Groups, F(Elem)) of - {ok, Existing} -> - gleam@dict:insert(Groups, F(Elem), [Elem | Existing]); - - {error, _} -> - gleam@dict:insert(Groups, F(Elem), [Elem]) - end end. - --spec do_filter(list(VP), fun((VP) -> boolean()), list(VP)) -> list(VP). -do_filter(List, Fun, Acc) -> - case List of - [] -> - reverse(Acc); - - [X | Xs] -> - New_acc = case Fun(X) of - true -> - [X | Acc]; - - false -> - Acc - end, - do_filter(Xs, Fun, New_acc) - end. - --spec filter(list(VT), fun((VT) -> boolean())) -> list(VT). -filter(List, Predicate) -> - do_filter(List, Predicate, []). - --spec do_filter_map(list(VW), fun((VW) -> {ok, VY} | {error, any()}), list(VY)) -> list(VY). -do_filter_map(List, Fun, Acc) -> - case List of - [] -> - reverse(Acc); - - [X | Xs] -> - New_acc = case Fun(X) of - {ok, X@1} -> - [X@1 | Acc]; - - {error, _} -> - Acc - end, - do_filter_map(Xs, Fun, New_acc) - end. - --spec filter_map(list(WE), fun((WE) -> {ok, WG} | {error, any()})) -> list(WG). -filter_map(List, Fun) -> - do_filter_map(List, Fun, []). - --spec do_map(list(WL), fun((WL) -> WN), list(WN)) -> list(WN). -do_map(List, Fun, Acc) -> - case List of - [] -> - reverse(Acc); - - [X | Xs] -> - do_map(Xs, Fun, [Fun(X) | Acc]) - end. - --spec map(list(WQ), fun((WQ) -> WS)) -> list(WS). -map(List, Fun) -> - do_map(List, Fun, []). - --spec do_map2(list(XA), list(XC), fun((XA, XC) -> XE), list(XE)) -> list(XE). -do_map2(List1, List2, Fun, Acc) -> - case {List1, List2} of - {[], _} -> - reverse(Acc); - - {_, []} -> - reverse(Acc); - - {[A | As_], [B | Bs]} -> - do_map2(As_, Bs, Fun, [Fun(A, B) | Acc]) - end. - --spec map2(list(WU), list(WW), fun((WU, WW) -> WY)) -> list(WY). -map2(List1, List2, Fun) -> - do_map2(List1, List2, Fun, []). - --spec do_index_map(list(XM), fun((integer(), XM) -> XO), integer(), list(XO)) -> list(XO). -do_index_map(List, Fun, Index, Acc) -> - case List of - [] -> - reverse(Acc); - - [X | Xs] -> - Acc@1 = [Fun(Index, X) | Acc], - do_index_map(Xs, Fun, Index + 1, Acc@1) - end. - --spec index_map(list(XR), fun((integer(), XR) -> XT)) -> list(XT). -index_map(List, Fun) -> - do_index_map(List, Fun, 0, []). - --spec do_try_map(list(XV), fun((XV) -> {ok, XX} | {error, XY}), list(XX)) -> {ok, - list(XX)} | - {error, XY}. -do_try_map(List, Fun, Acc) -> - case List of - [] -> - {ok, reverse(Acc)}; - - [X | Xs] -> - case Fun(X) of - {ok, Y} -> - do_try_map(Xs, Fun, [Y | Acc]); - - {error, Error} -> - {error, Error} - end - end. - --spec try_map(list(YF), fun((YF) -> {ok, YH} | {error, YI})) -> {ok, list(YH)} | - {error, YI}. -try_map(List, Fun) -> - do_try_map(List, Fun, []). - --spec drop(list(YO), integer()) -> list(YO). -drop(List, N) -> - case N =< 0 of - true -> - List; - - false -> - case List of - [] -> - []; - - [_ | Xs] -> - drop(Xs, N - 1) - end - end. - --spec do_take(list(YR), integer(), list(YR)) -> list(YR). -do_take(List, N, Acc) -> - case N =< 0 of - true -> - reverse(Acc); - - false -> - case List of - [] -> - reverse(Acc); - - [X | Xs] -> - do_take(Xs, N - 1, [X | Acc]) - end - end. - --spec take(list(YV), integer()) -> list(YV). -take(List, N) -> - do_take(List, N, []). - --spec new() -> list(any()). -new() -> - []. - --spec append(list(AAA), list(AAA)) -> list(AAA). -append(First, Second) -> - lists:append(First, Second). - --spec prepend(list(AAI), AAI) -> list(AAI). -prepend(List, Item) -> - [Item | List]. - --spec reverse_and_prepend(list(AAL), list(AAL)) -> list(AAL). -reverse_and_prepend(Prefix, Suffix) -> - case Prefix of - [] -> - Suffix; - - [First | Rest] -> - reverse_and_prepend(Rest, [First | Suffix]) - end. - --spec do_concat(list(list(AAP)), list(AAP)) -> list(AAP). -do_concat(Lists, Acc) -> - case Lists of - [] -> - reverse(Acc); - - [List | Further_lists] -> - do_concat(Further_lists, reverse_and_prepend(List, Acc)) - end. - --spec concat(list(list(AAU))) -> list(AAU). -concat(Lists) -> - do_concat(Lists, []). - --spec flatten(list(list(AAY))) -> list(AAY). -flatten(Lists) -> - do_concat(Lists, []). - --spec flat_map(list(ABC), fun((ABC) -> list(ABE))) -> list(ABE). -flat_map(List, Fun) -> - _pipe = map(List, Fun), - concat(_pipe). - --spec fold(list(ABH), ABJ, fun((ABJ, ABH) -> ABJ)) -> ABJ. -fold(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [X | Rest] -> - fold(Rest, Fun(Initial, X), Fun) - end. - --spec group(list(VJ), fun((VJ) -> VL)) -> gleam@dict:dict(VL, list(VJ)). -group(List, Key) -> - fold(List, gleam@dict:new(), update_group(Key)). - --spec map_fold(list(XH), XJ, fun((XJ, XH) -> {XJ, XK})) -> {XJ, list(XK)}. -map_fold(List, Acc, Fun) -> - _pipe = fold( - List, - {Acc, []}, - fun(Acc@1, Item) -> - {Current_acc, Items} = Acc@1, - {Next_acc, Next_item} = Fun(Current_acc, Item), - {Next_acc, [Next_item | Items]} - end - ), - gleam@pair:map_second(_pipe, fun reverse/1). - --spec fold_right(list(ABK), ABM, fun((ABM, ABK) -> ABM)) -> ABM. -fold_right(List, Initial, Fun) -> - case List of - [] -> - Initial; - - [X | Rest] -> - Fun(fold_right(Rest, Initial, Fun), X) - end. - --spec do_index_fold( - list(ABN), - ABP, - fun((ABP, ABN, integer()) -> ABP), - integer() -) -> ABP. -do_index_fold(Over, Acc, With, Index) -> - case Over of - [] -> - Acc; - - [First | Rest] -> - do_index_fold(Rest, With(Acc, First, Index), With, Index + 1) - end. - --spec index_fold(list(ABQ), ABS, fun((ABS, ABQ, integer()) -> ABS)) -> ABS. -index_fold(Over, Initial, Fun) -> - do_index_fold(Over, Initial, Fun, 0). - --spec try_fold(list(ABT), ABV, fun((ABV, ABT) -> {ok, ABV} | {error, ABW})) -> {ok, - ABV} | - {error, ABW}. -try_fold(Collection, Accumulator, Fun) -> - case Collection of - [] -> - {ok, Accumulator}; - - [First | Rest] -> - case Fun(Accumulator, First) of - {ok, Result} -> - try_fold(Rest, Result, Fun); - - {error, _} = Error -> - Error - end - end. - --spec fold_until(list(ACB), ACD, fun((ACD, ACB) -> continue_or_stop(ACD))) -> ACD. -fold_until(Collection, Accumulator, Fun) -> - case Collection of - [] -> - Accumulator; - - [First | Rest] -> - case Fun(Accumulator, First) of - {continue, Next_accumulator} -> - fold_until(Rest, Next_accumulator, Fun); - - {stop, B} -> - B - end - end. - --spec find(list(ACF), fun((ACF) -> boolean())) -> {ok, ACF} | {error, nil}. -find(Haystack, Is_desired) -> - case Haystack of - [] -> - {error, nil}; - - [X | Rest] -> - case Is_desired(X) of - true -> - {ok, X}; - - _ -> - find(Rest, Is_desired) - end - end. - --spec find_map(list(ACJ), fun((ACJ) -> {ok, ACL} | {error, any()})) -> {ok, ACL} | - {error, nil}. -find_map(Haystack, Fun) -> - case Haystack of - [] -> - {error, nil}; - - [X | Rest] -> - case Fun(X) of - {ok, X@1} -> - {ok, X@1}; - - _ -> - find_map(Rest, Fun) - end - end. - --spec all(list(ACR), fun((ACR) -> boolean())) -> boolean(). -all(List, Predicate) -> - case List of - [] -> - true; - - [First | Rest] -> - case Predicate(First) of - true -> - all(Rest, Predicate); - - false -> - false - end - end. - --spec any(list(ACT), fun((ACT) -> boolean())) -> boolean(). -any(List, Predicate) -> - case List of - [] -> - false; - - [First | Rest] -> - case Predicate(First) of - true -> - true; - - false -> - any(Rest, Predicate) - end - end. - --spec do_zip(list(ACV), list(ACX), list({ACV, ACX})) -> list({ACV, ACX}). -do_zip(Xs, Ys, Acc) -> - case {Xs, Ys} of - {[X | Xs@1], [Y | Ys@1]} -> - do_zip(Xs@1, Ys@1, [{X, Y} | Acc]); - - {_, _} -> - reverse(Acc) - end. - --spec zip(list(ADB), list(ADD)) -> list({ADB, ADD}). -zip(List, Other) -> - do_zip(List, Other, []). - --spec strict_zip(list(ADG), list(ADI)) -> {ok, list({ADG, ADI})} | - {error, length_mismatch()}. -strict_zip(List, Other) -> - case length(List) =:= length(Other) of - true -> - {ok, zip(List, Other)}; - - false -> - {error, length_mismatch} - end. - --spec do_unzip(list({ATA, ATB}), list(ATA), list(ATB)) -> {list(ATA), list(ATB)}. -do_unzip(Input, Xs, Ys) -> - case Input of - [] -> - {reverse(Xs), reverse(Ys)}; - - [{X, Y} | Rest] -> - do_unzip(Rest, [X | Xs], [Y | Ys]) - end. - --spec unzip(list({ADR, ADS})) -> {list(ADR), list(ADS)}. -unzip(Input) -> - do_unzip(Input, [], []). - --spec do_intersperse(list(ADW), ADW, list(ADW)) -> list(ADW). -do_intersperse(List, Separator, Acc) -> - case List of - [] -> - reverse(Acc); - - [X | Rest] -> - do_intersperse(Rest, Separator, [X, Separator | Acc]) - end. - --spec intersperse(list(AEA), AEA) -> list(AEA). -intersperse(List, Elem) -> - case List of - [] -> - List; - - [_] -> - List; - - [X | Rest] -> - do_intersperse(Rest, Elem, [X]) - end. - --spec at(list(AED), integer()) -> {ok, AED} | {error, nil}. -at(List, Index) -> - case Index >= 0 of - true -> - _pipe = List, - _pipe@1 = drop(_pipe, Index), - first(_pipe@1); - - false -> - {error, nil} - end. - --spec unique(list(AEH)) -> list(AEH). -unique(List) -> - case List of - [] -> - []; - - [X | Rest] -> - [X | unique(filter(Rest, fun(Y) -> Y /= X end))] - end. - --spec merge_up( - integer(), - integer(), - list(AEK), - list(AEK), - list(AEK), - fun((AEK, AEK) -> gleam@order:order()) -) -> list(AEK). -merge_up(Na, Nb, A, B, Acc, Compare) -> - case {Na, Nb, A, B} of - {0, 0, _, _} -> - Acc; - - {_, 0, [Ax | Ar], _} -> - merge_up(Na - 1, Nb, Ar, B, [Ax | Acc], Compare); - - {0, _, _, [Bx | Br]} -> - merge_up(Na, Nb - 1, A, Br, [Bx | Acc], Compare); - - {_, _, [Ax@1 | Ar@1], [Bx@1 | Br@1]} -> - case Compare(Ax@1, Bx@1) of - gt -> - merge_up(Na, Nb - 1, A, Br@1, [Bx@1 | Acc], Compare); - - _ -> - merge_up(Na - 1, Nb, Ar@1, B, [Ax@1 | Acc], Compare) - end; - - {_, _, _, _} -> - Acc - end. - --spec merge_down( - integer(), - integer(), - list(AEP), - list(AEP), - list(AEP), - fun((AEP, AEP) -> gleam@order:order()) -) -> list(AEP). -merge_down(Na, Nb, A, B, Acc, Compare) -> - case {Na, Nb, A, B} of - {0, 0, _, _} -> - Acc; - - {_, 0, [Ax | Ar], _} -> - merge_down(Na - 1, Nb, Ar, B, [Ax | Acc], Compare); - - {0, _, _, [Bx | Br]} -> - merge_down(Na, Nb - 1, A, Br, [Bx | Acc], Compare); - - {_, _, [Ax@1 | Ar@1], [Bx@1 | Br@1]} -> - case Compare(Bx@1, Ax@1) of - lt -> - merge_down(Na - 1, Nb, Ar@1, B, [Ax@1 | Acc], Compare); - - _ -> - merge_down(Na, Nb - 1, A, Br@1, [Bx@1 | Acc], Compare) - end; - - {_, _, _, _} -> - Acc - end. - --spec merge_sort( - list(AEU), - integer(), - fun((AEU, AEU) -> gleam@order:order()), - boolean() -) -> list(AEU). -merge_sort(L, Ln, Compare, Down) -> - N = Ln div 2, - A = L, - B = drop(L, N), - case Ln < 3 of - true -> - case Down of - true -> - merge_down(N, Ln - N, A, B, [], Compare); - - false -> - merge_up(N, Ln - N, A, B, [], Compare) - end; - - false -> - case Down of - true -> - merge_down( - N, - Ln - N, - merge_sort(A, N, Compare, false), - merge_sort(B, Ln - N, Compare, false), - [], - Compare - ); - - false -> - merge_up( - N, - Ln - N, - merge_sort(A, N, Compare, true), - merge_sort(B, Ln - N, Compare, true), - [], - Compare - ) - end - end. - --spec sort(list(AEX), fun((AEX, AEX) -> gleam@order:order())) -> list(AEX). -sort(List, Compare) -> - merge_sort(List, length(List), Compare, true). - --spec tail_recursive_range(integer(), integer(), list(integer())) -> list(integer()). -tail_recursive_range(Start, Stop, Acc) -> - case gleam@int:compare(Start, Stop) of - eq -> - [Stop | Acc]; - - gt -> - tail_recursive_range(Start, Stop + 1, [Stop | Acc]); - - lt -> - tail_recursive_range(Start, Stop - 1, [Stop | Acc]) - end. - --spec range(integer(), integer()) -> list(integer()). -range(Start, Stop) -> - tail_recursive_range(Start, Stop, []). - --spec do_repeat(AFD, integer(), list(AFD)) -> list(AFD). -do_repeat(A, Times, Acc) -> - case Times =< 0 of - true -> - Acc; - - false -> - do_repeat(A, Times - 1, [A | Acc]) - end. - --spec repeat(AFG, integer()) -> list(AFG). -repeat(A, Times) -> - do_repeat(A, Times, []). - --spec do_split(list(AFI), integer(), list(AFI)) -> {list(AFI), list(AFI)}. -do_split(List, N, Taken) -> - case N =< 0 of - true -> - {reverse(Taken), List}; - - false -> - case List of - [] -> - {reverse(Taken), []}; - - [X | Xs] -> - do_split(Xs, N - 1, [X | Taken]) - end - end. - --spec split(list(AFN), integer()) -> {list(AFN), list(AFN)}. -split(List, Index) -> - do_split(List, Index, []). - --spec do_split_while(list(AFR), fun((AFR) -> boolean()), list(AFR)) -> {list(AFR), - list(AFR)}. -do_split_while(List, F, Acc) -> - case List of - [] -> - {reverse(Acc), []}; - - [X | Xs] -> - case F(X) of - false -> - {reverse(Acc), List}; - - _ -> - do_split_while(Xs, F, [X | Acc]) - end - end. - --spec split_while(list(AFW), fun((AFW) -> boolean())) -> {list(AFW), list(AFW)}. -split_while(List, Predicate) -> - do_split_while(List, Predicate, []). - --spec key_find(list({AGA, AGB}), AGA) -> {ok, AGB} | {error, nil}. -key_find(Keyword_list, Desired_key) -> - find_map( - Keyword_list, - fun(Keyword) -> - {Key, Value} = Keyword, - case Key =:= Desired_key of - true -> - {ok, Value}; - - false -> - {error, nil} - end - end - ). - --spec key_filter(list({AGF, AGG}), AGF) -> list(AGG). -key_filter(Keyword_list, Desired_key) -> - filter_map( - Keyword_list, - fun(Keyword) -> - {Key, Value} = Keyword, - case Key =:= Desired_key of - true -> - {ok, Value}; - - false -> - {error, nil} - end - end - ). - --spec do_pop(list(AWT), fun((AWT) -> boolean()), list(AWT)) -> {ok, - {AWT, list(AWT)}} | - {error, nil}. -do_pop(Haystack, Predicate, Checked) -> - case Haystack of - [] -> - {error, nil}; - - [X | Rest] -> - case Predicate(X) of - true -> - {ok, {X, append(reverse(Checked), Rest)}}; - - false -> - do_pop(Rest, Predicate, [X | Checked]) - end - end. - --spec pop(list(AGN), fun((AGN) -> boolean())) -> {ok, {AGN, list(AGN)}} | - {error, nil}. -pop(Haystack, Is_desired) -> - do_pop(Haystack, Is_desired, []). - --spec do_pop_map(list(AXH), fun((AXH) -> {ok, AXU} | {error, any()}), list(AXH)) -> {ok, - {AXU, list(AXH)}} | - {error, nil}. -do_pop_map(Haystack, Mapper, Checked) -> - case Haystack of - [] -> - {error, nil}; - - [X | Rest] -> - case Mapper(X) of - {ok, Y} -> - {ok, {Y, append(reverse(Checked), Rest)}}; - - {error, _} -> - do_pop_map(Rest, Mapper, [X | Checked]) - end - end. - --spec pop_map(list(AGW), fun((AGW) -> {ok, AGY} | {error, any()})) -> {ok, - {AGY, list(AGW)}} | - {error, nil}. -pop_map(Haystack, Is_desired) -> - do_pop_map(Haystack, Is_desired, []). - --spec key_pop(list({AHF, AHG}), AHF) -> {ok, {AHG, list({AHF, AHG})}} | - {error, nil}. -key_pop(Haystack, Key) -> - pop_map( - Haystack, - fun(Entry) -> - {K, V} = Entry, - case K of - K@1 when K@1 =:= Key -> - {ok, V}; - - _ -> - {error, nil} - end - end - ). - --spec key_set(list({AHL, AHM}), AHL, AHM) -> list({AHL, AHM}). -key_set(List, Key, Value) -> - case List of - [] -> - [{Key, Value}]; - - [{K, _} | Rest] when K =:= Key -> - [{Key, Value} | Rest]; - - [First | Rest@1] -> - [First | key_set(Rest@1, Key, Value)] - end. - --spec each(list(AHP), fun((AHP) -> any())) -> nil. -each(List, F) -> - case List of - [] -> - nil; - - [X | Xs] -> - F(X), - each(Xs, F) - end. - --spec try_each(list(AHS), fun((AHS) -> {ok, any()} | {error, AHV})) -> {ok, nil} | - {error, AHV}. -try_each(List, Fun) -> - case List of - [] -> - {ok, nil}; - - [X | Xs] -> - case Fun(X) of - {ok, _} -> - try_each(Xs, Fun); - - {error, E} -> - {error, E} - end - end. - --spec do_partition(list(AZB), fun((AZB) -> boolean()), list(AZB), list(AZB)) -> {list(AZB), - list(AZB)}. -do_partition(List, Categorise, Trues, Falses) -> - case List of - [] -> - {reverse(Trues), reverse(Falses)}; - - [X | Xs] -> - case Categorise(X) of - true -> - do_partition(Xs, Categorise, [X | Trues], Falses); - - false -> - do_partition(Xs, Categorise, Trues, [X | Falses]) - end - end. - --spec partition(list(AIF), fun((AIF) -> boolean())) -> {list(AIF), list(AIF)}. -partition(List, Categorise) -> - do_partition(List, Categorise, [], []). - --spec permutations(list(AIJ)) -> list(list(AIJ)). -permutations(L) -> - case L of - [] -> - [[]]; - - _ -> - _pipe = L, - _pipe@5 = index_map(_pipe, fun(I_idx, I) -> _pipe@1 = L, - _pipe@2 = index_fold( - _pipe@1, - [], - fun(Acc, J, J_idx) -> case I_idx =:= J_idx of - true -> - Acc; - - false -> - [J | Acc] - end end - ), - _pipe@3 = reverse(_pipe@2), - _pipe@4 = permutations(_pipe@3), - map(_pipe@4, fun(Permutation) -> [I | Permutation] end) end), - concat(_pipe@5) - end. - --spec do_window(list(list(AIN)), list(AIN), integer()) -> list(list(AIN)). -do_window(Acc, L, N) -> - Window = take(L, N), - case length(Window) =:= N of - true -> - do_window([Window | Acc], drop(L, 1), N); - - false -> - Acc - end. - --spec window(list(AIT), integer()) -> list(list(AIT)). -window(L, N) -> - _pipe = do_window([], L, N), - reverse(_pipe). - --spec window_by_2(list(AIX)) -> list({AIX, AIX}). -window_by_2(L) -> - zip(L, drop(L, 1)). - --spec drop_while(list(AJA), fun((AJA) -> boolean())) -> list(AJA). -drop_while(List, Predicate) -> - case List of - [] -> - []; - - [X | Xs] -> - case Predicate(X) of - true -> - drop_while(Xs, Predicate); - - false -> - [X | Xs] - end - end. - --spec do_take_while(list(AJD), fun((AJD) -> boolean()), list(AJD)) -> list(AJD). -do_take_while(List, Predicate, Acc) -> - case List of - [] -> - reverse(Acc); - - [First | Rest] -> - case Predicate(First) of - true -> - do_take_while(Rest, Predicate, [First | Acc]); - - false -> - reverse(Acc) - end - end. - --spec take_while(list(AJH), fun((AJH) -> boolean())) -> list(AJH). -take_while(List, Predicate) -> - do_take_while(List, Predicate, []). - --spec do_chunk(list(AJK), fun((AJK) -> AJM), AJM, list(AJK), list(list(AJK))) -> list(list(AJK)). -do_chunk(List, F, Previous_key, Current_chunk, Acc) -> - case List of - [First | Rest] -> - Key = F(First), - case Key =:= Previous_key of - false -> - New_acc = [reverse(Current_chunk) | Acc], - do_chunk(Rest, F, Key, [First], New_acc); - - _ -> - do_chunk(Rest, F, Key, [First | Current_chunk], Acc) - end; - - _ -> - reverse([reverse(Current_chunk) | Acc]) - end. - --spec chunk(list(AJS), fun((AJS) -> any())) -> list(list(AJS)). -chunk(List, F) -> - case List of - [] -> - []; - - [First | Rest] -> - do_chunk(Rest, F, F(First), [First], []) - end. - --spec do_sized_chunk( - list(AJX), - integer(), - integer(), - list(AJX), - list(list(AJX)) -) -> list(list(AJX)). -do_sized_chunk(List, Count, Left, Current_chunk, Acc) -> - case List of - [] -> - case Current_chunk of - [] -> - reverse(Acc); - - Remaining -> - reverse([reverse(Remaining) | Acc]) - end; - - [First | Rest] -> - Chunk = [First | Current_chunk], - case Left > 1 of - false -> - do_sized_chunk( - Rest, - Count, - Count, - [], - [reverse(Chunk) | Acc] - ); - - true -> - do_sized_chunk(Rest, Count, Left - 1, Chunk, Acc) - end - end. - --spec sized_chunk(list(AKE), integer()) -> list(list(AKE)). -sized_chunk(List, Count) -> - do_sized_chunk(List, Count, Count, [], []). - --spec reduce(list(AKI), fun((AKI, AKI) -> AKI)) -> {ok, AKI} | {error, nil}. -reduce(List, Fun) -> - case List of - [] -> - {error, nil}; - - [First | Rest] -> - {ok, fold(Rest, First, Fun)} - end. - --spec do_scan(list(AKM), AKO, list(AKO), fun((AKO, AKM) -> AKO)) -> list(AKO). -do_scan(List, Accumulator, Accumulated, Fun) -> - case List of - [] -> - reverse(Accumulated); - - [X | Xs] -> - Next = Fun(Accumulator, X), - do_scan(Xs, Next, [Next | Accumulated], Fun) - end. - --spec scan(list(AKR), AKT, fun((AKT, AKR) -> AKT)) -> list(AKT). -scan(List, Initial, Fun) -> - do_scan(List, Initial, [], Fun). - --spec last(list(AKV)) -> {ok, AKV} | {error, nil}. -last(List) -> - _pipe = List, - reduce(_pipe, fun(_, Elem) -> Elem end). - --spec combinations(list(AKZ), integer()) -> list(list(AKZ)). -combinations(Items, N) -> - case N of - 0 -> - [[]]; - - _ -> - case Items of - [] -> - []; - - [X | Xs] -> - First_combinations = begin - _pipe = map( - combinations(Xs, N - 1), - fun(Com) -> [X | Com] end - ), - reverse(_pipe) - end, - fold( - First_combinations, - combinations(Xs, N), - fun(Acc, C) -> [C | Acc] end - ) - end - end. - --spec do_combination_pairs(list(ALD)) -> list(list({ALD, ALD})). -do_combination_pairs(Items) -> - case Items of - [] -> - []; - - [X | Xs] -> - First_combinations = map(Xs, fun(Other) -> {X, Other} end), - [First_combinations | do_combination_pairs(Xs)] - end. - --spec combination_pairs(list(ALH)) -> list({ALH, ALH}). -combination_pairs(Items) -> - _pipe = do_combination_pairs(Items), - concat(_pipe). - --spec transpose(list(list(ALO))) -> list(list(ALO)). -transpose(List_of_list) -> - Take_first = fun(List) -> case List of - [] -> - []; - - [F] -> - [F]; - - [F@1 | _] -> - [F@1] - end end, - case List_of_list of - [] -> - []; - - [[] | Xss] -> - transpose(Xss); - - Rows -> - Firsts = begin - _pipe = Rows, - _pipe@1 = map(_pipe, Take_first), - concat(_pipe@1) - end, - Rest = transpose(map(Rows, fun(_capture) -> drop(_capture, 1) end)), - [Firsts | Rest] - end. - --spec interleave(list(list(ALK))) -> list(ALK). -interleave(List) -> - _pipe = transpose(List), - concat(_pipe). - --spec do_shuffle_pair_unwrap(list({float(), ALT}), list(ALT)) -> list(ALT). -do_shuffle_pair_unwrap(List, Acc) -> - case List of - [] -> - Acc; - - [Elem_pair | Enumerable] -> - do_shuffle_pair_unwrap( - Enumerable, - [erlang:element(2, Elem_pair) | Acc] - ) - end. - --spec do_shuffle_by_pair_indexes(list({float(), ALX})) -> list({float(), ALX}). -do_shuffle_by_pair_indexes(List_of_pairs) -> - sort( - List_of_pairs, - fun(A_pair, B_pair) -> - gleam@float:compare( - erlang:element(1, A_pair), - erlang:element(1, B_pair) - ) - end - ). - --spec shuffle(list(AMA)) -> list(AMA). -shuffle(List) -> - _pipe = List, - _pipe@1 = fold( - _pipe, - [], - fun(Acc, A) -> [{gleam@float:random(+0.0, 1.0), A} | Acc] end - ), - _pipe@2 = do_shuffle_by_pair_indexes(_pipe@1), - do_shuffle_pair_unwrap(_pipe@2, []). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@map.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@map.erl deleted file mode 100644 index 33e89a9..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@map.erl +++ /dev/null @@ -1,76 +0,0 @@ --module(gleam@map). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([size/1, to_list/1, from_list/1, has_key/2, new/0, get/2, insert/3, map_values/2, keys/1, values/1, filter/2, take/2, merge/2, delete/2, drop/2, update/3, fold/3]). - --spec size(gleam@dict:dict(any(), any())) -> integer(). -size(Map) -> - gleam@dict:size(Map). - --spec to_list(gleam@dict:dict(DAJ, DAK)) -> list({DAJ, DAK}). -to_list(Map) -> - gleam@dict:to_list(Map). - --spec from_list(list({DAM, DAN})) -> gleam@dict:dict(DAM, DAN). -from_list(List) -> - gleam@dict:from_list(List). - --spec has_key(gleam@dict:dict(DAR, any()), DAR) -> boolean(). -has_key(Map, Key) -> - gleam@dict:has_key(Map, Key). - --spec new() -> gleam@dict:dict(any(), any()). -new() -> - gleam@dict:new(). - --spec get(gleam@dict:dict(DAU, DAV), DAU) -> {ok, DAV} | {error, nil}. -get(From, Get) -> - gleam@dict:get(From, Get). - --spec insert(gleam@dict:dict(DAZ, DBA), DAZ, DBA) -> gleam@dict:dict(DAZ, DBA). -insert(Map, Key, Value) -> - gleam@dict:insert(Map, Key, Value). - --spec map_values(gleam@dict:dict(DBD, DBE), fun((DBD, DBE) -> DBF)) -> gleam@dict:dict(DBD, DBF). -map_values(Map, Fun) -> - gleam@dict:map_values(Map, Fun). - --spec keys(gleam@dict:dict(DBI, any())) -> list(DBI). -keys(Map) -> - gleam@dict:keys(Map). - --spec values(gleam@dict:dict(any(), DBL)) -> list(DBL). -values(Map) -> - gleam@dict:values(Map). - --spec filter(gleam@dict:dict(DBO, DBP), fun((DBO, DBP) -> boolean())) -> gleam@dict:dict(DBO, DBP). -filter(Map, Predicate) -> - gleam@dict:filter(Map, Predicate). - --spec take(gleam@dict:dict(DBS, DDM), list(DBS)) -> gleam@dict:dict(DBS, DDM). -take(Map, Desired_keys) -> - gleam@dict:take(Map, Desired_keys). - --spec merge(gleam@dict:dict(DDN, DDO), gleam@dict:dict(DDN, DDO)) -> gleam@dict:dict(DDN, DDO). -merge(Map, New_entries) -> - gleam@dict:merge(Map, New_entries). - --spec delete(gleam@dict:dict(DBZ, DDQ), DBZ) -> gleam@dict:dict(DBZ, DDQ). -delete(Map, Key) -> - gleam@dict:delete(Map, Key). - --spec drop(gleam@dict:dict(DCC, DDS), list(DCC)) -> gleam@dict:dict(DCC, DDS). -drop(Map, Disallowed_keys) -> - gleam@dict:drop(Map, Disallowed_keys). - --spec update( - gleam@dict:dict(DCG, DCH), - DCG, - fun((gleam@option:option(DCH)) -> DCH) -) -> gleam@dict:dict(DCG, DCH). -update(Map, Key, Fun) -> - gleam@dict:update(Map, Key, Fun). - --spec fold(gleam@dict:dict(DCM, DCN), DCL, fun((DCL, DCM, DCN) -> DCL)) -> DCL. -fold(Map, Initial, Fun) -> - gleam@dict:fold(Map, Initial, Fun). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@option.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@option.erl deleted file mode 100644 index 5c20713..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@option.erl +++ /dev/null @@ -1,147 +0,0 @@ --module(gleam@option). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([all/1, is_some/1, is_none/1, to_result/2, from_result/1, unwrap/2, lazy_unwrap/2, map/2, flatten/1, then/2, 'or'/2, lazy_or/2, values/1]). --export_type([option/1]). - --type option(GB) :: {some, GB} | none. - --spec do_all(list(option(GC)), list(GC)) -> option(list(GC)). -do_all(List, Acc) -> - case List of - [] -> - {some, Acc}; - - [X | Rest] -> - Accumulate = fun(Acc@1, Item) -> case {Acc@1, Item} of - {{some, Values}, {some, Value}} -> - {some, [Value | Values]}; - - {_, _} -> - none - end end, - Accumulate(do_all(Rest, Acc), X) - end. - --spec all(list(option(GI))) -> option(list(GI)). -all(List) -> - do_all(List, []). - --spec is_some(option(any())) -> boolean(). -is_some(Option) -> - Option /= none. - --spec is_none(option(any())) -> boolean(). -is_none(Option) -> - Option =:= none. - --spec to_result(option(GR), GU) -> {ok, GR} | {error, GU}. -to_result(Option, E) -> - case Option of - {some, A} -> - {ok, A}; - - _ -> - {error, E} - end. - --spec from_result({ok, GX} | {error, any()}) -> option(GX). -from_result(Result) -> - case Result of - {ok, A} -> - {some, A}; - - _ -> - none - end. - --spec unwrap(option(HC), HC) -> HC. -unwrap(Option, Default) -> - case Option of - {some, X} -> - X; - - none -> - Default - end. - --spec lazy_unwrap(option(HE), fun(() -> HE)) -> HE. -lazy_unwrap(Option, Default) -> - case Option of - {some, X} -> - X; - - none -> - Default() - end. - --spec map(option(HG), fun((HG) -> HI)) -> option(HI). -map(Option, Fun) -> - case Option of - {some, X} -> - {some, Fun(X)}; - - none -> - none - end. - --spec flatten(option(option(HK))) -> option(HK). -flatten(Option) -> - case Option of - {some, X} -> - X; - - none -> - none - end. - --spec then(option(HO), fun((HO) -> option(HQ))) -> option(HQ). -then(Option, Fun) -> - case Option of - {some, X} -> - Fun(X); - - none -> - none - end. - --spec 'or'(option(HT), option(HT)) -> option(HT). -'or'(First, Second) -> - case First of - {some, _} -> - First; - - none -> - Second - end. - --spec lazy_or(option(HX), fun(() -> option(HX))) -> option(HX). -lazy_or(First, Second) -> - case First of - {some, _} -> - First; - - none -> - Second() - end. - --spec do_values(list(option(IB)), list(IB)) -> list(IB). -do_values(List, Acc) -> - case List of - [] -> - Acc; - - [X | Xs] -> - Accumulate = fun(Acc@1, Item) -> case Item of - {some, Value} -> - [Value | Acc@1]; - - none -> - Acc@1 - end end, - Accumulate(do_values(Xs, Acc), X) - end. - --spec values(list(option(IG))) -> list(IG). -values(Options) -> - do_values(Options, []). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@order.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@order.erl deleted file mode 100644 index 61649b9..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@order.erl +++ /dev/null @@ -1,79 +0,0 @@ --module(gleam@order). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([negate/1, to_int/1, compare/2, max/2, min/2, reverse/1]). --export_type([order/0]). - --type order() :: lt | eq | gt. - --spec negate(order()) -> order(). -negate(Order) -> - case Order of - lt -> - gt; - - eq -> - eq; - - gt -> - lt - end. - --spec to_int(order()) -> integer(). -to_int(Order) -> - case Order of - lt -> - -1; - - eq -> - 0; - - gt -> - 1 - end. - --spec compare(order(), order()) -> order(). -compare(A, B) -> - case {A, B} of - {X, Y} when X =:= Y -> - eq; - - {lt, _} -> - lt; - - {eq, gt} -> - lt; - - {_, _} -> - gt - end. - --spec max(order(), order()) -> order(). -max(A, B) -> - case {A, B} of - {gt, _} -> - gt; - - {eq, lt} -> - eq; - - {_, _} -> - B - end. - --spec min(order(), order()) -> order(). -min(A, B) -> - case {A, B} of - {lt, _} -> - lt; - - {eq, gt} -> - eq; - - {_, _} -> - B - end. - --spec reverse(fun((I, I) -> order())) -> fun((I, I) -> order()). -reverse(Orderer) -> - fun(A, B) -> Orderer(B, A) end. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@pair.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@pair.erl deleted file mode 100644 index f4eff52..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@pair.erl +++ /dev/null @@ -1,33 +0,0 @@ --module(gleam@pair). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([first/1, second/1, swap/1, map_first/2, map_second/2, new/2]). - --spec first({FM, any()}) -> FM. -first(Pair) -> - {A, _} = Pair, - A. - --spec second({any(), FP}) -> FP. -second(Pair) -> - {_, A} = Pair, - A. - --spec swap({FQ, FR}) -> {FR, FQ}. -swap(Pair) -> - {A, B} = Pair, - {B, A}. - --spec map_first({FS, FT}, fun((FS) -> FU)) -> {FU, FT}. -map_first(Pair, Fun) -> - {A, B} = Pair, - {Fun(A), B}. - --spec map_second({FV, FW}, fun((FW) -> FX)) -> {FV, FX}. -map_second(Pair, Fun) -> - {A, B} = Pair, - {A, Fun(B)}. - --spec new(FY, FZ) -> {FY, FZ}. -new(First, Second) -> - {First, Second}. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@queue.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@queue.erl deleted file mode 100644 index 6b587e7..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@queue.erl +++ /dev/null @@ -1,121 +0,0 @@ --module(gleam@queue). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([new/0, from_list/1, to_list/1, is_empty/1, length/1, push_back/2, push_front/2, pop_back/1, pop_front/1, reverse/1, is_logically_equal/3, is_equal/2]). --export_type([queue/1]). - --opaque queue(DRL) :: {queue, list(DRL), list(DRL)}. - --spec new() -> queue(any()). -new() -> - {queue, [], []}. - --spec from_list(list(DRO)) -> queue(DRO). -from_list(List) -> - {queue, [], List}. - --spec to_list(queue(DRR)) -> list(DRR). -to_list(Queue) -> - _pipe = erlang:element(3, Queue), - gleam@list:append(_pipe, gleam@list:reverse(erlang:element(2, Queue))). - --spec is_empty(queue(any())) -> boolean(). -is_empty(Queue) -> - (erlang:element(2, Queue) =:= []) andalso (erlang:element(3, Queue) =:= []). - --spec length(queue(any())) -> integer(). -length(Queue) -> - gleam@list:length(erlang:element(2, Queue)) + gleam@list:length( - erlang:element(3, Queue) - ). - --spec push_back(queue(DRY), DRY) -> queue(DRY). -push_back(Queue, Item) -> - {queue, [Item | erlang:element(2, Queue)], erlang:element(3, Queue)}. - --spec push_front(queue(DSB), DSB) -> queue(DSB). -push_front(Queue, Item) -> - {queue, erlang:element(2, Queue), [Item | erlang:element(3, Queue)]}. - --spec pop_back(queue(DSE)) -> {ok, {DSE, queue(DSE)}} | {error, nil}. -pop_back(Queue) -> - case Queue of - {queue, [], []} -> - {error, nil}; - - {queue, [], Out} -> - pop_back({queue, gleam@list:reverse(Out), []}); - - {queue, [First | Rest], Out@1} -> - Queue@1 = {queue, Rest, Out@1}, - {ok, {First, Queue@1}} - end. - --spec pop_front(queue(DSJ)) -> {ok, {DSJ, queue(DSJ)}} | {error, nil}. -pop_front(Queue) -> - case Queue of - {queue, [], []} -> - {error, nil}; - - {queue, In, []} -> - pop_front({queue, [], gleam@list:reverse(In)}); - - {queue, In@1, [First | Rest]} -> - Queue@1 = {queue, In@1, Rest}, - {ok, {First, Queue@1}} - end. - --spec reverse(queue(DSO)) -> queue(DSO). -reverse(Queue) -> - {queue, erlang:element(3, Queue), erlang:element(2, Queue)}. - --spec check_equal( - list(DSR), - list(DSR), - list(DSR), - list(DSR), - fun((DSR, DSR) -> boolean()) -) -> boolean(). -check_equal(Xs, X_tail, Ys, Y_tail, Eq) -> - case {Xs, X_tail, Ys, Y_tail} of - {[], [], [], []} -> - true; - - {[X | Xs@1], _, [Y | Ys@1], _} -> - case Eq(X, Y) of - false -> - false; - - true -> - check_equal(Xs@1, X_tail, Ys@1, Y_tail, Eq) - end; - - {[], [_ | _], _, _} -> - check_equal(gleam@list:reverse(X_tail), [], Ys, Y_tail, Eq); - - {_, _, [], [_ | _]} -> - check_equal(Xs, X_tail, gleam@list:reverse(Y_tail), [], Eq); - - {_, _, _, _} -> - false - end. - --spec is_logically_equal(queue(DSW), queue(DSW), fun((DSW, DSW) -> boolean())) -> boolean(). -is_logically_equal(A, B, Element_is_equal) -> - check_equal( - erlang:element(3, A), - erlang:element(2, A), - erlang:element(3, B), - erlang:element(2, B), - Element_is_equal - ). - --spec is_equal(queue(DSZ), queue(DSZ)) -> boolean(). -is_equal(A, B) -> - check_equal( - erlang:element(3, A), - erlang:element(2, A), - erlang:element(3, B), - erlang:element(2, B), - fun(A@1, B@1) -> A@1 =:= B@1 end - ). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@regex.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@regex.erl deleted file mode 100644 index 2d1c5fc..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@regex.erl +++ /dev/null @@ -1,33 +0,0 @@ --module(gleam@regex). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([compile/2, from_string/1, check/2, split/2, scan/2]). --export_type([regex/0, match/0, compile_error/0, options/0]). - --type regex() :: any(). - --type match() :: {match, binary(), list(gleam@option:option(binary()))}. - --type compile_error() :: {compile_error, binary(), integer()}. - --type options() :: {options, boolean(), boolean()}. - --spec compile(binary(), options()) -> {ok, regex()} | {error, compile_error()}. -compile(Pattern, Options) -> - gleam_stdlib:compile_regex(Pattern, Options). - --spec from_string(binary()) -> {ok, regex()} | {error, compile_error()}. -from_string(Pattern) -> - compile(Pattern, {options, false, false}). - --spec check(regex(), binary()) -> boolean(). -check(Regex, Content) -> - gleam_stdlib:regex_check(Regex, Content). - --spec split(regex(), binary()) -> list(binary()). -split(Regex, String) -> - gleam_stdlib:regex_split(Regex, String). - --spec scan(regex(), binary()) -> list(match()). -scan(Regex, String) -> - gleam_stdlib:regex_scan(Regex, String). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@result.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@result.erl deleted file mode 100644 index 7324e45..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@result.erl +++ /dev/null @@ -1,201 +0,0 @@ --module(gleam@result). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([is_ok/1, is_error/1, map/2, map_error/2, flatten/1, 'try'/2, then/2, unwrap/2, lazy_unwrap/2, unwrap_error/2, unwrap_both/1, nil_error/1, 'or'/2, lazy_or/2, all/1, partition/1, replace/2, replace_error/2, values/1, try_recover/2]). - --spec is_ok({ok, any()} | {error, any()}) -> boolean(). -is_ok(Result) -> - case Result of - {error, _} -> - false; - - {ok, _} -> - true - end. - --spec is_error({ok, any()} | {error, any()}) -> boolean(). -is_error(Result) -> - case Result of - {ok, _} -> - false; - - {error, _} -> - true - end. - --spec map({ok, BFM} | {error, BFN}, fun((BFM) -> BFQ)) -> {ok, BFQ} | - {error, BFN}. -map(Result, Fun) -> - case Result of - {ok, X} -> - {ok, Fun(X)}; - - {error, E} -> - {error, E} - end. - --spec map_error({ok, BFT} | {error, BFU}, fun((BFU) -> BFX)) -> {ok, BFT} | - {error, BFX}. -map_error(Result, Fun) -> - case Result of - {ok, X} -> - {ok, X}; - - {error, Error} -> - {error, Fun(Error)} - end. - --spec flatten({ok, {ok, BGA} | {error, BGB}} | {error, BGB}) -> {ok, BGA} | - {error, BGB}. -flatten(Result) -> - case Result of - {ok, X} -> - X; - - {error, Error} -> - {error, Error} - end. - --spec 'try'({ok, BGI} | {error, BGJ}, fun((BGI) -> {ok, BGM} | {error, BGJ})) -> {ok, - BGM} | - {error, BGJ}. -'try'(Result, Fun) -> - case Result of - {ok, X} -> - Fun(X); - - {error, E} -> - {error, E} - end. - --spec then({ok, BGR} | {error, BGS}, fun((BGR) -> {ok, BGV} | {error, BGS})) -> {ok, - BGV} | - {error, BGS}. -then(Result, Fun) -> - 'try'(Result, Fun). - --spec unwrap({ok, BHA} | {error, any()}, BHA) -> BHA. -unwrap(Result, Default) -> - case Result of - {ok, V} -> - V; - - {error, _} -> - Default - end. - --spec lazy_unwrap({ok, BHE} | {error, any()}, fun(() -> BHE)) -> BHE. -lazy_unwrap(Result, Default) -> - case Result of - {ok, V} -> - V; - - {error, _} -> - Default() - end. - --spec unwrap_error({ok, any()} | {error, BHJ}, BHJ) -> BHJ. -unwrap_error(Result, Default) -> - case Result of - {ok, _} -> - Default; - - {error, E} -> - E - end. - --spec unwrap_both({ok, BHM} | {error, BHM}) -> BHM. -unwrap_both(Result) -> - case Result of - {ok, A} -> - A; - - {error, A@1} -> - A@1 - end. - --spec nil_error({ok, BHP} | {error, any()}) -> {ok, BHP} | {error, nil}. -nil_error(Result) -> - map_error(Result, fun(_) -> nil end). - --spec 'or'({ok, BHV} | {error, BHW}, {ok, BHV} | {error, BHW}) -> {ok, BHV} | - {error, BHW}. -'or'(First, Second) -> - case First of - {ok, _} -> - First; - - {error, _} -> - Second - end. - --spec lazy_or({ok, BID} | {error, BIE}, fun(() -> {ok, BID} | {error, BIE})) -> {ok, - BID} | - {error, BIE}. -lazy_or(First, Second) -> - case First of - {ok, _} -> - First; - - {error, _} -> - Second() - end. - --spec all(list({ok, BIL} | {error, BIM})) -> {ok, list(BIL)} | {error, BIM}. -all(Results) -> - gleam@list:try_map(Results, fun(X) -> X end). - --spec do_partition(list({ok, BJA} | {error, BJB}), list(BJA), list(BJB)) -> {list(BJA), - list(BJB)}. -do_partition(Results, Oks, Errors) -> - case Results of - [] -> - {Oks, Errors}; - - [{ok, A} | Rest] -> - do_partition(Rest, [A | Oks], Errors); - - [{error, E} | Rest@1] -> - do_partition(Rest@1, Oks, [E | Errors]) - end. - --spec partition(list({ok, BIT} | {error, BIU})) -> {list(BIT), list(BIU)}. -partition(Results) -> - do_partition(Results, [], []). - --spec replace({ok, any()} | {error, BJJ}, BJM) -> {ok, BJM} | {error, BJJ}. -replace(Result, Value) -> - case Result of - {ok, _} -> - {ok, Value}; - - {error, Error} -> - {error, Error} - end. - --spec replace_error({ok, BJP} | {error, any()}, BJT) -> {ok, BJP} | {error, BJT}. -replace_error(Result, Error) -> - case Result of - {ok, X} -> - {ok, X}; - - {error, _} -> - {error, Error} - end. - --spec values(list({ok, BJW} | {error, any()})) -> list(BJW). -values(Results) -> - gleam@list:filter_map(Results, fun(R) -> R end). - --spec try_recover( - {ok, BKC} | {error, BKD}, - fun((BKD) -> {ok, BKC} | {error, BKG}) -) -> {ok, BKC} | {error, BKG}. -try_recover(Result, Fun) -> - case Result of - {ok, Value} -> - {ok, Value}; - - {error, Error} -> - Fun(Error) - end. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@set.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@set.erl deleted file mode 100644 index df87b13..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@set.erl +++ /dev/null @@ -1,85 +0,0 @@ --module(gleam@set). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([new/0, size/1, insert/2, contains/2, delete/2, to_list/1, from_list/1, fold/3, filter/2, drop/2, take/2, union/2, intersection/2]). --export_type([set/1]). - --opaque set(DJZ) :: {set, gleam@dict:dict(DJZ, list(nil))}. - --spec new() -> set(any()). -new() -> - {set, gleam@dict:new()}. - --spec size(set(any())) -> integer(). -size(Set) -> - gleam@dict:size(erlang:element(2, Set)). - --spec insert(set(DKF), DKF) -> set(DKF). -insert(Set, Member) -> - {set, gleam@dict:insert(erlang:element(2, Set), Member, [])}. - --spec contains(set(DKI), DKI) -> boolean(). -contains(Set, Member) -> - _pipe = erlang:element(2, Set), - _pipe@1 = gleam@dict:get(_pipe, Member), - gleam@result:is_ok(_pipe@1). - --spec delete(set(DKK), DKK) -> set(DKK). -delete(Set, Member) -> - {set, gleam@dict:delete(erlang:element(2, Set), Member)}. - --spec to_list(set(DKN)) -> list(DKN). -to_list(Set) -> - gleam@dict:keys(erlang:element(2, Set)). - --spec from_list(list(DKQ)) -> set(DKQ). -from_list(Members) -> - Map = gleam@list:fold( - Members, - gleam@dict:new(), - fun(M, K) -> gleam@dict:insert(M, K, []) end - ), - {set, Map}. - --spec fold(set(DKT), DKV, fun((DKV, DKT) -> DKV)) -> DKV. -fold(Set, Initial, Reducer) -> - gleam@dict:fold( - erlang:element(2, Set), - Initial, - fun(A, K, _) -> Reducer(A, K) end - ). - --spec filter(set(DKW), fun((DKW) -> boolean())) -> set(DKW). -filter(Set, Predicate) -> - {set, - gleam@dict:filter(erlang:element(2, Set), fun(M, _) -> Predicate(M) end)}. - --spec drop(set(DKZ), list(DKZ)) -> set(DKZ). -drop(Set, Disallowed) -> - gleam@list:fold(Disallowed, Set, fun delete/2). - --spec take(set(DLD), list(DLD)) -> set(DLD). -take(Set, Desired) -> - {set, gleam@dict:take(erlang:element(2, Set), Desired)}. - --spec order(set(DLH), set(DLH)) -> {set(DLH), set(DLH)}. -order(First, Second) -> - case gleam@dict:size(erlang:element(2, First)) > gleam@dict:size( - erlang:element(2, Second) - ) of - true -> - {First, Second}; - - false -> - {Second, First} - end. - --spec union(set(DLM), set(DLM)) -> set(DLM). -union(First, Second) -> - {Larger, Smaller} = order(First, Second), - fold(Smaller, Larger, fun insert/2). - --spec intersection(set(DLQ), set(DLQ)) -> set(DLQ). -intersection(First, Second) -> - {Larger, Smaller} = order(First, Second), - take(Larger, to_list(Smaller)). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@string.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@string.erl deleted file mode 100644 index 6cba31d..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@string.erl +++ /dev/null @@ -1,352 +0,0 @@ --module(gleam@string). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([is_empty/1, length/1, reverse/1, replace/3, lowercase/1, uppercase/1, compare/2, slice/3, crop/2, drop_left/2, drop_right/2, contains/2, starts_with/2, ends_with/2, split_once/2, append/2, concat/1, repeat/2, join/2, pad_left/3, pad_right/3, trim/1, trim_left/1, trim_right/1, pop_grapheme/1, to_graphemes/1, split/2, to_utf_codepoints/1, from_utf_codepoints/1, utf_codepoint/1, utf_codepoint_to_int/1, to_option/1, first/1, last/1, capitalise/1, inspect/1, byte_size/1]). --export_type([direction/0]). - --type direction() :: leading | trailing | both. - --spec is_empty(binary()) -> boolean(). -is_empty(Str) -> - Str =:= <<""/utf8>>. - --spec length(binary()) -> integer(). -length(String) -> - string:length(String). - --spec do_reverse(binary()) -> binary(). -do_reverse(String) -> - _pipe = String, - _pipe@1 = gleam@string_builder:from_string(_pipe), - _pipe@2 = gleam@string_builder:reverse(_pipe@1), - gleam@string_builder:to_string(_pipe@2). - --spec reverse(binary()) -> binary(). -reverse(String) -> - do_reverse(String). - --spec replace(binary(), binary(), binary()) -> binary(). -replace(String, Pattern, Substitute) -> - _pipe = String, - _pipe@1 = gleam@string_builder:from_string(_pipe), - _pipe@2 = gleam@string_builder:replace(_pipe@1, Pattern, Substitute), - gleam@string_builder:to_string(_pipe@2). - --spec lowercase(binary()) -> binary(). -lowercase(String) -> - string:lowercase(String). - --spec uppercase(binary()) -> binary(). -uppercase(String) -> - string:uppercase(String). - --spec compare(binary(), binary()) -> gleam@order:order(). -compare(A, B) -> - case A =:= B of - true -> - eq; - - _ -> - case gleam_stdlib:less_than(A, B) of - true -> - lt; - - _ -> - gt - end - end. - --spec slice(binary(), integer(), integer()) -> binary(). -slice(String, Idx, Len) -> - case Len < 0 of - true -> - <<""/utf8>>; - - false -> - case Idx < 0 of - true -> - Translated_idx = length(String) + Idx, - case Translated_idx < 0 of - true -> - <<""/utf8>>; - - false -> - string:slice(String, Translated_idx, Len) - end; - - false -> - string:slice(String, Idx, Len) - end - end. - --spec crop(binary(), binary()) -> binary(). -crop(String, Substring) -> - gleam_stdlib:crop_string(String, Substring). - --spec drop_left(binary(), integer()) -> binary(). -drop_left(String, Num_graphemes) -> - case Num_graphemes < 0 of - true -> - String; - - false -> - slice(String, Num_graphemes, length(String) - Num_graphemes) - end. - --spec drop_right(binary(), integer()) -> binary(). -drop_right(String, Num_graphemes) -> - case Num_graphemes < 0 of - true -> - String; - - false -> - slice(String, 0, length(String) - Num_graphemes) - end. - --spec contains(binary(), binary()) -> boolean(). -contains(Haystack, Needle) -> - gleam_stdlib:contains_string(Haystack, Needle). - --spec starts_with(binary(), binary()) -> boolean(). -starts_with(String, Prefix) -> - gleam_stdlib:string_starts_with(String, Prefix). - --spec ends_with(binary(), binary()) -> boolean(). -ends_with(String, Suffix) -> - gleam_stdlib:string_ends_with(String, Suffix). - --spec do_split_once(binary(), binary()) -> {ok, {binary(), binary()}} | - {error, nil}. -do_split_once(X, Substring) -> - case string:split(X, Substring) of - [First, Rest] -> - {ok, {First, Rest}}; - - _ -> - {error, nil} - end. - --spec split_once(binary(), binary()) -> {ok, {binary(), binary()}} | - {error, nil}. -split_once(X, Substring) -> - do_split_once(X, Substring). - --spec append(binary(), binary()) -> binary(). -append(First, Second) -> - _pipe = First, - _pipe@1 = gleam@string_builder:from_string(_pipe), - _pipe@2 = gleam@string_builder:append(_pipe@1, Second), - gleam@string_builder:to_string(_pipe@2). - --spec concat(list(binary())) -> binary(). -concat(Strings) -> - _pipe = Strings, - _pipe@1 = gleam@string_builder:from_strings(_pipe), - gleam@string_builder:to_string(_pipe@1). - --spec repeat(binary(), integer()) -> binary(). -repeat(String, Times) -> - _pipe = gleam@iterator:repeat(String), - _pipe@1 = gleam@iterator:take(_pipe, Times), - _pipe@2 = gleam@iterator:to_list(_pipe@1), - concat(_pipe@2). - --spec do_join(list(binary()), binary()) -> binary(). -do_join(Strings, Separator) -> - _pipe = Strings, - _pipe@1 = gleam@list:intersperse(_pipe, Separator), - concat(_pipe@1). - --spec join(list(binary()), binary()) -> binary(). -join(Strings, Separator) -> - do_join(Strings, Separator). - --spec padding(integer(), binary()) -> gleam@iterator:iterator(binary()). -padding(Size, Pad_string) -> - Pad_length = length(Pad_string), - Num_pads = case Pad_length of - 0 -> 0; - Gleam@denominator -> Size div Gleam@denominator - end, - Extra = case Pad_length of - 0 -> 0; - Gleam@denominator@1 -> Size rem Gleam@denominator@1 - end, - _pipe = gleam@iterator:repeat(Pad_string), - _pipe@1 = gleam@iterator:take(_pipe, Num_pads), - gleam@iterator:append( - _pipe@1, - gleam@iterator:single(slice(Pad_string, 0, Extra)) - ). - --spec pad_left(binary(), integer(), binary()) -> binary(). -pad_left(String, Desired_length, Pad_string) -> - Current_length = length(String), - To_pad_length = Desired_length - Current_length, - _pipe = padding(To_pad_length, Pad_string), - _pipe@1 = gleam@iterator:append(_pipe, gleam@iterator:single(String)), - _pipe@2 = gleam@iterator:to_list(_pipe@1), - concat(_pipe@2). - --spec pad_right(binary(), integer(), binary()) -> binary(). -pad_right(String, Desired_length, Pad_string) -> - Current_length = length(String), - To_pad_length = Desired_length - Current_length, - _pipe = gleam@iterator:single(String), - _pipe@1 = gleam@iterator:append(_pipe, padding(To_pad_length, Pad_string)), - _pipe@2 = gleam@iterator:to_list(_pipe@1), - concat(_pipe@2). - --spec do_trim(binary()) -> binary(). -do_trim(String) -> - string:trim(String, both). - --spec trim(binary()) -> binary(). -trim(String) -> - do_trim(String). - --spec do_trim_left(binary()) -> binary(). -do_trim_left(String) -> - string:trim(String, leading). - --spec trim_left(binary()) -> binary(). -trim_left(String) -> - do_trim_left(String). - --spec do_trim_right(binary()) -> binary(). -do_trim_right(String) -> - string:trim(String, trailing). - --spec trim_right(binary()) -> binary(). -trim_right(String) -> - do_trim_right(String). - --spec pop_grapheme(binary()) -> {ok, {binary(), binary()}} | {error, nil}. -pop_grapheme(String) -> - gleam_stdlib:string_pop_grapheme(String). - --spec do_to_graphemes(binary(), list(binary())) -> list(binary()). -do_to_graphemes(String, Acc) -> - case pop_grapheme(String) of - {ok, {Grapheme, Rest}} -> - do_to_graphemes(Rest, [Grapheme | Acc]); - - _ -> - Acc - end. - --spec to_graphemes(binary()) -> list(binary()). -to_graphemes(String) -> - _pipe = do_to_graphemes(String, []), - gleam@list:reverse(_pipe). - --spec split(binary(), binary()) -> list(binary()). -split(X, Substring) -> - case Substring of - <<""/utf8>> -> - to_graphemes(X); - - _ -> - _pipe = X, - _pipe@1 = gleam@string_builder:from_string(_pipe), - _pipe@2 = gleam@string_builder:split(_pipe@1, Substring), - gleam@list:map(_pipe@2, fun gleam@string_builder:to_string/1) - end. - --spec do_to_utf_codepoints_impl(bitstring(), list(integer())) -> list(integer()). -do_to_utf_codepoints_impl(Bit_array, Acc) -> - case Bit_array of - <<First/utf8, Rest/binary>> -> - do_to_utf_codepoints_impl(Rest, [First | Acc]); - - _ -> - Acc - end. - --spec do_to_utf_codepoints(binary()) -> list(integer()). -do_to_utf_codepoints(String) -> - _pipe = do_to_utf_codepoints_impl(<<String/binary>>, []), - gleam@list:reverse(_pipe). - --spec to_utf_codepoints(binary()) -> list(integer()). -to_utf_codepoints(String) -> - do_to_utf_codepoints(String). - --spec from_utf_codepoints(list(integer())) -> binary(). -from_utf_codepoints(Utf_codepoints) -> - gleam_stdlib:utf_codepoint_list_to_string(Utf_codepoints). - --spec utf_codepoint(integer()) -> {ok, integer()} | {error, nil}. -utf_codepoint(Value) -> - case Value of - I when I > 1114111 -> - {error, nil}; - - 65534 -> - {error, nil}; - - 65535 -> - {error, nil}; - - I@1 when (I@1 >= 55296) andalso (I@1 =< 57343) -> - {error, nil}; - - I@2 -> - {ok, gleam_stdlib:identity(I@2)} - end. - --spec utf_codepoint_to_int(integer()) -> integer(). -utf_codepoint_to_int(Cp) -> - gleam_stdlib:identity(Cp). - --spec to_option(binary()) -> gleam@option:option(binary()). -to_option(S) -> - case S of - <<""/utf8>> -> - none; - - _ -> - {some, S} - end. - --spec first(binary()) -> {ok, binary()} | {error, nil}. -first(S) -> - case pop_grapheme(S) of - {ok, {First, _}} -> - {ok, First}; - - {error, E} -> - {error, E} - end. - --spec last(binary()) -> {ok, binary()} | {error, nil}. -last(S) -> - case pop_grapheme(S) of - {ok, {First, <<""/utf8>>}} -> - {ok, First}; - - {ok, {_, Rest}} -> - {ok, slice(Rest, -1, 1)}; - - {error, E} -> - {error, E} - end. - --spec capitalise(binary()) -> binary(). -capitalise(S) -> - case pop_grapheme(S) of - {ok, {First, Rest}} -> - append(uppercase(First), lowercase(Rest)); - - _ -> - <<""/utf8>> - end. - --spec inspect(any()) -> binary(). -inspect(Term) -> - _pipe = gleam_stdlib:inspect(Term), - gleam@string_builder:to_string(_pipe). - --spec byte_size(binary()) -> integer(). -byte_size(String) -> - erlang:byte_size(String). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@string_builder.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@string_builder.erl deleted file mode 100644 index 693e840..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@string_builder.erl +++ /dev/null @@ -1,91 +0,0 @@ --module(gleam@string_builder). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([prepend_builder/2, append_builder/2, new/0, from_strings/1, concat/1, from_string/1, prepend/2, append/2, to_string/1, byte_size/1, join/2, lowercase/1, uppercase/1, reverse/1, split/2, replace/3, is_equal/2, is_empty/1]). --export_type([string_builder/0, direction/0]). - --type string_builder() :: any(). - --type direction() :: all. - --spec prepend_builder(string_builder(), string_builder()) -> string_builder(). -prepend_builder(Builder, Prefix) -> - gleam_stdlib:iodata_append(Prefix, Builder). - --spec append_builder(string_builder(), string_builder()) -> string_builder(). -append_builder(Builder, Suffix) -> - gleam_stdlib:iodata_append(Builder, Suffix). - --spec new() -> string_builder(). -new() -> - gleam_stdlib:identity([]). - --spec from_strings(list(binary())) -> string_builder(). -from_strings(Strings) -> - gleam_stdlib:identity(Strings). - --spec concat(list(string_builder())) -> string_builder(). -concat(Builders) -> - gleam_stdlib:identity(Builders). - --spec from_string(binary()) -> string_builder(). -from_string(String) -> - gleam_stdlib:identity(String). - --spec prepend(string_builder(), binary()) -> string_builder(). -prepend(Builder, Prefix) -> - append_builder(from_string(Prefix), Builder). - --spec append(string_builder(), binary()) -> string_builder(). -append(Builder, Second) -> - append_builder(Builder, from_string(Second)). - --spec to_string(string_builder()) -> binary(). -to_string(Builder) -> - unicode:characters_to_binary(Builder). - --spec byte_size(string_builder()) -> integer(). -byte_size(Builder) -> - erlang:iolist_size(Builder). - --spec join(list(string_builder()), binary()) -> string_builder(). -join(Builders, Sep) -> - _pipe = Builders, - _pipe@1 = gleam@list:intersperse(_pipe, from_string(Sep)), - concat(_pipe@1). - --spec lowercase(string_builder()) -> string_builder(). -lowercase(Builder) -> - string:lowercase(Builder). - --spec uppercase(string_builder()) -> string_builder(). -uppercase(Builder) -> - string:uppercase(Builder). - --spec reverse(string_builder()) -> string_builder(). -reverse(Builder) -> - string:reverse(Builder). - --spec do_split(string_builder(), binary()) -> list(string_builder()). -do_split(Iodata, Pattern) -> - string:split(Iodata, Pattern, all). - --spec split(string_builder(), binary()) -> list(string_builder()). -split(Iodata, Pattern) -> - do_split(Iodata, Pattern). - --spec do_replace(string_builder(), binary(), binary()) -> string_builder(). -do_replace(Iodata, Pattern, Substitute) -> - string:replace(Iodata, Pattern, Substitute, all). - --spec replace(string_builder(), binary(), binary()) -> string_builder(). -replace(Builder, Pattern, Substitute) -> - do_replace(Builder, Pattern, Substitute). - --spec is_equal(string_builder(), string_builder()) -> boolean(). -is_equal(A, B) -> - string:equal(A, B). - --spec is_empty(string_builder()) -> boolean(). -is_empty(Builder) -> - string:is_empty(Builder). diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam@uri.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam@uri.erl deleted file mode 100644 index 7ec4fe7..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam@uri.erl +++ /dev/null @@ -1,252 +0,0 @@ --module(gleam@uri). --compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function]). - --export([parse/1, parse_query/1, percent_encode/1, query_to_string/1, percent_decode/1, path_segments/1, to_string/1, origin/1, merge/2]). --export_type([uri/0]). - --type uri() :: {uri, - gleam@option:option(binary()), - gleam@option:option(binary()), - gleam@option:option(binary()), - gleam@option:option(integer()), - binary(), - gleam@option:option(binary()), - gleam@option:option(binary())}. - --spec parse(binary()) -> {ok, uri()} | {error, nil}. -parse(Uri_string) -> - gleam_stdlib:uri_parse(Uri_string). - --spec parse_query(binary()) -> {ok, list({binary(), binary()})} | {error, nil}. -parse_query(Query) -> - gleam_stdlib:parse_query(Query). - --spec percent_encode(binary()) -> binary(). -percent_encode(Value) -> - gleam_stdlib:percent_encode(Value). - --spec query_pair({binary(), binary()}) -> gleam@string_builder:string_builder(). -query_pair(Pair) -> - gleam@string_builder:from_strings( - [percent_encode(erlang:element(1, Pair)), - <<"="/utf8>>, - percent_encode(erlang:element(2, Pair))] - ). - --spec query_to_string(list({binary(), binary()})) -> binary(). -query_to_string(Query) -> - _pipe = Query, - _pipe@1 = gleam@list:map(_pipe, fun query_pair/1), - _pipe@2 = gleam@list:intersperse( - _pipe@1, - gleam@string_builder:from_string(<<"&"/utf8>>) - ), - _pipe@3 = gleam@string_builder:concat(_pipe@2), - gleam@string_builder:to_string(_pipe@3). - --spec percent_decode(binary()) -> {ok, binary()} | {error, nil}. -percent_decode(Value) -> - gleam_stdlib:percent_decode(Value). - --spec do_remove_dot_segments(list(binary()), list(binary())) -> list(binary()). -do_remove_dot_segments(Input, Accumulator) -> - case Input of - [] -> - gleam@list:reverse(Accumulator); - - [Segment | Rest] -> - Accumulator@5 = case {Segment, Accumulator} of - {<<""/utf8>>, Accumulator@1} -> - Accumulator@1; - - {<<"."/utf8>>, Accumulator@2} -> - Accumulator@2; - - {<<".."/utf8>>, []} -> - []; - - {<<".."/utf8>>, [_ | Accumulator@3]} -> - Accumulator@3; - - {Segment@1, Accumulator@4} -> - [Segment@1 | Accumulator@4] - end, - do_remove_dot_segments(Rest, Accumulator@5) - end. - --spec remove_dot_segments(list(binary())) -> list(binary()). -remove_dot_segments(Input) -> - do_remove_dot_segments(Input, []). - --spec path_segments(binary()) -> list(binary()). -path_segments(Path) -> - remove_dot_segments(gleam@string:split(Path, <<"/"/utf8>>)). - --spec to_string(uri()) -> binary(). -to_string(Uri) -> - Parts = case erlang:element(8, Uri) of - {some, Fragment} -> - [<<"#"/utf8>>, Fragment]; - - _ -> - [] - end, - Parts@1 = case erlang:element(7, Uri) of - {some, Query} -> - [<<"?"/utf8>>, Query | Parts]; - - _ -> - Parts - end, - Parts@2 = [erlang:element(6, Uri) | Parts@1], - Parts@3 = case {erlang:element(4, Uri), - gleam@string:starts_with(erlang:element(6, Uri), <<"/"/utf8>>)} of - {{some, Host}, false} when Host =/= <<""/utf8>> -> - [<<"/"/utf8>> | Parts@2]; - - {_, _} -> - Parts@2 - end, - Parts@4 = case {erlang:element(4, Uri), erlang:element(5, Uri)} of - {{some, _}, {some, Port}} -> - [<<":"/utf8>>, gleam@int:to_string(Port) | Parts@3]; - - {_, _} -> - Parts@3 - end, - Parts@5 = case {erlang:element(2, Uri), - erlang:element(3, Uri), - erlang:element(4, Uri)} of - {{some, S}, {some, U}, {some, H}} -> - [S, <<"://"/utf8>>, U, <<"@"/utf8>>, H | Parts@4]; - - {{some, S@1}, none, {some, H@1}} -> - [S@1, <<"://"/utf8>>, H@1 | Parts@4]; - - {{some, S@2}, {some, _}, none} -> - [S@2, <<":"/utf8>> | Parts@4]; - - {{some, S@2}, none, none} -> - [S@2, <<":"/utf8>> | Parts@4]; - - {none, none, {some, H@2}} -> - [<<"//"/utf8>>, H@2 | Parts@4]; - - {_, _, _} -> - Parts@4 - end, - gleam@string:concat(Parts@5). - --spec origin(uri()) -> {ok, binary()} | {error, nil}. -origin(Uri) -> - {uri, Scheme, _, Host, Port, _, _, _} = Uri, - case Scheme of - {some, <<"https"/utf8>>} when Port =:= {some, 443} -> - Origin = {uri, Scheme, none, Host, none, <<""/utf8>>, none, none}, - {ok, to_string(Origin)}; - - {some, <<"http"/utf8>>} when Port =:= {some, 80} -> - Origin@1 = {uri, Scheme, none, Host, none, <<""/utf8>>, none, none}, - {ok, to_string(Origin@1)}; - - {some, S} when (S =:= <<"http"/utf8>>) orelse (S =:= <<"https"/utf8>>) -> - Origin@2 = {uri, Scheme, none, Host, Port, <<""/utf8>>, none, none}, - {ok, to_string(Origin@2)}; - - _ -> - {error, nil} - end. - --spec drop_last(list(DFL)) -> list(DFL). -drop_last(Elements) -> - gleam@list:take(Elements, gleam@list:length(Elements) - 1). - --spec join_segments(list(binary())) -> binary(). -join_segments(Segments) -> - gleam@string:join([<<""/utf8>> | Segments], <<"/"/utf8>>). - --spec merge(uri(), uri()) -> {ok, uri()} | {error, nil}. -merge(Base, Relative) -> - case Base of - {uri, {some, _}, _, {some, _}, _, _, _, _} -> - case Relative of - {uri, _, _, {some, _}, _, _, _, _} -> - Path = begin - _pipe = gleam@string:split( - erlang:element(6, Relative), - <<"/"/utf8>> - ), - _pipe@1 = remove_dot_segments(_pipe), - join_segments(_pipe@1) - end, - Resolved = {uri, - gleam@option:'or'( - erlang:element(2, Relative), - erlang:element(2, Base) - ), - none, - erlang:element(4, Relative), - gleam@option:'or'( - erlang:element(5, Relative), - erlang:element(5, Base) - ), - Path, - erlang:element(7, Relative), - erlang:element(8, Relative)}, - {ok, Resolved}; - - _ -> - {New_path, New_query} = case erlang:element(6, Relative) of - <<""/utf8>> -> - {erlang:element(6, Base), - gleam@option:'or'( - erlang:element(7, Relative), - erlang:element(7, Base) - )}; - - _ -> - Path_segments = case gleam@string:starts_with( - erlang:element(6, Relative), - <<"/"/utf8>> - ) of - true -> - gleam@string:split( - erlang:element(6, Relative), - <<"/"/utf8>> - ); - - false -> - _pipe@2 = gleam@string:split( - erlang:element(6, Base), - <<"/"/utf8>> - ), - _pipe@3 = drop_last(_pipe@2), - gleam@list:append( - _pipe@3, - gleam@string:split( - erlang:element(6, Relative), - <<"/"/utf8>> - ) - ) - end, - Path@1 = begin - _pipe@4 = Path_segments, - _pipe@5 = remove_dot_segments(_pipe@4), - join_segments(_pipe@5) - end, - {Path@1, erlang:element(7, Relative)} - end, - Resolved@1 = {uri, - erlang:element(2, Base), - none, - erlang:element(4, Base), - erlang:element(5, Base), - New_path, - New_query, - erlang:element(8, Relative)}, - {ok, Resolved@1} - end; - - _ -> - {error, nil} - end. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.app.src b/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.app.src deleted file mode 100644 index bcf08e2..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.app.src +++ /dev/null @@ -1,31 +0,0 @@ -{application, gleam_stdlib, [ - {vsn, "0.33.0"}, - {applications, []}, - {description, "A standard library for the Gleam programming language"}, - {modules, [gleam@base, - gleam@bit_array, - gleam@bit_builder, - gleam@bit_string, - gleam@bool, - gleam@bytes_builder, - gleam@dict, - gleam@dynamic, - gleam@float, - gleam@function, - gleam@int, - gleam@io, - gleam@iterator, - gleam@list, - gleam@map, - gleam@option, - gleam@order, - gleam@pair, - gleam@queue, - gleam@regex, - gleam@result, - gleam@set, - gleam@string, - gleam@string_builder, - gleam@uri]}, - {registered, []} -]}. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.erl b/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.erl deleted file mode 100644 index c6ea125..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.erl +++ /dev/null @@ -1,529 +0,0 @@ --module(gleam_stdlib). - --export([ - map_get/2, iodata_append/2, identity/1, decode_int/1, decode_bool/1, - decode_float/1, decode_list/1, decode_option/2, decode_field/2, parse_int/1, - parse_float/1, less_than/2, string_pop_grapheme/1, string_starts_with/2, - wrap_list/1, string_ends_with/2, string_pad/4, decode_map/1, uri_parse/1, - bit_array_int_to_u32/1, bit_array_int_from_u32/1, decode_result/1, - bit_array_slice/3, decode_bit_array/1, compile_regex/2, regex_scan/2, - percent_encode/1, percent_decode/1, regex_check/2, regex_split/2, - base_decode64/1, parse_query/1, bit_array_concat/1, size_of_tuple/1, - decode_tuple/1, decode_tuple2/1, decode_tuple3/1, decode_tuple4/1, - decode_tuple5/1, decode_tuple6/1, tuple_get/2, classify_dynamic/1, print/1, - println/1, print_error/1, println_error/1, inspect/1, float_to_string/1, - int_from_base_string/2, utf_codepoint_list_to_string/1, contains_string/2, - crop_string/2, base16_decode/1 -]). - -%% Taken from OTP's uri_string module --define(DEC2HEX(X), - if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0; - ((X) >= 10) andalso ((X) =< 15) -> (X) + $A - 10 - end). - -%% Taken from OTP's uri_string module --define(HEX2DEC(X), - if ((X) >= $0) andalso ((X) =< $9) -> (X) - $0; - ((X) >= $A) andalso ((X) =< $F) -> (X) - $A + 10; - ((X) >= $a) andalso ((X) =< $f) -> (X) - $a + 10 - end). - --define(is_lowercase_char(X), (X > 96 andalso X < 123)). --define(is_underscore_char(X), (X == 95)). --define(is_digit_char(X), (X > 47 andalso X < 58)). - -uppercase(X) -> X - 32. - -map_get(Map, Key) -> - case maps:find(Key, Map) of - error -> {error, nil}; - OkFound -> OkFound - end. - -iodata_append(Iodata, String) -> [Iodata, String]. - -identity(X) -> X. - -decode_error_msg(Expected, Data) when is_binary(Expected) -> - decode_error(Expected, classify_dynamic(Data)). -decode_error(Expected, Got) when is_binary(Expected) andalso is_binary(Got) -> - {error, [{decode_error, Expected, Got, []}]}. - -classify_dynamic(nil) -> <<"Nil">>; -classify_dynamic(X) when is_atom(X) -> <<"Atom">>; -classify_dynamic(X) when is_binary(X) -> <<"String">>; -classify_dynamic(X) when is_bitstring(X) -> <<"BitArray">>; -classify_dynamic(X) when is_integer(X) -> <<"Int">>; -classify_dynamic(X) when is_float(X) -> <<"Float">>; -classify_dynamic(X) when is_list(X) -> <<"List">>; -classify_dynamic(X) when is_boolean(X) -> <<"Bool">>; -classify_dynamic(X) when is_map(X) -> <<"Map">>; -classify_dynamic(X) when is_tuple(X) -> - iolist_to_binary(["Tuple of ", integer_to_list(tuple_size(X)), " elements"]); -classify_dynamic(X) when - is_function(X, 0) orelse is_function(X, 1) orelse is_function(X, 2) orelse - is_function(X, 3) orelse is_function(X, 4) orelse is_function(X, 5) orelse - is_function(X, 6) orelse is_function(X, 7) orelse is_function(X, 8) orelse - is_function(X, 9) orelse is_function(X, 10) orelse is_function(X, 11) orelse - is_function(X, 12) -> <<"Function">>; -classify_dynamic(_) -> <<"Some other type">>. - -decode_map(Data) when is_map(Data) -> {ok, Data}; -decode_map(Data) -> decode_error_msg(<<"Map">>, Data). - -decode_bit_array(Data) when is_bitstring(Data) -> {ok, Data}; -decode_bit_array(Data) -> decode_error_msg(<<"BitArray">>, Data). - -decode_int(Data) when is_integer(Data) -> {ok, Data}; -decode_int(Data) -> decode_error_msg(<<"Int">>, Data). - -decode_float(Data) when is_float(Data) -> {ok, Data}; -decode_float(Data) -> decode_error_msg(<<"Float">>, Data). - -decode_bool(Data) when is_boolean(Data) -> {ok, Data}; -decode_bool(Data) -> decode_error_msg(<<"Bool">>, Data). - -decode_list(Data) when is_list(Data) -> {ok, Data}; -decode_list(Data) -> decode_error_msg(<<"List">>, Data). - -decode_field(Data, Key) when is_map(Data) -> - case Data of - #{Key := Value} -> {ok, {some, Value}}; - _ -> - {ok, none} - end; -decode_field(Data, _) -> - decode_error_msg(<<"Map">>, Data). - -size_of_tuple(Data) -> tuple_size(Data). - -tuple_get(_tup, Index) when Index < 0 -> {error, nil}; -tuple_get(Data, Index) when Index >= tuple_size(Data) -> {error, nil}; -tuple_get(Data, Index) -> {ok, element(Index + 1, Data)}. - -decode_tuple(Data) when is_tuple(Data) -> {ok, Data}; -decode_tuple(Data) -> decode_error_msg(<<"Tuple">>, Data). - -decode_tuple2({_,_} = A) -> {ok, A}; -decode_tuple2([A,B]) -> {ok, {A,B}}; -decode_tuple2(Data) -> decode_error_msg(<<"Tuple of 2 elements">>, Data). - -decode_tuple3({_,_,_} = A) -> {ok, A}; -decode_tuple3([A,B,C]) -> {ok, {A,B,C}}; -decode_tuple3(Data) -> decode_error_msg(<<"Tuple of 3 elements">>, Data). - -decode_tuple4({_,_,_,_} = A) -> {ok, A}; -decode_tuple4([A,B,C,D]) -> {ok, {A,B,C,D}}; -decode_tuple4(Data) -> decode_error_msg(<<"Tuple of 4 elements">>, Data). - -decode_tuple5({_,_,_,_,_} = A) -> {ok, A}; -decode_tuple5([A,B,C,D,E]) -> {ok, {A,B,C,D,E}}; -decode_tuple5(Data) -> decode_error_msg(<<"Tuple of 5 elements">>, Data). - -decode_tuple6({_,_,_,_,_,_} = A) -> {ok, A}; -decode_tuple6([A,B,C,D,E,F]) -> {ok, {A,B,C,D,E,F}}; -decode_tuple6(Data) -> decode_error_msg(<<"Tuple of 6 elements">>, Data). - -decode_option(Term, F) -> - Decode = fun(Inner) -> - case F(Inner) of - {ok, Decoded} -> {ok, {some, Decoded}}; - Error -> Error - end - end, - case Term of - undefined -> {ok, none}; - error -> {ok, none}; - null -> {ok, none}; - none -> {ok, none}; - nil -> {ok, none}; - {some, Inner} -> Decode(Inner); - _ -> Decode(Term) - end. - -decode_result(Term) -> - case Term of - {ok, Inner} -> {ok, {ok, Inner}}; - ok -> {ok, {ok, nil}}; - {error, Inner} -> {ok, {error, Inner}}; - error -> {ok, {error, nil}}; - _ -> decode_error_msg(<<"Result">>, Term) - end. - -int_from_base_string(String, Base) -> - case catch binary_to_integer(String, Base) of - Int when is_integer(Int) -> {ok, Int}; - _ -> {error, nil} - end. - -parse_int(String) -> - case catch binary_to_integer(String) of - Int when is_integer(Int) -> {ok, Int}; - _ -> {error, nil} - end. - -parse_float(String) -> - case catch binary_to_float(String) of - Float when is_float(Float) -> {ok, Float}; - _ -> {error, nil} - end. - -less_than(Lhs, Rhs) -> - Lhs < Rhs. - -string_starts_with(_, <<>>) -> true; -string_starts_with(String, Prefix) when byte_size(Prefix) > byte_size(String) -> false; -string_starts_with(String, Prefix) -> - PrefixSize = byte_size(Prefix), - Prefix == binary_part(String, 0, PrefixSize). - -string_ends_with(_, <<>>) -> true; -string_ends_with(String, Suffix) when byte_size(Suffix) > byte_size(String) -> false; -string_ends_with(String, Suffix) -> - SuffixSize = byte_size(Suffix), - Suffix == binary_part(String, byte_size(String) - SuffixSize, SuffixSize). - -string_pad(String, Length, Dir, PadString) -> - Chars = string:pad(String, Length, Dir, binary_to_list(PadString)), - case unicode:characters_to_binary(Chars) of - Bin when is_binary(Bin) -> Bin; - Error -> erlang:error({gleam_error, {string_invalid_utf8, Error}}) - end. - -string_pop_grapheme(String) -> - case string:next_grapheme(String) of - [ Next | Rest ] -> - {ok, {unicode:characters_to_binary([Next]), unicode:characters_to_binary(Rest)}}; - _ -> {error, nil} - end. - -bit_array_concat(BitArrays) -> - list_to_bitstring(BitArrays). - -bit_array_slice(Bin, Pos, Len) -> - try {ok, binary:part(Bin, Pos, Len)} - catch error:badarg -> {error, nil} - end. - -bit_array_int_to_u32(I) when 0 =< I, I < 4294967296 -> - {ok, <<I:32>>}; -bit_array_int_to_u32(_) -> - {error, nil}. - -bit_array_int_from_u32(<<I:32>>) -> - {ok, I}; -bit_array_int_from_u32(_) -> - {error, nil}. - -compile_regex(String, Options) -> - {options, Caseless, Multiline} = Options, - OptionsList = [ - unicode, - ucp, - Caseless andalso caseless, - Multiline andalso multiline - ], - FilteredOptions = [Option || Option <- OptionsList, Option /= false], - case re:compile(String, FilteredOptions) of - {ok, MP} -> {ok, MP}; - {error, {Str, Pos}} -> - {error, {compile_error, unicode:characters_to_binary(Str), Pos}} - end. - -regex_check(Regex, String) -> - re:run(String, Regex) /= nomatch. - -regex_split(Regex, String) -> - re:split(String, Regex). - -regex_submatches(_, {-1, 0}) -> none; -regex_submatches(String, {Start, Length}) -> - BinarySlice = binary:part(String, {Start, Length}), - case string:is_empty(binary_to_list(BinarySlice)) of - true -> none; - false -> {some, BinarySlice} - end. - -regex_matches(String, [{Start, Length} | Submatches]) -> - Submatches1 = lists:map(fun(X) -> regex_submatches(String, X) end, Submatches), - {match, binary:part(String, Start, Length), Submatches1}. - -regex_scan(Regex, String) -> - case re:run(String, Regex, [global]) of - {match, Captured} -> lists:map(fun(X) -> regex_matches(String, X) end, Captured); - nomatch -> [] - end. - -base_decode64(S) -> - try {ok, base64:decode(S)} - catch error:_ -> {error, nil} - end. - -wrap_list(X) when is_list(X) -> X; -wrap_list(X) -> [X]. - -parse_query(Query) -> - case uri_string:dissect_query(Query) of - {error, _, _} -> {error, nil}; - Pairs -> - Pairs1 = lists:map(fun - ({K, true}) -> {K, <<"">>}; - (Pair) -> Pair - end, Pairs), - {ok, Pairs1} - end. - -percent_encode(B) -> percent_encode(B, <<>>). -percent_encode(<<>>, Acc) -> - Acc; -percent_encode(<<H,T/binary>>, Acc) -> - case percent_ok(H) of - true -> - percent_encode(T, <<Acc/binary,H>>); - false -> - <<A:4,B:4>> = <<H>>, - percent_encode(T, <<Acc/binary,$%,(?DEC2HEX(A)),(?DEC2HEX(B))>>) - end. - -percent_decode(Cs) -> percent_decode(Cs, <<>>). -percent_decode(<<$%, C0, C1, Cs/binary>>, Acc) -> - case is_hex_digit(C0) andalso is_hex_digit(C1) of - true -> - B = ?HEX2DEC(C0)*16+?HEX2DEC(C1), - percent_decode(Cs, <<Acc/binary, B>>); - false -> - {error, nil} - end; -percent_decode(<<C,Cs/binary>>, Acc) -> - percent_decode(Cs, <<Acc/binary, C>>); -percent_decode(<<>>, Acc) -> - check_utf8(Acc). - -percent_ok($!) -> true; -percent_ok($$) -> true; -percent_ok($') -> true; -percent_ok($() -> true; -percent_ok($)) -> true; -percent_ok($*) -> true; -percent_ok($+) -> true; -percent_ok($-) -> true; -percent_ok($.) -> true; -percent_ok($_) -> true; -percent_ok($~) -> true; -percent_ok(C) when $0 =< C, C =< $9 -> true; -percent_ok(C) when $A =< C, C =< $Z -> true; -percent_ok(C) when $a =< C, C =< $z -> true; -percent_ok(_) -> false. - -is_hex_digit(C) -> - ($0 =< C andalso C =< $9) orelse ($a =< C andalso C =< $f) orelse ($A =< C andalso C =< $F). - -check_utf8(Cs) -> - case unicode:characters_to_list(Cs) of - {incomplete, _, _} -> {error, nil}; - {error, _, _} -> {error, nil}; - _ -> {ok, Cs} - end. - -uri_parse(String) -> - case uri_string:parse(String) of - {error, _, _} -> {error, nil}; - Uri -> - {ok, {uri, - maps_get_optional(Uri, scheme), - maps_get_optional(Uri, userinfo), - maps_get_optional(Uri, host), - maps_get_optional(Uri, port), - maps_get_or(Uri, path, <<>>), - maps_get_optional(Uri, query), - maps_get_optional(Uri, fragment) - }} - end. - -maps_get_optional(Map, Key) -> - try {some, maps:get(Key, Map)} - catch _:_ -> none - end. - -maps_get_or(Map, Key, Default) -> - try maps:get(Key, Map) - catch _:_ -> Default - end. - -print(String) -> - io:put_chars(String), - nil. - -println(String) -> - io:put_chars([String, $\n]), - nil. - -print_error(String) -> - io:put_chars(standard_error, String), - nil. - -println_error(String) -> - io:put_chars(standard_error, [String, $\n]), - nil. - -inspect(true) -> - "True"; -inspect(false) -> - "False"; -inspect(nil) -> - "Nil"; -inspect(Data) when is_map(Data) -> - Fields = [ - [<<"#(">>, inspect(Key), <<", ">>, inspect(Value), <<")">>] - || {Key, Value} <- maps:to_list(Data) - ], - ["dict.from_list([", lists:join(", ", Fields), "])"]; -inspect(Atom) when is_atom(Atom) -> - Binary = erlang:atom_to_binary(Atom), - case inspect_maybe_gleam_atom(Binary, none, <<>>) of - {ok, Inspected} -> Inspected; - {error, _} -> ["atom.create_from_string(\"", Binary, "\")"] - end; -inspect(Any) when is_integer(Any) -> - erlang:integer_to_list(Any); -inspect(Any) when is_float(Any) -> - io_lib_format:fwrite_g(Any); -inspect(Binary) when is_binary(Binary) -> - case inspect_maybe_utf8_string(Binary, <<>>) of - {ok, InspectedUtf8String} -> InspectedUtf8String; - {error, not_a_utf8_string} -> - Segments = [erlang:integer_to_list(X) || <<X>> <= Binary], - ["<<", lists:join(", ", Segments), ">>"] - end; -inspect(Bits) when is_bitstring(Bits) -> - inspect_bit_array(Bits); -inspect(List) when is_list(List) -> - case inspect_list(List) of - {proper, Elements} -> ["[", Elements, "]"]; - {improper, Elements} -> ["//erl([", Elements, "])"] - end; -inspect(Any) when is_tuple(Any) % Record constructors - andalso is_atom(element(1, Any)) - andalso element(1, Any) =/= false - andalso element(1, Any) =/= true - andalso element(1, Any) =/= nil --> - [Atom | ArgsList] = erlang:tuple_to_list(Any), - Args = lists:join(<<", ">>, - lists:map(fun inspect/1, ArgsList) - ), - [inspect(Atom), "(", Args, ")"]; -inspect(Tuple) when is_tuple(Tuple) -> - Elements = lists:map(fun inspect/1, erlang:tuple_to_list(Tuple)), - ["#(", lists:join(", ", Elements), ")"]; -inspect(Any) when is_function(Any) -> - {arity, Arity} = erlang:fun_info(Any, arity), - ArgsAsciiCodes = lists:seq($a, $a + Arity - 1), - Args = lists:join(<<", ">>, - lists:map(fun(Arg) -> <<Arg>> end, ArgsAsciiCodes) - ), - ["//fn(", Args, ") { ... }"]; -inspect(Any) -> - ["//erl(", io_lib:format("~p", [Any]), ")"]. - - -inspect_maybe_gleam_atom(<<>>, none, _) -> - {error, nil}; -inspect_maybe_gleam_atom(<<First, _Rest/binary>>, none, _) when ?is_digit_char(First) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, none, _) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_">>, _PrevChar, _Acc) -> - {error, nil}; -inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, $_, _Acc) -> - {error, nil}; -inspect_maybe_gleam_atom(<<First, _Rest/binary>>, _PrevChar, _Acc) - when not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First)) -> - {error, nil}; -inspect_maybe_gleam_atom(<<First, Rest/binary>>, none, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <<Acc/binary, (uppercase(First))>>); -inspect_maybe_gleam_atom(<<"_", Rest/binary>>, _PrevChar, Acc) -> - inspect_maybe_gleam_atom(Rest, $_, Acc); -inspect_maybe_gleam_atom(<<First, Rest/binary>>, $_, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <<Acc/binary, (uppercase(First))>>); -inspect_maybe_gleam_atom(<<First, Rest/binary>>, _PrevChar, Acc) -> - inspect_maybe_gleam_atom(Rest, First, <<Acc/binary, First>>); -inspect_maybe_gleam_atom(<<>>, _PrevChar, Acc) -> - {ok, Acc}; -inspect_maybe_gleam_atom(A, B, C) -> - erlang:display({A, B, C}), - throw({gleam_error, A, B, C}). - -inspect_list([]) -> - {proper, []}; -inspect_list([First]) -> - {proper, [inspect(First)]}; -inspect_list([First | Rest]) when is_list(Rest) -> - {Kind, Inspected} = inspect_list(Rest), - {Kind, [inspect(First), <<", ">> | Inspected]}; -inspect_list([First | ImproperTail]) -> - {improper, [inspect(First), <<" | ">>, inspect(ImproperTail)]}. - -inspect_bit_array(Bits) -> - Text = inspect_bit_array(Bits, <<"<<">>), - <<Text/binary, ">>">>. - -inspect_bit_array(<<>>, Acc) -> - Acc; -inspect_bit_array(<<X, Rest/bitstring>>, Acc) -> - inspect_bit_array(Rest, append_segment(Acc, erlang:integer_to_binary(X))); -inspect_bit_array(Rest, Acc) -> - Size = bit_size(Rest), - <<X:Size>> = Rest, - X1 = erlang:integer_to_binary(X), - Size1 = erlang:integer_to_binary(Size), - Segment = <<X1/binary, ":size(", Size1/binary, ")">>, - inspect_bit_array(<<>>, append_segment(Acc, Segment)). - -append_segment(<<"<<">>, Segment) -> - <<"<<", Segment/binary>>; -append_segment(Acc, Segment) -> - <<Acc/binary, ", ", Segment/binary>>. - - -inspect_maybe_utf8_string(Binary, Acc) -> - case Binary of - <<>> -> {ok, <<$", Acc/binary, $">>}; - <<First/utf8, Rest/binary>> -> - Escaped = case First of - $" -> <<$\\, $">>; - $\\ -> <<$\\, $\\>>; - $\r -> <<$\\, $r>>; - $\n -> <<$\\, $n>>; - $\t -> <<$\\, $t>>; - Other -> <<Other/utf8>> - end, - inspect_maybe_utf8_string(Rest, <<Acc/binary, Escaped/binary>>); - _ -> {error, not_a_utf8_string} - end. - -float_to_string(Float) when is_float(Float) -> - erlang:iolist_to_binary(io_lib_format:fwrite_g(Float)). - -utf_codepoint_list_to_string(List) -> - case unicode:characters_to_binary(List) of - {error, _} -> erlang:error({gleam_error, {string_invalid_utf8, List}}); - Binary -> Binary - end. - -crop_string(String, Prefix) -> - case string:find(String, Prefix) of - nomatch -> String; - New -> New - end. - -contains_string(String, Substring) -> - is_bitstring(string:find(String, Substring)). - -base16_decode(String) -> - try - {ok, binary:decode_hex(String)} - catch - _:_ -> {error, nil} - end. diff --git a/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.mjs b/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.mjs deleted file mode 100644 index a908b23..0000000 --- a/aoc2023/build/packages/gleam_stdlib/src/gleam_stdlib.mjs +++ /dev/null @@ -1,875 +0,0 @@ -import { - BitArray, - Error, - List, - Ok, - Result, - UtfCodepoint, - stringBits, - toBitArray, - NonEmpty, - CustomType, -} from "./gleam.mjs"; -import { - CompileError as RegexCompileError, - Match as RegexMatch, -} from "./gleam/regex.mjs"; -import { DecodeError } from "./gleam/dynamic.mjs"; -import { Some, None } from "./gleam/option.mjs"; -import Dict from "./dict.mjs"; - -const Nil = undefined; -const NOT_FOUND = {}; - -export function identity(x) { - return x; -} - -export function parse_int(value) { - if (/^[-+]?(\d+)$/.test(value)) { - return new Ok(parseInt(value)); - } else { - return new Error(Nil); - } -} - -export function parse_float(value) { - if (/^[-+]?(\d+)\.(\d+)$/.test(value)) { - return new Ok(parseFloat(value)); - } else { - return new Error(Nil); - } -} - -export function to_string(term) { - return term.toString(); -} - -export function float_to_string(float) { - const string = float.toString(); - if (string.indexOf(".") >= 0) { - return string; - } else { - return string + ".0"; - } -} - -export function int_to_base_string(int, base) { - return int.toString(base).toUpperCase(); -} - -const int_base_patterns = { - 2: /[^0-1]/, - 3: /[^0-2]/, - 4: /[^0-3]/, - 5: /[^0-4]/, - 6: /[^0-5]/, - 7: /[^0-6]/, - 8: /[^0-7]/, - 9: /[^0-8]/, - 10: /[^0-9]/, - 11: /[^0-9a]/, - 12: /[^0-9a-b]/, - 13: /[^0-9a-c]/, - 14: /[^0-9a-d]/, - 15: /[^0-9a-e]/, - 16: /[^0-9a-f]/, - 17: /[^0-9a-g]/, - 18: /[^0-9a-h]/, - 19: /[^0-9a-i]/, - 20: /[^0-9a-j]/, - 21: /[^0-9a-k]/, - 22: /[^0-9a-l]/, - 23: /[^0-9a-m]/, - 24: /[^0-9a-n]/, - 25: /[^0-9a-o]/, - 26: /[^0-9a-p]/, - 27: /[^0-9a-q]/, - 28: /[^0-9a-r]/, - 29: /[^0-9a-s]/, - 30: /[^0-9a-t]/, - 31: /[^0-9a-u]/, - 32: /[^0-9a-v]/, - 33: /[^0-9a-w]/, - 34: /[^0-9a-x]/, - 35: /[^0-9a-y]/, - 36: /[^0-9a-z]/, -}; - -export function int_from_base_string(string, base) { - if (int_base_patterns[base].test(string.replace(/^-/, "").toLowerCase())) { - return new Error(Nil); - } - - const result = parseInt(string, base); - - if (isNaN(result)) { - return new Error(Nil); - } - - return new Ok(result); -} - -export function string_replace(string, target, substitute) { - if (typeof string.replaceAll !== "undefined") { - return string.replaceAll(target, substitute); - } - // Fallback for older Node.js versions: - // 1. <https://stackoverflow.com/a/1144788> - // 2. <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping> - // TODO: This fallback could be remove once Node.js 14 is EOL - // aka <https://nodejs.org/en/about/releases/> on or after 2024-04-30 - return string.replace( - // $& means the whole matched string - new RegExp(target.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), - substitute - ); -} - -export function string_reverse(string) { - return [...string].reverse().join(""); -} - -export function string_length(string) { - if (string === "") { - return 0; - } - const iterator = graphemes_iterator(string); - if (iterator) { - let i = 0; - for (const _ of iterator) { - i++; - } - return i; - } else { - return string.match(/./gsu).length; - } -} - -export function graphemes(string) { - return List.fromArray( - Array.from(graphemes_iterator(string)).map((item) => item.segment) - ); -} - -function graphemes_iterator(string) { - if (Intl && Intl.Segmenter) { - return new Intl.Segmenter().segment(string)[Symbol.iterator](); - } -} - -export function pop_grapheme(string) { - let first; - const iterator = graphemes_iterator(string); - if (iterator) { - first = iterator.next().value?.segment; - } else { - first = string.match(/./su)?.[0]; - } - if (first) { - return new Ok([first, string.slice(first.length)]); - } else { - return new Error(Nil); - } -} - -export function lowercase(string) { - return string.toLowerCase(); -} - -export function uppercase(string) { - return string.toUpperCase(); -} - -export function less_than(a, b) { - return a < b; -} - -export function add(a, b) { - return a + b; -} - -export function equal(a, b) { - return a === b; -} - -export function split(xs, pattern) { - return List.fromArray(xs.split(pattern)); -} - -export function join(xs, separator) { - const iterator = xs[Symbol.iterator](); - let result = iterator.next().value || ""; - let current = iterator.next(); - while (!current.done) { - result = result + separator + current.value; - current = iterator.next(); - } - return result; -} - -export function concat(xs) { - let result = ""; - for (const x of xs) { - result = result + x; - } - return result; -} - -export function length(data) { - return data.length; -} - -export function crop_string(string, substring) { - return string.substring(string.indexOf(substring)); -} - -export function contains_string(haystack, needle) { - return haystack.indexOf(needle) >= 0; -} - -export function starts_with(haystack, needle) { - return haystack.startsWith(needle); -} - -export function ends_with(haystack, needle) { - return haystack.endsWith(needle); -} - -export function split_once(haystack, needle) { - const index = haystack.indexOf(needle); - if (index >= 0) { - const before = haystack.slice(0, index); - const after = haystack.slice(index + needle.length); - return new Ok([before, after]); - } else { - return new Error(Nil); - } -} - -export function trim(string) { - return string.trim(); -} - -export function trim_left(string) { - return string.trimLeft(); -} - -export function trim_right(string) { - return string.trimRight(); -} - -export function bit_array_from_string(string) { - return toBitArray([stringBits(string)]); -} - -export function bit_array_concat(bit_arrays) { - return toBitArray(bit_arrays.toArray().map((b) => b.buffer)); -} - -export function console_log(term) { - console.log(term); -} - -export function console_error(term) { - console.error(term); -} - -export function crash(message) { - throw new globalThis.Error(message); -} - -export function bit_array_to_string(bit_array) { - try { - const decoder = new TextDecoder("utf-8", { fatal: true }); - return new Ok(decoder.decode(bit_array.buffer)); - } catch (_error) { - return new Error(Nil); - } -} - -export function print(string) { - if (typeof process === "object") { - process.stdout.write(string); // We can write without a trailing newline - } else if (typeof Deno === "object") { - Deno.stdout.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline - } else { - console.log(string); // We're in a browser. Newlines are mandated - } -} - -export function print_error(string) { - if (typeof process === "object" && process.stderr?.write) { - process.stderr.write(string); // We can write without a trailing newline - } else if (typeof Deno === "object") { - Deno.stderr.writeSync(new TextEncoder().encode(string)); // We can write without a trailing newline - } else { - console.error(string); // We're in a browser. Newlines are mandated - } -} - -export function print_debug(string) { - if (typeof process === "object" && process.stderr?.write) { - process.stderr.write(string + "\n"); // If we're in Node.js, use `stderr` - } else if (typeof Deno === "object") { - Deno.stderr.writeSync(new TextEncoder().encode(string + "\n")); // If we're in Deno, use `stderr` - } else { - console.log(string); // Otherwise, use `console.log` (so that it doesn't look like an error) - } -} - -export function ceiling(float) { - return Math.ceil(float); -} - -export function floor(float) { - return Math.floor(float); -} - -export function round(float) { - return Math.round(float); -} - -export function truncate(float) { - return Math.trunc(float); -} - -export function power(base, exponent) { - // It is checked in Gleam that: - // - The base is non-negative and that the exponent is not fractional. - // - The base is non-zero and the exponent is non-negative (otherwise - // the result will essentially be division by zero). - // It can thus be assumed that valid input is passed to the Math.pow - // function and a NaN or Infinity value will not be produced. - return Math.pow(base, exponent); -} - -export function random_uniform() { - const random_uniform_result = Math.random(); - // With round-to-nearest-even behavior, the ranges claimed for the functions below - // (excluding the one for Math.random() itself) aren't exact. - // If extremely large bounds are chosen (2^53 or higher), - // it's possible in extremely rare cases to calculate the usually-excluded upper bound. - // Note that as numbers in JavaScript are IEEE 754 floating point numbers - // See: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random> - // Because of this, we just loop 'until' we get a valid result where 0.0 <= x < 1.0: - if (random_uniform_result === 1.0) { - return random_uniform(); - } - return random_uniform_result; -} - -export function bit_array_slice(bits, position, length) { - const start = Math.min(position, position + length); - const end = Math.max(position, position + length); - if (start < 0 || end > bits.length) return new Error(Nil); - const buffer = new Uint8Array(bits.buffer.buffer, start, Math.abs(length)); - return new Ok(new BitArray(buffer)); -} - -export function codepoint(int) { - return new UtfCodepoint(int); -} - -export function string_to_codepoint_integer_list(string) { - return List.fromArray(Array.from(string).map((item) => item.codePointAt(0))); -} - -export function utf_codepoint_list_to_string(utf_codepoint_integer_list) { - return utf_codepoint_integer_list - .toArray() - .map((x) => String.fromCodePoint(x.value)) - .join(""); -} - -export function utf_codepoint_to_int(utf_codepoint) { - return utf_codepoint.value; -} - -export function regex_check(regex, string) { - regex.lastIndex = 0; - return regex.test(string); -} - -export function compile_regex(pattern, options) { - try { - let flags = "gu"; - if (options.case_insensitive) flags += "i"; - if (options.multi_line) flags += "m"; - return new Ok(new RegExp(pattern, flags)); - } catch (error) { - const number = (error.columnNumber || 0) | 0; - return new Error(new RegexCompileError(error.message, number)); - } -} - -export function regex_scan(regex, string) { - const matches = Array.from(string.matchAll(regex)).map((match) => { - const content = match[0]; - const submatches = []; - for (let n = match.length - 1; n > 0; n--) { - if (match[n]) { - submatches[n - 1] = new Some(match[n]); - continue; - } - if (submatches.length > 0) { - submatches[n - 1] = new None(); - } - } - return new RegexMatch(content, List.fromArray(submatches)); - }); - return List.fromArray(matches); -} - -export function new_map() { - return Dict.new(); -} - -export function map_size(map) { - return map.size; -} - -export function map_to_list(map) { - return List.fromArray(map.entries()); -} - -export function map_remove(key, map) { - return map.delete(key); -} - -export function map_get(map, key) { - const value = map.get(key, NOT_FOUND); - if (value === NOT_FOUND) { - return new Error(Nil); - } - return new Ok(value); -} - -export function map_insert(key, value, map) { - return map.set(key, value); -} - -function unsafe_percent_decode(string) { - return decodeURIComponent((string || "").replace("+", " ")); -} - -export function percent_decode(string) { - try { - return new Ok(unsafe_percent_decode(string)); - } catch (_error) { - return new Error(Nil); - } -} - -export function percent_encode(string) { - return encodeURIComponent(string); -} - -export function parse_query(query) { - try { - const pairs = []; - for (const section of query.split("&")) { - const [key, value] = section.split("="); - if (!key) continue; - pairs.push([unsafe_percent_decode(key), unsafe_percent_decode(value)]); - } - return new Ok(List.fromArray(pairs)); - } catch (_error) { - return new Error(Nil); - } -} - -// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#Solution_2_%E2%80%93_rewrite_the_DOMs_atob()_and_btoa()_using_JavaScript's_TypedArrays_and_UTF-8 -export function encode64(bit_array) { - const aBytes = bit_array.buffer; - let nMod3 = 2; - let sB64Enc = ""; - - for (let nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) { - nMod3 = nIdx % 3; - if (nIdx > 0 && ((nIdx * 4) / 3) % 76 === 0) { - sB64Enc += "\r\n"; - } - nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24); - if (nMod3 === 2 || aBytes.length - nIdx === 1) { - sB64Enc += String.fromCharCode( - uint6ToB64((nUint24 >>> 18) & 63), - uint6ToB64((nUint24 >>> 12) & 63), - uint6ToB64((nUint24 >>> 6) & 63), - uint6ToB64(nUint24 & 63) - ); - nUint24 = 0; - } - } - - return ( - sB64Enc.substr(0, sB64Enc.length - 2 + nMod3) + - (nMod3 === 2 ? "" : nMod3 === 1 ? "=" : "==") - ); -} - -// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#Solution_2_%E2%80%93_rewrite_the_DOMs_atob()_and_btoa()_using_JavaScript's_TypedArrays_and_UTF-8 -function uint6ToB64(nUint6) { - return nUint6 < 26 - ? nUint6 + 65 - : nUint6 < 52 - ? nUint6 + 71 - : nUint6 < 62 - ? nUint6 - 4 - : nUint6 === 62 - ? 43 - : nUint6 === 63 - ? 47 - : 65; -} - -// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#Solution_2_%E2%80%93_rewrite_the_DOMs_atob()_and_btoa()_using_JavaScript's_TypedArrays_and_UTF-8 -function b64ToUint6(nChr) { - return nChr > 64 && nChr < 91 - ? nChr - 65 - : nChr > 96 && nChr < 123 - ? nChr - 71 - : nChr > 47 && nChr < 58 - ? nChr + 4 - : nChr === 43 - ? 62 - : nChr === 47 - ? 63 - : 0; -} - -// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#Solution_2_%E2%80%93_rewrite_the_DOMs_atob()_and_btoa()_using_JavaScript's_TypedArrays_and_UTF-8 -export function decode64(sBase64) { - if (sBase64.match(/[^A-Za-z0-9\+\/=]/g)) return new Error(Nil); - const sB64Enc = sBase64.replace(/=/g, ""); - const nInLen = sB64Enc.length; - const nOutLen = (nInLen * 3 + 1) >> 2; - const taBytes = new Uint8Array(nOutLen); - - for ( - let nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; - nInIdx < nInLen; - nInIdx++ - ) { - nMod4 = nInIdx & 3; - nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (6 * (3 - nMod4)); - if (nMod4 === 3 || nInLen - nInIdx === 1) { - for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { - taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255; - } - nUint24 = 0; - } - } - - return new Ok(new BitArray(taBytes)); -} - -export function classify_dynamic(data) { - if (typeof data === "string") { - return "String"; - } else if (data instanceof Result) { - return "Result"; - } else if (data instanceof List) { - return "List"; - } else if (data instanceof BitArray) { - return "BitArray"; - } else if (data instanceof Dict) { - return "Map"; - } else if (Number.isInteger(data)) { - return "Int"; - } else if (Array.isArray(data)) { - return `Tuple of ${data.length} elements`; - } else if (typeof data === "number") { - return "Float"; - } else if (data === null) { - return "Null"; - } else if (data === undefined) { - return "Nil"; - } else { - const type = typeof data; - return type.charAt(0).toUpperCase() + type.slice(1); - } -} - -function decoder_error(expected, got) { - return decoder_error_no_classify(expected, classify_dynamic(got)); -} - -function decoder_error_no_classify(expected, got) { - return new Error( - List.fromArray([new DecodeError(expected, got, List.fromArray([]))]) - ); -} - -export function decode_string(data) { - return typeof data === "string" - ? new Ok(data) - : decoder_error("String", data); -} - -export function decode_int(data) { - return Number.isInteger(data) ? new Ok(data) : decoder_error("Int", data); -} - -export function decode_float(data) { - return typeof data === "number" ? new Ok(data) : decoder_error("Float", data); -} - -export function decode_bool(data) { - return typeof data === "boolean" ? new Ok(data) : decoder_error("Bool", data); -} - -export function decode_bit_array(data) { - if (data instanceof BitArray) { - return new Ok(data); - } - if (data instanceof Uint8Array) { - return new Ok(new BitArray(data)); - } - return decoder_error("BitArray", data); -} - -export function decode_tuple(data) { - return Array.isArray(data) ? new Ok(data) : decoder_error("Tuple", data); -} - -export function decode_tuple2(data) { - return decode_tupleN(data, 2); -} - -export function decode_tuple3(data) { - return decode_tupleN(data, 3); -} - -export function decode_tuple4(data) { - return decode_tupleN(data, 4); -} - -export function decode_tuple5(data) { - return decode_tupleN(data, 5); -} - -export function decode_tuple6(data) { - return decode_tupleN(data, 6); -} - -function decode_tupleN(data, n) { - if (Array.isArray(data) && data.length == n) { - return new Ok(data); - } - - const list = decode_exact_length_list(data, n); - if (list) return new Ok(list); - - return decoder_error(`Tuple of ${n} elements`, data); -} - -function decode_exact_length_list(data, n) { - if (!(data instanceof List)) return; - - const elements = []; - let current = data; - - for (let i = 0; i < n; i++) { - if (!(current instanceof NonEmpty)) break; - elements.push(current.head); - current = current.tail; - } - - if (elements.length === n && !(current instanceof NonEmpty)) return elements; -} - -export function tuple_get(data, index) { - return index >= 0 && data.length > index - ? new Ok(data[index]) - : new Error(Nil); -} - -export function decode_list(data) { - if (Array.isArray(data)) { - return new Ok(List.fromArray(data)); - } - return data instanceof List ? new Ok(data) : decoder_error("List", data); -} - -export function decode_result(data) { - return data instanceof Result ? new Ok(data) : decoder_error("Result", data); -} - -export function decode_map(data) { - if (data instanceof Dict) { - return new Ok(Dict.fromMap(data)); - } - if (data == null) { - return decoder_error("Map", data); - } - if (typeof data !== "object") { - return decoder_error("Map", data); - } - const proto = Object.getPrototypeOf(data); - if (proto === Object.prototype || proto === null) { - return new Ok(Dict.fromObject(data)); - } - return decoder_error("Map", data); -} - -export function decode_option(data, decoder) { - if (data === null || data === undefined || data instanceof None) - return new Ok(new None()); - if (data instanceof Some) data = data[0]; - const result = decoder(data); - if (result.isOk()) { - return new Ok(new Some(result[0])); - } else { - return result; - } -} - -export function decode_field(value, name) { - const not_a_map_error = () => decoder_error("Map", value); - - if ( - value instanceof Dict || - value instanceof WeakMap || - value instanceof Map - ) { - const entry = map_get(value, name); - return new Ok(entry.isOk() ? new Some(entry[0]) : new None()); - } else if (Object.getPrototypeOf(value) == Object.prototype) { - return try_get_field(value, name, () => new Ok(new None())); - } else { - return try_get_field(value, name, not_a_map_error); - } -} - -function try_get_field(value, field, or_else) { - try { - return field in value ? new Ok(new Some(value[field])) : or_else(); - } catch { - return or_else(); - } -} - -export function byte_size(string) { - return new TextEncoder().encode(string).length; -} - -// In Javascript bitwise operations convert numbers to a sequence of 32 bits -// while Erlang uses arbitrary precision. -// To get around this problem and get consistent results use BigInt and then -// downcast the value back to a Number value. - -export function bitwise_and(x, y) { - return Number(BigInt(x) & BigInt(y)); -} - -export function bitwise_not(x) { - return Number(~BigInt(x)); -} - -export function bitwise_or(x, y) { - return Number(BigInt(x) | BigInt(y)); -} - -export function bitwise_exclusive_or(x, y) { - return Number(BigInt(x) ^ BigInt(y)); -} - -export function bitwise_shift_left(x, y) { - return Number(BigInt(x) << BigInt(y)); -} - -export function bitwise_shift_right(x, y) { - return Number(BigInt(x) >> BigInt(y)); -} - -export function inspect(v) { - const t = typeof v; - if (v === true) return "True"; - if (v === false) return "False"; - if (v === null) return "//js(null)"; - if (v === undefined) return "Nil"; - if (t === "string") return JSON.stringify(v); - if (t === "bigint" || t === "number") return v.toString(); - if (Array.isArray(v)) return `#(${v.map(inspect).join(", ")})`; - if (v instanceof List) return inspectList(v); - if (v instanceof UtfCodepoint) return inspectUtfCodepoint(v); - if (v instanceof BitArray) return inspectBitArray(v); - if (v instanceof CustomType) return inspectCustomType(v); - if (v instanceof Dict) return inspectDict(v); - if (v instanceof Set) return `//js(Set(${[...v].map(inspect).join(", ")}))`; - if (v instanceof RegExp) return `//js(${v})`; - if (v instanceof Date) return `//js(Date("${v.toISOString()}"))`; - if (v instanceof Function) { - const args = []; - for (const i of Array(v.length).keys()) - args.push(String.fromCharCode(i + 97)); - return `//fn(${args.join(", ")}) { ... }`; - } - return inspectObject(v); -} - -function inspectDict(map) { - let body = "dict.from_list(["; - let first = true; - map.forEach((value, key) => { - if (!first) body = body + ", "; - body = body + "#(" + inspect(key) + ", " + inspect(value) + ")"; - first = false; - }); - return body + "])"; -} - -function inspectObject(v) { - const name = Object.getPrototypeOf(v)?.constructor?.name || "Object"; - const props = []; - for (const k of Object.keys(v)) { - props.push(`${inspect(k)}: ${inspect(v[k])}`); - } - const body = props.length ? " " + props.join(", ") + " " : ""; - const head = name === "Object" ? "" : name + " "; - return `//js(${head}{${body}})`; -} - -function inspectCustomType(record) { - const props = Object.keys(record) - .map((label) => { - const value = inspect(record[label]); - return isNaN(parseInt(label)) ? `${label}: ${value}` : value; - }) - .join(", "); - return props - ? `${record.constructor.name}(${props})` - : record.constructor.name; -} - -export function inspectList(list) { - return `[${list.toArray().map(inspect).join(", ")}]`; -} - -export function inspectBitArray(bits) { - return `<<${Array.from(bits.buffer).join(", ")}>>`; -} - -export function inspectUtfCodepoint(codepoint) { - return `//utfcodepoint(${String.fromCodePoint(codepoint.value)})`; -} - -export function base16_encode(bit_array) { - let result = ""; - for (const byte of bit_array.buffer) { - result += byte.toString(16).padStart(2, "0").toUpperCase(); - } - return result; -} - -export function base16_decode(string) { - const bytes = new Uint8Array(string.length / 2); - for (let i = 0; i < string.length; i += 2) { - const a = parseInt(string[i], 16); - const b = parseInt(string[i + 1], 16); - if (isNaN(a) || isNaN(b)) return new Error(Nil); - bytes[i / 2] = a * 16 + b; - } - return new Ok(new BitArray(bytes)); -} |