@grain/stdlib 0.4.4 → 0.5.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.
Files changed (97) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +1 -1
  3. package/array.gr +92 -73
  4. package/array.md +18 -18
  5. package/bigint.gr +497 -0
  6. package/bigint.md +811 -0
  7. package/buffer.gr +56 -217
  8. package/buffer.md +24 -17
  9. package/bytes.gr +103 -205
  10. package/bytes.md +19 -0
  11. package/char.gr +152 -166
  12. package/char.md +200 -0
  13. package/exception.md +6 -0
  14. package/float32.gr +159 -82
  15. package/float32.md +315 -0
  16. package/float64.gr +163 -82
  17. package/float64.md +315 -0
  18. package/hash.gr +53 -49
  19. package/int32.gr +479 -230
  20. package/int32.md +937 -0
  21. package/int64.gr +479 -230
  22. package/int64.md +937 -0
  23. package/list.gr +530 -116
  24. package/list.md +1141 -0
  25. package/map.gr +302 -121
  26. package/map.md +525 -0
  27. package/number.gr +51 -57
  28. package/number.md +37 -3
  29. package/option.gr +25 -25
  30. package/option.md +1 -1
  31. package/package.json +3 -3
  32. package/pervasives.gr +504 -52
  33. package/pervasives.md +1116 -0
  34. package/queue.gr +8 -1
  35. package/queue.md +10 -0
  36. package/random.gr +196 -0
  37. package/random.md +179 -0
  38. package/range.gr +26 -26
  39. package/regex.gr +1833 -842
  40. package/regex.md +11 -11
  41. package/result.md +1 -1
  42. package/runtime/bigint.gr +2045 -0
  43. package/runtime/bigint.md +326 -0
  44. package/runtime/dataStructures.gr +99 -279
  45. package/runtime/dataStructures.md +391 -0
  46. package/runtime/debug.gr +0 -1
  47. package/runtime/debug.md +6 -0
  48. package/runtime/equal.gr +40 -37
  49. package/runtime/equal.md +6 -0
  50. package/runtime/exception.gr +28 -15
  51. package/runtime/exception.md +30 -0
  52. package/runtime/gc.gr +50 -20
  53. package/runtime/gc.md +36 -0
  54. package/runtime/malloc.gr +32 -22
  55. package/runtime/malloc.md +55 -0
  56. package/runtime/numberUtils.gr +297 -142
  57. package/runtime/numberUtils.md +54 -0
  58. package/runtime/numbers.gr +1204 -453
  59. package/runtime/numbers.md +300 -0
  60. package/runtime/string.gr +193 -228
  61. package/runtime/string.md +24 -0
  62. package/runtime/stringUtils.gr +62 -38
  63. package/runtime/stringUtils.md +6 -0
  64. package/runtime/unsafe/constants.gr +17 -0
  65. package/runtime/unsafe/constants.md +72 -0
  66. package/runtime/unsafe/conv.gr +10 -10
  67. package/runtime/unsafe/conv.md +71 -0
  68. package/runtime/unsafe/errors.md +204 -0
  69. package/runtime/unsafe/memory.gr +14 -3
  70. package/runtime/unsafe/memory.md +54 -0
  71. package/runtime/unsafe/printWasm.gr +4 -4
  72. package/runtime/unsafe/printWasm.md +24 -0
  73. package/runtime/unsafe/tags.gr +11 -10
  74. package/runtime/unsafe/tags.md +120 -0
  75. package/runtime/unsafe/wasmf32.gr +9 -2
  76. package/runtime/unsafe/wasmf32.md +168 -0
  77. package/runtime/unsafe/wasmf64.gr +9 -2
  78. package/runtime/unsafe/wasmf64.md +168 -0
  79. package/runtime/unsafe/wasmi32.gr +65 -47
  80. package/runtime/unsafe/wasmi32.md +282 -0
  81. package/runtime/unsafe/wasmi64.gr +78 -50
  82. package/runtime/unsafe/wasmi64.md +300 -0
  83. package/runtime/utils/printing.gr +62 -0
  84. package/runtime/utils/printing.md +18 -0
  85. package/runtime/wasi.gr +200 -46
  86. package/runtime/wasi.md +839 -0
  87. package/set.gr +125 -121
  88. package/set.md +24 -21
  89. package/stack.gr +29 -29
  90. package/stack.md +4 -6
  91. package/string.gr +434 -415
  92. package/string.md +3 -3
  93. package/sys/file.gr +477 -482
  94. package/sys/process.gr +33 -47
  95. package/sys/random.gr +48 -20
  96. package/sys/random.md +38 -0
  97. package/sys/time.gr +12 -28
