@grain/stdlib 0.4.2 → 0.4.6

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 (61) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +1 -1
  3. package/array.gr +200 -89
  4. package/array.md +81 -5
  5. package/buffer.gr +93 -36
  6. package/bytes.gr +10 -10
  7. package/char.gr +112 -56
  8. package/char.md +200 -0
  9. package/float32.gr +120 -4
  10. package/float32.md +315 -0
  11. package/float64.gr +120 -4
  12. package/float64.md +315 -0
  13. package/hash.gr +42 -15
  14. package/hash.md +44 -0
  15. package/int32.gr +370 -75
  16. package/int32.md +833 -0
  17. package/int64.gr +370 -75
  18. package/int64.md +833 -0
  19. package/list.gr +121 -50
  20. package/map.gr +106 -110
  21. package/number.gr +37 -1
  22. package/number.md +66 -0
  23. package/option.gr +260 -53
  24. package/option.md +579 -0
  25. package/package.json +1 -1
  26. package/pervasives.gr +32 -20
  27. package/queue.gr +102 -30
  28. package/queue.md +191 -0
  29. package/range.gr +26 -26
  30. package/range.md +1 -1
  31. package/regex.md +9 -9
  32. package/result.gr +216 -70
  33. package/result.md +446 -0
  34. package/runtime/dataStructures.gr +28 -29
  35. package/runtime/debug.gr +0 -1
  36. package/runtime/equal.gr +37 -16
  37. package/runtime/exception.gr +28 -15
  38. package/runtime/gc.gr +33 -20
  39. package/runtime/malloc.gr +19 -11
  40. package/runtime/numberUtils.gr +208 -103
  41. package/runtime/numbers.gr +217 -118
  42. package/runtime/string.gr +98 -39
  43. package/runtime/stringUtils.gr +176 -0
  44. package/runtime/unsafe/conv.gr +10 -10
  45. package/runtime/unsafe/memory.gr +14 -3
  46. package/runtime/unsafe/printWasm.gr +4 -4
  47. package/runtime/unsafe/tags.gr +2 -2
  48. package/runtime/unsafe/wasmf32.gr +9 -2
  49. package/runtime/unsafe/wasmf64.gr +9 -2
  50. package/runtime/unsafe/wasmi32.gr +65 -47
  51. package/runtime/unsafe/wasmi64.gr +78 -50
  52. package/runtime/wasi.gr +199 -45
  53. package/set.gr +281 -119
  54. package/set.md +502 -0
  55. package/stack.gr +26 -26
  56. package/string.gr +657 -341
  57. package/string.md +815 -0
  58. package/sys/file.gr +356 -177
  59. package/sys/process.gr +10 -6
  60. package/sys/random.gr +3 -6
  61. package/sys/time.gr +3 -3
package/set.gr CHANGED
@@ -1,35 +1,50 @@
1
- // Standard library for Set functionality
2
-
1
+ /**
2
+ * @module Set: 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
+ * @example import Set from "set"
4
+ *
5
+ * @since 0.3.0
6
+ */
3
7
  import List from "list"
4
8
  import Array from "array"
5
9
  import { hash } from "hash"
6
10
 
7
11
  record Bucket<t> {
8
12
  mut key: t,
9
- mut next: Option<Bucket<t>>
13
+ mut next: Option<Bucket<t>>,
10
14
  }
11
15
 
12
16
  record Set<k> {
13
17
  mut size: Number,
14
- mut buckets: Array<Option<Bucket<k>>>
18
+ mut buckets: Array<Option<Bucket<k>>>,
15
19
  }
16
20
 
17
21
  // TODO: This could take an `eq` function to custom comparisons
