a collection of lightweight TypeScript packages for AT Protocol, the protocol powering Bluesky
at trunk 129 lines 2.4 kB view raw
1interface Node<T> { 2 value: T; 3 next: Node<T> | undefined; 4} 5 6/** a stack data structure (lifo) */ 7class Stack<T> implements Iterable<T> { 8 #head: Node<T> | undefined; 9 #tail: Node<T> | undefined; 10 #size: number = 0; 11 12 /** size of the stack */ 13 get size(): number { 14 return this.#size; 15 } 16 17 /** 18 * clear the stack 19 */ 20 clear(): void { 21 this.#head = undefined; 22 this.#tail = undefined; 23 this.#size = 0; 24 } 25 26 /** 27 * adds a value to the top of the stack 28 * @param value value to add 29 * @returns the stack instance 30 */ 31 push(value: T): this { 32 const node: Node<T> = { value, next: this.#head }; 33 34 if (this.#head === undefined) { 35 this.#tail = node; 36 } 37 38 this.#head = node; 39 this.#size++; 40 return this; 41 } 42 43 /** 44 * removes the top value from the stack 45 * @returns last added value, or undefined if empty 46 */ 47 pop(): T | undefined { 48 const head = this.#head; 49 if (head === undefined) { 50 return; 51 } 52 53 this.#head = head.next; 54 this.#size--; 55 56 if (this.#head === undefined) { 57 this.#tail = undefined; 58 } 59 60 return head.value; 61 } 62 63 /** 64 * get the top value without removing from stack 65 * @returns last added value, or undefined if empty 66 */ 67 peek(): T | undefined { 68 return this.#head?.value; 69 } 70 71 /** 72 * get the bottom value without removing from stack 73 * @returns first added value, or undefined if empty 74 */ 75 peekBottom(): T | undefined { 76 return this.#tail?.value; 77 } 78 79 /** 80 * returns an iterator that drains all the values from stack 81 */ 82 drain(): IterableIterator<T, undefined, undefined> { 83 // oxlint-disable-next-line no-this-alias 84 const self = this; 85 86 return { 87 next() { 88 const head = self.#head; 89 if (head === undefined) { 90 return { done: true, value: undefined }; 91 } 92 93 self.#head = head.next; 94 self.#size--; 95 96 if (self.#head === undefined) { 97 self.#tail = undefined; 98 } 99 100 return { done: false, value: head.value }; 101 }, 102 [Symbol.iterator]() { 103 return this; 104 }, 105 }; 106 } 107 108 /** 109 * iterates over the stack without draining 110 */ 111 [Symbol.iterator](): Iterator<T, undefined, undefined> { 112 let current = this.#head; 113 114 return { 115 next() { 116 if (current === undefined) { 117 return { done: true, value: undefined }; 118 } 119 120 const value = current.value; 121 current = current.next; 122 123 return { done: false, value: value }; 124 }, 125 }; 126 } 127} 128 129export default Stack;