package/map.gr CHANGED
@@ -1,5 +1,9 @@
1
- // Standard library for Map (aka HashMap) functionality
2
-
1
+ /**
2
+ * @module Map: A Map holds key-value pairs. Any value may be used as a key or value. Operations on a Map mutate the internal state, so it never needs to be re-assigned.
3
+ * @example import Map from "map"
4
+ *
5
+ * @since v0.2.0
6
+ */
3
7
  import List from "list"
4
8
  import Array from "array"
5
9
  import { hash } from "hash"
@@ -11,30 +15,49 @@ import { allocateArray } from "runtime/dataStructures"
11
15
  record Bucket<k, v> {
12
16
  mut key: k,
13
17
  mut value: v,
14
- mut next: Option<Bucket<k, v>>
18
+ mut next: Option<Bucket<k, v>>,
15
19
  }
16
20
 
21
+ /**
22
+ * @section Types: Type declarations included in the Map module.
23
+ */
24
+
17
25
  record Map<k, v> {
18
26
  mut size: Number,
19
- mut buckets: Array<Option<Bucket<k, v>>>
20
- }
21
-
22
- // TODO: This could take an `eq` function to custom comparisons
23
- export let makeSized = (size) => {
24
- let buckets = Array.make(size, None);
25
- {
26
- size: 0,
27
- buckets
28
- }
29
- }
30
-
27
+ mut buckets: Array<Option<Bucket<k, v>>>,
28
+ }
29
+
30
+ /**
31
+ * @section Values: Functions for working with Maps.
32
+ */
33
+
34
+ /**
35
+ * Creates a new empty map with an initial storage of the given size. As values are added or removed, the internal storage may grow or shrink. Generally, you won't need to care about the storage size of your map and can use `Map.make()` instead.
36
+ *
37
+ * @param size: The initial storage size of the map
38
+ * @returns An empty map with the given initial storage size
39
+ *
40
+ * @since v0.2.0
41
+ */
42
+ export let makeSized = size => { // TODO: This could take an `eq` function to custom comparisons
43
+ let buckets = Array.make(size, None)
44
+ { size: 0, buckets }
45
+ }
46
+
47
+ /**
48
+ * Creates a new, empty map.
49
+ *
50
+ * @returns An empty map
51
+ *
52
+ * @since v0.2.0
53
+ */
31
54
  export let make = () => {
32
55
  makeSized(16)
33
56
  }
34
57
 
35
58
  let getBucketIndex = (key, buckets) => {
36
- let bucketsLength = Array.length(buckets);
37
- let hashedKey = hash(key);
59
+ let bucketsLength = Array.length(buckets)
60
+ let hashedKey = hash(key)
38
61
  hashedKey % bucketsLength
39
62
  }
40
63
 
@@ -42,45 +65,45 @@ let rec copyNodeWithNewHash = (oldNode, next, tail) => {
42
65
  match (oldNode) {
43
66
  None => void,
44
67
  Some(node) => {
45
- let idx = getBucketIndex(node.key, next);
46
- let newNode = Some(node);
68
+ let idx = getBucketIndex(node.key, next)
69
+ let newNode = Some(node)
47
70
  match (tail[idx]) {
48
71
  None => {
49
- next[idx] = newNode;
72
+ next[idx] = newNode
50
73
  },
51
74
  Some(tailNode) => {
52
75
  // If there's already a tail node, we add this to the end
53
- tailNode.next = newNode;
54
- }
76
+ tailNode.next = newNode
77
+ },
55
78
  }
56
79
  // Always place this node as the new tail
57
- tail[idx] = newNode;
80
+ tail[idx] = newNode
58
81
  // Recurse with the next node
59
- copyNodeWithNewHash(node.next, next, tail);
60
- }
82
+ copyNodeWithNewHash(node.next, next, tail)
83
+ },
61
84
  }
62
85
  }
63
86
 