18
- export let makeSized = (size) => {
19
- let buckets = Array.make(size, None);
20
- {
21
- size: 0,
22
- buckets
23
- }
22
+ /**
23
+ * Creates a new empty set with an initial storage of the given length. As values are added or removed, the length may grow or shrink. Generally, you won't need to care about the length of your set and can use `Set.make()` instead.
24
+ *
25
+ * @param storageLength: The initial storage length of the set
26
+ * @returns An empty set with the given initial storage length
27
+ *
28
+ * @since 0.3.0
29
+ */
30
+ export let makeSized = storageLength => {
31
+ let buckets = Array.make(storageLength, None)
32
+ { size: 0, buckets }
24
33
  }
25
-
34
+ /**
35
+ * Creates a new, empty set.
36
+ *
37
+ * @returns An empty set
38
+ *
39
+ * @since 0.3.0
40
+ */
26
41
  export let make = () => {
27
42
  makeSized(16)
28
43
  }
29
44
 
30
45
  let getBucketIndex = (key, buckets) => {
31
- let bucketsLength = Array.length(buckets);
32
- let hashedKey = hash(key);
46
+ let bucketsLength = Array.length(buckets)
47
+ let hashedKey = hash(key)
33
48
  hashedKey % bucketsLength
34
49
  }
35
50
 
@@ -37,45 +52,45 @@ let rec copyNodeWithNewHash = (oldNode, next, tail) => {
37
52
  match (oldNode) {
38
53
  None => void,
39
54
  Some(node) => {
40
- let idx = getBucketIndex(node.key, next);
41
- let newNode = Some(node);
55
+ let idx = getBucketIndex(node.key, next)
56
+ let newNode = Some(node)
42
57
  match (tail[idx]) {
43
58
  None => {
44
- next[idx] = newNode;
59
+ next[idx] = newNode
45
60
  },
46
61
  Some(tailNode) => {
47
62
  // If there's already a tail node, we add this to the end
48
- tailNode.next = newNode;
49
- }
63
+ tailNode.next = newNode
64
+ },
50
65
  }
51
66
  // Always place this node as the new tail
52
- tail[idx] = newNode;
67
+ tail[idx] = newNode
53
68
  // Recurse with the next node
54
- copyNodeWithNewHash(node.next, next, tail);
55
- }
69
+ copyNodeWithNewHash(node.next, next, tail)
70
+ },
56
71
  }
57
72
  }
58
73
 
59
- let resize = (set) => {
60
- let currentBuckets = set.buckets;
61
- let currentSize = Array.length(currentBuckets);
62
- let nextSize = currentSize * 2;
74
+ let resize = set => {
75
+ let currentBuckets = set.buckets
76
+ let currentSize = Array.length(currentBuckets)
77
+ let nextSize = currentSize * 2
63
78
  if (nextSize >= currentSize) {
64
- let nextBuckets = Array.make(nextSize, None);
79
+ let nextBuckets = Array.make(nextSize, None)
65
80
  // This tracks the tail nodes so we can set their `next` to None
66
- let tailNodes = Array.make(nextSize, None);
67
- set.buckets = nextBuckets;
68
- Array.forEach((old) => {
69
- copyNodeWithNewHash(old, nextBuckets, tailNodes);
70
- }, currentBuckets);
71
- Array.forEach((tail) => {
81
+ let tailNodes = Array.make(nextSize, None)
82
+ set.buckets = nextBuckets
83
+ Array.forEach(old => {
84
+ copyNodeWithNewHash(old, nextBuckets, tailNodes)
85
+ }, currentBuckets)
86
+ Array.forEach(tail => {
72
87
  match (tail) {
73
88
  None => void,
74
89
  Some(node) => {
75
- node.next = None;
76
- }
90
+ node.next = None
91
+ },
77
92
  }
78
- }, tailNodes);
93
+ }, tailNodes)
79
94
  } else {
80
95
  void
81
96
  }
@@ -87,42 +102,59 @@ let rec nodeInBucket = (key, node) => {
87
102
  } else {
88
103
  match (node.next) {
89
104
  None => false,
90
- Some(next) => nodeInBucket(key, next)
105
+ Some(next) => nodeInBucket(key, next),
91
106
  }
92
107
  }
93
108
  }
94
109
 
110
+ /**
111
+ * Adds a new value to the set. If the value already exists, nothing happens.
112
+ *
113
+ * @param key: The value to add
114
+ * @param set: The set to update
115
+ *
116
+ * @since 0.3.0
117
+ */
95
118
  export let add = (key, set) => {
96
- let buckets = set.buckets;
119
+ let buckets = set.buckets
97
120
  let idx = getBucketIndex(key, buckets)
98
- let bucket = buckets[idx];
121
+ let bucket = buckets[idx]
99
122
  match (bucket) {
100
123
  None => {
101
- buckets[idx] = Some({ key, next: None });
102
- set.size = incr(set.size);
124
+ buckets[idx] = Some({ key, next: None })
125
+ set.size = incr(set.size)
103
126
  },
104
127
  Some(node) => {
105
128
  if (!nodeInBucket(key, node)) {
106
- buckets[idx] = Some({ key, next: bucket });
107
- set.size = incr(set.size);
108
- };
109
- }
129
+ buckets[idx] = Some({ key, next: bucket })
130
+ set.size = incr(set.size)
131
+ }
132
+ },
110
133
  }
