ic-mops 0.8.3 → 0.8.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/.mops/base@0.7.4/LICENSE +208 -0
- package/.mops/base@0.7.4/README.md +64 -0
- package/.mops/base@0.7.4/mops.toml +5 -0
- package/.mops/base@0.7.4/src/Array.mo +686 -0
- package/.mops/base@0.7.4/src/AssocList.mo +203 -0
- package/.mops/base@0.7.4/src/Blob.mo +55 -0
- package/.mops/base@0.7.4/src/Bool.mo +44 -0
- package/.mops/base@0.7.4/src/Buffer.mo +1937 -0
- package/.mops/base@0.7.4/src/CertifiedData.mo +29 -0
- package/.mops/base@0.7.4/src/Char.mo +67 -0
- package/.mops/base@0.7.4/src/Debug.mo +15 -0
- package/.mops/base@0.7.4/src/Deque.mo +75 -0
- package/.mops/base@0.7.4/src/Error.mo +41 -0
- package/.mops/base@0.7.4/src/ExperimentalCycles.mo +51 -0
- package/.mops/base@0.7.4/src/ExperimentalInternetComputer.mo +36 -0
- package/.mops/base@0.7.4/src/ExperimentalStableMemory.mo +121 -0
- package/.mops/base@0.7.4/src/Float.mo +150 -0
- package/.mops/base@0.7.4/src/Func.mo +38 -0
- package/.mops/base@0.7.4/src/Hash.mo +83 -0
- package/.mops/base@0.7.4/src/HashMap.mo +229 -0
- package/.mops/base@0.7.4/src/Heap.mo +113 -0
- package/.mops/base@0.7.4/src/Int.mo +150 -0
- package/.mops/base@0.7.4/src/Int16.mo +159 -0
- package/.mops/base@0.7.4/src/Int32.mo +160 -0
- package/.mops/base@0.7.4/src/Int64.mo +161 -0
- package/.mops/base@0.7.4/src/Int8.mo +160 -0
- package/.mops/base@0.7.4/src/Iter.mo +220 -0
- package/.mops/base@0.7.4/src/IterType.mo +7 -0
- package/.mops/base@0.7.4/src/List.mo +433 -0
- package/.mops/base@0.7.4/src/Nat.mo +75 -0
- package/.mops/base@0.7.4/src/Nat16.mo +146 -0
- package/.mops/base@0.7.4/src/Nat32.mo +146 -0
- package/.mops/base@0.7.4/src/Nat64.mo +146 -0
- package/.mops/base@0.7.4/src/Nat8.mo +146 -0
- package/.mops/base@0.7.4/src/None.mo +19 -0
- package/.mops/base@0.7.4/src/Option.mo +160 -0
- package/.mops/base@0.7.4/src/Order.mo +46 -0
- package/.mops/base@0.7.4/src/Prelude.mo +33 -0
- package/.mops/base@0.7.4/src/Principal.mo +58 -0
- package/.mops/base@0.7.4/src/RBTree.mo +218 -0
- package/.mops/base@0.7.4/src/Random.mo +188 -0
- package/.mops/base@0.7.4/src/Result.mo +210 -0
- package/.mops/base@0.7.4/src/Stack.mo +40 -0
- package/.mops/base@0.7.4/src/Text.mo +615 -0
- package/.mops/base@0.7.4/src/Time.mo +37 -0
- package/.mops/base@0.7.4/src/Trie.mo +1200 -0
- package/.mops/base@0.7.4/src/TrieMap.mo +180 -0
- package/.mops/base@0.7.4/src/TrieSet.mo +97 -0
- package/.mops/base@0.8.3/LICENSE +208 -0
- package/.mops/base@0.8.3/README.md +64 -0
- package/.mops/base@0.8.3/mops.toml +6 -0
- package/.mops/base@0.8.3/src/Array.mo +717 -0
- package/.mops/base@0.8.3/src/AssocList.mo +404 -0
- package/.mops/base@0.8.3/src/Blob.mo +212 -0
- package/.mops/base@0.8.3/src/Bool.mo +44 -0
- package/.mops/base@0.8.3/src/Buffer.mo +2660 -0
- package/.mops/base@0.8.3/src/CertifiedData.mo +53 -0
- package/.mops/base@0.8.3/src/Char.mo +65 -0
- package/.mops/base@0.8.3/src/Debug.mo +56 -0
- package/.mops/base@0.8.3/src/Deque.mo +243 -0
- package/.mops/base@0.8.3/src/Error.mo +68 -0
- package/.mops/base@0.8.3/src/ExperimentalCycles.mo +151 -0
- package/.mops/base@0.8.3/src/ExperimentalInternetComputer.mo +60 -0
- package/.mops/base@0.8.3/src/ExperimentalStableMemory.mo +348 -0
- package/.mops/base@0.8.3/src/Float.mo +843 -0
- package/.mops/base@0.8.3/src/Func.mo +46 -0
- package/.mops/base@0.8.3/src/Hash.mo +82 -0
- package/.mops/base@0.8.3/src/HashMap.mo +457 -0
- package/.mops/base@0.8.3/src/Heap.mo +233 -0
- package/.mops/base@0.8.3/src/Int.mo +365 -0
- package/.mops/base@0.8.3/src/Int16.mo +521 -0
- package/.mops/base@0.8.3/src/Int32.mo +522 -0
- package/.mops/base@0.8.3/src/Int64.mo +522 -0
- package/.mops/base@0.8.3/src/Int8.mo +522 -0
- package/.mops/base@0.8.3/src/Iter.mo +227 -0
- package/.mops/base@0.8.3/src/IterType.mo +7 -0
- package/.mops/base@0.8.3/src/List.mo +930 -0
- package/.mops/base@0.8.3/src/Nat.mo +305 -0
- package/.mops/base@0.8.3/src/Nat16.mo +144 -0
- package/.mops/base@0.8.3/src/Nat32.mo +144 -0
- package/.mops/base@0.8.3/src/Nat64.mo +144 -0
- package/.mops/base@0.8.3/src/Nat8.mo +144 -0
- package/.mops/base@0.8.3/src/None.mo +19 -0
- package/.mops/base@0.8.3/src/Option.mo +154 -0
- package/.mops/base@0.8.3/src/Order.mo +46 -0
- package/.mops/base@0.8.3/src/Prelude.mo +33 -0
- package/.mops/base@0.8.3/src/Principal.mo +249 -0
- package/.mops/base@0.8.3/src/RBTree.mo +681 -0
- package/.mops/base@0.8.3/src/Random.mo +270 -0
- package/.mops/base@0.8.3/src/Result.mo +209 -0
- package/.mops/base@0.8.3/src/Stack.mo +93 -0
- package/.mops/base@0.8.3/src/Text.mo +761 -0
- package/.mops/base@0.8.3/src/Time.mo +36 -0
- package/.mops/base@0.8.3/src/Timer.mo +62 -0
- package/.mops/base@0.8.3/src/Trie.mo +1603 -0
- package/.mops/base@0.8.3/src/TrieMap.mo +392 -0
- package/.mops/base@0.8.3/src/TrieSet.mo +148 -0
- package/mops.js +1 -1
- package/network.txt +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/// Map implemented as a linked-list of key-value pairs ("Associations").
|
|
2
|
+
///
|
|
3
|
+
/// NOTE: This map implementation is mainly used as underlying buckets for other map
|
|
4
|
+
/// structures. Thus, other map implementations are easier to use in most cases.
|
|
5
|
+
|
|
6
|
+
import List "List";
|
|
7
|
+
|
|
8
|
+
module {
|
|
9
|
+
/// Import from the base library to use this module.
|
|
10
|
+
///
|
|
11
|
+
/// ```motoko name=import
|
|
12
|
+
/// import AssocList "mo:base/AssocList";
|
|
13
|
+
/// import List "mo:base/List";
|
|
14
|
+
/// import Nat "mo:base/Nat";
|
|
15
|
+
///
|
|
16
|
+
/// type AssocList<K, V> = AssocList.AssocList<K, V>;
|
|
17
|
+
/// ```
|
|
18
|
+
///
|
|
19
|
+
/// Initialize an empty map using an empty list.
|
|
20
|
+
/// ```motoko name=initialize include=import
|
|
21
|
+
/// var map : AssocList<Nat, Nat> = List.nil(); // Empty list as an empty map
|
|
22
|
+
/// map := null; // Alternative: null as empty list.
|
|
23
|
+
/// map
|
|
24
|
+
/// ```
|
|
25
|
+
public type AssocList<K, V> = List.List<(K, V)>;
|
|
26
|
+
|
|
27
|
+
/// Find the value associated with key `key`, or `null` if no such key exists.
|
|
28
|
+
/// Compares keys using the provided function `equal`.
|
|
29
|
+
///
|
|
30
|
+
/// Example:
|
|
31
|
+
/// ```motoko include=import,initialize
|
|
32
|
+
/// // Create map = [(0, 10), (1, 11), (2, 12)]
|
|
33
|
+
/// map := AssocList.replace(map, 0, Nat.equal, ?10).0;
|
|
34
|
+
/// map := AssocList.replace(map, 1, Nat.equal, ?11).0;
|
|
35
|
+
/// map := AssocList.replace(map, 2, Nat.equal, ?12).0;
|
|
36
|
+
///
|
|
37
|
+
/// // Find value associated with key 1
|
|
38
|
+
/// AssocList.find(map, 1, Nat.equal)
|
|
39
|
+
/// ```
|
|
40
|
+
/// Runtime: O(size)
|
|
41
|
+
///
|
|
42
|
+
/// Space: O(1)
|
|
43
|
+
///
|
|
44
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
45
|
+
public func find<K, V>(
|
|
46
|
+
map : AssocList<K, V>,
|
|
47
|
+
key : K,
|
|
48
|
+
equal : (K, K) -> Bool
|
|
49
|
+
) : ?V {
|
|
50
|
+
func rec(al : AssocList<K, V>) : ?V {
|
|
51
|
+
label profile_assocList_find_rec : (?V) switch (al) {
|
|
52
|
+
case (null) { label profile_assocList_find_end_fail : (?V) { null } };
|
|
53
|
+
case (?((hd_k, hd_v), tl)) {
|
|
54
|
+
if (equal(key, hd_k)) {
|
|
55
|
+
label profile_assocList_find_end_success : (?V) {
|
|
56
|
+
?hd_v
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
rec(tl)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
label profile_assocList_find_begin : (?V) {
|
|
65
|
+
rec(map)
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/// Maps `key` to `value` in `map`, and overwrites the old entry if the key
|
|
70
|
+
/// was already present. Returns the old value in an option if it existed and
|
|
71
|
+
/// `null` otherwise, as well as the new map. Compares keys using the provided
|
|
72
|
+
/// function `equal`.
|
|
73
|
+
///
|
|
74
|
+
/// Example:
|
|
75
|
+
/// ```motoko include=import,initialize
|
|
76
|
+
/// // Add three entries to the map
|
|
77
|
+
/// // map = [(0, 10), (1, 11), (2, 12)]
|
|
78
|
+
/// map := AssocList.replace(map, 0, Nat.equal, ?10).0;
|
|
79
|
+
/// map := AssocList.replace(map, 1, Nat.equal, ?11).0;
|
|
80
|
+
/// map := AssocList.replace(map, 2, Nat.equal, ?12).0;
|
|
81
|
+
/// // Override second entry
|
|
82
|
+
/// map := AssocList.replace(map, 1, Nat.equal, ?21).0;
|
|
83
|
+
///
|
|
84
|
+
/// List.toArray(map)
|
|
85
|
+
/// ```
|
|
86
|
+
/// Runtime: O(size)
|
|
87
|
+
///
|
|
88
|
+
/// Space: O(size)
|
|
89
|
+
///
|
|
90
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
91
|
+
public func replace<K, V>(
|
|
92
|
+
map : AssocList<K, V>,
|
|
93
|
+
key : K,
|
|
94
|
+
equal : (K, K) -> Bool,
|
|
95
|
+
value : ?V
|
|
96
|
+
) : (AssocList<K, V>, ?V) {
|
|
97
|
+
func rec(al : AssocList<K, V>) : (AssocList<K, V>, ?V) {
|
|
98
|
+
switch (al) {
|
|
99
|
+
case (null) {
|
|
100
|
+
switch value {
|
|
101
|
+
case (null) { (null, null) };
|
|
102
|
+
case (?value) { (?((key, value), null), null) }
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
case (?((hd_k, hd_v), tl)) {
|
|
106
|
+
if (equal(key, hd_k)) {
|
|
107
|
+
// if value is null, remove the key; otherwise, replace key's old value
|
|
108
|
+
// return old value
|
|
109
|
+
switch value {
|
|
110
|
+
case (null) { (tl, ?hd_v) };
|
|
111
|
+
case (?value) { (?((hd_k, value), tl), ?hd_v) }
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
let (tl2, old_v) = rec(tl);
|
|
115
|
+
(?((hd_k, hd_v), tl2), old_v)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
rec(map)
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/// Produces a new map containing all entries from `map1` whose keys are not
|
|
124
|
+
/// contained in `map2`. The "extra" entries in `map2` are ignored. Compares
|
|
125
|
+
/// keys using the provided function `equal`.
|
|
126
|
+
///
|
|
127
|
+
/// Example:
|
|
128
|
+
/// ```motoko include=import,initialize
|
|
129
|
+
/// // Create map1 = [(0, 10), (1, 11), (2, 12)]
|
|
130
|
+
/// var map1 : AssocList<Nat, Nat> = null;
|
|
131
|
+
/// map1 := AssocList.replace(map1, 0, Nat.equal, ?10).0;
|
|
132
|
+
/// map1 := AssocList.replace(map1, 1, Nat.equal, ?11).0;
|
|
133
|
+
/// map1 := AssocList.replace(map1, 2, Nat.equal, ?12).0;
|
|
134
|
+
///
|
|
135
|
+
/// // Create map2 = [(2, 12), (3, 13)]
|
|
136
|
+
/// var map2 : AssocList<Nat, Nat> = null;
|
|
137
|
+
/// map2 := AssocList.replace(map2, 2, Nat.equal, ?12).0;
|
|
138
|
+
/// map2 := AssocList.replace(map2, 3, Nat.equal, ?13).0;
|
|
139
|
+
///
|
|
140
|
+
/// // Take the difference
|
|
141
|
+
/// let newMap = AssocList.diff(map1, map2, Nat.equal);
|
|
142
|
+
/// List.toArray(newMap)
|
|
143
|
+
/// ```
|
|
144
|
+
/// Runtime: O(size1 * size2)
|
|
145
|
+
///
|
|
146
|
+
/// Space: O(1)
|
|
147
|
+
///
|
|
148
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
149
|
+
public func diff<K, V, W>(
|
|
150
|
+
map1 : AssocList<K, V>,
|
|
151
|
+
map2 : AssocList<K, W>,
|
|
152
|
+
equal : (K, K) -> Bool
|
|
153
|
+
) : AssocList<K, V> {
|
|
154
|
+
func rec(al1 : AssocList<K, V>) : AssocList<K, V> {
|
|
155
|
+
switch al1 {
|
|
156
|
+
case (null) { null };
|
|
157
|
+
case (?((k, v1), tl)) {
|
|
158
|
+
switch (find<K, W>(map2, k, equal)) {
|
|
159
|
+
case (null) { ?((k, v1), rec(tl)) };
|
|
160
|
+
case (?v2) { rec(tl) }
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
rec(map1)
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/// @deprecated
|
|
169
|
+
public func mapAppend<K, V, W, X>(
|
|
170
|
+
map1 : AssocList<K, V>,
|
|
171
|
+
map2 : AssocList<K, W>,
|
|
172
|
+
f : (?V, ?W) -> X
|
|
173
|
+
) : AssocList<K, X> = label profile_assocList_mapAppend : AssocList<K, X> {
|
|
174
|
+
func rec(al1 : AssocList<K, V>, al2 : AssocList<K, W>) : AssocList<K, X> = label profile_assocList_mapAppend_rec : AssocList<K, X> {
|
|
175
|
+
switch (al1, al2) {
|
|
176
|
+
case (null, null) { null };
|
|
177
|
+
case (?((k, v), al1_), _) { ?((k, f(?v, null)), rec(al1_, al2)) };
|
|
178
|
+
case (null, ?((k, v), al2_)) { ?((k, f(null, ?v)), rec(null, al2_)) }
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
rec(map1, map2)
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/// Produces a new map by mapping entries in `map1` and `map2` using `f` and
|
|
185
|
+
/// concatenating the results. Assumes that there are no collisions between
|
|
186
|
+
/// keys in `map1` and `map2`.
|
|
187
|
+
///
|
|
188
|
+
/// Example:
|
|
189
|
+
/// ```motoko include=import,initialize
|
|
190
|
+
/// import { trap } "mo:base/Debug";
|
|
191
|
+
///
|
|
192
|
+
/// // Create map1 = [(0, 10), (1, 11), (2, 12)]
|
|
193
|
+
/// var map1 : AssocList<Nat, Nat> = null;
|
|
194
|
+
/// map1 := AssocList.replace(map1, 0, Nat.equal, ?10).0;
|
|
195
|
+
/// map1 := AssocList.replace(map1, 1, Nat.equal, ?11).0;
|
|
196
|
+
/// map1 := AssocList.replace(map1, 2, Nat.equal, ?12).0;
|
|
197
|
+
///
|
|
198
|
+
/// // Create map2 = [(4, "14"), (3, "13")]
|
|
199
|
+
/// var map2 : AssocList<Nat, Text> = null;
|
|
200
|
+
/// map2 := AssocList.replace(map2, 4, Nat.equal, ?"14").0;
|
|
201
|
+
/// map2 := AssocList.replace(map2, 3, Nat.equal, ?"13").0;
|
|
202
|
+
///
|
|
203
|
+
/// // Map and append the two AssocLists
|
|
204
|
+
/// let newMap =
|
|
205
|
+
/// AssocList.disjDisjoint<Nat, Nat, Text, Text>(
|
|
206
|
+
/// map1,
|
|
207
|
+
/// map2,
|
|
208
|
+
/// func((v1, v2) : (?Nat, ?Text)) {
|
|
209
|
+
/// switch(v1, v2) {
|
|
210
|
+
/// case(?v1, null) {
|
|
211
|
+
/// debug_show(v1) // convert values from map1 to Text
|
|
212
|
+
/// };
|
|
213
|
+
/// case(null, ?v2) {
|
|
214
|
+
/// v2 // keep values from map2 as Text
|
|
215
|
+
/// };
|
|
216
|
+
/// case _ {
|
|
217
|
+
/// trap "These cases will never happen in mapAppend"
|
|
218
|
+
/// }
|
|
219
|
+
/// }
|
|
220
|
+
/// }
|
|
221
|
+
/// );
|
|
222
|
+
///
|
|
223
|
+
/// List.toArray(newMap)
|
|
224
|
+
/// ```
|
|
225
|
+
/// Runtime: O(size1 + size2)
|
|
226
|
+
///
|
|
227
|
+
/// Space: O(1)
|
|
228
|
+
///
|
|
229
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
230
|
+
public func disjDisjoint<K, V, W, X>(
|
|
231
|
+
map1 : AssocList<K, V>,
|
|
232
|
+
map2 : AssocList<K, W>,
|
|
233
|
+
f : (?V, ?W) -> X
|
|
234
|
+
) : AssocList<K, X> = label profile_assocList_disjDisjoint : AssocList<K, X> {
|
|
235
|
+
mapAppend<K, V, W, X>(map1, map2, f)
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/// Creates a new map by merging entries from `map1` and `map2`, and mapping
|
|
239
|
+
/// them using `combine`. `combine` is also used to combine the values of colliding keys.
|
|
240
|
+
/// Keys are compared using the given `equal` function.
|
|
241
|
+
///
|
|
242
|
+
/// NOTE: `combine` will never be applied to `(null, null)`.
|
|
243
|
+
///
|
|
244
|
+
/// Example:
|
|
245
|
+
/// ```motoko include=import,initialize
|
|
246
|
+
/// import { trap } "mo:base/Debug";
|
|
247
|
+
///
|
|
248
|
+
/// // Create map1 = [(0, 10), (1, 11), (2, 12)]
|
|
249
|
+
/// var map1 : AssocList<Nat, Nat> = null;
|
|
250
|
+
/// map1 := AssocList.replace(map1, 0, Nat.equal, ?10).0;
|
|
251
|
+
/// map1 := AssocList.replace(map1, 1, Nat.equal, ?11).0;
|
|
252
|
+
/// map1 := AssocList.replace(map1, 2, Nat.equal, ?12).0;
|
|
253
|
+
///
|
|
254
|
+
/// // Create map2 = [(2, 12), (3, 13)]
|
|
255
|
+
/// var map2 : AssocList<Nat, Nat> = null;
|
|
256
|
+
/// map2 := AssocList.replace(map2, 2, Nat.equal, ?12).0;
|
|
257
|
+
/// map2 := AssocList.replace(map2, 3, Nat.equal, ?13).0;
|
|
258
|
+
///
|
|
259
|
+
/// // Merge the two maps using `combine`
|
|
260
|
+
/// let newMap =
|
|
261
|
+
/// AssocList.disj<Nat, Nat, Nat, Nat>(
|
|
262
|
+
/// map1,
|
|
263
|
+
/// map2,
|
|
264
|
+
/// Nat.equal,
|
|
265
|
+
/// func((v1, v2) : (?Nat, ?Nat)) : Nat {
|
|
266
|
+
/// switch(v1, v2) {
|
|
267
|
+
/// case(?v1, ?v2) {
|
|
268
|
+
/// v1 + v2 // combine values of colliding keys by adding them
|
|
269
|
+
/// };
|
|
270
|
+
/// case(?v1, null) {
|
|
271
|
+
/// v1 // when a key doesn't collide, keep the original value
|
|
272
|
+
/// };
|
|
273
|
+
/// case(null, ?v2) {
|
|
274
|
+
/// v2
|
|
275
|
+
/// };
|
|
276
|
+
/// case _ {
|
|
277
|
+
/// trap "This case will never happen in disj"
|
|
278
|
+
/// }
|
|
279
|
+
/// }
|
|
280
|
+
/// }
|
|
281
|
+
/// );
|
|
282
|
+
///
|
|
283
|
+
/// List.toArray(newMap)
|
|
284
|
+
/// ```
|
|
285
|
+
/// Runtime: O(size1 * size2)
|
|
286
|
+
///
|
|
287
|
+
/// Space: O(size1 + size2)
|
|
288
|
+
///
|
|
289
|
+
/// *Runtime and space assumes that `equal` and `combine` runs in O(1) time and space.
|
|
290
|
+
public func disj<K, V, W, X>(
|
|
291
|
+
map1 : AssocList<K, V>,
|
|
292
|
+
map2 : AssocList<K, W>,
|
|
293
|
+
equal : (K, K) -> Bool,
|
|
294
|
+
combine : (?V, ?W) -> X
|
|
295
|
+
) : AssocList<K, X> {
|
|
296
|
+
func rec1(al1Rec : AssocList<K, V>) : AssocList<K, X> {
|
|
297
|
+
switch al1Rec {
|
|
298
|
+
case (null) {
|
|
299
|
+
func rec2(al2 : AssocList<K, W>) : AssocList<K, X> {
|
|
300
|
+
switch al2 {
|
|
301
|
+
case (null) { null };
|
|
302
|
+
case (?((k, v2), tl)) {
|
|
303
|
+
switch (find<K, V>(map1, k, equal)) {
|
|
304
|
+
case (null) { ?((k, combine(null, ?v2)), rec2(tl)) };
|
|
305
|
+
case (?v1) { ?((k, combine(?v1, ?v2)), rec2(tl)) }
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
rec2(map2)
|
|
311
|
+
};
|
|
312
|
+
case (?((k, v1), tl)) {
|
|
313
|
+
switch (find<K, W>(map2, k, equal)) {
|
|
314
|
+
case (null) { ?((k, combine(?v1, null)), rec1(tl)) };
|
|
315
|
+
case (?v2) { /* handled above */ rec1(tl) }
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
rec1(map1)
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
/// Takes the intersection of `map1` and `map2`, only keeping colliding keys
|
|
324
|
+
/// and combining values using the `combine` function. Keys are compared using
|
|
325
|
+
/// the `equal` function.
|
|
326
|
+
///
|
|
327
|
+
/// Example:
|
|
328
|
+
/// ```motoko include=import,initialize
|
|
329
|
+
/// // Create map1 = [(0, 10), (1, 11), (2, 12)]
|
|
330
|
+
/// var map1 : AssocList<Nat, Nat> = null;
|
|
331
|
+
/// map1 := AssocList.replace(map1, 0, Nat.equal, ?10).0;
|
|
332
|
+
/// map1 := AssocList.replace(map1, 1, Nat.equal, ?11).0;
|
|
333
|
+
/// map1 := AssocList.replace(map1, 2, Nat.equal, ?12).0;
|
|
334
|
+
///
|
|
335
|
+
/// // Create map2 = [(2, 12), (3, 13)]
|
|
336
|
+
/// var map2 : AssocList<Nat, Nat> = null;
|
|
337
|
+
/// map2 := AssocList.replace(map2, 2, Nat.equal, ?12).0;
|
|
338
|
+
/// map2 := AssocList.replace(map2, 3, Nat.equal, ?13).0;
|
|
339
|
+
///
|
|
340
|
+
/// // Take the intersection of the two maps, combining values by adding them
|
|
341
|
+
/// let newMap = AssocList.join<Nat, Nat, Nat, Nat>(map1, map2, Nat.equal, Nat.add);
|
|
342
|
+
///
|
|
343
|
+
/// List.toArray(newMap)
|
|
344
|
+
/// ```
|
|
345
|
+
/// Runtime: O(size1 * size2)
|
|
346
|
+
///
|
|
347
|
+
/// Space: O(size1 + size2)
|
|
348
|
+
///
|
|
349
|
+
/// *Runtime and space assumes that `equal` and `combine` runs in O(1) time and space.
|
|
350
|
+
public func join<K, V, W, X>(
|
|
351
|
+
map1 : AssocList<K, V>,
|
|
352
|
+
map2 : AssocList<K, W>,
|
|
353
|
+
equal : (K, K) -> Bool,
|
|
354
|
+
combine : (V, W) -> X
|
|
355
|
+
) : AssocList<K, X> {
|
|
356
|
+
func rec(al1 : AssocList<K, V>) : AssocList<K, X> {
|
|
357
|
+
switch al1 {
|
|
358
|
+
case (null) { null };
|
|
359
|
+
case (?((k, v1), tl)) {
|
|
360
|
+
switch (find<K, W>(map2, k, equal)) {
|
|
361
|
+
case (null) { rec(tl) };
|
|
362
|
+
case (?v2) { ?((k, combine(v1, v2)), rec(tl)) }
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
rec(map1)
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
/// Collapses the elements in `map` into a single value by starting with `base`
|
|
371
|
+
/// and progessively combining elements into `base` with `combine`. Iteration runs
|
|
372
|
+
/// left to right.
|
|
373
|
+
///
|
|
374
|
+
/// Example:
|
|
375
|
+
/// ```motoko include=import,initialize
|
|
376
|
+
/// // Create map = [(0, 10), (1, 11), (2, 12)]
|
|
377
|
+
/// var map : AssocList<Nat, Nat> = null;
|
|
378
|
+
/// map := AssocList.replace(map, 0, Nat.equal, ?10).0;
|
|
379
|
+
/// map := AssocList.replace(map, 1, Nat.equal, ?11).0;
|
|
380
|
+
/// map := AssocList.replace(map, 2, Nat.equal, ?12).0;
|
|
381
|
+
///
|
|
382
|
+
/// // (0 * 10) + (1 * 11) + (2 * 12)
|
|
383
|
+
/// AssocList.fold<Nat, Nat, Nat>(map, 0, func(k, v, sumSoFar) = (k * v) + sumSoFar)
|
|
384
|
+
/// ```
|
|
385
|
+
///
|
|
386
|
+
/// Runtime: O(size)
|
|
387
|
+
///
|
|
388
|
+
/// Space: O(size)
|
|
389
|
+
///
|
|
390
|
+
/// *Runtime and space assumes that `combine` runs in O(1) time and space.
|
|
391
|
+
public func fold<K, V, X>(
|
|
392
|
+
map : AssocList<K, V>,
|
|
393
|
+
base : X,
|
|
394
|
+
combine : (K, V, X) -> X
|
|
395
|
+
) : X {
|
|
396
|
+
func rec(al : AssocList<K, V>) : X {
|
|
397
|
+
switch al {
|
|
398
|
+
case null { base };
|
|
399
|
+
case (?((k, v), t)) { combine(k, v, rec(t)) }
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
rec(map)
|
|
403
|
+
}
|
|
404
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/// Module for working with Blobs: immutable sequence of bytes.
|
|
2
|
+
///
|
|
3
|
+
/// Blobs represent sequences of bytes. They are immutable, iterable, but not indexable and can be empty.
|
|
4
|
+
///
|
|
5
|
+
/// Byte sequences are also often represented as `[Nat8]`, i.e. an array of bytes, but this representation is currently much less compact than `Blob`, taking 4 physical bytes to represent each logical byte in the sequence.
|
|
6
|
+
/// If you would like to manipulate Blobs, it is recommended that you convert
|
|
7
|
+
/// Blobs to `[var Nat8]` or `Buffer<Nat8>`, do the manipulation, then convert back.
|
|
8
|
+
///
|
|
9
|
+
/// Import from the base library to use this module.
|
|
10
|
+
/// ```motoko name=import
|
|
11
|
+
/// import Blob "mo:base/Blob";
|
|
12
|
+
/// ```
|
|
13
|
+
///
|
|
14
|
+
/// Some built in features not listed in this module:
|
|
15
|
+
///
|
|
16
|
+
/// * You can create a `Blob` literal from a `Text` literal, provided the context expects an expression of type `Blob`.
|
|
17
|
+
/// * `b.size() : Nat` returns the number of bytes in the blob `b`;
|
|
18
|
+
/// * `b.vals() : Iter.Iter<Nat8>` returns an iterator to enumerate the bytes of the blob `b`.
|
|
19
|
+
///
|
|
20
|
+
/// For example:
|
|
21
|
+
/// ```motoko include=import
|
|
22
|
+
/// import Debug "mo:base/Debug";
|
|
23
|
+
/// import Nat8 "mo:base/Nat8";
|
|
24
|
+
///
|
|
25
|
+
/// let blob = "\00\00\00\ff" : Blob; // blob literals, where each byte is delimited by a back-slash and represented in hex
|
|
26
|
+
/// let blob2 = "charsもあり" : Blob; // you can also use characters in the literals
|
|
27
|
+
/// let numBytes = blob.size(); // => 4 (returns the number of bytes in the Blob)
|
|
28
|
+
/// for (byte : Nat8 in blob.vals()) { // iterator over the Blob
|
|
29
|
+
/// Debug.print(Nat8.toText(byte))
|
|
30
|
+
/// }
|
|
31
|
+
/// ```
|
|
32
|
+
import Prim "mo:⛔";
|
|
33
|
+
module {
|
|
34
|
+
public type Blob = Prim.Types.Blob;
|
|
35
|
+
/// Creates a `Blob` from an array of bytes (`[Nat8]`), by copying each element.
|
|
36
|
+
///
|
|
37
|
+
/// Example:
|
|
38
|
+
/// ```motoko include=import
|
|
39
|
+
/// let bytes : [Nat8] = [0, 255, 0];
|
|
40
|
+
/// let blob = Blob.fromArray(bytes); // => "\00\FF\00"
|
|
41
|
+
/// ```
|
|
42
|
+
public func fromArray(bytes : [Nat8]) : Blob = Prim.arrayToBlob bytes;
|
|
43
|
+
|
|
44
|
+
/// Creates a `Blob` from a mutable array of bytes (`[var Nat8]`), by copying each element.
|
|
45
|
+
///
|
|
46
|
+
/// Example:
|
|
47
|
+
/// ```motoko include=import
|
|
48
|
+
/// let bytes : [var Nat8] = [var 0, 255, 0];
|
|
49
|
+
/// let blob = Blob.fromArrayMut(bytes); // => "\00\FF\00"
|
|
50
|
+
/// ```
|
|
51
|
+
public func fromArrayMut(bytes : [var Nat8]) : Blob = Prim.arrayMutToBlob bytes;
|
|
52
|
+
|
|
53
|
+
/// Converts a `Blob` to an array of bytes (`[Nat8]`), by copying each element.
|
|
54
|
+
///
|
|
55
|
+
/// Example:
|
|
56
|
+
/// ```motoko include=import
|
|
57
|
+
/// let blob = "\00\FF\00" : Blob;
|
|
58
|
+
/// let bytes = Blob.toArray(blob); // => [0, 255, 0]
|
|
59
|
+
/// ```
|
|
60
|
+
public func toArray(blob : Blob) : [Nat8] = Prim.blobToArray blob;
|
|
61
|
+
|
|
62
|
+
/// Converts a `Blob` to a mutable array of bytes (`[var Nat8]`), by copying each element.
|
|
63
|
+
///
|
|
64
|
+
/// Example:
|
|
65
|
+
/// ```motoko include=import
|
|
66
|
+
/// let blob = "\00\FF\00" : Blob;
|
|
67
|
+
/// let bytes = Blob.toArrayMut(blob); // => [var 0, 255, 0]
|
|
68
|
+
/// ```
|
|
69
|
+
public func toArrayMut(blob : Blob) : [var Nat8] = Prim.blobToArrayMut blob;
|
|
70
|
+
|
|
71
|
+
/// Returns the (non-cryptographic) hash of `blob`.
|
|
72
|
+
///
|
|
73
|
+
/// Example:
|
|
74
|
+
/// ```motoko include=import
|
|
75
|
+
/// let blob = "\00\FF\00" : Blob;
|
|
76
|
+
/// Blob.hash(blob) // => 1_818_567_776
|
|
77
|
+
/// ```
|
|
78
|
+
public func hash(blob : Blob) : Nat32 = Prim.hashBlob blob;
|
|
79
|
+
|
|
80
|
+
/// General purpose comparison function for `Blob` by comparing the value of
|
|
81
|
+
/// the bytes. Returns the `Order` (either `#less`, `#equal`, or `#greater`)
|
|
82
|
+
/// by comparing `blob1` with `blob2`.
|
|
83
|
+
///
|
|
84
|
+
/// Example:
|
|
85
|
+
/// ```motoko include=import
|
|
86
|
+
/// let blob1 = "\00\00\00" : Blob;
|
|
87
|
+
/// let blob2 = "\00\FF\00" : Blob;
|
|
88
|
+
/// Blob.compare(blob1, blob2) // => #less
|
|
89
|
+
/// ```
|
|
90
|
+
public func compare(blob1 : Blob, blob2 : Blob) : { #less; #equal; #greater } {
|
|
91
|
+
if (blob1 < blob2) {
|
|
92
|
+
#less
|
|
93
|
+
} else if (blob1 == blob2) {
|
|
94
|
+
#equal
|
|
95
|
+
} else {
|
|
96
|
+
#greater
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/// Equality function for `Blob` types.
|
|
101
|
+
/// This is equivalent to `blob1 == blob2`.
|
|
102
|
+
///
|
|
103
|
+
/// Example:
|
|
104
|
+
/// ```motoko include=import
|
|
105
|
+
/// let blob1 = "\00\FF\00" : Blob;
|
|
106
|
+
/// let blob2 = "\00\FF\00" : Blob;
|
|
107
|
+
/// ignore Blob.equal(blob1, blob2);
|
|
108
|
+
/// blob1 == blob2 // => true
|
|
109
|
+
/// ```
|
|
110
|
+
///
|
|
111
|
+
/// Note: The reason why this function is defined in this library (in addition
|
|
112
|
+
/// to the existing `==` operator) is so that you can use it as a function value
|
|
113
|
+
/// to pass to a higher order function. It is not possible to use `==` as a
|
|
114
|
+
/// function value at the moment.
|
|
115
|
+
///
|
|
116
|
+
/// Example:
|
|
117
|
+
/// ```motoko include=import
|
|
118
|
+
/// import Buffer "mo:base/Buffer";
|
|
119
|
+
///
|
|
120
|
+
/// let buffer1 = Buffer.Buffer<Blob>(3);
|
|
121
|
+
/// let buffer2 = Buffer.Buffer<Blob>(3);
|
|
122
|
+
/// Buffer.equal(buffer1, buffer2, Blob.equal) // => true
|
|
123
|
+
/// ```
|
|
124
|
+
public func equal(blob1 : Blob, blob2 : Blob) : Bool { blob1 == blob2 };
|
|
125
|
+
|
|
126
|
+
/// Inequality function for `Blob` types.
|
|
127
|
+
/// This is equivalent to `blob1 != blob2`.
|
|
128
|
+
///
|
|
129
|
+
/// Example:
|
|
130
|
+
/// ```motoko include=import
|
|
131
|
+
/// let blob1 = "\00\AA\AA" : Blob;
|
|
132
|
+
/// let blob2 = "\00\FF\00" : Blob;
|
|
133
|
+
/// ignore Blob.notEqual(blob1, blob2);
|
|
134
|
+
/// blob1 != blob2 // => true
|
|
135
|
+
/// ```
|
|
136
|
+
///
|
|
137
|
+
/// Note: The reason why this function is defined in this library (in addition
|
|
138
|
+
/// to the existing `!=` operator) is so that you can use it as a function value
|
|
139
|
+
/// to pass to a higher order function. It is not possible to use `!=` as a
|
|
140
|
+
/// function value at the moment.
|
|
141
|
+
public func notEqual(blob1 : Blob, blob2 : Blob) : Bool { blob1 != blob2 };
|
|
142
|
+
|
|
143
|
+
/// "Less than" function for `Blob` types.
|
|
144
|
+
/// This is equivalent to `blob1 < blob2`.
|
|
145
|
+
///
|
|
146
|
+
/// Example:
|
|
147
|
+
/// ```motoko include=import
|
|
148
|
+
/// let blob1 = "\00\AA\AA" : Blob;
|
|
149
|
+
/// let blob2 = "\00\FF\00" : Blob;
|
|
150
|
+
/// ignore Blob.less(blob1, blob2);
|
|
151
|
+
/// blob1 < blob2 // => true
|
|
152
|
+
/// ```
|
|
153
|
+
///
|
|
154
|
+
/// Note: The reason why this function is defined in this library (in addition
|
|
155
|
+
/// to the existing `<` operator) is so that you can use it as a function value
|
|
156
|
+
/// to pass to a higher order function. It is not possible to use `<` as a
|
|
157
|
+
/// function value at the moment.
|
|
158
|
+
public func less(blob1 : Blob, blob2 : Blob) : Bool { blob1 < blob2 };
|
|
159
|
+
|
|
160
|
+
/// "Less than or equal to" function for `Blob` types.
|
|
161
|
+
/// This is equivalent to `blob1 <= blob2`.
|
|
162
|
+
///
|
|
163
|
+
/// Example:
|
|
164
|
+
/// ```motoko include=import
|
|
165
|
+
/// let blob1 = "\00\AA\AA" : Blob;
|
|
166
|
+
/// let blob2 = "\00\FF\00" : Blob;
|
|
167
|
+
/// ignore Blob.lessOrEqual(blob1, blob2);
|
|
168
|
+
/// blob1 <= blob2 // => true
|
|
169
|
+
/// ```
|
|
170
|
+
///
|
|
171
|
+
/// Note: The reason why this function is defined in this library (in addition
|
|
172
|
+
/// to the existing `<=` operator) is so that you can use it as a function value
|
|
173
|
+
/// to pass to a higher order function. It is not possible to use `<=` as a
|
|
174
|
+
/// function value at the moment.
|
|
175
|
+
public func lessOrEqual(blob1 : Blob, blob2 : Blob) : Bool { blob1 <= blob2 };
|
|
176
|
+
|
|
177
|
+
/// "Greater than" function for `Blob` types.
|
|
178
|
+
/// This is equivalent to `blob1 > blob2`.
|
|
179
|
+
///
|
|
180
|
+
/// Example:
|
|
181
|
+
/// ```motoko include=import
|
|
182
|
+
/// let blob1 = "\BB\AA\AA" : Blob;
|
|
183
|
+
/// let blob2 = "\00\00\00" : Blob;
|
|
184
|
+
/// ignore Blob.greater(blob1, blob2);
|
|
185
|
+
/// blob1 > blob2 // => true
|
|
186
|
+
/// ```
|
|
187
|
+
///
|
|
188
|
+
/// Note: The reason why this function is defined in this library (in addition
|
|
189
|
+
/// to the existing `>` operator) is so that you can use it as a function value
|
|
190
|
+
/// to pass to a higher order function. It is not possible to use `>` as a
|
|
191
|
+
/// function value at the moment.
|
|
192
|
+
public func greater(blob1 : Blob, blob2 : Blob) : Bool { blob1 > blob2 };
|
|
193
|
+
|
|
194
|
+
/// "Greater than or equal to" function for `Blob` types.
|
|
195
|
+
/// This is equivalent to `blob1 >= blob2`.
|
|
196
|
+
///
|
|
197
|
+
/// Example:
|
|
198
|
+
/// ```motoko include=import
|
|
199
|
+
/// let blob1 = "\BB\AA\AA" : Blob;
|
|
200
|
+
/// let blob2 = "\00\00\00" : Blob;
|
|
201
|
+
/// ignore Blob.greaterOrEqual(blob1, blob2);
|
|
202
|
+
/// blob1 >= blob2 // => true
|
|
203
|
+
/// ```
|
|
204
|
+
///
|
|
205
|
+
/// Note: The reason why this function is defined in this library (in addition
|
|
206
|
+
/// to the existing `>=` operator) is so that you can use it as a function value
|
|
207
|
+
/// to pass to a higher order function. It is not possible to use `>=` as a
|
|
208
|
+
/// function value at the moment.
|
|
209
|
+
public func greaterOrEqual(blob1 : Blob, blob2 : Blob) : Bool {
|
|
210
|
+
blob1 >= blob2
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/// Boolean type and operations.
|
|
2
|
+
///
|
|
3
|
+
/// While boolean operators `_ and _` and `_ or _` are short-circuiting,
|
|
4
|
+
/// avoiding computation of the right argument when possible, the functions
|
|
5
|
+
/// `logand(_, _)` and `logor(_, _)` are *strict* and will always evaluate *both*
|
|
6
|
+
/// of their arguments.
|
|
7
|
+
|
|
8
|
+
import Prim "mo:⛔";
|
|
9
|
+
module {
|
|
10
|
+
|
|
11
|
+
/// Booleans with constants `true` and `false`.
|
|
12
|
+
public type Bool = Prim.Types.Bool;
|
|
13
|
+
|
|
14
|
+
/// Conversion.
|
|
15
|
+
public func toText(x : Bool) : Text {
|
|
16
|
+
if x { "true" } else { "false" }
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/// Returns `x and y`.
|
|
20
|
+
public func logand(x : Bool, y : Bool) : Bool { x and y };
|
|
21
|
+
|
|
22
|
+
/// Returns `x or y`.
|
|
23
|
+
public func logor(x : Bool, y : Bool) : Bool { x or y };
|
|
24
|
+
|
|
25
|
+
/// Returns exclusive or of `x` and `y`, `x != y`.
|
|
26
|
+
public func logxor(x : Bool, y : Bool) : Bool {
|
|
27
|
+
x != y
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/// Returns `not x`.
|
|
31
|
+
public func lognot(x : Bool) : Bool { not x };
|
|
32
|
+
|
|
33
|
+
/// Returns `x == y`.
|
|
34
|
+
public func equal(x : Bool, y : Bool) : Bool { x == y };
|
|
35
|
+
|
|
36
|
+
/// Returns `x != y`.
|
|
37
|
+
public func notEqual(x : Bool, y : Bool) : Bool { x != y };
|
|
38
|
+
|
|
39
|
+
/// Returns the order of `x` and `y`, where `false < true`.
|
|
40
|
+
public func compare(x : Bool, y : Bool) : { #less; #equal; #greater } {
|
|
41
|
+
if (x == y) { #equal } else if (x) { #greater } else { #less }
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
}
|