64
- let resize = (map) => {
65
- let currentBuckets = map.buckets;
66
- let currentSize = Array.length(currentBuckets);
67
- let nextSize = currentSize * 2;
87
+ let resize = map => {
88
+ let currentBuckets = map.buckets
89
+ let currentSize = Array.length(currentBuckets)
90
+ let nextSize = currentSize * 2
68
91
  if (nextSize >= currentSize) {
69
- let nextBuckets = Array.make(nextSize, None);
92
+ let nextBuckets = Array.make(nextSize, None)
70
93
  // This tracks the tail nodes so we can set their `next` to None
71
- let tailNodes = Array.make(nextSize, None);
72
- map.buckets = nextBuckets;
73
- Array.forEach((old) => {
74
- copyNodeWithNewHash(old, nextBuckets, tailNodes);
75
- }, currentBuckets);
76
- Array.forEach((tail) => {
94
+ let tailNodes = Array.make(nextSize, None)
95
+ map.buckets = nextBuckets
96
+ Array.forEach(old => {
97
+ copyNodeWithNewHash(old, nextBuckets, tailNodes)
98
+ }, currentBuckets)
99
+ Array.forEach(tail => {
77
100
  match (tail) {
78
101
  None => void,
79
102
  Some(node) => {
80
- node.next = None;
81
- }
103
+ node.next = None
104
+ },
82
105
  }
83
- }, tailNodes);
106
+ }, tailNodes)
84
107
  } else {
85
108
  void
86
109
  }
@@ -88,35 +111,44 @@ let resize = (map) => {
88
111
 
89
112
  let rec replaceInBucket = (key, value, node) => {
90
113
  if (key == node.key) {
91
- node.value = value;
114
+ node.value = value
92
115
  false
93
116
  } else {
94
117
  match (node.next) {
95
118
  None => true,
96
- Some(next) => replaceInBucket(key, value, next)
119
+ Some(next) => replaceInBucket(key, value, next),
97
120
  }
98
121
  }
99
122
  }
100
123
 
124
+ /**
125
+ * Adds a new key-value pair to the map. If the key already exists in the map, the value is replaced.
126
+ *
127
+ * @param key: The unique key in the map
128
+ * @param value: The value to store
129
+ * @param map: The map to modify
130
+ *
131
+ * @since v0.2.0
132
+ */
101
133
  export let set = (key, value, map) => {
102
- let buckets = map.buckets;
134
+ let buckets = map.buckets
103
135
  let idx = getBucketIndex(key, buckets)
104
- let bucket = buckets[idx];
136
+ let bucket = buckets[idx]
105
137
  match (bucket) {
106
138
  None => {
107
- buckets[idx] = Some({ key, value, next: None });
108
- map.size = incr(map.size);
139
+ buckets[idx] = Some({ key, value, next: None })
140
+ map.size = incr(map.size)
109
141
  },
110
142
  Some(node) => {
111
143
  if (replaceInBucket(key, value, node)) {
112
- buckets[idx] = Some({ key, value, next: bucket });
113
- map.size = incr(map.size);
114
- };
115
- }
144
+ buckets[idx] = Some({ key, value, next: bucket })
145
+ map.size = incr(map.size)
146
+ }
147
+ },
116
148
  }
117
149
  // Resize if there are more than 2x the amount of nodes as buckets
118
- if (map.size > (Array.length(buckets) * 2)) {
119
- resize(map);
150
+ if (map.size > Array.length(buckets) * 2) {
151
+ resize(map)
120
152
  } else {
121
153
  void
122
154
  }
@@ -128,18 +160,27 @@ let rec valueFromBucket = (key, node) => {
128
160
  } else {
129
161
  match (node.next) {
130
162
  None => None,
131
- Some(next) => valueFromBucket(key, next)
163
+ Some(next) => valueFromBucket(key, next),
132
164
  }
133
165
  }
134
166
  }
135
167
 
168
+ /**
169
+ * Retrieves the value for the given key.
170
+ *
171
+ * @param key: The key to access
172
+ * @param map: The map to access
173
+ * @returns `Some(value)` if the key exists in the map or `None` otherwise
174
+ *
175
+ * @since v0.2.0
176
+ */
136
177
  export let get = (key, map) => {
137
- let buckets = map.buckets;
138
- let idx = getBucketIndex(key, buckets);
139
- let bucket = buckets[idx];
178
+ let buckets = map.buckets
179
+ let idx = getBucketIndex(key, buckets)
180
+ let bucket = buckets[idx]
140
181
  match (bucket) {
141
182
  None => None,
142
- Some(node) => valueFromBucket(key, node)
183
+ Some(node) => valueFromBucket(key, node),
143
184
  }
144
185
  }
145
186
 
@@ -149,18 +190,27 @@ let rec nodeInBucket = (key, node) => {
149
190
  } else {
150
191
  match (node.next) {
151
192
  None => false,
152
- Some(next) => nodeInBucket(key, next)
193
+ Some(next) => nodeInBucket(key, next),
153
194
  }
154
195
  }
155
196
  }