111
134
  // Resize if there are more than 2x the amount of nodes as buckets
112
- if (set.size > (Array.length(buckets) * 2)) {
113
- resize(set);
135
+ if (set.size > Array.length(buckets) * 2) {
136
+ resize(set)
114
137
  } else {
115
138
  void
116
139
  }
117
140
  }
118
141
 
142
+ /**
143
+ * Determines if the set contains the given value.
144
+ *
145
+ * @param key: The value to search for
146
+ * @param set: The set to search
147
+ * @returns `true` if the set contains the given value or `false` otherwise
148
+ *
149
+ * @since 0.3.0
150
+ */
119
151
  export let contains = (key, set) => {
120
- let buckets = set.buckets;
121
- let idx = getBucketIndex(key, buckets);
122
- let bucket = buckets[idx];
152
+ let buckets = set.buckets
153
+ let idx = getBucketIndex(key, buckets)
154
+ let bucket = buckets[idx]
123
155
  match (bucket) {
124
156
  None => false,
125
- Some(node) => nodeInBucket(key, node)
157
+ Some(node) => nodeInBucket(key, node),
126
158
  }
127
159
  }
128
160
 
@@ -131,168 +163,298 @@ let rec removeInBucket = (key, node) => {
131
163
  None => false,
132
164
  Some(next) => {
133
165
  if (key == next.key) {
134
- node.next = next.next;
166
+ node.next = next.next
135
167
  true
136
168
  } else {
137
169
  removeInBucket(key, next)
138
170
  }
139
- }
171
+ },
140
172
  }
141
173
  }
142
174
 
175
+ /**
176
+ * Removes the given value from the set. If the value doesn't exist, nothing happens.
177
+ *
178
+ * @param key: The value to remove
179
+ * @param set: The set to update
180
+ *
181
+ * @since 0.3.0
182
+ */
143
183
  export let remove = (key, set) => {
144
- let buckets = set.buckets;
145
- let idx = getBucketIndex(key, buckets);
146
- let bucket = buckets[idx];
184
+ let buckets = set.buckets
185
+ let idx = getBucketIndex(key, buckets)
186
+ let bucket = buckets[idx]
147
187
  match (bucket) {
148
188
  None => void,
149
189
  Some(node) => {
150
190
  // If it is a top-level node, just replace with next node
151
191
  if (key == node.key) {
152
- set.size = decr(set.size);
153
- buckets[idx] = node.next;
192
+ set.size = decr(set.size)
193
+ buckets[idx] = node.next
154
194
  } else {
155
195
  if (removeInBucket(key, node)) {
156
- set.size = decr(set.size);
196
+ set.size = decr(set.size)
157
197
  }
158
198
  }
159
- }
199
+ },
160
200
  }
161
201
  }
162
202
 
163
- export let size = (set) => {
203
+ /**
204
+ * Returns the number of values within the set.
205
+ *
206
+ * @param set: The set to inspect
207
+ * @returns The number of elements in the set
208
+ *
209
+ * @since 0.3.0
210
+ */
211
+ export let size = set => {
164
212
  set.size
165
213
  }
166
214
 
167
- export let isEmpty = (set) => {
215
+ /**
216
+ * Determines if the set contains no elements.
217
+ *
218
+ * @param set: The set to inspect
219
+ * @returns `true` if the given set is empty or `false` otherwise
220
+ *
221
+ * @since 0.3.0
222
+ */
223
+ export let isEmpty = set => {
168
224
  size(set) == 0
169
225
  }
170
226
 
171
- export let clear = (set) => {
172
- set.size = 0;
173
- let buckets = set.buckets;
227
+ /**
228
+ * Resets the set by removing all values.
229
+ *
230
+ * @param set: The set to reset
231
+ *
232
+ * @since 0.3.0
233
+ */
234
+ export let clear = set => {
235
+ set.size = 0
236
+ let buckets = set.buckets
174
237
  Array.forEachi((bucket, idx) => {
175
- buckets[idx] = None;
176
- }, buckets);
238
+ buckets[idx] = None
239
+ }, buckets)
177
240
  }
178
241
 
179
242
  let rec forEachBucket = (fn, node) => {
180
243
  match (node) {
181
244
  None => void,
182
245
  Some({ key, next }) => {
183
- fn(key);
184
- forEachBucket(fn, next);
185
- }
246
+ fn(key)
247
+ forEachBucket(fn, next)
248
+ },
186
249
  }
187
250
  }
