UNPKG

3.45 kBJavaScriptView Raw
1import { id } from './function.js'
2import * as error from './error.js'
3
4export class ListNode {
5 constructor () {
6 /**
7 * @type {this|null}
8 */
9 this.next = null
10 /**
11 * @type {this|null}
12 */
13 this.prev = null
14 }
15}
16
17/**
18 * @template {ListNode} N
19 */
20export class List {
21 constructor () {
22 /**
23 * @type {N | null}
24 */
25 this.start = null
26 /**
27 * @type {N | null}
28 */
29 this.end = null
30 this.len = 0
31 }
32}
33
34/**
35 * @note The queue implementation is experimental and unfinished.
36 * Don't use this in production yet.
37 *
38 * @template {ListNode} N
39 *
40 * @return {List<N>}
41 */
42export const create = () => new List()
43
44/**
45 * @template {ListNode} N
46 *
47 * @param {List<N>} queue
48 */
49export const isEmpty = queue => queue.start === null
50
51/**
52 * Remove a single node from the queue. Only works with Queues that operate on Doubly-linked lists of nodes.
53 *
54 * @template {ListNode} N
55 *
56 * @param {List<N>} queue
57 * @param {N} node
58 */
59export const remove = (queue, node) => {
60 const prev = node.prev
61 const next = node.next
62 if (prev) {
63 prev.next = next
64 } else {
65 queue.start = next
66 }
67 if (next) {
68 next.prev = prev
69 } else {
70 queue.end = prev
71 }
72 queue.len--
73 return node
74}
75
76/**
77 * @deprecated @todo remove in next major release
78 */
79export const removeNode = remove
80
81/**
82 * @template {ListNode} N
83 *
84 * @param {List<N>} queue
85 * @param {N| null} left
86 * @param {N| null} right
87 * @param {N} node
88 */
89export const insertBetween = (queue, left, right, node) => {
90 /* istanbul ignore if */
91 if (left != null && left.next !== right) {
92 throw error.unexpectedCase()
93 }
94 if (left) {
95 left.next = node
96 } else {
97 queue.start = node
98 }
99 if (right) {
100 right.prev = node
101 } else {
102 queue.end = node
103 }
104 node.prev = left
105 node.next = right
106 queue.len++
107}
108
109/**
110 * Remove a single node from the queue. Only works with Queues that operate on Doubly-linked lists of nodes.
111 *
112 * @template {ListNode} N
113 *
114 * @param {List<N>} queue
115 * @param {N} node
116 * @param {N} newNode
117 */
118export const replace = (queue, node, newNode) => {
119 insertBetween(queue, node, node.next, newNode)
120 remove(queue, node)
121}
122
123/**
124 * @template {ListNode} N
125 *
126 * @param {List<N>} queue
127 * @param {N} n
128 */
129export const pushEnd = (queue, n) =>
130 insertBetween(queue, queue.end, null, n)
131
132/**
133 * @template {ListNode} N
134 *
135 * @param {List<N>} queue
136 * @param {N} n
137 */
138export const pushFront = (queue, n) =>
139 insertBetween(queue, null, queue.start, n)
140
141/**
142 * @template {ListNode} N
143 *
144 * @param {List<N>} list
145 * @return {N| null}
146 */
147export const popFront = list =>
148 list.start ? removeNode(list, list.start) : null
149
150/**
151 * @template {ListNode} N
152 *
153 * @param {List<N>} list
154 * @return {N| null}
155 */
156export const popEnd = list =>
157 list.end ? removeNode(list, list.end) : null
158
159/**
160 * @template {ListNode} N
161 * @template M
162 *
163 * @param {List<N>} list
164 * @param {function(N):M} f
165 * @return {Array<M>}
166 */
167export const map = (list, f) => {
168 /**
169 * @type {Array<M>}
170 */
171 const arr = []
172 let n = list.start
173 while (n) {
174 arr.push(f(n))
175 n = n.next
176 }
177 return arr
178}
179
180/**
181 * @template {ListNode} N
182 *
183 * @param {List<N>} list
184 */
185export const toArray = list => map(list, id)
186
187/**
188 * @template {ListNode} N
189 * @template M
190 *
191 * @param {List<N>} list
192 * @param {function(N):M} f
193 */
194export const forEach = (list, f) => {
195 let n = list.start
196 while (n) {
197 f(n)
198 n = n.next
199 }
200}