@grain/stdlib 0.5.12 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +200 -0
- package/LICENSE +1 -1
- package/README.md +25 -2
- package/array.gr +1512 -199
- package/array.md +2032 -94
- package/bigint.gr +239 -140
- package/bigint.md +450 -106
- package/buffer.gr +595 -102
- package/buffer.md +903 -145
- package/bytes.gr +401 -110
- package/bytes.md +551 -63
- package/char.gr +228 -49
- package/char.md +373 -7
- package/exception.gr +26 -12
- package/exception.md +29 -5
- package/float32.gr +130 -109
- package/float32.md +185 -57
- package/float64.gr +112 -99
- package/float64.md +185 -57
- package/hash.gr +47 -37
- package/hash.md +21 -3
- package/int16.gr +430 -0
- package/int16.md +618 -0
- package/int32.gr +200 -269
- package/int32.md +254 -289
- package/int64.gr +142 -225
- package/int64.md +254 -289
- package/int8.gr +511 -0
- package/int8.md +786 -0
- package/json.gr +2084 -0
- package/json.md +608 -0
- package/list.gr +120 -68
- package/list.md +125 -80
- package/map.gr +560 -57
- package/map.md +672 -56
- package/marshal.gr +239 -227
- package/marshal.md +36 -4
- package/number.gr +626 -676
- package/number.md +738 -153
- package/option.gr +33 -35
- package/option.md +58 -42
- package/package.json +2 -2
- package/path.gr +148 -187
- package/path.md +47 -96
- package/pervasives.gr +75 -416
- package/pervasives.md +85 -180
- package/priorityqueue.gr +433 -74
- package/priorityqueue.md +422 -54
- package/queue.gr +362 -80
- package/queue.md +433 -38
- package/random.gr +67 -75
- package/random.md +68 -40
- package/range.gr +135 -63
- package/range.md +198 -43
- package/rational.gr +284 -0
- package/rational.md +545 -0
- package/regex.gr +933 -1066
- package/regex.md +59 -60
- package/result.gr +23 -25
- package/result.md +54 -39
- package/runtime/atof/common.gr +78 -82
- package/runtime/atof/common.md +22 -10
- package/runtime/atof/decimal.gr +102 -127
- package/runtime/atof/decimal.md +28 -7
- package/runtime/atof/lemire.gr +56 -71
- package/runtime/atof/lemire.md +9 -1
- package/runtime/atof/parse.gr +83 -110
- package/runtime/atof/parse.md +12 -2
- package/runtime/atof/slow.gr +28 -35
- package/runtime/atof/slow.md +9 -1
- package/runtime/atof/table.gr +19 -18
- package/runtime/atof/table.md +10 -2
- package/runtime/atoi/parse.gr +153 -136
- package/runtime/atoi/parse.md +50 -1
- package/runtime/bigint.gr +410 -517
- package/runtime/bigint.md +71 -57
- package/runtime/compare.gr +176 -85
- package/runtime/compare.md +31 -1
- package/runtime/dataStructures.gr +144 -32
- package/runtime/dataStructures.md +267 -31
- package/runtime/debugPrint.gr +34 -15
- package/runtime/debugPrint.md +37 -5
- package/runtime/equal.gr +53 -52
- package/runtime/equal.md +30 -1
- package/runtime/exception.gr +38 -47
- package/runtime/exception.md +10 -8
- package/runtime/gc.gr +23 -152
- package/runtime/gc.md +13 -17
- package/runtime/malloc.gr +31 -31
- package/runtime/malloc.md +11 -3
- package/runtime/numberUtils.gr +191 -172
- package/runtime/numberUtils.md +17 -9
- package/runtime/numbers.gr +1695 -1021
- package/runtime/numbers.md +1098 -134
- package/runtime/string.gr +540 -242
- package/runtime/string.md +76 -6
- package/runtime/unsafe/constants.gr +30 -13
- package/runtime/unsafe/constants.md +80 -0
- package/runtime/unsafe/conv.gr +55 -28
- package/runtime/unsafe/conv.md +41 -9
- package/runtime/unsafe/memory.gr +10 -30
- package/runtime/unsafe/memory.md +15 -19
- package/runtime/unsafe/tags.gr +37 -21
- package/runtime/unsafe/tags.md +88 -8
- package/runtime/unsafe/wasmf32.gr +30 -36
- package/runtime/unsafe/wasmf32.md +64 -56
- package/runtime/unsafe/wasmf64.gr +30 -36
- package/runtime/unsafe/wasmf64.md +64 -56
- package/runtime/unsafe/wasmi32.gr +49 -66
- package/runtime/unsafe/wasmi32.md +102 -94
- package/runtime/unsafe/wasmi64.gr +52 -79
- package/runtime/unsafe/wasmi64.md +108 -100
- package/runtime/utils/printing.gr +13 -15
- package/runtime/utils/printing.md +11 -3
- package/runtime/wasi.gr +294 -295
- package/runtime/wasi.md +62 -42
- package/set.gr +574 -64
- package/set.md +634 -54
- package/stack.gr +181 -64
- package/stack.md +271 -42
- package/string.gr +453 -533
- package/string.md +241 -151
- package/uint16.gr +369 -0
- package/uint16.md +585 -0
- package/uint32.gr +470 -0
- package/uint32.md +737 -0
- package/uint64.gr +471 -0
- package/uint64.md +737 -0
- package/uint8.gr +369 -0
- package/uint8.md +585 -0
- package/uri.gr +1093 -0
- package/uri.md +477 -0
- package/{sys → wasi}/file.gr +914 -500
- package/{sys → wasi}/file.md +454 -50
- package/wasi/process.gr +292 -0
- package/{sys → wasi}/process.md +164 -6
- package/wasi/random.gr +77 -0
- package/wasi/random.md +80 -0
- package/{sys → wasi}/time.gr +15 -22
- package/{sys → wasi}/time.md +5 -5
- package/immutablearray.gr +0 -929
- package/immutablearray.md +0 -1038
- package/immutablemap.gr +0 -493
- package/immutablemap.md +0 -479
- package/immutablepriorityqueue.gr +0 -360
- package/immutablepriorityqueue.md +0 -291
- package/immutableset.gr +0 -498
- package/immutableset.md +0 -449
- package/runtime/debug.gr +0 -2
- package/runtime/debug.md +0 -6
- package/runtime/unsafe/errors.gr +0 -36
- package/runtime/unsafe/errors.md +0 -204
- package/sys/process.gr +0 -254
- package/sys/random.gr +0 -79
- package/sys/random.md +0 -66
package/priorityqueue.gr
CHANGED
|
@@ -1,33 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* A priority queue is a data structure that maintains elements in a priority order. Elements with higher priority are served before elements with lower priority when extracting from the priority queue.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* An immutable priority queue implementation is available in the `Immutable` submodule.
|
|
5
|
+
*
|
|
6
|
+
* @example from "priorityqueue" include Priorityqueue
|
|
5
7
|
*
|
|
6
8
|
* @since v0.5.3
|
|
7
9
|
*/
|
|
10
|
+
module PriorityQueue
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @section Types: Type declarations included in the PriorityQueue module.
|
|
16
|
-
*/
|
|
12
|
+
from "array" include Array
|
|
13
|
+
from "list" include List
|
|
14
|
+
from "number" include Number
|
|
15
|
+
from "option" include Option
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* Mutable data structure which maintains a priority order for its elements.
|
|
20
19
|
*/
|
|
21
|
-
record PriorityQueue<a> {
|
|
20
|
+
abstract record PriorityQueue<a> {
|
|
22
21
|
mut size: Number,
|
|
23
22
|
mut array: Array<Option<a>>,
|
|
24
|
-
comp: (a, a)
|
|
23
|
+
comp: (a, a) => Number,
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
/**
|
|
28
|
-
* @section Values: Functions for working with PriorityQueues.
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
26
|
let swap = (i1, i2, array) => {
|
|
32
27
|
let t = array[i2]
|
|
33
28
|
array[i2] = array[i1]
|
|
@@ -37,8 +32,8 @@ let swap = (i1, i2, array) => {
|
|
|
37
32
|
let get = (array, i) =>
|
|
38
33
|
Option.expect(
|
|
39
34
|
"Impossible: " ++
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
toString(i) ++
|
|
36
|
+
" in PriorityQueue's inner storage array is None",
|
|
42
37
|
array[i]
|
|
43
38
|
)
|
|
44
39
|
|
|
@@ -78,71 +73,58 @@ let rec siftUp = (i, pq) => {
|
|
|
78
73
|
* comparator function takes two elements and must return 0 if both share
|
|
79
74
|
* priority, a positive number if the first has greater priority, and a
|
|
80
75
|
* negative number if the first has less priority.
|
|
81
|
-
*
|
|
76
|
+
*
|
|
82
77
|
* Generally, you won't need to care about the storage size of your priority
|
|
83
|
-
* queue and can use
|
|
84
|
-
*
|
|
78
|
+
* queue and can use the default size.
|
|
79
|
+
*
|
|
80
|
+
* @param compare: The comparator function used to indicate priority order
|
|
85
81
|
* @param size: The initial storage size of the priority queue
|
|
86
|
-
* @param comp: The comparator function used to indicate priority order
|
|
87
82
|
* @returns An empty priority queue
|
|
88
83
|
*
|
|
89
84
|
* @since v0.5.3
|
|
90
|
-
|
|
91
|
-
export let makeSized = (size, comp) => {
|
|
92
|
-
{ size: 0, array: Array.make(size, None), comp }
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Creates a new priority queue with a comparator function, which is used to
|
|
97
|
-
* determine priority of elements. The comparator function takes two elements
|
|
98
|
-
* and must return 0 if both share priority, a positive number if the first
|
|
99
|
-
* has greater priority, and a negative number if the first has less priority.
|
|
100
|
-
*
|
|
101
|
-
* @param comp: The comparator function used to indicate priority order
|
|
102
|
-
* @returns An empty priority queue
|
|
103
|
-
*
|
|
104
|
-
* @example PriorityQueue.make(compare) // creates a min priority queue of numbers using the compare pervasive
|
|
105
|
-
* @example PriorityQueue.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
|
|
85
|
+
* @history v0.6.0: Merged with `makeSized`; modified signature to accept size
|
|
106
86
|
*
|
|
107
|
-
* @
|
|
87
|
+
* @example PriorityQueue.make() // creates a min priority queue of numbers using the compare pervasive
|
|
88
|
+
* @example PriorityQueue.make(compare=compare, size=32) // creates a min priority queue of numbers using the compare pervasive and an initial size of 32
|
|
89
|
+
* @example PriorityQueue.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
|
|
108
90
|
*/
|
|
109
|
-
|
|
110
|
-
|
|
91
|
+
provide let make = (compare=compare, size=16) => {
|
|
92
|
+
{ size: 0, array: Array.make(size, None), comp: compare }
|
|
111
93
|
}
|
|
112
94
|
|
|
113
95
|
/**
|
|
114
96
|
* Gets the number of elements in a priority queue.
|
|
115
|
-
*
|
|
97
|
+
*
|
|
116
98
|
* @param pq: The priority queue to inspect
|
|
117
99
|
* @returns The number of elements in the priority queue
|
|
118
100
|
*
|
|
119
101
|
* @since v0.5.3
|
|
120
102
|
*/
|
|
121
|
-
|
|
103
|
+
provide let size = pq => {
|
|
122
104
|
pq.size
|
|
123
105
|
}
|
|
124
106
|
|
|
125
107
|
/**
|
|
126
108
|
* Determines if the priority queue contains no elements.
|
|
127
|
-
*
|
|
109
|
+
*
|
|
128
110
|
* @param pq: The priority queue to check
|
|
129
111
|
* @returns `true` if the priority queue is empty and `false` otherwise
|
|
130
112
|
*
|
|
131
113
|
* @since v0.5.3
|
|
132
114
|
*/
|
|
133
|
-
|
|
115
|
+
provide let isEmpty = pq => {
|
|
134
116
|
pq.size == 0
|
|
135
117
|
}
|
|
136
118
|
|
|
137
119
|
/**
|
|
138
120
|
* Adds a new element to the priority queue.
|
|
139
|
-
*
|
|
121
|
+
*
|
|
140
122
|
* @param val: The value to add into the priority queue
|
|
141
123
|
* @param pq: The priority queue to update
|
|
142
124
|
*
|
|
143
125
|
* @since v0.5.3
|
|
144
126
|
*/
|
|
145
|
-
|
|
127
|
+
provide let push = (val, pq) => {
|
|
146
128
|
let arrLen = Array.length(pq.array)
|
|
147
129
|
// double size of internal array if out of space
|
|
148
130
|
if (pq.size == arrLen) {
|
|
@@ -162,13 +144,13 @@ export let push = (val, pq) => {
|
|
|
162
144
|
/**
|
|
163
145
|
* Retrieves the highest priority element in the priority queue. It is not
|
|
164
146
|
* removed from the queue.
|
|
165
|
-
*
|
|
147
|
+
*
|
|
166
148
|
* @param pq: The priority queue to inspect
|
|
167
149
|
* @returns `Some(value)` containing the highest priority element or `None` if the priority queue is empty
|
|
168
150
|
*
|
|
169
151
|
* @since v0.5.3
|
|
170
152
|
*/
|
|
171
|
-
|
|
153
|
+
provide let peek = pq => {
|
|
172
154
|
if (pq.size == 0) {
|
|
173
155
|
None
|
|
174
156
|
} else {
|
|
@@ -178,38 +160,35 @@ export let peek = pq => {
|
|
|
178
160
|
|
|
179
161
|
/**
|
|
180
162
|
* Removes and retrieves the highest priority element in the priority queue.
|
|
181
|
-
*
|
|
163
|
+
*
|
|
182
164
|
* @param pq: The priority queue to inspect
|
|
183
165
|
* @returns `Some(value)` containing the highest priority element or `None` if the priority queue is empty
|
|
184
166
|
*
|
|
185
167
|
* @since v0.5.3
|
|
186
168
|
*/
|
|
187
|
-
|
|
188
|
-
if (pq.size == 0)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
siftDown(0, pq)
|
|
199
|
-
root
|
|
200
|
-
}
|
|
169
|
+
provide let pop = pq => {
|
|
170
|
+
if (pq.size == 0) return None
|
|
171
|
+
let root = pq.array[0]
|
|
172
|
+
|
|
173
|
+
pq.array[0] = pq.array[pq.size - 1]
|
|
174
|
+
pq.array[pq.size - 1] = None
|
|
175
|
+
pq.size -= 1
|
|
176
|
+
// reorder heap to ensure that binary heap property of parent nodes having
|
|
177
|
+
// larger values than their children is upheld
|
|
178
|
+
siftDown(0, pq)
|
|
179
|
+
return root
|
|
201
180
|
}
|
|
202
181
|
|
|
203
182
|
/**
|
|
204
183
|
* Clears the priority queue and produces a list of all of the elements in the priority
|
|
205
184
|
* queue in priority order.
|
|
206
|
-
*
|
|
185
|
+
*
|
|
207
186
|
* @param pq: The priority queue to drain
|
|
208
187
|
* @returns A list of all elements in the priority in priority order
|
|
209
188
|
*
|
|
210
189
|
* @since v0.5.3
|
|
211
190
|
*/
|
|
212
|
-
|
|
191
|
+
provide let drain = pq => {
|
|
213
192
|
let rec drainRec = acc => {
|
|
214
193
|
match (pop(pq)) {
|
|
215
194
|
Some(val) => drainRec([val, ...acc]),
|
|
@@ -225,17 +204,18 @@ export let drain = pq => {
|
|
|
225
204
|
* elements. The comparator function takes two elements and must return 0 if
|
|
226
205
|
* both share priority, a positive number if the first has greater priority,
|
|
227
206
|
* and a negative number if the first has less priority.
|
|
228
|
-
*
|
|
207
|
+
*
|
|
229
208
|
* @param array: An array of values used to initialize the priority queue
|
|
230
|
-
* @param
|
|
209
|
+
* @param compare: A comparator function used to assign priority to elements
|
|
231
210
|
* @returns A priority queue containing the elements from the array
|
|
232
211
|
*
|
|
233
212
|
* @since v0.5.4
|
|
213
|
+
* @history v0.6.0: Made `compare` a default argument
|
|
234
214
|
*/
|
|
235
|
-
|
|
215
|
+
provide let fromArray = (array, compare=compare) => {
|
|
236
216
|
let size = Array.length(array)
|
|
237
217
|
let array = Array.map(x => Some(x), array)
|
|
238
|
-
let heap = { size, array, comp }
|
|
218
|
+
let heap = { size, array, comp: compare }
|
|
239
219
|
for (let mut i = size - 1; i >= 0; i -= 1) {
|
|
240
220
|
siftDown(i, heap)
|
|
241
221
|
}
|
|
@@ -248,14 +228,393 @@ export let fromArray = (array, comp) => {
|
|
|
248
228
|
* elements. The comparator function takes two elements and must return 0 if
|
|
249
229
|
* both share priority, a positive number if the first has greater priority,
|
|
250
230
|
* and a negative number if the first has less priority.
|
|
251
|
-
*
|
|
231
|
+
*
|
|
252
232
|
* @param list: A list of values used to initialize the priority queue
|
|
253
|
-
* @param
|
|
233
|
+
* @param compare: A comparator function used to assign priority to elements
|
|
254
234
|
* @returns A priority queue containing the elements from the list
|
|
255
235
|
*
|
|
256
236
|
* @since v0.5.3
|
|
237
|
+
* @history v0.6.0: Made `compare` a default argument
|
|
257
238
|
*/
|
|
258
|
-
|
|
239
|
+
provide let fromList = (list, compare=compare) => {
|
|
259
240
|
let array = Array.fromList(list)
|
|
260
|
-
fromArray(array,
|
|
241
|
+
fromArray(array, compare=compare)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* An immutable priority queue implementation.
|
|
246
|
+
*
|
|
247
|
+
* @since v0.6.0
|
|
248
|
+
* @history v0.5.4: Originally in `"immutablepriorityqueue"` module
|
|
249
|
+
*/
|
|
250
|
+
provide module Immutable {
|
|
251
|
+
// implementation based on immutable skew binomial queue with global root optimization
|
|
252
|
+
// as described in the paper "Optimal Purely Functional Priority Queues" by Chris Okasaki.
|
|
253
|
+
|
|
254
|
+
// rank is a stand-in for height of this skew binomial tree
|
|
255
|
+
record rec Node<a> {
|
|
256
|
+
val: a,
|
|
257
|
+
rank: Number,
|
|
258
|
+
children: List<Node<a>>,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// an optimization over binomial queue that allows keeping track of the root value
|
|
262
|
+
|
|
263
|
+
// a skew binomial queue is defined as a forest of heap-ordered skew binomial trees
|
|
264
|
+
record PQRoot<a> {
|
|
265
|
+
rootVal: a,
|
|
266
|
+
pq: List<Node<a>>,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Immutable data structure which maintains a priority order for its elements.
|
|
271
|
+
*/
|
|
272
|
+
abstract record PriorityQueue<a> {
|
|
273
|
+
comp: (a, a) => Number,
|
|
274
|
+
size: Number,
|
|
275
|
+
root: Option<PQRoot<a>>,
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* An empty priority queue with the default `compare` comparator.
|
|
280
|
+
*
|
|
281
|
+
* @since v0.6.0
|
|
282
|
+
* @history v0.5.4: Originally in `"immutablepriorityqueue"` module
|
|
283
|
+
*/
|
|
284
|
+
provide let empty = {
|
|
285
|
+
let empty = { comp: compare, size: 0, root: None }
|
|
286
|
+
empty
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Creates a new priority queue with a comparator function, which is used to
|
|
291
|
+
* determine priority of elements. The comparator function takes two elements
|
|
292
|
+
* and must return 0 if both share priority, a positive number if the first
|
|
293
|
+
* has greater priority, and a negative number if the first has less priority.
|
|
294
|
+
*
|
|
295
|
+
* @param compare: The comparator function used to indicate priority order
|
|
296
|
+
* @returns An empty priority queue
|
|
297
|
+
*
|
|
298
|
+
* @example PriorityQueue.Immutable.make(compare) // creates a min priority queue of numbers using the compare pervasive
|
|
299
|
+
* @example PriorityQueue.Immutable.make((a, b) => String.length(b) - String.length(a)) // creates a priority queue by string length (longest to shortest)
|
|
300
|
+
*
|
|
301
|
+
* @since v0.6.0
|
|
302
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module with `compare` being a required argument
|
|
303
|
+
*/
|
|
304
|
+
provide let make = (compare=compare) => {
|
|
305
|
+
{ comp: compare, size: 0, root: None }
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Gets the number of elements in a priority queue.
|
|
310
|
+
*
|
|
311
|
+
* @param pq: The priority queue to inspect
|
|
312
|
+
* @returns The number of elements in the priority queue
|
|
313
|
+
*
|
|
314
|
+
* @since v0.6.0
|
|
315
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module
|
|
316
|
+
*/
|
|
317
|
+
provide let size = ({ size, _ } as pq: PriorityQueue<a>) => {
|
|
318
|
+
size
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Determines if the priority queue contains no elements.
|
|
323
|
+
*
|
|
324
|
+
* @param pq: The priority queue to check
|
|
325
|
+
* @returns `true` if the priority queue is empty and `false` otherwise
|
|
326
|
+
*
|
|
327
|
+
* @since v0.6.0
|
|
328
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module
|
|
329
|
+
*/
|
|
330
|
+
provide let isEmpty = ({ size, _ } as pq: PriorityQueue<a>) => {
|
|
331
|
+
size == 0
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let skewLinkNodes = (comp, newNode, node1, node2) => {
|
|
335
|
+
// make the two nodes with larger values children of the node with the smallest value
|
|
336
|
+
if (comp(node1.val, newNode.val) <= 0 && comp(node1.val, node2.val) <= 0) {
|
|
337
|
+
{
|
|
338
|
+
val: node1.val,
|
|
339
|
+
rank: node1.rank + 1,
|
|
340
|
+
children: [newNode, node2, ...node1.children],
|
|
341
|
+
}
|
|
342
|
+
} else if (
|
|
343
|
+
comp(node2.val, newNode.val) <= 0 &&
|
|
344
|
+
comp(node2.val, node1.val) <= 0
|
|
345
|
+
) {
|
|
346
|
+
{
|
|
347
|
+
val: node2.val,
|
|
348
|
+
rank: node2.rank + 1,
|
|
349
|
+
children: [newNode, node1, ...node2.children],
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
{ val: newNode.val, rank: node1.rank + 1, children: [node1, node2] }
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
let skewInsert = (comp, val, pq) => {
|
|
357
|
+
let newNode = { val, rank: 0, children: [] }
|
|
358
|
+
match (pq) {
|
|
359
|
+
// the only time two trees will have the same rank is if they are the
|
|
360
|
+
// smallest-ranked trees in the queue, in which case we should link
|
|
361
|
+
// them with the new node
|
|
362
|
+
[node1, node2, ...rest] when node1.rank == node2.rank =>
|
|
363
|
+
[skewLinkNodes(comp, newNode, node1, node2), ...rest],
|
|
364
|
+
_ => [newNode, ...pq],
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Produces a new priority queue by inserting the given element into the given priority queue.
|
|
370
|
+
*
|
|
371
|
+
* @param val: The value to add into the priority queue
|
|
372
|
+
* @param pq: The priority queue
|
|
373
|
+
* @returns A new priority queue with the given element inserted
|
|
374
|
+
*
|
|
375
|
+
* @since v0.6.0
|
|
376
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module
|
|
377
|
+
*/
|
|
378
|
+
provide let push = (val, pq) => {
|
|
379
|
+
let { comp, size, root } = pq
|
|
380
|
+
match (root) {
|
|
381
|
+
None => { comp, size: 1, root: Some({ rootVal: val, pq: [] }) },
|
|
382
|
+
Some({ rootVal, pq }) => {
|
|
383
|
+
// make the new value the root if it has higher priority than the highest priority value
|
|
384
|
+
let (morePriorityVal, lessPriorityVal) = if (comp(val, rootVal) <= 0)
|
|
385
|
+
(val, rootVal)
|
|
386
|
+
else
|
|
387
|
+
(rootVal, val)
|
|
388
|
+
|
|
389
|
+
let newRoot = Some(
|
|
390
|
+
{
|
|
391
|
+
rootVal: morePriorityVal,
|
|
392
|
+
pq: skewInsert(comp, lessPriorityVal, pq),
|
|
393
|
+
},
|
|
394
|
+
)
|
|
395
|
+
{ comp, size: size + 1, root: newRoot }
|
|
396
|
+
},
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Retrieves the highest priority element in the priority queue. It is not
|
|
402
|
+
* removed from the queue.
|
|
403
|
+
*
|
|
404
|
+
* @param pq: The priority queue to inspect
|
|
405
|
+
* @returns `Some(value)` containing the highest priority element or `None` if the priority queue is empty
|
|
406
|
+
*
|
|
407
|
+
* @since v0.6.0
|
|
408
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module
|
|
409
|
+
*/
|
|
410
|
+
provide let peek = pq => {
|
|
411
|
+
match (pq.root) {
|
|
412
|
+
None => None,
|
|
413
|
+
Some({ rootVal, _ }) => Some(rootVal),
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
let linkNodes = (comp, node1, node2) => {
|
|
418
|
+
// make the node with higher priority the parent of the node with smaller
|
|
419
|
+
// priority to presere heap-ordering
|
|
420
|
+
let (morePriority, lessPriority) = if (comp(node1.val, node2.val) <= 0)
|
|
421
|
+
(node1, node2)
|
|
422
|
+
else
|
|
423
|
+
(node2, node1)
|
|
424
|
+
{
|
|
425
|
+
val: morePriority.val,
|
|
426
|
+
rank: morePriority.rank + 1,
|
|
427
|
+
children: [lessPriority, ...morePriority.children],
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// step through the trees in the priority queue in increasing rank order until we
|
|
432
|
+
// find a missing rank, linking trees of equal rank as we go
|
|
433
|
+
let rec ins = (comp, node, pq) => {
|
|
434
|
+
match (pq) {
|
|
435
|
+
[] => [node],
|
|
436
|
+
[firstNode, ...rest] => {
|
|
437
|
+
if (node.rank < firstNode.rank) {
|
|
438
|
+
[node, firstNode, ...rest]
|
|
439
|
+
} else {
|
|
440
|
+
ins(comp, linkNodes(comp, node, firstNode), rest)
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
let uniquify = (comp, pq) => {
|
|
447
|
+
match (pq) {
|
|
448
|
+
[] => [],
|
|
449
|
+
[node, ...rest] => ins(comp, node, rest),
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// step through the trees of two priority queues in increasing rank order,
|
|
454
|
+
// performing a simple link whenever we find two trees of equal rank
|
|
455
|
+
let rec mergeUniq = (comp, pq1, pq2) => {
|
|
456
|
+
match ((pq1, pq2)) {
|
|
457
|
+
([], ts) | (ts, []) => ts,
|
|
458
|
+
([node1, ...rest1], [node2, ...rest2]) => {
|
|
459
|
+
if (node1.rank < node2.rank) {
|
|
460
|
+
[node1, ...mergeUniq(comp, rest1, pq2)]
|
|
461
|
+
} else if (node2.rank < node1.rank) {
|
|
462
|
+
[node2, ...mergeUniq(comp, pq1, rest2)]
|
|
463
|
+
} else {
|
|
464
|
+
ins(
|
|
465
|
+
comp,
|
|
466
|
+
linkNodes(comp, node1, node2),
|
|
467
|
+
mergeUniq(comp, rest1, rest2)
|
|
468
|
+
)
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
let merge = (comp, pq1, pq2) =>
|
|
475
|
+
mergeUniq(comp, uniquify(comp, pq1), uniquify(comp, pq2))
|
|
476
|
+
|
|
477
|
+
// splits the node with the minimum value out from the rest of the nodes
|
|
478
|
+
let rec separateHighestPriority = (comp, pq) => {
|
|
479
|
+
match (pq) {
|
|
480
|
+
// empty list case should never happen; this is here just to satisfy the compiler
|
|
481
|
+
[] => fail "Impossible: getHighestPriority called with empty PQ",
|
|
482
|
+
[node] => (node, []),
|
|
483
|
+
[node, ...rest] => {
|
|
484
|
+
let (currMinNode, currNonMinNodes) = separateHighestPriority(comp, rest)
|
|
485
|
+
if (comp(node.val, currMinNode.val) <= 0) {
|
|
486
|
+
(node, rest)
|
|
487
|
+
} else {
|
|
488
|
+
(currMinNode, [node, ...currNonMinNodes])
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// splits the nodes of rank 0 out from the other nodes
|
|
495
|
+
let rec splitRankZero = (rankZeroVals, nonRankZeroNodes, pq) => {
|
|
496
|
+
match (pq) {
|
|
497
|
+
[] => (rankZeroVals, nonRankZeroNodes),
|
|
498
|
+
[node, ...rest] => {
|
|
499
|
+
if (node.rank == 0) {
|
|
500
|
+
splitRankZero([node.val, ...rankZeroVals], nonRankZeroNodes, rest)
|
|
501
|
+
} else {
|
|
502
|
+
splitRankZero(rankZeroVals, [node, ...nonRankZeroNodes], rest)
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
let withoutHighestPriority = (comp, pq) => {
|
|
509
|
+
// split out the node with the highest priority
|
|
510
|
+
let (hpNode, nonHpNodes) = separateHighestPriority(comp, pq)
|
|
511
|
+
// split out the values with nodes of rank 0, which will all be singleton nodes
|
|
512
|
+
let (rankZeroVals, nonRankZeroNodes) = splitRankZero(
|
|
513
|
+
[],
|
|
514
|
+
[],
|
|
515
|
+
hpNode.children
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
let mergedPq = merge(comp, nonHpNodes, nonRankZeroNodes)
|
|
519
|
+
List.reduce((pq, val) => skewInsert(comp, val, pq), mergedPq, rankZeroVals)
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
let rec findHighestPriority = (comp, pq) => {
|
|
523
|
+
match (pq) {
|
|
524
|
+
// empty list case should never happen; this is here just to satisfy the compiler
|
|
525
|
+
[] => fail "Impossible: findHighestPriority with empty PQ",
|
|
526
|
+
[node] => node.val,
|
|
527
|
+
[node, ...rest] => {
|
|
528
|
+
let currMin = findHighestPriority(comp, rest)
|
|
529
|
+
if (comp(node.val, currMin) <= 0) node.val else currMin
|
|
530
|
+
},
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Produces a new priority queue without the highest priority element in the
|
|
536
|
+
* given priority queue. If the input priority queue is empty, this function will
|
|
537
|
+
* return it.
|
|
538
|
+
*
|
|
539
|
+
* @param pq: The priority queue
|
|
540
|
+
* @returns A new priority queue without the highest priority element
|
|
541
|
+
*
|
|
542
|
+
* @since v0.6.0
|
|
543
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module
|
|
544
|
+
*/
|
|
545
|
+
provide let pop = pq => {
|
|
546
|
+
let pqWithRoot = pq
|
|
547
|
+
let { comp, size, root } = pq
|
|
548
|
+
match (root) {
|
|
549
|
+
None => pq,
|
|
550
|
+
Some({ pq, rootVal }) => {
|
|
551
|
+
let newRoot = if (pq == []) {
|
|
552
|
+
None
|
|
553
|
+
} else {
|
|
554
|
+
Some(
|
|
555
|
+
{
|
|
556
|
+
rootVal: findHighestPriority(comp, pq),
|
|
557
|
+
pq: withoutHighestPriority(comp, pq),
|
|
558
|
+
},
|
|
559
|
+
)
|
|
560
|
+
}
|
|
561
|
+
{ comp, size: size - 1, root: newRoot }
|
|
562
|
+
},
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Produces a list of all elements in the priority queue in priority order.
|
|
568
|
+
*
|
|
569
|
+
* @param pq: The priority queue to drain
|
|
570
|
+
* @returns A list of all elements in the priority in priority order
|
|
571
|
+
*
|
|
572
|
+
* @since v0.6.0
|
|
573
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module
|
|
574
|
+
*/
|
|
575
|
+
provide let drain = pq => {
|
|
576
|
+
let rec drainRec = (acc, pq) => {
|
|
577
|
+
match (pq.root) {
|
|
578
|
+
None => acc,
|
|
579
|
+
Some(root) => drainRec([root.rootVal, ...acc], pop(pq)),
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
List.reverse(drainRec([], pq))
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Constructs a new priority queue initialized with the elements in the list
|
|
587
|
+
* using a custom comparator function, which is used to determine priority of
|
|
588
|
+
* elements. The comparator function takes two elements and must return 0 if
|
|
589
|
+
* both share priority, a positive number if the first has greater priority,
|
|
590
|
+
* and a negative number if the first has less priority.
|
|
591
|
+
*
|
|
592
|
+
* @param list: A list of values used to initialize the priority queue
|
|
593
|
+
* @param compare: A comparator function used to assign priority to elements
|
|
594
|
+
* @returns A priority queue containing the elements from the list
|
|
595
|
+
*
|
|
596
|
+
* @since v0.6.0
|
|
597
|
+
* @history v0.5.3: Originally in `"immutablepriorityqueue"` module with `compare` being a required argument
|
|
598
|
+
*/
|
|
599
|
+
provide let fromList = (list, compare=compare) => {
|
|
600
|
+
List.reduce((pq, val) => push(val, pq), make(compare=compare), list)
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Constructs a new priority queue initialized with the elements in the array
|
|
605
|
+
* using a custom comparator function, which is used to determine priority of
|
|
606
|
+
* elements. The comparator function takes two elements and must return 0 if
|
|
607
|
+
* both share priority, a positive number if the first has greater priority,
|
|
608
|
+
* and a negative number if the first has less priority.
|
|
609
|
+
*
|
|
610
|
+
* @param array: An array of values used to initialize the priority queue
|
|
611
|
+
* @param compare: A comparator function used to assign priority to elements
|
|
612
|
+
* @returns A priority queue containing the elements from the array
|
|
613
|
+
*
|
|
614
|
+
* @since v0.6.0
|
|
615
|
+
* @history v0.5.4: Originally in `"immutablepriorityqueue"` module with `compare` being a required argument
|
|
616
|
+
*/
|
|
617
|
+
provide let fromArray = (array, compare=compare) => {
|
|
618
|
+
Array.reduce((pq, val) => push(val, pq), make(compare=compare), array)
|
|
619
|
+
}
|
|
261
620
|
}
|