188
251
 
252
+ /**
253
+ * Iterates the set, calling an iterator function on each element.
254
+ *
255
+ * @param fn: The iterator function to call with each element
256
+ * @param set: The set to iterate
257
+ *
258
+ * @since 0.3.0
259
+ */
189
260
  export let forEach = (fn, set) => {
190
- let buckets = set.buckets;
191
- Array.forEach((bucket) => {
261
+ let buckets = set.buckets
262
+ Array.forEach(bucket => {
192
263
  forEachBucket(fn, bucket)
193
- }, buckets);
264
+ }, buckets)
194
265
  }
195
266
 
196
267
  let rec reduceEachBucket = (fn, node, acc) => {
197
268
  match (node) {
198
269
  None => acc,
199
- Some({ key, next }) =>
200
- reduceEachBucket(fn, next, fn(acc, key))
270
+ Some({ key, next }) => reduceEachBucket(fn, next, fn(acc, key)),
201
271
  }
202
272
  }
203
273
 
274
+ /**
275
+ * Combines all elements of a set using a reducer function.
276
+ *
277
+ * @param fn: The reducer function to call on each element, where the value returned will be the next accumulator value
278
+ * @param init: The initial value to use for the accumulator on the first iteration
279
+ * @param set: The set to iterate
280
+ * @returns The final accumulator returned from `fn`
281
+ *
282
+ * @since 0.3.0
283
+ */
204
284
  export let reduce = (fn, init, set) => {
205
- let buckets = set.buckets;
206
- let mut acc = init;
207
- Array.forEach((bucket) => {
285
+ let buckets = set.buckets
286
+ let mut acc = init
287
+ Array.forEach(bucket => {
208
288
  acc = reduceEachBucket(fn, bucket, acc)
209
- }, buckets);
289
+ }, buckets)
210
290
  acc
211
291
  }
212
292
 
293
+ /**
294
+ * Removes elements from a set where a predicate function returns `false`.
295
+ *
296
+ * @param fn: The predicate function to indicate which elements to remove from the set, where returning `false` indicates the value should be removed
297
+ * @param set: The set to iterate
298
+ *
299
+ * @since 0.3.0
300
+ */
213
301
  export let filter = (predicate, set) => {
214
- let keysToRemove = reduce((list, key) =>
215
- if (!predicate(key)) {
216
- [key, ...list]
217
- } else {
218
- list
219
- }, [], set);
220
- List.forEach((key) => {
221
- remove(key, set);
222
- }, keysToRemove);
302
+ let keysToRemove = reduce((list, key) => if (!predicate(key)) {
303
+ [key, ...list]
304
+ } else {
305
+ list
306
+ }, [], set)
307
+ List.forEach(key => {
308
+ remove(key, set)
309
+ }, keysToRemove)
223
310
  }
224
311
 
312
+ /**
313
+ * Removes elements from a set where a predicate function returns `true`.
314
+ *
315
+ * @param fn: The predicate function to indicate which elements to remove from the set, where returning `true` indicates the value should be removed
316
+ * @param set: The set to iterate
317
+ *
318
+ * @since 0.3.0
319
+ */
225
320
  export let reject = (predicate, set) => {
226
- filter((key) => !predicate(key), set)
321
+ filter(key => !predicate(key), set)
227
322
  }
228
323
 
