| /** | |
| * Mutable lists for collecting ordered values and draining them from the front. | |
| * A `MutableList<A>` can append values to the end, prepend values to the | |
| * beginning, take one or more values from the front, inspect its contents as an | |
| * array, filter values, remove values, and clear itself. All operations update | |
| * the same list object in place and keep its `length` field current. Taking | |
| * from an empty list returns the `Empty` symbol. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| import * as Arr from "./Array.ts" | |
| /** | |
| * A mutable linked list data structure optimized for high-throughput operations. | |
| * MutableList provides efficient append/prepend operations and is ideal for | |
| * producer-consumer patterns, queues, and streaming scenarios. | |
| * | |
| * **Example** (Creating and consuming a mutable list) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * // Create a mutable list | |
| * const list: MutableList.MutableList<number> = MutableList.make() | |
| * | |
| * // Add elements | |
| * MutableList.append(list, 1) | |
| * MutableList.append(list, 2) | |
| * MutableList.prepend(list, 0) | |
| * | |
| * // Access properties | |
| * console.log(list.length) // 3 | |
| * console.log(list.head?.array) // Contains elements from head bucket | |
| * console.log(list.tail?.array) // Contains elements from tail bucket | |
| * | |
| * // Take elements | |
| * console.log(MutableList.take(list)) // 0 | |
| * console.log(MutableList.take(list)) // 1 | |
| * console.log(MutableList.take(list)) // 2 | |
| * ``` | |
| * | |
| * @category models | |
| * @since 2.0.0 | |
| */ | |
| export interface MutableList<in out A> { | |
| head: MutableList.Bucket<A> | undefined | |
| tail: MutableList.Bucket<A> | undefined | |
| length: number | |
| } | |
| /** | |
| * The MutableList namespace contains type definitions and utilities for working | |
| * with mutable linked lists. | |
| * | |
| * **Example** (Typing queue processors) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * // Type annotation using the namespace | |
| * const processQueue = (queue: MutableList.MutableList<string>) => { | |
| * while (queue.length > 0) { | |
| * const item = MutableList.take(queue) | |
| * if (item !== MutableList.Empty) { | |
| * console.log("Processing:", item) | |
| * } | |
| * } | |
| * } | |
| * | |
| * // Using the namespace for type definitions | |
| * const createProcessor = <T>(): { | |
| * queue: MutableList.MutableList<T> | |
| * add: (item: T) => void | |
| * process: () => Array<T> | |
| * } => { | |
| * const queue = MutableList.make<T>() | |
| * return { | |
| * queue, | |
| * add: (item) => MutableList.append(queue, item), | |
| * process: () => MutableList.takeAll(queue) | |
| * } | |
| * } | |
| * ``` | |
| * | |
| * @since 2.0.0 | |
| */ | |
| export declare namespace MutableList { | |
| /** | |
| * Storage node used by the exposed `head` and `tail` fields of a | |
| * `MutableList`. | |
| * | |
| * **Details** | |
| * | |
| * Most code should treat buckets as an implementation detail and use | |
| * `MutableList` operations such as `append`, `prepend`, and `take` instead | |
| * of constructing or mutating buckets directly. | |
| * | |
| * **Example** (Inspecting buckets) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.append(list, 1) | |
| * MutableList.append(list, 2) | |
| * | |
| * // Access bucket information (for debugging or advanced usage) | |
| * const inspectBucket = ( | |
| * bucket: MutableList.MutableList.Bucket<number> | undefined | |
| * ) => { | |
| * if (bucket) { | |
| * console.log("Bucket array:", bucket.array) | |
| * console.log("Bucket offset:", bucket.offset) | |
| * console.log("Bucket mutable:", bucket.mutable) | |
| * console.log("Has next bucket:", bucket.next !== undefined) | |
| * } | |
| * } | |
| * | |
| * inspectBucket(list.head) | |
| * inspectBucket(list.tail) | |
| * ``` | |
| * | |
| * @category models | |
| * @since 4.0.0 | |
| */ | |
| export interface Bucket<A> { | |
| readonly array: Array<A> | |
| mutable: boolean | |
| offset: number | |
| next: Bucket<A> | undefined | |
| } | |
| } | |
| /** | |
| * Defines the unique symbol used to represent an empty result when taking elements from a MutableList. | |
| * This symbol is returned by `take` when the list is empty, allowing for safe type checking. | |
| * | |
| * **When to use** | |
| * | |
| * Use to detect that `take` returned no element before handling the result as a | |
| * list item. | |
| * | |
| * **Example** (Checking for empty results) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<string>() | |
| * | |
| * // Take from empty list returns Empty symbol | |
| * const result = MutableList.take(list) | |
| * console.log(result === MutableList.Empty) // true | |
| * | |
| * // Safe pattern for checking emptiness | |
| * const processNext = (queue: MutableList.MutableList<string>) => { | |
| * const item = MutableList.take(queue) | |
| * if (item === MutableList.Empty) { | |
| * console.log("Queue is empty") | |
| * return null | |
| * } | |
| * return item.toUpperCase() | |
| * } | |
| * | |
| * // Compare with other empty results | |
| * MutableList.append(list, "hello") | |
| * const next = MutableList.take(list) | |
| * console.log(next !== MutableList.Empty) // true, got "hello" | |
| * | |
| * const empty = MutableList.take(list) | |
| * console.log(empty === MutableList.Empty) // true, list is empty | |
| * ``` | |
| * | |
| * @category symbols | |
| * @since 4.0.0 | |
| */ | |
| export const Empty: unique symbol = Symbol.for("effect/MutableList/Empty") | |
| /** | |
| * The type of the Empty symbol, used for type checking when taking elements from a MutableList. | |
| * This provides compile-time safety when checking for empty results. | |
| * | |
| * **Example** (Handling empty results type-safely) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * | |
| * // Type-safe handling of empty results | |
| * const takeAndDouble = ( | |
| * queue: MutableList.MutableList<number> | |
| * ): number | null => { | |
| * const item: number | MutableList.Empty = MutableList.take(queue) | |
| * | |
| * if (item === MutableList.Empty) { | |
| * return null | |
| * } | |
| * | |
| * // TypeScript knows item is number here | |
| * return item * 2 | |
| * } | |
| * | |
| * console.log(takeAndDouble(list)) // null (empty list) | |
| * | |
| * MutableList.append(list, 5) | |
| * console.log(takeAndDouble(list)) // 10 | |
| * | |
| * // Type guard function | |
| * const isEmpty = ( | |
| * result: number | MutableList.Empty | |
| * ): result is MutableList.Empty => { | |
| * return result === MutableList.Empty | |
| * } | |
| * | |
| * const value = MutableList.take(list) | |
| * if (isEmpty(value)) { | |
| * console.log("List is empty") | |
| * } else { | |
| * console.log("Got value:", value) | |
| * } | |
| * ``` | |
| * | |
| * @category symbols | |
| * @since 4.0.0 | |
| */ | |
| export type Empty = typeof Empty | |
| /** | |
| * Creates an empty MutableList. | |
| * | |
| * **Example** (Creating an empty mutable list) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<string>() | |
| * | |
| * // Add elements | |
| * MutableList.append(list, "first") | |
| * MutableList.append(list, "second") | |
| * MutableList.prepend(list, "beginning") | |
| * | |
| * console.log(list.length) // 3 | |
| * | |
| * // Take elements in FIFO order (from head) | |
| * console.log(MutableList.take(list)) // "beginning" | |
| * console.log(MutableList.take(list)) // "first" | |
| * console.log(MutableList.take(list)) // "second" | |
| * ``` | |
| * | |
| * @category constructors | |
| * @since 2.0.0 | |
| */ | |
| export const make = <A>(): MutableList<A> => ({ | |
| head: undefined, | |
| tail: undefined, | |
| length: 0 | |
| }) | |
| const emptyBucket = <A = never>(): MutableList.Bucket<A> => ({ | |
| array: [], | |
| mutable: true, | |
| offset: 0, | |
| next: undefined | |
| }) | |
| /** | |
| * Appends an element to the end of the MutableList. | |
| * This operation is optimized for high-frequency usage. | |
| * | |
| * **Example** (Appending elements) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * | |
| * // Append elements one by one | |
| * MutableList.append(list, 1) | |
| * MutableList.append(list, 2) | |
| * MutableList.append(list, 3) | |
| * | |
| * console.log(list.length) // 3 | |
| * | |
| * // Elements are taken from head (FIFO) | |
| * console.log(MutableList.take(list)) // 1 | |
| * console.log(MutableList.take(list)) // 2 | |
| * console.log(MutableList.take(list)) // 3 | |
| * | |
| * // High-throughput usage | |
| * for (let i = 0; i < 10000; i++) { | |
| * MutableList.append(list, i) | |
| * } | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 2.0.0 | |
| */ | |
| export const append = <A>(self: MutableList<A>, message: A): void => { | |
| if (!self.tail) { | |
| self.head = self.tail = emptyBucket() | |
| } else if (!self.tail.mutable) { | |
| self.tail.next = emptyBucket() | |
| self.tail = self.tail.next | |
| } | |
| self.tail!.array.push(message) | |
| self.length++ | |
| } | |
| /** | |
| * Prepends an element to the beginning of the MutableList. | |
| * This operation is optimized for high-frequency usage. | |
| * | |
| * **Example** (Prepending elements) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<string>() | |
| * | |
| * // Prepend elements (they'll be at the front) | |
| * MutableList.prepend(list, "third") | |
| * MutableList.prepend(list, "second") | |
| * MutableList.prepend(list, "first") | |
| * | |
| * console.log(list.length) // 3 | |
| * | |
| * // Elements taken from head (most recently prepended first) | |
| * console.log(MutableList.take(list)) // "first" | |
| * console.log(MutableList.take(list)) // "second" | |
| * console.log(MutableList.take(list)) // "third" | |
| * | |
| * // Use case: priority items or stack-like behavior | |
| * MutableList.append(list, "normal") | |
| * MutableList.prepend(list, "priority") // This will be taken first | |
| * console.log(MutableList.take(list)) // "priority" | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 2.0.0 | |
| */ | |
| export const prepend = <A>(self: MutableList<A>, message: A): void => { | |
| self.head = { | |
| array: [message], | |
| mutable: true, | |
| offset: 0, | |
| next: self.head | |
| } | |
| self.length++ | |
| } | |
| /** | |
| * Prepends all elements from an iterable to the beginning of the MutableList. | |
| * The elements are added in order, so the first element in the iterable becomes | |
| * the new head of the list. | |
| * | |
| * **Example** (Prepending multiple elements) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.append(list, 4) | |
| * MutableList.append(list, 5) | |
| * | |
| * // Prepend multiple elements | |
| * MutableList.prependAll(list, [1, 2, 3]) | |
| * | |
| * console.log(list.length) // 5 | |
| * | |
| * // Elements are taken in order: [1, 2, 3, 4, 5] | |
| * console.log(MutableList.takeAll(list)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Works with any iterable | |
| * const newList = MutableList.make<string>() | |
| * MutableList.prependAll(newList, "hello") // Prepends each character | |
| * console.log(MutableList.takeAll(newList)) // ["h", "e", "l", "l", "o"] | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 4.0.0 | |
| */ | |
| export const prependAll = <A>(self: MutableList<A>, messages: Iterable<A>): void => | |
| prependAllUnsafe(self, Arr.fromIterable(messages), !Array.isArray(messages)) | |
| /** | |
| * Prepends all elements from a ReadonlyArray to the beginning of the MutableList. | |
| * This is an optimized version that can reuse the array when mutable=true. | |
| * | |
| * **When to use** | |
| * | |
| * Use when prepending a trusted array directly is worth the optimized path and | |
| * you control whether the input may be reused. | |
| * | |
| * **Gotchas** | |
| * | |
| * When mutable=true, the input array may be modified internally. Only use | |
| * mutable=true when you control the array lifecycle. | |
| * | |
| * **Example** (Prepending arrays with optional mutation) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.append(list, 4) | |
| * | |
| * // Safe usage (default mutable=false) | |
| * const items = [1, 2, 3] | |
| * MutableList.prependAllUnsafe(list, items) | |
| * console.log(items) // [1, 2, 3] - unchanged | |
| * | |
| * // Unsafe but efficient usage (mutable=true) | |
| * const mutableItems = [10, 20, 30] | |
| * MutableList.prependAllUnsafe(list, mutableItems, true) | |
| * // mutableItems may be modified internally for efficiency | |
| * | |
| * console.log(MutableList.takeAll(list)) // [10, 20, 30, 1, 2, 3, 4] | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 4.0.0 | |
| */ | |
| export const prependAllUnsafe = <A>(self: MutableList<A>, messages: ReadonlyArray<A>, mutable = false): void => { | |
| self.head = { | |
| array: messages as Array<A>, | |
| mutable, | |
| offset: 0, | |
| next: self.head | |
| } | |
| self.length += self.head.array.length | |
| } | |
| /** | |
| * Appends all elements from an iterable to the end of the MutableList. | |
| * Returns the number of elements added. | |
| * | |
| * **Example** (Appending multiple elements) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.append(list, 1) | |
| * MutableList.append(list, 2) | |
| * | |
| * // Append multiple elements | |
| * const added = MutableList.appendAll(list, [3, 4, 5]) | |
| * console.log(added) // 3 | |
| * console.log(list.length) // 5 | |
| * | |
| * // Elements maintain order: [1, 2, 3, 4, 5] | |
| * console.log(MutableList.takeAll(list)) // [1, 2, 3, 4, 5] | |
| * | |
| * // Works with any iterable | |
| * const newList = MutableList.make<string>() | |
| * MutableList.appendAll(newList, new Set(["a", "b", "c"])) | |
| * console.log(MutableList.takeAll(newList)) // ["a", "b", "c"] | |
| * | |
| * // Useful for bulk loading | |
| * const bulkList = MutableList.make<number>() | |
| * const count = MutableList.appendAll( | |
| * bulkList, | |
| * Array.from({ length: 1000 }, (_, i) => i) | |
| * ) | |
| * console.log(count) // 1000 | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 4.0.0 | |
| */ | |
| export const appendAll = <A>(self: MutableList<A>, messages: Iterable<A>): number => | |
| appendAllUnsafe(self, Arr.fromIterable(messages), !Array.isArray(messages)) | |
| /** | |
| * Appends all elements from a ReadonlyArray to the end of the MutableList. | |
| * This is an optimized version that can reuse the array when mutable=true. | |
| * Returns the number of elements added. | |
| * | |
| * **When to use** | |
| * | |
| * Use when appending a trusted array directly is worth the optimized path and | |
| * you control whether the input may be reused. | |
| * | |
| * **Gotchas** | |
| * | |
| * When mutable=true, the input array may be modified internally. Only use | |
| * mutable=true when you control the array lifecycle. | |
| * | |
| * **Example** (Appending arrays with optional mutation) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.append(list, 1) | |
| * | |
| * // Safe usage (default mutable=false) | |
| * const items = [2, 3, 4] | |
| * const added = MutableList.appendAllUnsafe(list, items) | |
| * console.log(added) // 3 | |
| * console.log(items) // [2, 3, 4] - unchanged | |
| * | |
| * // Unsafe but efficient usage (mutable=true) | |
| * const mutableItems = [5, 6, 7] | |
| * MutableList.appendAllUnsafe(list, mutableItems, true) | |
| * // mutableItems may be modified internally for efficiency | |
| * | |
| * console.log(MutableList.takeAll(list)) // [1, 2, 3, 4, 5, 6, 7] | |
| * | |
| * // High-performance bulk operations | |
| * const bigArray = new Array(10000).fill(0).map((_, i) => i) | |
| * MutableList.appendAllUnsafe(list, bigArray, true) // Very efficient | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 4.0.0 | |
| */ | |
| export const appendAllUnsafe = <A>(self: MutableList<A>, messages: ReadonlyArray<A>, mutable = false): number => { | |
| if (messages.length === 0) { | |
| return 0 | |
| } | |
| const chunk: MutableList.Bucket<A> = { | |
| array: messages as Array<A>, | |
| mutable, | |
| offset: 0, | |
| next: undefined | |
| } | |
| if (self.head) { | |
| self.tail = self.tail!.next = chunk | |
| } else { | |
| self.head = self.tail = chunk | |
| } | |
| self.length += messages.length | |
| return messages.length | |
| } | |
| /** | |
| * Removes all elements from the MutableList, resetting it to an empty state. | |
| * This operation is highly optimized and releases all internal memory. | |
| * | |
| * **Example** (Clearing a mutable list) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.appendAll(list, [1, 2, 3, 4, 5]) | |
| * | |
| * console.log(list.length) // 5 | |
| * | |
| * // Clear all elements | |
| * MutableList.clear(list) | |
| * | |
| * console.log(list.length) // 0 | |
| * console.log(MutableList.take(list)) // Empty | |
| * | |
| * // Can still use the list after clearing | |
| * MutableList.append(list, 42) | |
| * console.log(list.length) // 1 | |
| * | |
| * // Useful for resetting queues or buffers | |
| * function resetBuffer<T>(buffer: MutableList.MutableList<T>) { | |
| * MutableList.clear(buffer) | |
| * console.log("Buffer cleared and ready for reuse") | |
| * } | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 4.0.0 | |
| */ | |
| export const clear = <A>(self: MutableList<A>): void => { | |
| self.head = self.tail = undefined | |
| self.length = 0 | |
| } | |
| /** | |
| * Takes up to N elements from the beginning of the MutableList and returns them as an array. | |
| * The taken elements are removed from the list. This operation is optimized for performance | |
| * and includes zero-copy optimizations when possible. | |
| * | |
| * **Example** (Taking batches) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.appendAll(list, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) | |
| * | |
| * console.log(list.length) // 10 | |
| * | |
| * // Take first 3 elements | |
| * const first3 = MutableList.takeN(list, 3) | |
| * console.log(first3) // [1, 2, 3] | |
| * console.log(list.length) // 7 | |
| * | |
| * // Take more than available | |
| * const remaining = MutableList.takeN(list, 20) | |
| * console.log(remaining) // [4, 5, 6, 7, 8, 9, 10] | |
| * console.log(list.length) // 0 | |
| * | |
| * // Take from empty list | |
| * const empty = MutableList.takeN(list, 5) | |
| * console.log(empty) // [] | |
| * | |
| * // Batch processing pattern | |
| * const queue = MutableList.make<string>() | |
| * MutableList.appendAll(queue, ["task1", "task2", "task3", "task4", "task5"]) | |
| * | |
| * while (queue.length > 0) { | |
| * const batch = MutableList.takeN(queue, 2) // Process 2 at a time | |
| * console.log("Processing batch:", batch) | |
| * } | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 4.0.0 | |
| */ | |
| export const takeN = <A>(self: MutableList<A>, n: number): Array<A> => { | |
| if (n <= 0 || !self.head) return [] | |
| n = Math.min(n, self.length) | |
| if (n === self.length && self.head?.offset === 0 && !self.head.next) { | |
| const array = self.head.array | |
| clear(self) | |
| return array | |
| } | |
| const array = new Array<A>(n) | |
| let index = 0 | |
| let chunk: MutableList.Bucket<A> | undefined = self.head | |
| while (chunk) { | |
| while (chunk.offset < chunk.array.length) { | |
| array[index++] = chunk.array[chunk.offset] | |
| if (chunk.mutable) chunk.array[chunk.offset] = undefined as any | |
| chunk.offset++ | |
| if (index === n) { | |
| self.head = chunk | |
| self.length -= n | |
| if (self.length === 0) clear(self) | |
| return array | |
| } | |
| } | |
| chunk = chunk.next | |
| } | |
| clear(self) | |
| return array | |
| } | |
| /** | |
| * Removes up to `n` elements from the beginning of the `MutableList` without | |
| * returning them. | |
| * | |
| * **When to use** | |
| * | |
| * Use to discard a bounded number of values from the head of a `MutableList` | |
| * when the removed values are not needed. | |
| * | |
| * **Details** | |
| * | |
| * If `n` is less than or equal to zero, or the list is empty, the list is left | |
| * unchanged. If `n` is greater than or equal to the current length, the list is | |
| * cleared. | |
| * | |
| * @see {@link takeN} for removing up to `n` values and returning them as an array | |
| * @see {@link clear} for removing every value from the list | |
| * | |
| * @category elements | |
| * @since 4.0.0 | |
| */ | |
| export const takeNVoid = <A>(self: MutableList<A>, n: number): void => { | |
| if (n <= 0 || !self.head) return | |
| n = Math.min(n, self.length) | |
| if (n === self.length && self.head?.offset === 0 && !self.head.next) { | |
| clear(self) | |
| return | |
| } | |
| let count = 0 | |
| let chunk: MutableList.Bucket<A> | undefined = self.head | |
| while (chunk) { | |
| const size = chunk.array.length - chunk.offset | |
| if (count + size > n) { | |
| chunk.offset += n - count | |
| self.head = chunk | |
| self.length -= n | |
| return | |
| } | |
| count += size | |
| chunk = chunk.next | |
| } | |
| clear(self) | |
| return | |
| } | |
| /** | |
| * Takes all elements from the MutableList and returns them as an array. | |
| * The list becomes empty after this operation. This is equivalent to takeN(list, list.length). | |
| * | |
| * **Example** (Draining all elements) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<string>() | |
| * MutableList.appendAll(list, ["apple", "banana", "cherry"]) | |
| * | |
| * console.log(list.length) // 3 | |
| * | |
| * // Take all elements | |
| * const allItems = MutableList.takeAll(list) | |
| * console.log(allItems) // ["apple", "banana", "cherry"] | |
| * console.log(list.length) // 0 | |
| * | |
| * // Useful for converting to array and clearing | |
| * const queue = MutableList.make<number>() | |
| * MutableList.appendAll(queue, [1, 2, 3, 4, 5]) | |
| * | |
| * const snapshot = MutableList.takeAll(queue) | |
| * console.log("Queue contents:", snapshot) | |
| * console.log("Queue is now empty:", queue.length === 0) | |
| * | |
| * // Drain pattern for processing | |
| * function drainAndProcess<T>( | |
| * list: MutableList.MutableList<T>, | |
| * processor: (items: Array<T>) => void | |
| * ) { | |
| * if (list.length > 0) { | |
| * const items = MutableList.takeAll(list) | |
| * processor(items) | |
| * } | |
| * } | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 4.0.0 | |
| */ | |
| export const takeAll = <A>(self: MutableList<A>): Array<A> => takeN(self, self.length) | |
| /** | |
| * Takes a single element from the beginning of the MutableList. | |
| * Returns the element if available, or the Empty symbol if the list is empty. | |
| * The taken element is removed from the list. | |
| * | |
| * **Example** (Taking one element) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<string>() | |
| * MutableList.appendAll(list, ["first", "second", "third"]) | |
| * | |
| * // Take elements one by one | |
| * console.log(MutableList.take(list)) // "first" | |
| * console.log(list.length) // 2 | |
| * | |
| * console.log(MutableList.take(list)) // "second" | |
| * console.log(MutableList.take(list)) // "third" | |
| * console.log(list.length) // 0 | |
| * | |
| * // Take from empty list | |
| * console.log(MutableList.take(list)) // Empty symbol | |
| * | |
| * // Check for empty using the Empty symbol | |
| * const result = MutableList.take(list) | |
| * if (result === MutableList.Empty) { | |
| * console.log("List is empty") | |
| * } else { | |
| * console.log("Got element:", result) | |
| * } | |
| * | |
| * // Consumer pattern | |
| * function processNext<T>( | |
| * queue: MutableList.MutableList<T>, | |
| * processor: (item: T) => void | |
| * ): boolean { | |
| * const item = MutableList.take(queue) | |
| * if (item !== MutableList.Empty) { | |
| * processor(item) | |
| * return true | |
| * } | |
| * return false | |
| * } | |
| * ``` | |
| * | |
| * @category elements | |
| * @since 4.0.0 | |
| */ | |
| export const take = <A>(self: MutableList<A>): Empty | A => { | |
| if (!self.head) return Empty | |
| const message = self.head.array[self.head.offset] | |
| if (self.head.mutable) self.head.array[self.head.offset] = undefined as any | |
| self.head.offset++ | |
| self.length-- | |
| if (self.head.offset === self.head.array.length) { | |
| if (self.head.next) { | |
| self.head = self.head.next | |
| } else { | |
| clear(self) | |
| } | |
| } | |
| return message | |
| } | |
| /** | |
| * Copies up to `n` elements from the beginning of the `MutableList` into a new | |
| * array without modifying the list. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need to inspect or snapshot a bounded prefix of the list without | |
| * consuming it. | |
| * | |
| * @see {@link takeN} for removing up to `n` values and returning them as an array | |
| * | |
| * @category elements | |
| * @since 4.0.0 | |
| */ | |
| export const toArrayN = <A>(self: MutableList<A>, n: number): Array<A> => { | |
| const length = Math.min(n, self.length) | |
| const out = new Array<A>(length) | |
| let index = 0 | |
| let bucket = self.head | |
| while (bucket) { | |
| for (let i = bucket.offset; i < bucket.array.length; i++) { | |
| out[index++] = bucket.array[i] | |
| if (index === length) return out | |
| } | |
| bucket = bucket.next | |
| } | |
| return out | |
| } | |
| /** | |
| * Copies all current elements of the `MutableList` into a new array without | |
| * modifying the list. | |
| * | |
| * **When to use** | |
| * | |
| * Use when you need a snapshot of all current elements while keeping the list | |
| * unchanged. | |
| * | |
| * @see {@link takeAll} for converting all elements to an array and clearing the list | |
| * | |
| * @category elements | |
| * @since 4.0.0 | |
| */ | |
| export const toArray = <A>(self: MutableList<A>): Array<A> => toArrayN(self, self.length) | |
| /** | |
| * Filters the MutableList in place, keeping only elements that satisfy the predicate. | |
| * This operation modifies the list and rebuilds its internal structure for efficiency. | |
| * | |
| * **Example** (Filtering in place) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<number>() | |
| * MutableList.appendAll(list, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) | |
| * | |
| * console.log(list.length) // 10 | |
| * | |
| * // Keep only even numbers | |
| * MutableList.filter(list, (n) => n % 2 === 0) | |
| * | |
| * console.log(MutableList.takeAll(list)) // [2, 4, 6, 8, 10] | |
| * | |
| * // Filter with index | |
| * const indexed = MutableList.make<string>() | |
| * MutableList.appendAll(indexed, ["a", "b", "c", "d", "e"]) | |
| * | |
| * // Keep elements at even indices | |
| * MutableList.filter(indexed, (value, index) => index % 2 === 0) | |
| * console.log(MutableList.takeAll(indexed)) // ["a", "c", "e"] | |
| * | |
| * // Real-world example: filtering a log queue | |
| * const logs = MutableList.make<{ level: string; message: string }>() | |
| * MutableList.appendAll(logs, [ | |
| * { level: "INFO", message: "App started" }, | |
| * { level: "ERROR", message: "Connection failed" }, | |
| * { level: "DEBUG", message: "Cache hit" }, | |
| * { level: "ERROR", message: "Timeout" } | |
| * ]) | |
| * | |
| * // Keep only errors | |
| * MutableList.filter(logs, (log) => log.level === "ERROR") | |
| * console.log(MutableList.takeAll(logs).map((log) => log.message)) // ["Connection failed", "Timeout"] | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 4.0.0 | |
| */ | |
| export const filter = <A>(self: MutableList<A>, f: (value: A, i: number) => boolean): void => { | |
| const array: Array<A> = [] | |
| let chunk: MutableList.Bucket<A> | undefined = self.head | |
| while (chunk) { | |
| for (let i = chunk.offset; i < chunk.array.length; i++) { | |
| if (f(chunk.array[i], i)) { | |
| array.push(chunk.array[i]) | |
| } | |
| } | |
| chunk = chunk.next | |
| } | |
| self.head = self.tail = { | |
| array, | |
| mutable: true, | |
| offset: 0, | |
| next: undefined | |
| } | |
| self.length = array.length | |
| } | |
| /** | |
| * Removes all occurrences of a value from the `MutableList` using JavaScript | |
| * strict equality semantics. | |
| * | |
| * **When to use** | |
| * | |
| * Use when in-place removal should use JavaScript identity/strict equality | |
| * rather than Effect structural equality. | |
| * | |
| * **Details** | |
| * | |
| * The list is modified in place. | |
| * | |
| * **Gotchas** | |
| * | |
| * Values are compared with `!==`, so this does not use Effect structural | |
| * equality. | |
| * | |
| * **Example** (Removing matching values) | |
| * | |
| * ```ts | |
| * import { MutableList } from "effect" | |
| * | |
| * const list = MutableList.make<string>() | |
| * MutableList.appendAll(list, ["apple", "banana", "apple", "cherry", "apple"]) | |
| * | |
| * console.log(list.length) // 5 | |
| * | |
| * // Remove all occurrences of "apple" | |
| * MutableList.remove(list, "apple") | |
| * | |
| * console.log(MutableList.takeAll(list)) // ["banana", "cherry"] | |
| * | |
| * // Remove non-existent value (no effect) | |
| * const colors = MutableList.make<string>() | |
| * MutableList.appendAll(colors, ["red", "blue"]) | |
| * MutableList.remove(colors, "green") | |
| * console.log(MutableList.takeAll(colors)) // ["red", "blue"] | |
| * | |
| * // Real-world example: removing completed tasks | |
| * const tasks = MutableList.make<{ id: number; status: string }>() | |
| * MutableList.appendAll(tasks, [ | |
| * { id: 1, status: "pending" }, | |
| * { id: 2, status: "completed" }, | |
| * { id: 3, status: "pending" }, | |
| * { id: 4, status: "completed" } | |
| * ]) | |
| * | |
| * // Remove completed tasks by filtering status | |
| * MutableList.filter(tasks, (task) => task.status !== "completed") | |
| * console.log(MutableList.takeAll(tasks).map((task) => task.id)) // [1, 3] | |
| * ``` | |
| * | |
| * @category mutations | |
| * @since 4.0.0 | |
| */ | |
| export const remove = <A>(self: MutableList<A>, value: A): void => filter(self, (v) => v !== value) | |
Xet Storage Details
- Size:
- 27.2 kB
- Xet hash:
- f99ab063a34c702856d1da0cd36e9e402b30f0ef37e25a26a53964ffca1ff21e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.