@grain/stdlib 0.5.3 → 0.5.5
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 +61 -0
- package/array.gr +65 -57
- package/array.md +54 -6
- package/buffer.gr +71 -1
- package/buffer.md +142 -0
- package/bytes.gr +52 -3
- package/bytes.md +117 -0
- package/char.gr +23 -20
- package/char.md +18 -3
- package/immutablemap.gr +493 -0
- package/immutablemap.md +479 -0
- package/immutablepriorityqueue.gr +44 -16
- package/immutablepriorityqueue.md +44 -1
- package/immutableset.gr +498 -0
- package/immutableset.md +449 -0
- package/int32.gr +39 -37
- package/int32.md +6 -0
- package/int64.gr +39 -37
- package/int64.md +6 -0
- package/list.gr +33 -24
- package/list.md +39 -10
- package/map.gr +19 -28
- package/marshal.gr +4 -4
- package/number.gr +727 -26
- package/number.md +345 -23
- package/option.gr +30 -26
- package/option.md +12 -0
- package/package.json +1 -1
- package/path.gr +787 -0
- package/path.md +727 -0
- package/pervasives.gr +3 -4
- package/pervasives.md +6 -1
- package/priorityqueue.gr +25 -5
- package/priorityqueue.md +30 -0
- package/queue.gr +22 -7
- package/queue.md +18 -1
- package/regex.gr +161 -65
- package/regex.md +70 -0
- package/result.gr +24 -20
- package/result.md +12 -0
- package/runtime/atof/common.gr +198 -0
- package/runtime/atof/common.md +243 -0
- package/runtime/atof/decimal.gr +663 -0
- package/runtime/atof/decimal.md +59 -0
- package/runtime/atof/lemire.gr +264 -0
- package/runtime/atof/lemire.md +6 -0
- package/runtime/atof/parse.gr +615 -0
- package/runtime/atof/parse.md +12 -0
- package/runtime/atof/slow.gr +238 -0
- package/runtime/atof/slow.md +6 -0
- package/runtime/atof/table.gr +2016 -0
- package/runtime/atof/table.md +12 -0
- package/runtime/{stringUtils.gr → atoi/parse.gr} +1 -1
- package/runtime/{stringUtils.md → atoi/parse.md} +1 -1
- package/runtime/bigint.gr +7 -7
- package/runtime/compare.gr +2 -1
- package/runtime/equal.gr +3 -2
- package/runtime/exception.gr +9 -5
- package/runtime/exception.md +8 -2
- package/runtime/gc.gr +2 -1
- package/runtime/malloc.gr +1 -3
- package/runtime/numberUtils.gr +13 -13
- package/runtime/numberUtils.md +6 -0
- package/runtime/numbers.gr +123 -39
- package/runtime/numbers.md +26 -0
- package/runtime/string.gr +4 -2
- package/runtime/unsafe/conv.gr +21 -41
- package/runtime/unsafe/conv.md +0 -3
- package/runtime/unsafe/printWasm.gr +4 -40
- package/runtime/utils/printing.gr +3 -3
- package/set.gr +25 -25
- package/stack.gr +14 -0
- package/stack.md +17 -0
- package/string.gr +313 -39
- package/string.md +99 -0
- package/sys/file.gr +1 -1
- package/sys/time.gr +4 -4
package/char.gr
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The Char type represents a single [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value).
|
|
5
5
|
*
|
|
6
6
|
* @example import Char from "char"
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @since 0.3.0
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -26,37 +26,37 @@ exception MalformedUtf8
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* The minimum valid Unicode scalar value.
|
|
29
|
-
*
|
|
29
|
+
*
|
|
30
30
|
* @since 0.3.0
|
|
31
31
|
*/
|
|
32
32
|
export let min = 0x0000
|
|
33
33
|
/**
|
|
34
34
|
* The maximum valid Unicode scalar value.
|
|
35
|
-
*
|
|
35
|
+
*
|
|
36
36
|
* @since 0.3.0
|
|
37
37
|
*/
|
|
38
38
|
export let max = 0x10FFFF
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* Determines whether the given character code is a valid Unicode scalar value.
|
|
42
|
-
*
|
|
42
|
+
*
|
|
43
43
|
* @param charCode: The number to check
|
|
44
44
|
* @returns `true` if the number refers to a valid Unicode scalar value or `false` otherwise
|
|
45
|
-
*
|
|
45
|
+
*
|
|
46
46
|
* @since 0.3.0
|
|
47
47
|
*/
|
|
48
48
|
export let isValid = charCode => {
|
|
49
49
|
charCode >= min &&
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
(charCode <= 0xD7FF || charCode >= 0xE000) &&
|
|
51
|
+
charCode <= max
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Determines the Unicode scalar value for a character.
|
|
56
|
-
*
|
|
56
|
+
*
|
|
57
57
|
* @param char: The character
|
|
58
58
|
* @returns The Unicode scalar value for the given character
|
|
59
|
-
*
|
|
59
|
+
*
|
|
60
60
|
* @since 0.3.0
|
|
61
61
|
*/
|
|
62
62
|
@unsafe
|
|
@@ -70,11 +70,12 @@ export let code = (char: Char) => {
|
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Creates a character from the given Unicode scalar value.
|
|
73
|
-
*
|
|
74
|
-
*
|
|
73
|
+
*
|
|
75
74
|
* @param usv: The Unicode scalar value
|
|
76
75
|
* @returns The character for the given Unicode scalar value
|
|
77
|
-
*
|
|
76
|
+
*
|
|
77
|
+
* @throws InvalidArgument(String): When the Unicode scalar value is invalid
|
|
78
|
+
*
|
|
78
79
|
* @since 0.3.0
|
|
79
80
|
*/
|
|
80
81
|
@unsafe
|
|
@@ -101,11 +102,12 @@ export let fromCode = (usv: Number) => {
|
|
|
101
102
|
|
|
102
103
|
/**
|
|
103
104
|
* Returns the next valid character by Unicode scalar value.
|
|
104
|
-
*
|
|
105
|
-
*
|
|
105
|
+
*
|
|
106
106
|
* @param char: The character
|
|
107
107
|
* @returns The next valid character by Unicode scalar value
|
|
108
|
-
*
|
|
108
|
+
*
|
|
109
|
+
* @throws Failure(String): When the input character is the maximum valid Unicode scalar value
|
|
110
|
+
*
|
|
109
111
|
* @since 0.3.0
|
|
110
112
|
*/
|
|
111
113
|
export let succ = char => {
|
|
@@ -121,11 +123,12 @@ export let succ = char => {
|
|
|
121
123
|
|
|
122
124
|
/**
|
|
123
125
|
* Returns the previous valid character by Unicode scalar value.
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
+
*
|
|
126
127
|
* @param char: The character
|
|
127
128
|
* @returns The previous valid character by Unicode scalar value
|
|
128
|
-
*
|
|
129
|
+
*
|
|
130
|
+
* @throws Failure(String): When the input character is the minimum valid Unicode scalar value
|
|
131
|
+
*
|
|
129
132
|
* @since 0.3.0
|
|
130
133
|
*/
|
|
131
134
|
export let pred = char => {
|
|
@@ -141,10 +144,10 @@ export let pred = char => {
|
|
|
141
144
|
|
|
142
145
|
/**
|
|
143
146
|
* Converts the given character to a string.
|
|
144
|
-
*
|
|
147
|
+
*
|
|
145
148
|
* @param char: The character to convert
|
|
146
149
|
* @returns A string containing the given character
|
|
147
|
-
*
|
|
150
|
+
*
|
|
148
151
|
* @since 0.3.0
|
|
149
152
|
*/
|
|
150
153
|
@unsafe
|
package/char.md
CHANGED
|
@@ -107,7 +107,6 @@ fromCode : Number -> Char
|
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
Creates a character from the given Unicode scalar value.
|
|
110
|
-
Throws an exception if the Unicode scalar value is invalid.
|
|
111
110
|
|
|
112
111
|
Parameters:
|
|
113
112
|
|
|
@@ -121,6 +120,12 @@ Returns:
|
|
|
121
120
|
|----|-----------|
|
|
122
121
|
|`Char`|The character for the given Unicode scalar value|
|
|
123
122
|
|
|
123
|
+
Throws:
|
|
124
|
+
|
|
125
|
+
`InvalidArgument(String)`
|
|
126
|
+
|
|
127
|
+
* When the Unicode scalar value is invalid
|
|
128
|
+
|
|
124
129
|
### Char.**succ**
|
|
125
130
|
|
|
126
131
|
<details disabled>
|
|
@@ -133,7 +138,6 @@ succ : Char -> Char
|
|
|
133
138
|
```
|
|
134
139
|
|
|
135
140
|
Returns the next valid character by Unicode scalar value.
|
|
136
|
-
Throws if the input character is the max valid Unicode scalar value.
|
|
137
141
|
|
|
138
142
|
Parameters:
|
|
139
143
|
|
|
@@ -147,6 +151,12 @@ Returns:
|
|
|
147
151
|
|----|-----------|
|
|
148
152
|
|`Char`|The next valid character by Unicode scalar value|
|
|
149
153
|
|
|
154
|
+
Throws:
|
|
155
|
+
|
|
156
|
+
`Failure(String)`
|
|
157
|
+
|
|
158
|
+
* When the input character is the maximum valid Unicode scalar value
|
|
159
|
+
|
|
150
160
|
### Char.**pred**
|
|
151
161
|
|
|
152
162
|
<details disabled>
|
|
@@ -159,7 +169,6 @@ pred : Char -> Char
|
|
|
159
169
|
```
|
|
160
170
|
|
|
161
171
|
Returns the previous valid character by Unicode scalar value.
|
|
162
|
-
Throws if the input character is the min valid Unicode scalar value.
|
|
163
172
|
|
|
164
173
|
Parameters:
|
|
165
174
|
|
|
@@ -173,6 +182,12 @@ Returns:
|
|
|
173
182
|
|----|-----------|
|
|
174
183
|
|`Char`|The previous valid character by Unicode scalar value|
|
|
175
184
|
|
|
185
|
+
Throws:
|
|
186
|
+
|
|
187
|
+
`Failure(String)`
|
|
188
|
+
|
|
189
|
+
* When the input character is the minimum valid Unicode scalar value
|
|
190
|
+
|
|
176
191
|
### Char.**toString**
|
|
177
192
|
|
|
178
193
|
<details disabled>
|
package/immutablemap.gr
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ImmutableMap: An ImmutableMap holds key-value pairs. Any value may be used as a key or value. Operations on an ImmutableMap do not mutate the map's internal state.
|
|
3
|
+
* @example import ImmutableMap from "immutablemap"
|
|
4
|
+
*
|
|
5
|
+
* @since v0.5.4
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import List from "list"
|
|
9
|
+
import Array from "array"
|
|
10
|
+
import Option from "option"
|
|
11
|
+
|
|
12
|
+
// implementation based on the paper "Implementing Sets Efficiently in a
|
|
13
|
+
// Functional Language" by Stephen Adams
|
|
14
|
+
record Node<k, v> {
|
|
15
|
+
key: k,
|
|
16
|
+
val: v,
|
|
17
|
+
size: Number,
|
|
18
|
+
left: ImmutableMap<k, v>,
|
|
19
|
+
right: ImmutableMap<k, v>,
|
|
20
|
+
},
|
|
21
|
+
/**
|
|
22
|
+
* @section Types: Type declarations included in the ImmutableMap module.
|
|
23
|
+
*/
|
|
24
|
+
enum ImmutableMap<k, v> {
|
|
25
|
+
Empty,
|
|
26
|
+
Tree(Node<k, v>),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @section Values: Functions and constants for working with ImmutableMaps.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
// semi-arbitrary value chosen for algorithm for determining when to balance
|
|
34
|
+
// trees; no tree can have a left subtree containing this number of times
|
|
35
|
+
// more elements than its right subtree or vice versa
|
|
36
|
+
let weight = 4
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* An empty map
|
|
40
|
+
*
|
|
41
|
+
* @since v0.5.4
|
|
42
|
+
*/
|
|
43
|
+
export let empty = Empty
|
|
44
|
+
|
|
45
|
+
// returns the key-value pair of the minimum key in a tree
|
|
46
|
+
let rec min = node => {
|
|
47
|
+
match (node) {
|
|
48
|
+
Tree({ key, val, left: Empty, _ }) => (key, val),
|
|
49
|
+
Tree({ left, _ }) => min(left),
|
|
50
|
+
Empty => fail "Impossible: min of empty element in ImmutableMap",
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Provides the count of key-value pairs stored within the map.
|
|
56
|
+
*
|
|
57
|
+
* @param map: The map to inspect
|
|
58
|
+
* @returns The count of key-value pairs in the map
|
|
59
|
+
*
|
|
60
|
+
* @since v0.5.4
|
|
61
|
+
*/
|
|
62
|
+
export let size = map => {
|
|
63
|
+
match (map) {
|
|
64
|
+
Empty => 0,
|
|
65
|
+
Tree({ size, _ }) => size,
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Determines if the map contains no key-value pairs.
|
|
71
|
+
*
|
|
72
|
+
* @param map: The map to inspect
|
|
73
|
+
* @returns `true` if the given map is empty or `false` otherwise
|
|
74
|
+
*
|
|
75
|
+
* @since v0.5.4
|
|
76
|
+
*/
|
|
77
|
+
export let isEmpty = map => {
|
|
78
|
+
match (map) {
|
|
79
|
+
Empty => true,
|
|
80
|
+
Tree(_) => false,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let unwrapTree = node => {
|
|
85
|
+
match (node) {
|
|
86
|
+
Empty => fail "Impossible: ImmutableMap unwrapTree got an empty tree node",
|
|
87
|
+
Tree(tree) => tree,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// helper function for creating a tree node with correct size from
|
|
92
|
+
// two balanced trees
|
|
93
|
+
let makeNode = (key, val, left, right) => {
|
|
94
|
+
Tree({ key, val, size: 1 + size(left) + size(right), left, right })
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// note: see Figure 1 of paper referenced above for visual illustration of
|
|
98
|
+
// the rotations below
|
|
99
|
+
|
|
100
|
+
// node rotation moving the left subtree of the right node to the left side
|
|
101
|
+
let singleL = (key, val, left, right) => {
|
|
102
|
+
let { key: rKey, val: rVal, left: rl, right: rr, _ } = unwrapTree(right)
|
|
103
|
+
makeNode(rKey, rVal, makeNode(key, val, left, rl), rr)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// node rotation moving left child of right tree to the root
|
|
107
|
+
let doubleL = (key, val, left, right) => {
|
|
108
|
+
let { key: rKey, val: rVal, left: rl, right: rr, _ } = unwrapTree(right)
|
|
109
|
+
let { key: rlKey, val: rlVal, left: rll, right: rlr, _ } = unwrapTree(rl)
|
|
110
|
+
makeNode(
|
|
111
|
+
rlKey,
|
|
112
|
+
rlVal,
|
|
113
|
+
makeNode(key, val, left, rll),
|
|
114
|
+
makeNode(rKey, rVal, rlr, rr)
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// node rotation moving the right subtree of the left node to the right side
|
|
119
|
+
let singleR = (key, val, left, right) => {
|
|
120
|
+
let { key: lKey, val: lVal, left: ll, right: lr, _ } = unwrapTree(left)
|
|
121
|
+
makeNode(lKey, lVal, ll, makeNode(key, val, lr, right))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// node rotation moving right child of left tree to the root
|
|
125
|
+
let doubleR = (key, val, left, right) => {
|
|
126
|
+
let { key: lKey, val: lVal, left: ll, right: lr, _ } = unwrapTree(left)
|
|
127
|
+
let { key: lrKey, val: lrVal, left: lrl, right: lrr, _ } = unwrapTree(lr)
|
|
128
|
+
makeNode(
|
|
129
|
+
lrKey,
|
|
130
|
+
lrVal,
|
|
131
|
+
makeNode(lKey, lVal, ll, lrl),
|
|
132
|
+
makeNode(key, val, lrr, right)
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// creates a new node after either the left or right trees have just had an
|
|
137
|
+
// element inserted or removed from them, maintaining balance in the tree
|
|
138
|
+
let balancedNode = (key, val, left, right) => {
|
|
139
|
+
let makeNodeFn = if (size(left) + size(right) < 2) {
|
|
140
|
+
makeNode
|
|
141
|
+
} else if (size(right) > weight * size(left)) {
|
|
142
|
+
// if the right tree is too much larger than the left then move part of
|
|
143
|
+
// the right tree to the left side
|
|
144
|
+
let { left: rl, right: rr, _ } = unwrapTree(right)
|
|
145
|
+
if (size(rl) < size(rr)) singleL else doubleL
|
|
146
|
+
} else if (size(left) > weight * size(right)) {
|
|
147
|
+
// if the left tree is too much larger than the right then move part of
|
|
148
|
+
// the left tree to the right side
|
|
149
|
+
let { left: ll, right: lr, _ } = unwrapTree(left)
|
|
150
|
+
if (size(lr) < size(ll)) singleR else doubleR
|
|
151
|
+
} else {
|
|
152
|
+
// if neither tree is too much larger than the other then simply create
|
|
153
|
+
// a new node
|
|
154
|
+
makeNode
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
makeNodeFn(key, val, left, right)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Produces a new map containing a new key-value pair. If the key already exists in the map, the value is replaced.
|
|
162
|
+
*
|
|
163
|
+
* @param key: The unique key in the map
|
|
164
|
+
* @param value: The value to store
|
|
165
|
+
* @param map: The base map
|
|
166
|
+
* @returns A new map containing the new key-value pair
|
|
167
|
+
*
|
|
168
|
+
* @since v0.5.4
|
|
169
|
+
*/
|
|
170
|
+
export let rec set = (key, val, map) => {
|
|
171
|
+
match (map) {
|
|
172
|
+
Empty => Tree({ key, val, size: 1, left: Empty, right: Empty }),
|
|
173
|
+
Tree({ key: nodeKey, val: nodeVal, left, right, _ }) => {
|
|
174
|
+
match (compare(key, nodeKey)) {
|
|
175
|
+
cmp when cmp < 0 =>
|
|
176
|
+
balancedNode(nodeKey, nodeVal, set(key, val, left), right),
|
|
177
|
+
cmp when cmp > 0 =>
|
|
178
|
+
balancedNode(nodeKey, nodeVal, left, set(key, val, right)),
|
|
179
|
+
_ => makeNode(key, val, left, right),
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Retrieves the value for the given key.
|
|
187
|
+
*
|
|
188
|
+
* @param key: The key to access
|
|
189
|
+
* @param map: The map to access
|
|
190
|
+
* @returns `Some(value)` if the key exists in the map or `None` otherwise
|
|
191
|
+
*
|
|
192
|
+
* @since v0.5.4
|
|
193
|
+
*/
|
|
194
|
+
export let rec get = (key, map) => {
|
|
195
|
+
match (map) {
|
|
196
|
+
Empty => None,
|
|
197
|
+
Tree({ key: nodeKey, val: nodeVal, left, right, _ }) => {
|
|
198
|
+
match (compare(key, nodeKey)) {
|
|
199
|
+
cmp when cmp < 0 => get(key, left),
|
|
200
|
+
cmp when cmp > 0 => get(key, right),
|
|
201
|
+
_ => Some(nodeVal),
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Determines if the map contains the given key. In such a case, it will always contain a value for the given key.
|
|
209
|
+
*
|
|
210
|
+
* @param key: The key to search for
|
|
211
|
+
* @param map: The map to search
|
|
212
|
+
* @returns `true` if the map contains the given key or `false` otherwise
|
|
213
|
+
*
|
|
214
|
+
* @since v0.5.4
|
|
215
|
+
*/
|
|
216
|
+
export let rec contains = (key, map) => {
|
|
217
|
+
Option.isSome(get(key, map))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// removes the minimum element from a tree
|
|
221
|
+
let rec removeMin = node => {
|
|
222
|
+
match (node) {
|
|
223
|
+
Tree({ left: Empty, right, _ }) => right,
|
|
224
|
+
Tree({ key, val, left, right, _ }) =>
|
|
225
|
+
balancedNode(key, val, removeMin(left), right),
|
|
226
|
+
_ => fail "Impossible: ImmutableMap removeMin on empty node",
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// helper function for removing a node by creating a new node containing the
|
|
231
|
+
// removed node's left and right subtrees
|
|
232
|
+
let removeInner = (left, right) => {
|
|
233
|
+
match ((left, right)) {
|
|
234
|
+
(Empty, node) | (node, Empty) => node,
|
|
235
|
+
(left, right) => {
|
|
236
|
+
let (minKey, minVal) = min(right)
|
|
237
|
+
balancedNode(minKey, minVal, left, removeMin(right))
|
|
238
|
+
},
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Produces a new map without the key-value pair corresponding to the given
|
|
244
|
+
* key. If the key doesn't exist in the map, the map will be returned unmodified.
|
|
245
|
+
*
|
|
246
|
+
* @param key: The key to exclude
|
|
247
|
+
* @param map: The map to exclude from
|
|
248
|
+
* @returns A new map without the given key
|
|
249
|
+
*
|
|
250
|
+
* @since v0.5.4
|
|
251
|
+
*/
|
|
252
|
+
export let rec remove = (key, map) => {
|
|
253
|
+
match (map) {
|
|
254
|
+
Empty => Empty,
|
|
255
|
+
Tree({ key: nodeKey, val: nodeVal, left, right, _ }) => {
|
|
256
|
+
match (compare(key, nodeKey)) {
|
|
257
|
+
cmp when cmp < 0 =>
|
|
258
|
+
balancedNode(nodeKey, nodeVal, remove(key, left), right),
|
|
259
|
+
cmp when cmp > 0 =>
|
|
260
|
+
balancedNode(nodeKey, nodeVal, left, remove(key, right)),
|
|
261
|
+
_ => removeInner(left, right),
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Produces a new map by calling an updater function that receives the
|
|
269
|
+
* previously stored value as an `Option` and returns the new value to be
|
|
270
|
+
* stored as an `Option`. If the key didn't exist previously, the value
|
|
271
|
+
* will be `None`. If `None` is returned from the updater function, the
|
|
272
|
+
* key-value pair is excluded.
|
|
273
|
+
*
|
|
274
|
+
* @param key: The unique key in the map
|
|
275
|
+
* @param fn: The updater function
|
|
276
|
+
* @param map: The base map
|
|
277
|
+
* @returns A new map with the value at the given key modified according to the function's output
|
|
278
|
+
*
|
|
279
|
+
* @since v0.5.4
|
|
280
|
+
*/
|
|
281
|
+
export let update = (key, fn, map) => {
|
|
282
|
+
let val = get(key, map)
|
|
283
|
+
match (fn(val)) {
|
|
284
|
+
Some(next) => set(key, next, map),
|
|
285
|
+
None => remove(key, map),
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Iterates the map, calling an iterator function with each key and value.
|
|
291
|
+
*
|
|
292
|
+
* @param fn: The iterator function to call with each key and value
|
|
293
|
+
* @param map: The map to iterate
|
|
294
|
+
*
|
|
295
|
+
* @since v0.5.4
|
|
296
|
+
*/
|
|
297
|
+
export let forEach = (fn, map) => {
|
|
298
|
+
let rec forEachInner = node => {
|
|
299
|
+
match (node) {
|
|
300
|
+
Empty => void,
|
|
301
|
+
Tree({ key, val, left, right, _ }) => {
|
|
302
|
+
forEachInner(left)
|
|
303
|
+
fn(key, val): Void
|
|
304
|
+
forEachInner(right)
|
|
305
|
+
},
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
forEachInner(map)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Combines all key-value pairs of a map using a reducer function.
|
|
313
|
+
*
|
|
314
|
+
* @param fn: The reducer function to call on each key and value, where the value returned will be the next accumulator value
|
|
315
|
+
* @param init: The initial value to use for the accumulator on the first iteration
|
|
316
|
+
* @param map: The map to iterate
|
|
317
|
+
* @returns The final accumulator returned from `fn`
|
|
318
|
+
*
|
|
319
|
+
* @since v0.5.4
|
|
320
|
+
*/
|
|
321
|
+
export let reduce = (fn, init, map) => {
|
|
322
|
+
let rec reduceInner = (acc, node) => {
|
|
323
|
+
match (node) {
|
|
324
|
+
Empty => acc,
|
|
325
|
+
Tree({ key, val, left, right, _ }) => {
|
|
326
|
+
let newAcc = fn(reduceInner(acc, left), key, val)
|
|
327
|
+
reduceInner(newAcc, right)
|
|
328
|
+
},
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
reduceInner(init, map)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// joins two trees with a value, preserving the BST property of left children
|
|
335
|
+
// being less the node and right children being greater than the node
|
|
336
|
+
let rec concat3 = (key, val, left, right) => {
|
|
337
|
+
match ((left, right)) {
|
|
338
|
+
(Empty, node) | (node, Empty) => set(key, val, node),
|
|
339
|
+
(Tree(left) as leftOpt, Tree(right) as rightOpt) => {
|
|
340
|
+
if (weight * left.size < right.size) {
|
|
341
|
+
balancedNode(
|
|
342
|
+
right.key,
|
|
343
|
+
right.val,
|
|
344
|
+
concat3(key, val, leftOpt, right.left),
|
|
345
|
+
right.right
|
|
346
|
+
)
|
|
347
|
+
} else if (weight * right.size < left.size) {
|
|
348
|
+
balancedNode(
|
|
349
|
+
left.key,
|
|
350
|
+
left.val,
|
|
351
|
+
left.left,
|
|
352
|
+
concat3(key, val, left.right, rightOpt)
|
|
353
|
+
)
|
|
354
|
+
} else {
|
|
355
|
+
makeNode(key, val, leftOpt, rightOpt)
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// concatenates two trees of arbitrary size
|
|
362
|
+
let concat = (node1, node2) => {
|
|
363
|
+
match (node2) {
|
|
364
|
+
Empty => node1,
|
|
365
|
+
_ => {
|
|
366
|
+
let (minKey, minVal) = min(node2)
|
|
367
|
+
concat3(minKey, minVal, node1, removeMin(node2))
|
|
368
|
+
},
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
let reduceRight = (fn, init, map) => {
|
|
373
|
+
let rec reduceInner = (acc, node) => {
|
|
374
|
+
match (node) {
|
|
375
|
+
Empty => acc,
|
|
376
|
+
Tree({ key, val, left, right, _ }) => {
|
|
377
|
+
let newAcc = fn(reduceInner(acc, right), key, val)
|
|
378
|
+
reduceInner(newAcc, left)
|
|
379
|
+
},
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
reduceInner(init, map)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Enumerates all keys in the given map.
|
|
387
|
+
*
|
|
388
|
+
* @param map: The map to enumerate
|
|
389
|
+
* @returns A list containing all keys from the given map
|
|
390
|
+
*
|
|
391
|
+
* @since v0.5.4
|
|
392
|
+
*/
|
|
393
|
+
export let keys = map => {
|
|
394
|
+
reduceRight((list, key, _) => [key, ...list], [], map)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Enumerates all values in the given map.
|
|
399
|
+
*
|
|
400
|
+
* @param map: The map to enumerate
|
|
401
|
+
* @returns A list containing all values from the given map
|
|
402
|
+
*
|
|
403
|
+
* @since v0.5.4
|
|
404
|
+
*/
|
|
405
|
+
export let values = map => {
|
|
406
|
+
reduceRight((list, _, value) => [value, ...list], [], map)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Produces a new map excluding the key-value pairs where a predicate function returns `false`.
|
|
411
|
+
*
|
|
412
|
+
* @param fn: The predicate function to indicate which key-value pairs to exclude from the map, where returning `false` indicates the key-value pair should be excluded
|
|
413
|
+
* @param map: The map to iterate
|
|
414
|
+
* @returns A new map excluding the key-value pairs not fulfilling the predicate
|
|
415
|
+
*
|
|
416
|
+
* @since v0.5.4
|
|
417
|
+
*/
|
|
418
|
+
export let filter = (fn, map) => {
|
|
419
|
+
let rec filterInner = node => {
|
|
420
|
+
match (node) {
|
|
421
|
+
Empty => Empty,
|
|
422
|
+
Tree({ key, val, left, right, _ }) => {
|
|
423
|
+
if (fn(key, val)) {
|
|
424
|
+
concat3(key, val, filterInner(left), filterInner(right))
|
|
425
|
+
} else {
|
|
426
|
+
concat(filterInner(left), filterInner(right))
|
|
427
|
+
}
|
|
428
|
+
},
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
filterInner(map)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Produces a new map excluding the key-value pairs where a predicate function returns `true`.
|
|
436
|
+
*
|
|
437
|
+
* @param fn: The predicate function to indicate which key-value pairs to exclude from the map, where returning `true` indicates the key-value pair should be excluded
|
|
438
|
+
* @param map: The map to iterate
|
|
439
|
+
* @returns A new map excluding the key-value pairs fulfilling the predicate
|
|
440
|
+
*
|
|
441
|
+
* @since v0.5.4
|
|
442
|
+
*/
|
|
443
|
+
export let reject = (fn, map) => {
|
|
444
|
+
filter((key, val) => !fn(key, val), map)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Creates a map from a list.
|
|
449
|
+
*
|
|
450
|
+
* @param list: The list to convert
|
|
451
|
+
* @returns A map containing all key-value pairs from the list
|
|
452
|
+
*
|
|
453
|
+
* @since v0.5.4
|
|
454
|
+
*/
|
|
455
|
+
export let fromList = list => {
|
|
456
|
+
List.reduce((map, (key, val)) => set(key, val, map), empty, list)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Enumerates all key-value pairs in the given map.
|
|
461
|
+
*
|
|
462
|
+
* @param map: The map to enumerate
|
|
463
|
+
* @returns A list containing all key-value pairs from the given map
|
|
464
|
+
*
|
|
465
|
+
* @since v0.5.4
|
|
466
|
+
*/
|
|
467
|
+
export let toList = map => {
|
|
468
|
+
reduceRight((list, key, val) => [(key, val), ...list], [], map)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* Creates a map from an array.
|
|
473
|
+
*
|
|
474
|
+
* @param array: The array to convert
|
|
475
|
+
* @returns A map containing all key-value pairs from the array
|
|
476
|
+
*
|
|
477
|
+
* @since v0.5.4
|
|
478
|
+
*/
|
|
479
|
+
export let fromArray = array => {
|
|
480
|
+
Array.reduce((map, (key, val)) => set(key, val, map), empty, array)
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Converts a map into an array of its key-value pairs.
|
|
485
|
+
*
|
|
486
|
+
* @param map: The map to convert
|
|
487
|
+
* @returns An array containing all key-value pairs from the given map
|
|
488
|
+
*
|
|
489
|
+
* @since v0.5.4
|
|
490
|
+
*/
|
|
491
|
+
export let toArray = map => {
|
|
492
|
+
Array.fromList(toList(map))
|
|
493
|
+
}
|