156
197
 
198
+ /**
199
+ * Determines if the map contains the given key. In such a case, it will always contain a value for the given key.
200
+ *
201
+ * @param key: The key to search for
202
+ * @param map: The map to search
203
+ * @returns `true` if the map contains the given key or `false` otherwise
204
+ *
205
+ * @since v0.2.0
206
+ */
157
207
  export let contains = (key, map) => {
158
- let buckets = map.buckets;
159
- let idx = getBucketIndex(key, buckets);
160
- let bucket = buckets[idx];
208
+ let buckets = map.buckets
209
+ let idx = getBucketIndex(key, buckets)
210
+ let bucket = buckets[idx]
161
211
  match (bucket) {
162
212
  None => false,
163
- Some(node) => nodeInBucket(key, node)
213
+ Some(node) => nodeInBucket(key, node),
164
214
  }
165
215
  }
166
216
 
@@ -169,130 +219,230 @@ let rec removeInBucket = (key, node) => {
169
219
  None => false,
170
220
  Some(next) => {
171
221
  if (key == next.key) {
172
- node.next = next.next;
222
+ node.next = next.next
173
223
  true
174
224
  } else {
175
225
  removeInBucket(key, next)
176
226
  }
177
- }
227
+ },
178
228
  }
179
229
  }
180
230
 
231
+ /**
232
+ * Removes the given key from the map, which also removes the value. If the key pair doesn't exist, nothing happens.
233
+ *
234
+ * @param key: The key to remove
235
+ * @param map: The map to update
236
+ *
237
+ * @since v0.2.0
238
+ */
181
239
  export let remove = (key, map) => {
182
- let buckets = map.buckets;
183
- let idx = getBucketIndex(key, buckets);
184
- let bucket = buckets[idx];
240
+ let buckets = map.buckets
241
+ let idx = getBucketIndex(key, buckets)
242
+ let bucket = buckets[idx]
185
243
  match (bucket) {
186
244
  None => void,
187
245
  Some(node) => {
188
246
  // If it is a top-level node, just replace with next node
189
247
  if (key == node.key) {
190
- map.size = decr(map.size);
191
- buckets[idx] = node.next;
248
+ map.size = decr(map.size)
249
+ buckets[idx] = node.next
192
250
  } else {
193
251
  if (removeInBucket(key, node)) {
194
- map.size = decr(map.size);
252
+ map.size = decr(map.size)
195
253
  }
196
254
  }
197
- }
255
+ },
198
256
  }
199
257
  }
200
258
 
259
+ /**
260
+ * Updates a value in the map by calling an updater function that receives the previously stored value as an `Option` and returns the new value to be stored as an `Option`. If the key didn't exist previously, the value will be `None`. If `None` is returned from the updater function, the key-value pair is removed.
261
+ *
262
+ * @param key: The unique key in the map
263
+ * @param fn: The updater function
264
+ * @param map: The map to modify
265
+ *
266
+ * @since v0.3.0
267
+ */
201
268
  export let update = (key, fn, map) => {
202
- let val = get(key, map);
269
+ let val = get(key, map)
203
270
  match (fn(val)) {
204
271
  Some(next) => set(key, next, map),
205
- None => remove(key, map)
272
+ None => remove(key, map),
206
273
  }
207
274
  }
208
275
 
209
- export let size = (map) => {
276
+ /**
277
+ * Provides the count of key-value pairs stored within the map.
278
+ *
279
+ * @param map: The map to inspect
280
+ * @returns The count of key-value pairs in the map
281
+ *
282
+ * @since v0.2.0
283
+ */
284
+ export let size = map => {
210
285
  map.size
211
286
  }
212
287
 
213
- export let isEmpty = (map) => {
288
+ /**
289
+ * Determines if the map contains no key-value pairs.
290
+ *
291
+ * @param map: The map to inspect
292
+ * @returns `true` if the given map is empty or `false` otherwise
293
+ *
294
+ * @since v0.2.0
295
+ */
296
+ export let isEmpty = map => {
214
297
  size(map) == 0
215
298
  }
216
299
 
217
- export let clear = (map) => {
218
- map.size = 0;
219
- let buckets = map.buckets;
300
+ /**
301
+ * Resets the map by removing all key-value pairs.
302
+ *
303
+ * @param map: The map to reset
304
+ *
305
+ * @since v0.2.0
306
+ */
307
+ export let clear = map => {
308
+ map.size = 0
309
+ let buckets = map.buckets
220
310
  Array.forEachi((bucket, idx) => {
221
- buckets[idx] = None;
222
- }, buckets);
311
+ buckets[idx] = None
312
+ }, buckets)
223
313
  }
224
314
 
225
315
  let rec forEachBucket = (fn, node) => {
226
316
  match (node) {
227
317
  None => void,
228
318
  Some({ key, value, next }) => {
229
- fn(key, value);
230
- forEachBucket(fn, next);
231
- }
319
+ fn(key, value): Void
320
+ forEachBucket(fn, next)
321
+ },
232
322
  }
233
323
  }
