@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.
- package/CHANGELOG.md +87 -0
- package/LICENSE +1 -1
- package/array.gr +92 -73
- package/array.md +18 -18
- package/bigint.gr +497 -0
- package/bigint.md +811 -0
- package/buffer.gr +56 -217
- package/buffer.md +24 -17
- package/bytes.gr +103 -205
- package/bytes.md +19 -0
- package/char.gr +152 -166
- package/char.md +200 -0
- package/exception.md +6 -0
- package/float32.gr +159 -82
- package/float32.md +315 -0
- package/float64.gr +163 -82
- package/float64.md +315 -0
- package/hash.gr +53 -49
- package/int32.gr +479 -230
- package/int32.md +937 -0
- package/int64.gr +479 -230
- package/int64.md +937 -0
- package/list.gr +530 -116
- package/list.md +1141 -0
- package/map.gr +302 -121
- package/map.md +525 -0
- package/number.gr +51 -57
- package/number.md +37 -3
- package/option.gr +25 -25
- package/option.md +1 -1
- package/package.json +3 -3
- package/pervasives.gr +504 -52
- package/pervasives.md +1116 -0
- package/queue.gr +8 -1
- package/queue.md +10 -0
- package/random.gr +196 -0
- package/random.md +179 -0
- package/range.gr +26 -26
- package/regex.gr +1833 -842
- package/regex.md +11 -11
- package/result.md +1 -1
- package/runtime/bigint.gr +2045 -0
- package/runtime/bigint.md +326 -0
- package/runtime/dataStructures.gr +99 -279
- package/runtime/dataStructures.md +391 -0
- package/runtime/debug.gr +0 -1
- package/runtime/debug.md +6 -0
- package/runtime/equal.gr +40 -37
- package/runtime/equal.md +6 -0
- package/runtime/exception.gr +28 -15
- package/runtime/exception.md +30 -0
- package/runtime/gc.gr +50 -20
- package/runtime/gc.md +36 -0
- package/runtime/malloc.gr +32 -22
- package/runtime/malloc.md +55 -0
- package/runtime/numberUtils.gr +297 -142
- package/runtime/numberUtils.md +54 -0
- package/runtime/numbers.gr +1204 -453
- package/runtime/numbers.md +300 -0
- package/runtime/string.gr +193 -228
- package/runtime/string.md +24 -0
- package/runtime/stringUtils.gr +62 -38
- package/runtime/stringUtils.md +6 -0
- package/runtime/unsafe/constants.gr +17 -0
- package/runtime/unsafe/constants.md +72 -0
- package/runtime/unsafe/conv.gr +10 -10
- package/runtime/unsafe/conv.md +71 -0
- package/runtime/unsafe/errors.md +204 -0
- package/runtime/unsafe/memory.gr +14 -3
- package/runtime/unsafe/memory.md +54 -0
- package/runtime/unsafe/printWasm.gr +4 -4
- package/runtime/unsafe/printWasm.md +24 -0
- package/runtime/unsafe/tags.gr +11 -10
- package/runtime/unsafe/tags.md +120 -0
- package/runtime/unsafe/wasmf32.gr +9 -2
- package/runtime/unsafe/wasmf32.md +168 -0
- package/runtime/unsafe/wasmf64.gr +9 -2
- package/runtime/unsafe/wasmf64.md +168 -0
- package/runtime/unsafe/wasmi32.gr +65 -47
- package/runtime/unsafe/wasmi32.md +282 -0
- package/runtime/unsafe/wasmi64.gr +78 -50
- package/runtime/unsafe/wasmi64.md +300 -0
- package/runtime/utils/printing.gr +62 -0
- package/runtime/utils/printing.md +18 -0
- package/runtime/wasi.gr +200 -46
- package/runtime/wasi.md +839 -0
- package/set.gr +125 -121
- package/set.md +24 -21
- package/stack.gr +29 -29
- package/stack.md +4 -6
- package/string.gr +434 -415
- package/string.md +3 -3
- package/sys/file.gr +477 -482
- package/sys/process.gr +33 -47
- package/sys/random.gr +48 -20
- package/sys/random.md +38 -0
- package/sys/time.gr +12 -28
package/map.gr
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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 =
|
|
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(
|
|
74
|
-
copyNodeWithNewHash(old, nextBuckets, tailNodes)
|
|
75
|
-
}, currentBuckets)
|
|
76
|
-
Array.forEach(
|
|
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 >
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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 =
|
|
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 =
|
|
443
|
+
export let rec toArray = map => {
|
|
293
444
|
let length = WasmI32.shrS(WasmI32.fromGrain(map.size), 1n)
|
|
294
|
-
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
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
|
}
|