@grain/stdlib 0.5.13 → 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 +193 -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/set.gr
CHANGED
|
@@ -1,54 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* A Set is an unordered collection of unique values. Operations on a Set mutate the internal state, so it never needs to be re-assigned.
|
|
3
|
+
*
|
|
4
|
+
* An immutable set implementation is available in the `Immutable` submodule.
|
|
5
|
+
* @example from "set" include Set
|
|
6
|
+
*
|
|
5
7
|
* @since v0.3.0
|
|
6
8
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
module Set
|
|
10
|
+
|
|
11
|
+
from "list" include List
|
|
12
|
+
from "array" include Array
|
|
13
|
+
from "hash" include Hash
|
|
14
|
+
use Hash.{ hash }
|
|
10
15
|
|
|
11
|
-
record Bucket<t> {
|
|
16
|
+
record rec Bucket<t> {
|
|
12
17
|
mut key: t,
|
|
13
18
|
mut next: Option<Bucket<t>>,
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
* @section Types: Type declarations included in the Set module.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
record Set<k> {
|
|
21
|
+
abstract record Set<k> {
|
|
21
22
|
mut size: Number,
|
|
22
23
|
mut buckets: Array<Option<Bucket<k>>>,
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
+
* Represents the internal state of a set.
|
|
27
28
|
*/
|
|
29
|
+
provide record InternalSetStats {
|
|
30
|
+
currentSize: Number,
|
|
31
|
+
bucketCount: Number,
|
|
32
|
+
}
|
|
28
33
|
|
|
29
34
|
// TODO: This could take an `eq` function to custom comparisons
|
|
30
35
|
/**
|
|
31
|
-
* Creates a new empty set with an initial storage of the given size. As
|
|
36
|
+
* Creates a new empty set with an initial storage of the given size. As
|
|
37
|
+
* values are added or removed, the internal storage may grow or shrink.
|
|
38
|
+
* Generally, you won't need to care about the storage size of your set and
|
|
39
|
+
* can use the default size.
|
|
32
40
|
*
|
|
33
41
|
* @param size: The initial storage size of the set
|
|
34
42
|
* @returns An empty set with the given initial storage size
|
|
35
|
-
*
|
|
43
|
+
*
|
|
36
44
|
* @since v0.3.0
|
|
45
|
+
* @history v0.6.0: Merged with `makeSized`; modified signature to accept size
|
|
37
46
|
*/
|
|
38
|
-
|
|
47
|
+
provide let make = (size=16) => {
|
|
39
48
|
let buckets = Array.make(size, None)
|
|
40
49
|
{ size: 0, buckets }
|
|
41
50
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Creates a new, empty set.
|
|
44
|
-
*
|
|
45
|
-
* @returns An empty set
|
|
46
|
-
*
|
|
47
|
-
* @since v0.3.0
|
|
48
|
-
*/
|
|
49
|
-
export let make = () => {
|
|
50
|
-
makeSized(16)
|
|
51
|
-
}
|
|
52
51
|
|
|
53
52
|
let getBucketIndex = (key, buckets) => {
|
|
54
53
|
let bucketsLength = Array.length(buckets)
|
|
@@ -120,10 +119,10 @@ let rec nodeInBucket = (key, node) => {
|
|
|
120
119
|
*
|
|
121
120
|
* @param key: The value to add
|
|
122
121
|
* @param set: The set to update
|
|
123
|
-
*
|
|
122
|
+
*
|
|
124
123
|
* @since v0.3.0
|
|
125
124
|
*/
|
|
126
|
-
|
|
125
|
+
provide let add = (key, set) => {
|
|
127
126
|
let buckets = set.buckets
|
|
128
127
|
let idx = getBucketIndex(key, buckets)
|
|
129
128
|
let bucket = buckets[idx]
|
|
@@ -153,10 +152,10 @@ export let add = (key, set) => {
|
|
|
153
152
|
* @param key: The value to search for
|
|
154
153
|
* @param set: The set to search
|
|
155
154
|
* @returns `true` if the set contains the given value or `false` otherwise
|
|
156
|
-
*
|
|
155
|
+
*
|
|
157
156
|
* @since v0.3.0
|
|
158
157
|
*/
|
|
159
|
-
|
|
158
|
+
provide let contains = (key, set) => {
|
|
160
159
|
let buckets = set.buckets
|
|
161
160
|
let idx = getBucketIndex(key, buckets)
|
|
162
161
|
let bucket = buckets[idx]
|
|
@@ -185,10 +184,10 @@ let rec removeInBucket = (key, node) => {
|
|
|
185
184
|
*
|
|
186
185
|
* @param key: The value to remove
|
|
187
186
|
* @param set: The set to update
|
|
188
|
-
*
|
|
187
|
+
*
|
|
189
188
|
* @since v0.3.0
|
|
190
189
|
*/
|
|
191
|
-
|
|
190
|
+
provide let remove = (key, set) => {
|
|
192
191
|
let buckets = set.buckets
|
|
193
192
|
let idx = getBucketIndex(key, buckets)
|
|
194
193
|
let bucket = buckets[idx]
|
|
@@ -213,10 +212,10 @@ export let remove = (key, set) => {
|
|
|
213
212
|
*
|
|
214
213
|
* @param set: The set to inspect
|
|
215
214
|
* @returns The count of elements in the set
|
|
216
|
-
*
|
|
215
|
+
*
|
|
217
216
|
* @since v0.3.0
|
|
218
217
|
*/
|
|
219
|
-
|
|
218
|
+
provide let size = set => {
|
|
220
219
|
set.size
|
|
221
220
|
}
|
|
222
221
|
|
|
@@ -225,10 +224,10 @@ export let size = set => {
|
|
|
225
224
|
*
|
|
226
225
|
* @param set: The set to inspect
|
|
227
226
|
* @returns `true` if the given set is empty or `false` otherwise
|
|
228
|
-
*
|
|
227
|
+
*
|
|
229
228
|
* @since v0.3.0
|
|
230
229
|
*/
|
|
231
|
-
|
|
230
|
+
provide let isEmpty = set => {
|
|
232
231
|
size(set) == 0
|
|
233
232
|
}
|
|
234
233
|
|
|
@@ -236,10 +235,10 @@ export let isEmpty = set => {
|
|
|
236
235
|
* Resets the set by removing all values.
|
|
237
236
|
*
|
|
238
237
|
* @param set: The set to reset
|
|
239
|
-
*
|
|
238
|
+
*
|
|
240
239
|
* @since v0.3.0
|
|
241
240
|
*/
|
|
242
|
-
|
|
241
|
+
provide let clear = set => {
|
|
243
242
|
set.size = 0
|
|
244
243
|
let buckets = set.buckets
|
|
245
244
|
Array.forEachi((bucket, idx) => {
|
|
@@ -262,11 +261,11 @@ let rec forEachBucket = (fn, node) => {
|
|
|
262
261
|
*
|
|
263
262
|
* @param fn: The iterator function to call with each element
|
|
264
263
|
* @param set: The set to iterate
|
|
265
|
-
*
|
|
264
|
+
*
|
|
266
265
|
* @since v0.3.0
|
|
267
266
|
* @history v0.5.0: Ensured the iterator function return type is always `Void`
|
|
268
267
|
*/
|
|
269
|
-
|
|
268
|
+
provide let forEach = (fn, set) => {
|
|
270
269
|
let buckets = set.buckets
|
|
271
270
|
Array.forEach(bucket => {
|
|
272
271
|
forEachBucket(fn, bucket)
|
|
@@ -287,10 +286,10 @@ let rec reduceEachBucket = (fn, node, acc) => {
|
|
|
287
286
|
* @param init: The initial value to use for the accumulator on the first iteration
|
|
288
287
|
* @param set: The set to iterate
|
|
289
288
|
* @returns The final accumulator returned from `fn`
|
|
290
|
-
*
|
|
289
|
+
*
|
|
291
290
|
* @since v0.3.0
|
|
292
291
|
*/
|
|
293
|
-
|
|
292
|
+
provide let reduce = (fn, init, set) => {
|
|
294
293
|
let buckets = set.buckets
|
|
295
294
|
let mut acc = init
|
|
296
295
|
Array.forEach(bucket => {
|
|
@@ -304,10 +303,10 @@ export let reduce = (fn, init, set) => {
|
|
|
304
303
|
*
|
|
305
304
|
* @param fn: The predicate function to indicate which elements to remove from the set, where returning `false` indicates the value should be removed
|
|
306
305
|
* @param set: The set to iterate
|
|
307
|
-
*
|
|
306
|
+
*
|
|
308
307
|
* @since v0.3.0
|
|
309
308
|
*/
|
|
310
|
-
|
|
309
|
+
provide let filter = (fn, set) => {
|
|
311
310
|
let keysToRemove = reduce((list, key) => if (!fn(key)) {
|
|
312
311
|
[key, ...list]
|
|
313
312
|
} else {
|
|
@@ -323,10 +322,10 @@ export let filter = (fn, set) => {
|
|
|
323
322
|
*
|
|
324
323
|
* @param fn: The predicate function to indicate which elements to remove from the set, where returning `true` indicates the value should be removed
|
|
325
324
|
* @param set: The set to iterate
|
|
326
|
-
*
|
|
325
|
+
*
|
|
327
326
|
* @since v0.3.0
|
|
328
327
|
*/
|
|
329
|
-
|
|
328
|
+
provide let reject = (fn, set) => {
|
|
330
329
|
filter(key => !fn(key), set)
|
|
331
330
|
}
|
|
332
331
|
|
|
@@ -335,10 +334,10 @@ export let reject = (fn, set) => {
|
|
|
335
334
|
*
|
|
336
335
|
* @param set: The set to convert
|
|
337
336
|
* @returns A list containing all set values
|
|
338
|
-
*
|
|
337
|
+
*
|
|
339
338
|
* @since v0.3.0
|
|
340
339
|
*/
|
|
341
|
-
|
|
340
|
+
provide let toList = set => {
|
|
342
341
|
reduce((list, key) => [key, ...list], [], set)
|
|
343
342
|
}
|
|
344
343
|
|
|
@@ -347,10 +346,10 @@ export let toList = set => {
|
|
|
347
346
|
*
|
|
348
347
|
* @param list: The list to convert
|
|
349
348
|
* @returns A set containing all list values
|
|
350
|
-
*
|
|
349
|
+
*
|
|
351
350
|
* @since v0.3.0
|
|
352
351
|
*/
|
|
353
|
-
|
|
352
|
+
provide let fromList = list => {
|
|
354
353
|
let set = make()
|
|
355
354
|
List.forEach(key => {
|
|
356
355
|
add(key, set)
|
|
@@ -363,10 +362,10 @@ export let fromList = list => {
|
|
|
363
362
|
*
|
|
364
363
|
* @param set: The set to convert
|
|
365
364
|
* @returns An array containing all set values
|
|
366
|
-
*
|
|
365
|
+
*
|
|
367
366
|
* @since v0.3.0
|
|
368
367
|
*/
|
|
369
|
-
|
|
368
|
+
provide let toArray = set => {
|
|
370
369
|
Array.fromList(toList(set))
|
|
371
370
|
}
|
|
372
371
|
|
|
@@ -375,10 +374,10 @@ export let toArray = set => {
|
|
|
375
374
|
*
|
|
376
375
|
* @param array: The array to convert
|
|
377
376
|
* @returns A set containing all array values
|
|
378
|
-
*
|
|
377
|
+
*
|
|
379
378
|
* @since v0.3.0
|
|
380
379
|
*/
|
|
381
|
-
|
|
380
|
+
provide let fromArray = array => {
|
|
382
381
|
let set = make()
|
|
383
382
|
Array.forEach(key => {
|
|
384
383
|
add(key, set)
|
|
@@ -392,10 +391,10 @@ export let fromArray = array => {
|
|
|
392
391
|
* @param set1: The first set to combine
|
|
393
392
|
* @param set2: The second set to combine
|
|
394
393
|
* @returns A set containing all elements of both sets
|
|
395
|
-
*
|
|
394
|
+
*
|
|
396
395
|
* @since v0.3.0
|
|
397
396
|
*/
|
|
398
|
-
|
|
397
|
+
provide let union = (set1, set2) => {
|
|
399
398
|
let set = make()
|
|
400
399
|
forEach(key => {
|
|
401
400
|
add(key, set)
|
|
@@ -412,10 +411,10 @@ export let union = (set1, set2) => {
|
|
|
412
411
|
* @param set1: The first set to combine
|
|
413
412
|
* @param set2: The second set to combine
|
|
414
413
|
* @returns A set containing only unshared elements from both sets
|
|
415
|
-
*
|
|
414
|
+
*
|
|
416
415
|
* @since v0.3.0
|
|
417
416
|
*/
|
|
418
|
-
|
|
417
|
+
provide let diff = (set1, set2) => {
|
|
419
418
|
let set = make()
|
|
420
419
|
forEach(key => {
|
|
421
420
|
if (!contains(key, set2)) {
|
|
@@ -436,10 +435,10 @@ export let diff = (set1, set2) => {
|
|
|
436
435
|
* @param set1: The first set to combine
|
|
437
436
|
* @param set2: The second set to combine
|
|
438
437
|
* @returns A set containing only shared elements from both sets
|
|
439
|
-
*
|
|
438
|
+
*
|
|
440
439
|
* @since v0.3.0
|
|
441
440
|
*/
|
|
442
|
-
|
|
441
|
+
provide let intersect = (set1, set2) => {
|
|
443
442
|
let set = make()
|
|
444
443
|
forEach(key => {
|
|
445
444
|
if (contains(key, set2)) {
|
|
@@ -454,15 +453,526 @@ export let intersect = (set1, set2) => {
|
|
|
454
453
|
set
|
|
455
454
|
}
|
|
456
455
|
|
|
457
|
-
// TODO(#190): Should return a Record type instead of a Tuple
|
|
458
456
|
/**
|
|
459
457
|
* Provides data representing the internal state state of the set.
|
|
460
458
|
*
|
|
461
459
|
* @param set: The set to inspect
|
|
462
460
|
* @returns The internal state of the set
|
|
463
|
-
*
|
|
461
|
+
*
|
|
464
462
|
* @since v0.3.0
|
|
463
|
+
* @history v0.6.0: Return `InternalSetStats` record instead of a tuple
|
|
464
|
+
*/
|
|
465
|
+
provide let getInternalStats = set => {
|
|
466
|
+
{ currentSize: set.size, bucketCount: Array.length(set.buckets) }
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* An immutable set implementation.
|
|
471
|
+
*
|
|
472
|
+
* @since v0.6.0
|
|
473
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
465
474
|
*/
|
|
466
|
-
|
|
467
|
-
|
|
475
|
+
provide module Immutable {
|
|
476
|
+
// implementation based on the paper "Implementing Sets Efficiently in a
|
|
477
|
+
// Functional Language" by Stephen Adams
|
|
478
|
+
|
|
479
|
+
record rec Node<a> {
|
|
480
|
+
key: a,
|
|
481
|
+
size: Number,
|
|
482
|
+
left: Set<a>,
|
|
483
|
+
right: Set<a>,
|
|
484
|
+
}
|
|
485
|
+
and abstract enum Set<a> {
|
|
486
|
+
Empty,
|
|
487
|
+
Tree(Node<a>),
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// semi-arbitrary value chosen for algorithm for determining when to balance
|
|
491
|
+
// trees; no tree can have a left subtree containing this number of times
|
|
492
|
+
// more elements than its right subtree or vice versa
|
|
493
|
+
let weight = 4
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* An empty set
|
|
497
|
+
*
|
|
498
|
+
* @since v0.6.0
|
|
499
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
500
|
+
*/
|
|
501
|
+
provide let empty = Empty
|
|
502
|
+
|
|
503
|
+
// returns the minimum value in a tree
|
|
504
|
+
let rec min = node => {
|
|
505
|
+
match (node) {
|
|
506
|
+
Tree({ key, left: Empty, _ }) => key,
|
|
507
|
+
Tree({ left, _ }) => min(left),
|
|
508
|
+
Empty => fail "Impossible: min of empty element in Set.Immutable",
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Provides the count of values within the set.
|
|
514
|
+
*
|
|
515
|
+
* @param set: The set to inspect
|
|
516
|
+
* @returns The count of elements in the set
|
|
517
|
+
*
|
|
518
|
+
* @since v0.6.0
|
|
519
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
520
|
+
*/
|
|
521
|
+
provide let size = set => {
|
|
522
|
+
match (set) {
|
|
523
|
+
Empty => 0,
|
|
524
|
+
Tree({ size, _ }) => size,
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Determines if the set contains no elements.
|
|
530
|
+
*
|
|
531
|
+
* @param set: The set to inspect
|
|
532
|
+
* @returns `true` if the given set is empty or `false` otherwise
|
|
533
|
+
*
|
|
534
|
+
* @since v0.6.0
|
|
535
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
536
|
+
*/
|
|
537
|
+
provide let isEmpty = set => {
|
|
538
|
+
match (set) {
|
|
539
|
+
Empty => true,
|
|
540
|
+
Tree(_) => false,
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
let unwrapTree = node => {
|
|
545
|
+
match (node) {
|
|
546
|
+
Empty =>
|
|
547
|
+
fail "Impossible: Set.Immutable unwrapTree got an empty tree node",
|
|
548
|
+
Tree(tree) => tree,
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// helper function for creating a tree node with correct size from
|
|
553
|
+
// two balanced trees
|
|
554
|
+
let makeNode = (key, left, right) => {
|
|
555
|
+
Tree({ key, size: 1 + size(left) + size(right), left, right })
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// note: see Figure 1 of paper referenced above for visual illustration of
|
|
559
|
+
// the rotations below
|
|
560
|
+
|
|
561
|
+
// node rotation moving the left subtree of the right node to the left side
|
|
562
|
+
let singleL = (key, left, right) => {
|
|
563
|
+
let { key: rKey, left: rl, right: rr, _ } = unwrapTree(right)
|
|
564
|
+
makeNode(rKey, makeNode(key, left, rl), rr)
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// node rotation moving left child of right tree to the root
|
|
568
|
+
let doubleL = (key, left, right) => {
|
|
569
|
+
let { key: rKey, left: rl, right: rr, _ } = unwrapTree(right)
|
|
570
|
+
let { key: rlKey, left: rll, right: rlr, _ } = unwrapTree(rl)
|
|
571
|
+
makeNode(rlKey, makeNode(key, left, rll), makeNode(rKey, rlr, rr))
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// node rotation moving the right subtree of the left node to the right side
|
|
575
|
+
let singleR = (key, left, right) => {
|
|
576
|
+
let { key: lKey, left: ll, right: lr, _ } = unwrapTree(left)
|
|
577
|
+
makeNode(lKey, ll, makeNode(key, lr, right))
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// node rotation moving right child of left tree to the root
|
|
581
|
+
let doubleR = (key, left, right) => {
|
|
582
|
+
let { key: lKey, left: ll, right: lr, _ } = unwrapTree(left)
|
|
583
|
+
let { key: lrKey, left: lrl, right: lrr, _ } = unwrapTree(lr)
|
|
584
|
+
makeNode(lrKey, makeNode(lKey, ll, lrl), makeNode(key, lrr, right))
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// creates a new node after either the left or right trees have just had an
|
|
588
|
+
// element inserted or removed from them, maintaining balance in the tree
|
|
589
|
+
let balancedNode = (key, left, right) => {
|
|
590
|
+
let makeNodeFn = if (size(left) + size(right) < 2) {
|
|
591
|
+
makeNode
|
|
592
|
+
} else if (size(right) > weight * size(left)) {
|
|
593
|
+
// if the right tree is too much larger than the left then move part of
|
|
594
|
+
// the right tree to the left side
|
|
595
|
+
let { left: rl, right: rr, _ } = unwrapTree(right)
|
|
596
|
+
if (size(rl) < size(rr)) singleL else doubleL
|
|
597
|
+
} else if (size(left) > weight * size(right)) {
|
|
598
|
+
// if the left tree is too much larger than the right then move part of
|
|
599
|
+
// the left tree to the right side
|
|
600
|
+
let { left: ll, right: lr, _ } = unwrapTree(left)
|
|
601
|
+
if (size(lr) < size(ll)) singleR else doubleR
|
|
602
|
+
} else {
|
|
603
|
+
// if neither tree is too much larger than the other then simply create
|
|
604
|
+
// a new node
|
|
605
|
+
makeNode
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
makeNodeFn(key, left, right)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Produces a new set by inserting the given value into the set. If the value
|
|
613
|
+
* already exists, the new set will have the same elements as the input set.
|
|
614
|
+
*
|
|
615
|
+
* @param key: The value to add
|
|
616
|
+
* @param set: The base set
|
|
617
|
+
* @returns A new set containing the new element
|
|
618
|
+
*
|
|
619
|
+
* @since v0.6.0
|
|
620
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
621
|
+
*/
|
|
622
|
+
provide let rec add = (key, set) => {
|
|
623
|
+
match (set) {
|
|
624
|
+
Empty => Tree({ key, size: 1, left: Empty, right: Empty }),
|
|
625
|
+
Tree({ key: nodeKey, left, right, _ }) => {
|
|
626
|
+
match (compare(key, nodeKey)) {
|
|
627
|
+
cmp when cmp < 0 => balancedNode(nodeKey, add(key, left), right),
|
|
628
|
+
cmp when cmp > 0 => balancedNode(nodeKey, left, add(key, right)),
|
|
629
|
+
_ => makeNode(key, left, right),
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Determines if the set contains the given value.
|
|
637
|
+
*
|
|
638
|
+
* @param key: The value to search for
|
|
639
|
+
* @param set: The set to search
|
|
640
|
+
* @returns `true` if the set contains the given value or `false` otherwise
|
|
641
|
+
*
|
|
642
|
+
* @since v0.6.0
|
|
643
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
644
|
+
*/
|
|
645
|
+
provide let rec contains = (key, set) => {
|
|
646
|
+
match (set) {
|
|
647
|
+
Empty => false,
|
|
648
|
+
Tree({ key: nodeKey, left, right, _ }) => {
|
|
649
|
+
match (compare(key, nodeKey)) {
|
|
650
|
+
cmp when cmp < 0 => contains(key, left),
|
|
651
|
+
cmp when cmp > 0 => contains(key, right),
|
|
652
|
+
_ => true,
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// removes the minimum element from a tree
|
|
659
|
+
let rec removeMin = node => {
|
|
660
|
+
match (node) {
|
|
661
|
+
Tree({ left: Empty, right, _ }) => right,
|
|
662
|
+
Tree({ key, left, right, _ }) =>
|
|
663
|
+
balancedNode(key, removeMin(left), right),
|
|
664
|
+
_ => fail "Impossible: Set.Immutable removeMin on empty node",
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// helper function for removing a node by creating a new node containing the
|
|
669
|
+
// removed node's left and right subtrees
|
|
670
|
+
let removeInner = (left, right) => {
|
|
671
|
+
match ((left, right)) {
|
|
672
|
+
(Empty, node) | (node, Empty) => node,
|
|
673
|
+
(left, right) => {
|
|
674
|
+
balancedNode(min(right), left, removeMin(right))
|
|
675
|
+
},
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Produces a new set without the given element. If the value doesn't exist in
|
|
681
|
+
* the set, the set will be returned unmodified.
|
|
682
|
+
*
|
|
683
|
+
* @param key: The value to exclude
|
|
684
|
+
* @param set: The set to exclude from
|
|
685
|
+
* @returns A new set without the excluded element
|
|
686
|
+
*
|
|
687
|
+
* @since v0.6.0
|
|
688
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
689
|
+
*/
|
|
690
|
+
provide let rec remove = (key, set) => {
|
|
691
|
+
match (set) {
|
|
692
|
+
Empty => Empty,
|
|
693
|
+
Tree({ key: nodeKey, left, right, _ }) => {
|
|
694
|
+
match (compare(key, nodeKey)) {
|
|
695
|
+
cmp when cmp < 0 => balancedNode(nodeKey, remove(key, left), right),
|
|
696
|
+
cmp when cmp > 0 => balancedNode(nodeKey, left, remove(key, right)),
|
|
697
|
+
_ => removeInner(left, right),
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Iterates the set, calling an iterator function on each element.
|
|
705
|
+
*
|
|
706
|
+
* @param fn: The iterator function to call with each element
|
|
707
|
+
* @param set: The set to iterate
|
|
708
|
+
*
|
|
709
|
+
* @since v0.6.0
|
|
710
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
711
|
+
*/
|
|
712
|
+
provide let forEach = (fn, set) => {
|
|
713
|
+
let rec forEachInner = node => {
|
|
714
|
+
match (node) {
|
|
715
|
+
Empty => void,
|
|
716
|
+
Tree({ key, left, right, _ }) => {
|
|
717
|
+
forEachInner(left)
|
|
718
|
+
fn(key): Void
|
|
719
|
+
forEachInner(right)
|
|
720
|
+
},
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
forEachInner(set)
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Combines all elements of a set using a reducer function.
|
|
728
|
+
*
|
|
729
|
+
* @param fn: The reducer function to call on each element, where the value returned will be the next accumulator value
|
|
730
|
+
* @param init: The initial value to use for the accumulator on the first iteration
|
|
731
|
+
* @param set: The set to iterate
|
|
732
|
+
* @returns The final accumulator returned from `fn`
|
|
733
|
+
*
|
|
734
|
+
* @since v0.6.0
|
|
735
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
736
|
+
*/
|
|
737
|
+
provide let reduce = (fn, init, set) => {
|
|
738
|
+
let rec reduceInner = (acc, node) => {
|
|
739
|
+
match (node) {
|
|
740
|
+
Empty => acc,
|
|
741
|
+
Tree({ key, left, right, _ }) => {
|
|
742
|
+
let newAcc = fn(reduceInner(acc, left), key)
|
|
743
|
+
reduceInner(newAcc, right)
|
|
744
|
+
},
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
reduceInner(init, set)
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// joins two trees with a value, preserving the BST property of left children
|
|
751
|
+
// being less the node and right children being greater than the node
|
|
752
|
+
let rec concat3 = (key, left, right) => {
|
|
753
|
+
match ((left, right)) {
|
|
754
|
+
(Empty, node) | (node, Empty) => add(key, node),
|
|
755
|
+
(Tree(left) as leftOpt, Tree(right) as rightOpt) => {
|
|
756
|
+
let { size: lSize, key: lKey, left: lLeft, right: lRight } = left
|
|
757
|
+
let { size: rSize, key: rKey, left: rLeft, right: rRight } = right
|
|
758
|
+
if (weight * lSize < rSize) {
|
|
759
|
+
balancedNode(rKey, concat3(key, leftOpt, rLeft), rRight)
|
|
760
|
+
} else if (weight * rSize < lSize) {
|
|
761
|
+
balancedNode(lKey, lLeft, concat3(key, lRight, rightOpt))
|
|
762
|
+
} else {
|
|
763
|
+
makeNode(key, leftOpt, rightOpt)
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// returns a tree containing all of the nodes in the input tree whose values
|
|
770
|
+
// are less than the given value
|
|
771
|
+
let rec splitLt = (splitKey, node) => {
|
|
772
|
+
match (node) {
|
|
773
|
+
Empty => Empty,
|
|
774
|
+
Tree({ key, left, right, _ }) => {
|
|
775
|
+
match (compare(key, splitKey)) {
|
|
776
|
+
// we want this node, join it to the output
|
|
777
|
+
cmp when cmp < 0 => concat3(key, left, splitLt(splitKey, right)),
|
|
778
|
+
cmp when cmp > 0 => splitLt(splitKey, left),
|
|
779
|
+
_ => left,
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// returns a tree containing all of the nodes in the input tree whose values
|
|
786
|
+
// are greater than the given value
|
|
787
|
+
let rec splitGt = (splitKey, node) => {
|
|
788
|
+
match (node) {
|
|
789
|
+
Empty => Empty,
|
|
790
|
+
Tree({ key, left, right, _ }) => {
|
|
791
|
+
match (compare(key, splitKey)) {
|
|
792
|
+
// we want this node, join it to the output
|
|
793
|
+
cmp when cmp > 0 => concat3(key, splitGt(splitKey, left), right),
|
|
794
|
+
cmp when cmp < 0 => splitGt(splitKey, right),
|
|
795
|
+
_ => right,
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// concatenates two trees of arbitrary size
|
|
802
|
+
let concat = (node1, node2) => {
|
|
803
|
+
match (node2) {
|
|
804
|
+
Empty => node1,
|
|
805
|
+
_ => concat3(min(node2), node1, removeMin(node2)),
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Produces a new set without the elements from the input set where a predicate function returns `false`.
|
|
811
|
+
*
|
|
812
|
+
* @param fn: The predicate function to indicate which elements to exclude from the set, where returning `false` indicates the value should be excluded
|
|
813
|
+
* @param set: The set to iterate
|
|
814
|
+
* @returns A new set excluding the elements not fulfilling the predicate
|
|
815
|
+
*
|
|
816
|
+
* @since v0.6.0
|
|
817
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
818
|
+
*/
|
|
819
|
+
provide let filter = (fn, set) => {
|
|
820
|
+
let rec filterInner = node => {
|
|
821
|
+
match (node) {
|
|
822
|
+
Empty => Empty,
|
|
823
|
+
Tree({ key, left, right, _ }) => {
|
|
824
|
+
if (fn(key)) {
|
|
825
|
+
concat3(key, filterInner(left), filterInner(right))
|
|
826
|
+
} else {
|
|
827
|
+
concat(filterInner(left), filterInner(right))
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
filterInner(set)
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Produces a new set without the elements from the input set where a predicate function returns `true`.
|
|
837
|
+
*
|
|
838
|
+
* @param fn: The predicate function to indicate which elements to exclude from the set, where returning `true` indicates the value should be excluded
|
|
839
|
+
* @param set: The set to iterate
|
|
840
|
+
* @returns A new set excluding the elements fulfilling the predicate
|
|
841
|
+
*
|
|
842
|
+
* @since v0.6.0
|
|
843
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
844
|
+
*/
|
|
845
|
+
provide let reject = (fn, set) => {
|
|
846
|
+
filter(key => !fn(key), set)
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Combines two sets into a single set containing all elements from both sets.
|
|
851
|
+
*
|
|
852
|
+
* @param set1: The first set to combine
|
|
853
|
+
* @param set2: The second set to combine
|
|
854
|
+
* @returns A set containing all elements of both sets
|
|
855
|
+
*
|
|
856
|
+
* @since v0.6.0
|
|
857
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
858
|
+
*/
|
|
859
|
+
provide let rec union = (set1, set2) => {
|
|
860
|
+
match ((set1, set2)) {
|
|
861
|
+
(Empty, node) | (node, Empty) => node,
|
|
862
|
+
(node1, Tree({ key: key2, left: left2, right: right2, _ })) => {
|
|
863
|
+
let l = splitLt(key2, node1)
|
|
864
|
+
let r = splitGt(key2, node1)
|
|
865
|
+
concat3(key2, union(l, left2), union(r, right2))
|
|
866
|
+
},
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Combines two sets into a single set containing only the elements not shared between both sets.
|
|
872
|
+
*
|
|
873
|
+
* @param set1: The first set to combine
|
|
874
|
+
* @param set2: The second set to combine
|
|
875
|
+
* @returns A set containing only unshared elements from both sets
|
|
876
|
+
*
|
|
877
|
+
* @since v0.6.0
|
|
878
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
879
|
+
*/
|
|
880
|
+
provide let diff = (set1, set2) => {
|
|
881
|
+
let rec diffInner = (node1, node2) => {
|
|
882
|
+
match ((node1, node2)) {
|
|
883
|
+
(Empty, node) | (node, Empty) => node,
|
|
884
|
+
(node1, Tree({ key: key2, left: left2, right: right2, _ })) => {
|
|
885
|
+
let l = splitLt(key2, node1)
|
|
886
|
+
let r = splitGt(key2, node1)
|
|
887
|
+
concat(diffInner(l, left2), diffInner(r, right2))
|
|
888
|
+
},
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
union(diffInner(set1, set2), diffInner(set2, set1))
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Combines two sets into a single set containing only the elements shared between both sets.
|
|
896
|
+
*
|
|
897
|
+
* @param set1: The first set to combine
|
|
898
|
+
* @param set2: The second set to combine
|
|
899
|
+
* @returns A set containing only shared elements from both sets
|
|
900
|
+
*
|
|
901
|
+
* @since v0.6.0
|
|
902
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
903
|
+
*/
|
|
904
|
+
provide let rec intersect = (set1, set2) => {
|
|
905
|
+
match ((set1, set2)) {
|
|
906
|
+
(Empty, _) | (_, Empty) => Empty,
|
|
907
|
+
(node1, Tree({ key: key2, left: left2, right: right2, _ })) => {
|
|
908
|
+
let l = splitLt(key2, node1)
|
|
909
|
+
let r = splitGt(key2, node1)
|
|
910
|
+
if (contains(key2, node1)) {
|
|
911
|
+
concat3(key2, intersect(l, left2), intersect(r, right2))
|
|
912
|
+
} else {
|
|
913
|
+
concat(intersect(l, left2), intersect(r, right2))
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Creates a set from a list.
|
|
921
|
+
*
|
|
922
|
+
* @param list: The list to convert
|
|
923
|
+
* @returns A set containing all list values
|
|
924
|
+
*
|
|
925
|
+
* @since v0.6.0
|
|
926
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
927
|
+
*/
|
|
928
|
+
provide let fromList = list => {
|
|
929
|
+
List.reduce((set, key) => add(key, set), empty, list)
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Converts a set into a list of its elements.
|
|
934
|
+
*
|
|
935
|
+
* @param set: The set to convert
|
|
936
|
+
* @returns A list containing all set values
|
|
937
|
+
*
|
|
938
|
+
* @since v0.6.0
|
|
939
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
940
|
+
*/
|
|
941
|
+
provide let toList = set => {
|
|
942
|
+
let rec toListInner = (acc, node) => {
|
|
943
|
+
match (node) {
|
|
944
|
+
Empty => acc,
|
|
945
|
+
Tree({ key, left, right, _ }) => {
|
|
946
|
+
toListInner([key, ...toListInner(acc, right)], left)
|
|
947
|
+
},
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
toListInner([], set)
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/**
|
|
954
|
+
* Creates a set from an array.
|
|
955
|
+
*
|
|
956
|
+
* @param array: The array to convert
|
|
957
|
+
* @returns A set containing all array values
|
|
958
|
+
*
|
|
959
|
+
* @since v0.6.0
|
|
960
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
961
|
+
*/
|
|
962
|
+
provide let fromArray = array => {
|
|
963
|
+
Array.reduce((set, key) => add(key, set), empty, array)
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/**
|
|
967
|
+
* Converts a set into an array of its elements.
|
|
968
|
+
*
|
|
969
|
+
* @param set: The set to convert
|
|
970
|
+
* @returns An array containing all set values
|
|
971
|
+
*
|
|
972
|
+
* @since v0.6.0
|
|
973
|
+
* @history v0.5.4: Originally in `"immutableset"` module
|
|
974
|
+
*/
|
|
975
|
+
provide let toArray = set => {
|
|
976
|
+
Array.fromList(toList(set))
|
|
977
|
+
}
|
|
468
978
|
}
|