229
- export let toList = (set) => {
324
+ /**
325
+ * Converts a set into a list of its elements.
326
+ *
327
+ * @param set: The set to convert
328
+ * @returns A list containing all set values
329
+ *
330
+ * @since 0.3.0
331
+ */
332
+ export let toList = set => {
230
333
  reduce((list, key) => [key, ...list], [], set)
231
334
  }
232
335
 
233
- export let fromList = (list) => {
234
- let set = make();
235
- List.forEach((key) => {
236
- add(key, set);
237
- }, list);
336
+ /**
337
+ * Creates a set from a list.
338
+ *
339
+ * @param list: The list to convert
340
+ * @returns A set containing all list values
341
+ *
342
+ * @since 0.3.0
343
+ */
344
+ export let fromList = list => {
345
+ let set = make()
346
+ List.forEach(key => {
347
+ add(key, set)
348
+ }, list)
238
349
  set
239
350
  }
240
351
 
241
- export let toArray = (set) => {
352
+ /**
353
+ * Converts a set into an array of its elements.
354
+ *
355
+ * @param set: The set to convert
356
+ * @returns An array containing all set values
357
+ *
358
+ * @since 0.3.0
359
+ */
360
+ export let toArray = set => {
242
361
  Array.fromList(toList(set))
243
362
  }
244
363
 
245
- export let fromArray = (array) => {
246
- let set = make();
247
- Array.forEach((key) => {
248
- add(key, set);
249
- }, array);
364
+ /**
365
+ * Creates a set from an array.
366
+ *
367
+ * @param array: The array to convert
368
+ * @returns A set containing all array values
369
+ *
370
+ * @since 0.3.0
371
+ */
372
+ export let fromArray = array => {
373
+ let set = make()
374
+ Array.forEach(key => {
375
+ add(key, set)
376
+ }, array)
250
377
  set
251
378
  }
252
379
 
380
+ /**
381
+ * Combines two sets into a single set containing all elements from both sets.
382
+ *
383
+ * @param set1: The first set to combine
384
+ * @param set2: The second set to combine
385
+ * @returns A set containing all elements of both sets
386
+ *
387
+ * @since 0.3.0
388
+ */
253
389
  export let union = (set1, set2) => {
254
- let set = make();
255
- forEach((key) => {
256
- add(key, set);
390
+ let set = make()
391
+ forEach(key => {
392
+ add(key, set)
257
393
  }, set1)
258
- forEach((key) => {
259
- add(key, set);
260
- }, set2);
394
+ forEach(key => {
395
+ add(key, set)
396
+ }, set2)
261
397
  set
262
398
  }
263
399
 
400
+ /**
401
+ * Combines two sets into a single set containing only the elements not shared between both sets.
402
+ *
403
+ * @param set1: The first set to combine
404
+ * @param set2: The second set to combine
405
+ * @returns A set containing only unshared elements from both sets
406
+ *
407
+ * @since 0.3.0
408
+ */
264
409
  export let diff = (set1, set2) => {
265
- let set = make();
266
- forEach((key) => {
410
+ let set = make()
411
+ forEach(key => {
267
412
  if (!contains(key, set2)) {
268
- add(key, set);
413
+ add(key, set)
269
414
  }
270
415
  }, set1)
271
- forEach((key) => {
416
+ forEach(key => {
272
417
  if (!contains(key, set1)) {
273
- add(key, set);
418
+ add(key, set)
274
419
  }
275
- }, set2);
420
+ }, set2)
276
421
  set
277
422
  }
278
423
 
424
+ /**
425
+ * Combines two sets into a single set containing only the elements shared between both sets.
426
+ *
427
+ * @param set1: The first set to combine
428
+ * @param set2: The second set to combine
429
+ * @returns A set containing only shared elements from both sets
430
+ *
431
+ * @since 0.3.0
432
+ */
279
433
  export let intersect = (set1, set2) => {
280
- let set = make();
281
- forEach((key) => {
434
+ let set = make()
435
+ forEach(key => {
282
436
  if (contains(key, set2)) {
283
- add(key, set);
437
+ add(key, set)
284
438
  }
285
439
  }, set1)
286
- forEach((key) => {
440
+ forEach(key => {
287
441
  if (contains(key, set1)) {
288
- add(key, set);
442
+ add(key, set)
289
443
  }
290
- }, set2);
444
+ }, set2)
291
445
  set
292
446
  }
293
447
 
294
448
  // TODO: Should return a Record type instead of a Tuple
295
449
  // Waiting on https://github.com/grain-lang/grain/issues/190
296
- export let getInternalStats = (set) => {
450
+ /**
451
+ * Provides data representing the internal state state of the set.
452
+ *
453
+ * @param set: The set to inspect
454
+ * @returns The internal state of the set
455
+ *
456
+ * @since 0.3.0
457
+ */
458
+ export let getInternalStats = set => {
297
459
  (set.size, Array.length(set.buckets))
298
460
  }