@grain/stdlib 0.6.5 → 0.7.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 +64 -0
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/array.gr +55 -7
- package/array.md +123 -77
- package/bigint.md +30 -30
- package/buffer.gr +20 -53
- package/buffer.md +47 -47
- package/bytes.gr +111 -35
- package/bytes.md +111 -32
- package/char.gr +201 -99
- package/char.md +361 -34
- package/exception.gr +11 -11
- package/exception.md +26 -1
- package/float32.gr +327 -3
- package/float32.md +606 -19
- package/float64.gr +320 -3
- package/float64.md +606 -19
- package/fs.gr +1082 -0
- package/fs.md +630 -0
- package/hash.gr +142 -88
- package/hash.md +102 -14
- package/int16.md +23 -23
- package/int32.gr +25 -4
- package/int32.md +65 -30
- package/int64.gr +26 -1
- package/int64.md +65 -30
- package/int8.md +23 -23
- package/json.gr +366 -51
- package/json.md +418 -2
- package/list.gr +387 -49
- package/list.md +492 -69
- package/map.gr +20 -12
- package/map.md +44 -38
- package/marshal.gr +41 -40
- package/marshal.md +2 -2
- package/number.gr +159 -30
- package/number.md +215 -38
- package/option.md +21 -21
- package/package.json +5 -3
- package/path.gr +48 -0
- package/path.md +103 -12
- package/pervasives.gr +2 -2
- package/pervasives.md +37 -37
- package/priorityqueue.gr +7 -7
- package/priorityqueue.md +19 -19
- package/queue.gr +183 -29
- package/queue.md +296 -40
- package/random.md +6 -6
- package/range.gr +4 -4
- package/range.md +6 -6
- package/rational.md +16 -16
- package/regex.gr +52 -51
- package/regex.md +11 -11
- package/result.md +16 -16
- package/runtime/atof/common.md +39 -39
- package/runtime/atof/decimal.gr +6 -6
- package/runtime/atof/decimal.md +8 -8
- package/runtime/atof/lemire.gr +5 -5
- package/runtime/atof/lemire.md +1 -1
- package/runtime/atof/parse.gr +16 -16
- package/runtime/atof/parse.md +2 -2
- package/runtime/atof/slow.md +1 -1
- package/runtime/atof/table.md +2 -2
- package/runtime/atoi/parse.gr +3 -3
- package/runtime/atoi/parse.md +1 -1
- package/runtime/bigint.gr +15 -47
- package/runtime/bigint.md +54 -60
- package/runtime/compare.gr +2 -2
- package/runtime/compare.md +1 -1
- package/runtime/dataStructures.md +33 -33
- package/runtime/debugPrint.gr +4 -1
- package/runtime/debugPrint.md +9 -9
- package/runtime/equal.gr +99 -77
- package/runtime/equal.md +1 -1
- package/runtime/exception.gr +62 -82
- package/runtime/exception.md +62 -11
- package/runtime/gc.gr +39 -45
- package/runtime/gc.md +4 -4
- package/runtime/malloc.gr +7 -7
- package/runtime/malloc.md +4 -4
- package/runtime/math/kernel/cos.gr +70 -0
- package/runtime/math/kernel/cos.md +14 -0
- package/runtime/math/kernel/sin.gr +65 -0
- package/runtime/math/kernel/sin.md +14 -0
- package/runtime/math/kernel/tan.gr +136 -0
- package/runtime/math/kernel/tan.md +14 -0
- package/runtime/math/rempio2.gr +244 -0
- package/runtime/math/rempio2.md +14 -0
- package/runtime/math/trig.gr +130 -0
- package/runtime/math/trig.md +28 -0
- package/runtime/math/umuldi.gr +26 -0
- package/runtime/math/umuldi.md +14 -0
- package/runtime/numberUtils.gr +29 -29
- package/runtime/numberUtils.md +12 -12
- package/runtime/numbers.gr +373 -381
- package/runtime/numbers.md +79 -73
- package/runtime/string.gr +37 -105
- package/runtime/string.md +3 -9
- package/runtime/unsafe/constants.md +24 -24
- package/runtime/unsafe/conv.md +13 -13
- package/runtime/unsafe/memory.gr +24 -20
- package/runtime/unsafe/memory.md +27 -7
- package/runtime/unsafe/offsets.gr +36 -0
- package/runtime/unsafe/offsets.md +88 -0
- package/runtime/unsafe/panic.gr +28 -0
- package/runtime/unsafe/panic.md +14 -0
- package/runtime/unsafe/tags.md +32 -32
- package/runtime/unsafe/wasmf32.md +28 -28
- package/runtime/unsafe/wasmf64.md +28 -28
- package/runtime/unsafe/wasmi32.md +47 -47
- package/runtime/unsafe/wasmi64.md +50 -50
- package/runtime/utf8.gr +189 -0
- package/runtime/utf8.md +117 -0
- package/runtime/wasi.gr +4 -2
- package/runtime/wasi.md +138 -138
- package/set.gr +18 -11
- package/set.md +42 -36
- package/stack.gr +171 -2
- package/stack.md +297 -15
- package/string.gr +352 -557
- package/string.md +77 -34
- package/uint16.gr +81 -0
- package/uint16.md +183 -22
- package/uint32.gr +25 -4
- package/uint32.md +63 -28
- package/uint64.gr +25 -5
- package/uint64.md +63 -28
- package/uint8.gr +81 -0
- package/uint8.md +183 -22
- package/uri.gr +57 -53
- package/uri.md +11 -12
- package/wasi/file.gr +67 -59
- package/wasi/file.md +39 -39
- package/wasi/process.md +5 -5
- package/wasi/random.md +3 -3
- package/wasi/time.md +4 -4
- package/runtime/utils/printing.gr +0 -60
- package/runtime/utils/printing.md +0 -26
package/list.gr
CHANGED
|
@@ -9,6 +9,28 @@
|
|
|
9
9
|
*/
|
|
10
10
|
module List
|
|
11
11
|
|
|
12
|
+
from "runtime/unsafe/memory" include Memory
|
|
13
|
+
from "runtime/unsafe/wasmi32" include WasmI32
|
|
14
|
+
from "runtime/dataStructures" include DataStructures
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new list with all elements in reverse order.
|
|
18
|
+
*
|
|
19
|
+
* @param list: The list to reverse
|
|
20
|
+
* @returns The new list
|
|
21
|
+
*
|
|
22
|
+
* @since v0.1.0
|
|
23
|
+
*/
|
|
24
|
+
provide let reverse = list => {
|
|
25
|
+
let rec revHelp = (list, acc) => {
|
|
26
|
+
match (list) {
|
|
27
|
+
[] => acc,
|
|
28
|
+
[first, ...rest] => revHelp(rest, [first, ...acc]),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
revHelp(list, [])
|
|
32
|
+
}
|
|
33
|
+
|
|
12
34
|
/**
|
|
13
35
|
* Creates a new list of the specified length where each element is
|
|
14
36
|
* initialized with the result of an initializer function. The initializer
|
|
@@ -23,17 +45,18 @@ module List
|
|
|
23
45
|
* @since v0.3.0
|
|
24
46
|
*/
|
|
25
47
|
provide let init = (length, fn) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (idx >= length) {
|
|
31
|
-
[]
|
|
32
|
-
} else {
|
|
33
|
-
[fn(idx), ...iter(idx + 1, length)]
|
|
48
|
+
if (length < 2048) {
|
|
49
|
+
// For small lists, use a faster non-tail-recursive version
|
|
50
|
+
let rec iter = (idx, length) => {
|
|
51
|
+
if (idx >= length) [] else [fn(idx), ...iter(idx + 1, length)]
|
|
34
52
|
}
|
|
53
|
+
iter(0, length)
|
|
54
|
+
} else {
|
|
55
|
+
let rec iter = (idx, length, acc) => {
|
|
56
|
+
if (idx >= length) acc else iter(idx + 1, length, [fn(idx), ...acc])
|
|
57
|
+
}
|
|
58
|
+
reverse(iter(0, length, []))
|
|
35
59
|
}
|
|
36
|
-
iter(0, length)
|
|
37
60
|
}
|
|
38
61
|
|
|
39
62
|
/**
|
|
@@ -70,24 +93,6 @@ provide let isEmpty = list => {
|
|
|
70
93
|
}
|
|
71
94
|
}
|
|
72
95
|
|
|
73
|
-
/**
|
|
74
|
-
* Creates a new list with all elements in reverse order.
|
|
75
|
-
*
|
|
76
|
-
* @param list: The list to reverse
|
|
77
|
-
* @returns The new list
|
|
78
|
-
*
|
|
79
|
-
* @since v0.1.0
|
|
80
|
-
*/
|
|
81
|
-
provide let reverse = list => {
|
|
82
|
-
let rec iter = (list, acc) => {
|
|
83
|
-
match (list) {
|
|
84
|
-
[] => acc,
|
|
85
|
-
[first, ...rest] => iter(rest, [first, ...acc]),
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
iter(list, [])
|
|
89
|
-
}
|
|
90
|
-
|
|
91
96
|
/**
|
|
92
97
|
* Creates a new list with the elements of the first list followed by
|
|
93
98
|
* the elements of the second list.
|
|
@@ -213,6 +218,56 @@ provide let mapi = (fn, list) => {
|
|
|
213
218
|
iter(fn, list, 0)
|
|
214
219
|
}
|
|
215
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Produces a new list initialized with the results of a mapper function
|
|
223
|
+
* called on each element of the input list.
|
|
224
|
+
* The mapper function can return `None` to exclude the element from the new list.
|
|
225
|
+
*
|
|
226
|
+
* @param fn: The mapper function to call on each element, where the value returned will be used to initialize the element in the new list
|
|
227
|
+
* @param list: The list to iterate
|
|
228
|
+
* @returns The new list with filtered mapped values
|
|
229
|
+
*
|
|
230
|
+
* @example List.filterMap(x => if (x % 2 == 0) Some(toString(x)) else None, [1, 2, 3, 4]) == ["2", "4"]
|
|
231
|
+
*
|
|
232
|
+
* @since v0.7.0
|
|
233
|
+
*/
|
|
234
|
+
provide let rec filterMap = (fn, list) => {
|
|
235
|
+
match (list) {
|
|
236
|
+
[] => [],
|
|
237
|
+
[first, ...rest] => match (fn(first)) {
|
|
238
|
+
Some(v) => [v, ...filterMap(fn, rest)],
|
|
239
|
+
None => filterMap(fn, rest),
|
|
240
|
+
},
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Produces a new list initialized with the results of a mapper function
|
|
246
|
+
* called on each element of the input list and its index.
|
|
247
|
+
* The mapper function can return `None` to exclude the element from the new list.
|
|
248
|
+
*
|
|
249
|
+
* @param fn: The mapper function to call on each element, where the value returned will be used to initialize the element in the new list
|
|
250
|
+
* @param list: The list to iterate
|
|
251
|
+
* @returns The new list with filtered mapped values
|
|
252
|
+
*
|
|
253
|
+
* @example List.filterMapi((x, i) => if (x % 2 == 0) Some(toString(x)) else None, [1, 2, 3, 4]) == ["2", "4"]
|
|
254
|
+
* @example List.filterMapi((x, i) => if (i == 0) Some(toString(x)) else None, [1, 2, 3, 4]) == ["1"]
|
|
255
|
+
*
|
|
256
|
+
* @since v0.7.0
|
|
257
|
+
*/
|
|
258
|
+
provide let filterMapi = (fn, list) => {
|
|
259
|
+
let rec iter = (fn, list, index) => {
|
|
260
|
+
match (list) {
|
|
261
|
+
[] => [],
|
|
262
|
+
[first, ...rest] => match (fn(first, index)) {
|
|
263
|
+
Some(v) => [v, ...iter(fn, rest, index + 1)],
|
|
264
|
+
None => iter(fn, rest, index + 1),
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
iter(fn, list, 0)
|
|
269
|
+
}
|
|
270
|
+
|
|
216
271
|
/**
|
|
217
272
|
* Produces a new list by calling a function on each element
|
|
218
273
|
* of the input list. Each iteration produces an intermediate
|
|
@@ -238,7 +293,7 @@ provide let rec flatMap = (fn, list) => {
|
|
|
238
293
|
*
|
|
239
294
|
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
240
295
|
* @param list: The list to check
|
|
241
|
-
* @returns `true` if all elements
|
|
296
|
+
* @returns `true` if all elements satisfy the condition or `false` otherwise
|
|
242
297
|
*
|
|
243
298
|
* @since v0.1.0
|
|
244
299
|
*/
|
|
@@ -256,7 +311,7 @@ provide let rec every = (fn, list) => {
|
|
|
256
311
|
*
|
|
257
312
|
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
258
313
|
* @param list: The list to iterate
|
|
259
|
-
* @returns `true` if one or more elements
|
|
314
|
+
* @returns `true` if one or more elements satisfy the condition or `false` otherwise
|
|
260
315
|
*
|
|
261
316
|
* @since v0.1.0
|
|
262
317
|
*/
|
|
@@ -765,7 +820,7 @@ provide let rec takeWhile = (fn, list) => {
|
|
|
765
820
|
}
|
|
766
821
|
|
|
767
822
|
/**
|
|
768
|
-
* Finds the first element in a list that
|
|
823
|
+
* Finds the first element in a list that satisfies the given condition.
|
|
769
824
|
*
|
|
770
825
|
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
771
826
|
* @param list: The list to search
|
|
@@ -783,7 +838,7 @@ provide let rec find = (fn, list) => {
|
|
|
783
838
|
}
|
|
784
839
|
|
|
785
840
|
/**
|
|
786
|
-
* Finds the first index in a list where the element
|
|
841
|
+
* Finds the first index in a list where the element satisfies the given condition.
|
|
787
842
|
*
|
|
788
843
|
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
789
844
|
* @param list: The list to search
|
|
@@ -804,6 +859,31 @@ provide let findIndex = (fn, list) => {
|
|
|
804
859
|
findItemIndex(list, 0)
|
|
805
860
|
}
|
|
806
861
|
|
|
862
|
+
/**
|
|
863
|
+
* Finds the first element in a list that satisfies the given condition and
|
|
864
|
+
* returns the result of applying a mapper function to it.
|
|
865
|
+
*
|
|
866
|
+
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
867
|
+
* @param list: The list to search
|
|
868
|
+
* @returns `Some(mapped)` containing the first value found with the given mapping or `None` otherwise
|
|
869
|
+
*
|
|
870
|
+
* @example
|
|
871
|
+
* let jsonObject = [(1, 'a'), (2, 'b'), (1, 'c')]
|
|
872
|
+
* let getItem = (key, obj) => List.findMap(((k, v)) => if (k == key) Some(v) else None, obj)
|
|
873
|
+
* assert getItem(1, jsonObject) == Some('a')
|
|
874
|
+
*
|
|
875
|
+
* @since v0.7.0
|
|
876
|
+
*/
|
|
877
|
+
provide let rec findMap = (fn, list) => {
|
|
878
|
+
match (list) {
|
|
879
|
+
[] => None,
|
|
880
|
+
[first, ...rest] => match (fn(first)) {
|
|
881
|
+
None => findMap(fn, rest),
|
|
882
|
+
Some(v) => Some(v),
|
|
883
|
+
},
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
807
887
|
/**
|
|
808
888
|
* Combines two lists into a Cartesian product of tuples containing
|
|
809
889
|
* all ordered pairs `(a, b)`.
|
|
@@ -842,6 +922,51 @@ provide let sub = (start, length, list) => {
|
|
|
842
922
|
take(length, drop(start, list))
|
|
843
923
|
}
|
|
844
924
|
|
|
925
|
+
// List.join helpers
|
|
926
|
+
@unsafe
|
|
927
|
+
let rec computeJoinSize = (sepSize: WasmI32, size: WasmI32, lst: List<String>) => {
|
|
928
|
+
use WasmI32.{ (+) }
|
|
929
|
+
use DataStructures.{ stringSize }
|
|
930
|
+
match (lst) {
|
|
931
|
+
[] => size,
|
|
932
|
+
[hd] => size + stringSize(WasmI32.fromGrain(hd)),
|
|
933
|
+
[hd, ...tl] => {
|
|
934
|
+
let size = size + stringSize(WasmI32.fromGrain(hd)) + sepSize
|
|
935
|
+
ignore(hd)
|
|
936
|
+
computeJoinSize(sepSize, size, tl)
|
|
937
|
+
},
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
@unsafe
|
|
941
|
+
let rec buildJoinedString = (
|
|
942
|
+
strPtr: WasmI32,
|
|
943
|
+
sepPtr: WasmI32,
|
|
944
|
+
sepSize: WasmI32,
|
|
945
|
+
offset: WasmI32,
|
|
946
|
+
lst: List<String>,
|
|
947
|
+
) => {
|
|
948
|
+
use WasmI32.{ (+) }
|
|
949
|
+
use DataStructures.{ stringSize }
|
|
950
|
+
match (lst) {
|
|
951
|
+
[] => void,
|
|
952
|
+
// Last element
|
|
953
|
+
[hd] => {
|
|
954
|
+
let ptr = WasmI32.fromGrain(hd)
|
|
955
|
+
let size = stringSize(ptr)
|
|
956
|
+
Memory.copy(offset, ptr + 8n, size)
|
|
957
|
+
ignore(hd)
|
|
958
|
+
},
|
|
959
|
+
[hd, ...tl] => {
|
|
960
|
+
let ptr = WasmI32.fromGrain(hd)
|
|
961
|
+
let size = stringSize(ptr)
|
|
962
|
+
Memory.copy(offset, ptr + 8n, size)
|
|
963
|
+
ignore(hd)
|
|
964
|
+
let offset = offset + size
|
|
965
|
+
Memory.copy(offset, sepPtr, sepSize)
|
|
966
|
+
buildJoinedString(strPtr, sepPtr, sepSize, offset + sepSize, tl)
|
|
967
|
+
},
|
|
968
|
+
}
|
|
969
|
+
}
|
|
845
970
|
/**
|
|
846
971
|
* Combine the given list of strings into one string with the specified
|
|
847
972
|
* separator inserted between each item.
|
|
@@ -852,25 +977,17 @@ provide let sub = (start, length, list) => {
|
|
|
852
977
|
*
|
|
853
978
|
* @since v0.4.0
|
|
854
979
|
*/
|
|
980
|
+
@unsafe
|
|
855
981
|
provide let join = (separator: String, list: List<String>) => {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
},
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
// Reverse and reduce to take advantage of TCE
|
|
870
|
-
match (iter(separator, None, reverse(list))) {
|
|
871
|
-
None => "",
|
|
872
|
-
Some(s) => s,
|
|
873
|
-
}
|
|
982
|
+
use WasmI32.{ (+), (-), (<=) }
|
|
983
|
+
use DataStructures.{ allocateString, stringSize }
|
|
984
|
+
let sepPtr = WasmI32.fromGrain(separator)
|
|
985
|
+
let sepSize = stringSize(sepPtr)
|
|
986
|
+
let strSize = computeJoinSize(sepSize, 0n, list)
|
|
987
|
+
let newString = allocateString(strSize)
|
|
988
|
+
buildJoinedString(newString, sepPtr + 8n, sepSize, newString + 8n, list)
|
|
989
|
+
ignore(sepPtr)
|
|
990
|
+
return WasmI32.toGrain(newString): String
|
|
874
991
|
}
|
|
875
992
|
|
|
876
993
|
/**
|
|
@@ -931,3 +1048,224 @@ provide let sort = (compare=compare, list) => {
|
|
|
931
1048
|
|
|
932
1049
|
mergesort(list)
|
|
933
1050
|
}
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* Utilities for working with lists of key-key value pairs.
|
|
1054
|
+
*
|
|
1055
|
+
* @example
|
|
1056
|
+
* let data = [
|
|
1057
|
+
* ("name", "Alice"),
|
|
1058
|
+
* ("age", "30"),
|
|
1059
|
+
* ]
|
|
1060
|
+
* assert List.Associative.get("name", data) == Some("Alice")
|
|
1061
|
+
*
|
|
1062
|
+
* @since v0.7.0
|
|
1063
|
+
*/
|
|
1064
|
+
provide module Associative {
|
|
1065
|
+
/**
|
|
1066
|
+
* Checks if the given key is present in the list of key-value pairs.
|
|
1067
|
+
*
|
|
1068
|
+
* @param key: The key to search for
|
|
1069
|
+
* @param list: The list of key-value pairs
|
|
1070
|
+
*
|
|
1071
|
+
* @returns `true` if the key is found or `false` otherwise
|
|
1072
|
+
*
|
|
1073
|
+
* @example
|
|
1074
|
+
* let data = [
|
|
1075
|
+
* ("name", "Alice"),
|
|
1076
|
+
* ("age", "30"),
|
|
1077
|
+
* ]
|
|
1078
|
+
* assert List.Associative.has("name", data) == true
|
|
1079
|
+
* @example List.Associative.has("age", []) == false
|
|
1080
|
+
*
|
|
1081
|
+
* @since v0.7.0
|
|
1082
|
+
*/
|
|
1083
|
+
provide let rec has = (key, list) => {
|
|
1084
|
+
match (list) {
|
|
1085
|
+
[] => false,
|
|
1086
|
+
[(k, _), ...rest] when key == k => true,
|
|
1087
|
+
[_, ...rest] => has(key, rest),
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Retrieves the first value in the list of key-value pairs that matches the given key.
|
|
1093
|
+
*
|
|
1094
|
+
* @param key: The key to search for
|
|
1095
|
+
* @param list: The list of key-value pairs
|
|
1096
|
+
*
|
|
1097
|
+
* @returns `Some(value)` if the key is found or `None` otherwise
|
|
1098
|
+
*
|
|
1099
|
+
* @example
|
|
1100
|
+
* let data = [
|
|
1101
|
+
* ("name", "Alice"),
|
|
1102
|
+
* ("name", "Bob"),
|
|
1103
|
+
* ("age", "30"),
|
|
1104
|
+
* ]
|
|
1105
|
+
* assert List.Associative.get("name", data) == Some("Alice")
|
|
1106
|
+
*
|
|
1107
|
+
* @example List.Associative.get("age", []) == None
|
|
1108
|
+
*
|
|
1109
|
+
* @since v0.7.0
|
|
1110
|
+
*/
|
|
1111
|
+
provide let rec get = (key, list) => {
|
|
1112
|
+
match (list) {
|
|
1113
|
+
[] => None,
|
|
1114
|
+
[(k, v), ...rest] when key == k => Some(v),
|
|
1115
|
+
[_, ...rest] => get(key, rest),
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Retrieves all values in the list of key-value pairs that match the given key.
|
|
1121
|
+
*
|
|
1122
|
+
* @param key: The key to search for
|
|
1123
|
+
* @param list: The list of key-value pairs
|
|
1124
|
+
*
|
|
1125
|
+
* @returns An array of values matching the given key
|
|
1126
|
+
*
|
|
1127
|
+
* @example
|
|
1128
|
+
* let data = [
|
|
1129
|
+
* ("name", "Alice"),
|
|
1130
|
+
* ("name", "Bob"),
|
|
1131
|
+
* ("age", "30"),
|
|
1132
|
+
* ]
|
|
1133
|
+
* assert List.Associative.getAll("name", data) == [
|
|
1134
|
+
* "Alice",
|
|
1135
|
+
* "Bob"
|
|
1136
|
+
* ]
|
|
1137
|
+
*
|
|
1138
|
+
* @example List.Associative.getAll("age", []) == []
|
|
1139
|
+
*
|
|
1140
|
+
* @since v0.7.0
|
|
1141
|
+
*/
|
|
1142
|
+
provide let rec getAll = (key, list) => {
|
|
1143
|
+
match (list) {
|
|
1144
|
+
[] => [],
|
|
1145
|
+
[(k, v), ...rest] when key == k => [v, ...getAll(key, rest)],
|
|
1146
|
+
[_, ...rest] => getAll(key, rest),
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* Creates a new list with the first value in the list of key-value pairs that matches the key replaced.
|
|
1152
|
+
* If the key is not found the item is appended to the list.
|
|
1153
|
+
*
|
|
1154
|
+
* @param key: The key to replace
|
|
1155
|
+
* @param value: The new value to set
|
|
1156
|
+
* @param list: The list of key-value pairs
|
|
1157
|
+
*
|
|
1158
|
+
* @returns A new list with the key-value pair replaced
|
|
1159
|
+
*
|
|
1160
|
+
* @example
|
|
1161
|
+
* let data = [
|
|
1162
|
+
* ("name", "Alice"),
|
|
1163
|
+
* ("name", "Bob"),
|
|
1164
|
+
* ("age", "30"),
|
|
1165
|
+
* ]
|
|
1166
|
+
* assert List.Associative.set("name", "Charlie", data) == [("name", "Charlie"), ("name", "Bob"), ("age", "30")]
|
|
1167
|
+
*
|
|
1168
|
+
* @example List.Associative.set("age", "30", [("name", "Alice")]) == [("name", "Alice"), ("age", "30")]
|
|
1169
|
+
*
|
|
1170
|
+
* @since v0.7.0
|
|
1171
|
+
*/
|
|
1172
|
+
provide let rec set = (key, value, list) => {
|
|
1173
|
+
match (list) {
|
|
1174
|
+
[] => [(key, value)],
|
|
1175
|
+
[(k, _), ...rest] when key == k => [(k, value), ...rest],
|
|
1176
|
+
[first, ...rest] => [first, ...set(key, value, rest)],
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
let rec setAllHelp = (key, value, list, hitMatch=false) => {
|
|
1181
|
+
match (list) {
|
|
1182
|
+
[] when !hitMatch => [(key, value)],
|
|
1183
|
+
[] => [],
|
|
1184
|
+
[(k, _), ...rest] when key == k =>
|
|
1185
|
+
[(k, value), ...setAllHelp(key, value, rest, hitMatch=true)],
|
|
1186
|
+
[first, ...rest] =>
|
|
1187
|
+
[first, ...setAllHelp(key, value, rest, hitMatch=hitMatch)],
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Creates a new list with all values in the list of key-value pairs that match the key replaced.
|
|
1192
|
+
* If the key is not found the item is appended to the list.
|
|
1193
|
+
*
|
|
1194
|
+
* @param key: The key to replace
|
|
1195
|
+
* @param value: The new value to set
|
|
1196
|
+
* @param list: The list of key-value pairs
|
|
1197
|
+
*
|
|
1198
|
+
* @returns A new list with the key-value pairs replaced
|
|
1199
|
+
*
|
|
1200
|
+
* @example
|
|
1201
|
+
* let data = [
|
|
1202
|
+
* ("name", "Alice"),
|
|
1203
|
+
* ("name", "Bob"),
|
|
1204
|
+
* ("age", "30"),
|
|
1205
|
+
* ]
|
|
1206
|
+
* assert List.Associative.setAll("name", "Charlie", data) == [("name", "Charlie"), ("name", "Charlie"), ("age", "30")]
|
|
1207
|
+
*
|
|
1208
|
+
* @example List.Associative.setAll("age", "30", [("name", "Alice")]) == [("name", "Alice"), ("age", "30")]
|
|
1209
|
+
*
|
|
1210
|
+
* @since v0.7.0
|
|
1211
|
+
*/
|
|
1212
|
+
provide let setAll = (key, value, list) => setAllHelp(key, value, list)
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Creates a new list with the first value in the list of key-value pairs that matches the key removed.
|
|
1216
|
+
* If the key is not found, the list is returned unchanged.
|
|
1217
|
+
*
|
|
1218
|
+
* @param key: The key to remove
|
|
1219
|
+
* @param list: The list of key-value pairs
|
|
1220
|
+
*
|
|
1221
|
+
* @returns The new list with the key-value pair removed
|
|
1222
|
+
*
|
|
1223
|
+
* @example
|
|
1224
|
+
* let data = [
|
|
1225
|
+
* ("name", "Alice"),
|
|
1226
|
+
* ("name", "Bob"),
|
|
1227
|
+
* ("age", "30"),
|
|
1228
|
+
* ]
|
|
1229
|
+
* assert List.Associative.remove("name", data) == [("name", "Bob"), ("age", "30")]
|
|
1230
|
+
*
|
|
1231
|
+
* @example List.Associative.remove("age", [("name", "Alice")]) == []
|
|
1232
|
+
*
|
|
1233
|
+
* @since v0.7.0
|
|
1234
|
+
*/
|
|
1235
|
+
provide let rec remove = (key, list) => {
|
|
1236
|
+
match (list) {
|
|
1237
|
+
[] => [],
|
|
1238
|
+
[(k, v), ...rest] when key == k => rest,
|
|
1239
|
+
[first, ...rest] => [first, ...remove(key, rest)],
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Creates a new list with all values in the list of key-value pairs matching the key removed.
|
|
1245
|
+
* If the key is not found, the list is returned unchanged.
|
|
1246
|
+
*
|
|
1247
|
+
* @param key: The key to remove
|
|
1248
|
+
* @param list: The list of key-value pairs
|
|
1249
|
+
*
|
|
1250
|
+
* @returns The new list with the key-value pairs removed
|
|
1251
|
+
*
|
|
1252
|
+
* @example
|
|
1253
|
+
* let data = [
|
|
1254
|
+
* ("name", "Alice"),
|
|
1255
|
+
* ("name", "Bob"),
|
|
1256
|
+
* ("age", "30"),
|
|
1257
|
+
* ]
|
|
1258
|
+
* assert List.Associative.removeAll("name", data) == [("age", "30")]
|
|
1259
|
+
*
|
|
1260
|
+
* @example List.Associative.removeAll("age", [("name", "Alice")]) == [("name", "Alice")]
|
|
1261
|
+
*
|
|
1262
|
+
* @since v0.7.0
|
|
1263
|
+
*/
|
|
1264
|
+
provide let rec removeAll = (key, list) => {
|
|
1265
|
+
match (list) {
|
|
1266
|
+
[] => [],
|
|
1267
|
+
[(k, v), ...rest] when key == k => removeAll(key, rest),
|
|
1268
|
+
[first, ...rest] => [first, ...removeAll(key, rest)],
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|