234
324
 
325
+ /**
326
+ * Iterates the map, calling an iterator function with each key and value.
327
+ *
328
+ * @param fn: The iterator function to call with each key and value
329
+ * @param map: The map to iterate
330
+ *
331
+ * @since v0.2.0
332
+ * @history v0.5.0: Ensured the iterator function return type is always `Void`
333
+ */
235
334
  export let forEach = (fn, map) => {
236
- let buckets = map.buckets;
237
- Array.forEach((bucket) => {
335
+ let buckets = map.buckets
336
+ Array.forEach(bucket => {
238
337
  forEachBucket(fn, bucket)
239
- }, buckets);
338
+ }, buckets)
240
339
  }
241
340
 
242
341
  let rec reduceEachBucket = (fn, node, acc) => {
243
342
  match (node) {
244
343
  None => acc,
245
344
  Some({ key, value, next }) =>
246
- reduceEachBucket(fn, next, fn(acc, key, value))
345
+ reduceEachBucket(fn, next, fn(acc, key, value)),
247
346
  }
248
347
  }
249
348
 
349
+ /**
350
+ * Combines all key-value pairs of a map using a reducer function.
351
+ *
352
+ * @param fn: The reducer function to call on each key and value, where the value returned will be the next accumulator value
353
+ * @param init: The initial value to use for the accumulator on the first iteration
354
+ * @param map: The map to iterate
355
+ * @returns The final accumulator returned from `fn`
356
+ *
357
+ * @since v0.2.0
358
+ */
250
359
  export let reduce = (fn, init, map) => {
251
- let buckets = map.buckets;
252
- let mut acc = init;
253
- Array.forEach((bucket) => {
360
+ let buckets = map.buckets
361
+ let mut acc = init
362
+ Array.forEach(bucket => {
254
363
  acc = reduceEachBucket(fn, bucket, acc)
255
- }, buckets);
364
+ }, buckets)
256
365
  acc
257
366
  }
258
367
 
259
- export let keys = (map) => {
368
+ /**
369
+ * Enumerates all keys in the given map.
370
+ *
371
+ * @param map: The map to enumerate
372
+ * @returns A list containing all keys from the given map
373
+ *
374
+ * @since v0.2.0
375
+ */
376
+ export let keys = map => {
260
377
  reduce((list, key, _value) => [key, ...list], [], map)
261
378
  }
262
379
 
263
- export let values = (map) => {
380
+ /**
381
+ * Enumerates all values in the given map.
382
+ *
383
+ * @param map: The map to enumerate
384
+ * @returns A list containing all values from the given map
385
+ *
386
+ * @since v0.2.0
387
+ */
388
+ export let values = map => {
264
389
  reduce((list, _key, value) => [value, ...list], [], map)
265
390
  }
266
391
 
267
- export let toList = (map) => {
392
+ /**
393
+ * Enumerates all key-value pairs in the given map.
394
+ *
395
+ * @param map: The map to enumerate
396
+ * @returns A list containing all key-value pairs from the given map
397
+ *
398
+ * @since v0.2.0
399
+ */
400
+ export let toList = map => {
268
401
  reduce((list, key, value) => [(key, value), ...list], [], map)
269
402
  }
270
403
 
271
- export let fromList = (list) => {
272
- let map = make();
273
- List.forEach((pair) => {
274
- let (key, value) = pair;
275
- set(key, value, map);
276
- }, list);
404
+ /**
405
+ * Creates a map from a list.
406
+ *
407
+ * @param list: The list to convert
408
+ * @returns A map containing all key-value pairs from the list
409
+ *
410
+ * @since v0.2.0
411
+ */
412
+ export let fromList = list => {
413
+ let map = make()
414
+ List.forEach(pair => {
415
+ let (key, value) = pair
416
+ set(key, value, map)
417
+ }, list)
277
418
  map
278
419
  }
279
420
 
280
- let setInArray = (array) => {
421
+ let setInArray = array => {
281
422
  @disableGC
282
423
  let rec iter = (i, key, value) => {
283
424
  array[i] = (key, value)
284
425
  // no decRef on key and value, since they are stored in array
285
426
  Memory.decRef(WasmI32.fromGrain(iter))
427
+ Memory.incRef(WasmI32.fromGrain((+)))
428
+ Memory.incRef(WasmI32.fromGrain(i))
286
429
  i + 1
287
430
  }
288
431
  iter
289
432
  }
290
433
 
434
+ /**
435
+ * Converts a map into an array of its key-value pairs.
436
+ *
437
+ * @param map: The map to convert
438
+ * @returns An array containing all key-value pairs from the given map
439
+ *
440
+ * @since v0.2.0
441
+ */
291
442
  @disableGC
292
- export let rec toArray = (map) => {
443
+ export let rec toArray = map => {
293
444
  let length = WasmI32.shrS(WasmI32.fromGrain(map.size), 1n)
294
- // TODO(#783): Removing parens around Array<a> causes a parse error
295
- let array = WasmI32.toGrain(allocateArray(length)): (Array<a>)
445
+ let array = WasmI32.toGrain(allocateArray(length)): Array<a>
296
446
  Memory.incRef(WasmI32.fromGrain(setInArray))
297
447
  Memory.incRef(WasmI32.fromGrain(array))
298
448
  let setInArray = setInArray(array)
@@ -306,33 +456,64 @@ export let rec toArray = (map) => {
306
456
  array
307
457
  }
308
458
 
309
- export let fromArray = (array) => {
310
- let map = make();
311
- Array.forEach((pair) => {
312
- let (key, value) = pair;
313
- set(key, value, map);
314
- }, array);
459
+ /**
460
+ * Creates a map from an array.
461
+ *
462
+ * @param array: The array to convert
463
+ * @returns A map containing all key-value pairs from the array
464
+ *
465
+ * @since v0.2.0
466
+ */
467
+ export let fromArray = array => {
468
+ let map = make()
469
+ Array.forEach(pair => {
470
+ let (key, value) = pair
471
+ set(key, value, map)
472
+ }, array)
315
473
  map
316
474
  }
317
475
 
476
+ /**
477
+ * Removes key-value pairs from a map where a predicate function returns `false`.
478
+ *
479
+ * @param fn: The predicate function to indicate which key-value pairs to remove from the map, where returning `false` indicates the key-value pair should be removed
480
+ * @param map: The map to iterate
481
+ *
482
+ * @since v0.2.0
483
+ */
318
484
  export let filter = (predicate, map) => {
319
- let keysToRemove = reduce((list, key, value) =>
320
- if (!predicate(key, value)) {
321
- [key, ...list]
322
- } else {
323
- list
324
- }, [], map);
325
- List.forEach((key) => {
326
- remove(key, map);
327
- }, keysToRemove);
328
- }
329
-
485
+ let keysToRemove = reduce((list, key, value) => if (!predicate(key, value)) {
486
+ [key, ...list]
487
+ } else {
488
+ list
489
+ }, [], map)
490
+ List.forEach(key => {
491
+ remove(key, map)
492
+ }, keysToRemove)
493
+ }
494
+
495
+ /**
496
+ * Removes key-value pairs from a map where a predicate function returns `true`.
497
+ *
498
+ * @param fn: The predicate function to indicate which key-value pairs to remove from the map, where returning `true` indicates the key-value pair should be removed
499
+ * @param map: The map to iterate
500
+ *
501
+ * @since v0.2.0
502
+ */
330
503
  export let reject = (predicate, map) => {
331
504
  filter((key, value) => !predicate(key, value), map)
332
505
  }
333
506
 
334
507
  // TODO: Should return a Record type instead of a Tuple
335
508
  // Waiting on https://github.com/grain-lang/grain/issues/190
336
- export let getInternalStats = (map) => {
509
+ /**
510
+ * Provides data representing the internal state state of the map.
511
+ *
512
+ * @param map: The map to inspect
513
+ * @returns The internal state of the map
514
+ *
515
+ * @since v0.2.0
516
+ */
517
+ export let getInternalStats = map => {
337
518
  (map.size, Array.length(map.buckets))
338
519
  }