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,46 @@
|
|
|
1
|
+
/// Functions on functions, creating functions from simpler inputs.
|
|
2
|
+
///
|
|
3
|
+
/// (Most commonly used when programming in functional style using higher-order
|
|
4
|
+
/// functions.)
|
|
5
|
+
|
|
6
|
+
module {
|
|
7
|
+
/// Import from the base library to use this module.
|
|
8
|
+
///
|
|
9
|
+
/// ```motoko name=import
|
|
10
|
+
/// import { compose; const; identity } = "mo:base/Func";
|
|
11
|
+
/// import Text = "mo:base/Text";
|
|
12
|
+
/// import Char = "mo:base/Char";
|
|
13
|
+
/// ```
|
|
14
|
+
|
|
15
|
+
/// The composition of two functions `f` and `g` is a function that applies `g` and then `f`.
|
|
16
|
+
///
|
|
17
|
+
/// Example:
|
|
18
|
+
/// ```motoko include=import
|
|
19
|
+
/// let textFromNat32 = compose(Text.fromChar, Char.fromNat32);
|
|
20
|
+
/// assert textFromNat32(65) == "A";
|
|
21
|
+
/// ```
|
|
22
|
+
public func compose<A, B, C>(f : B -> C, g : A -> B) : A -> C {
|
|
23
|
+
func(x : A) : C {
|
|
24
|
+
f(g(x))
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/// The `identity` function returns its argument.
|
|
29
|
+
/// Example:
|
|
30
|
+
/// ```motoko include=import
|
|
31
|
+
/// assert identity(10) == 10;
|
|
32
|
+
/// assert identity(true) == true;
|
|
33
|
+
/// ```
|
|
34
|
+
public func identity<A>(x : A) : A = x;
|
|
35
|
+
|
|
36
|
+
/// The const function is a _curried_ function that accepts an argument `x`,
|
|
37
|
+
/// and then returns a function that discards its argument and always returns
|
|
38
|
+
/// the `x`.
|
|
39
|
+
///
|
|
40
|
+
/// Example:
|
|
41
|
+
/// ```motoko include=import
|
|
42
|
+
/// assert const<Nat, Text>(10)("hello") == 10;
|
|
43
|
+
/// assert const(true)(20) == true;
|
|
44
|
+
/// ```
|
|
45
|
+
public func const<A, B>(x : A) : B -> A = func _ = x
|
|
46
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/// Hash values
|
|
2
|
+
|
|
3
|
+
import Prim "mo:⛔";
|
|
4
|
+
import Iter "Iter";
|
|
5
|
+
|
|
6
|
+
module {
|
|
7
|
+
|
|
8
|
+
/// Hash values represent a string of _hash bits_, packed into a `Nat32`.
|
|
9
|
+
public type Hash = Nat32;
|
|
10
|
+
|
|
11
|
+
/// The hash length, always 31.
|
|
12
|
+
public let length : Nat = 31; // Why not 32?
|
|
13
|
+
|
|
14
|
+
/// Project a given bit from the bit vector.
|
|
15
|
+
public func bit(h : Hash, pos : Nat) : Bool {
|
|
16
|
+
assert (pos <= length);
|
|
17
|
+
(h & (Prim.natToNat32(1) << Prim.natToNat32(pos))) != Prim.natToNat32(0)
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/// Test if two hashes are equal
|
|
21
|
+
public func equal(ha : Hash, hb : Hash) : Bool {
|
|
22
|
+
ha == hb
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/// Computes a hash from the least significant 32-bits of `n`, ignoring other bits.
|
|
26
|
+
/// @deprecated For large `Nat` values consider using a bespoke hash function that considers all of the argument's bits.
|
|
27
|
+
public func hash(n : Nat) : Hash {
|
|
28
|
+
let j = Prim.intToNat32Wrap(n);
|
|
29
|
+
hashNat8([
|
|
30
|
+
j & (255 << 0),
|
|
31
|
+
j & (255 << 8),
|
|
32
|
+
j & (255 << 16),
|
|
33
|
+
j & (255 << 24)
|
|
34
|
+
])
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/// @deprecated This function will be removed in future.
|
|
38
|
+
public func debugPrintBits(bits : Hash) {
|
|
39
|
+
for (j in Iter.range(0, length - 1)) {
|
|
40
|
+
if (bit(bits, j)) {
|
|
41
|
+
Prim.debugPrint("1")
|
|
42
|
+
} else {
|
|
43
|
+
Prim.debugPrint("0")
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/// @deprecated This function will be removed in future.
|
|
49
|
+
public func debugPrintBitsRev(bits : Hash) {
|
|
50
|
+
for (j in Iter.revRange(length - 1, 0)) {
|
|
51
|
+
if (bit(bits, Prim.abs(j))) {
|
|
52
|
+
Prim.debugPrint("1")
|
|
53
|
+
} else {
|
|
54
|
+
Prim.debugPrint("0")
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/// Jenkin's one at a time:
|
|
60
|
+
///
|
|
61
|
+
/// https://en.wikipedia.org/wiki/Jenkins_hash_function#one_at_a_time
|
|
62
|
+
///
|
|
63
|
+
/// The input type should actually be `[Nat8]`.
|
|
64
|
+
/// Note: Be sure to explode each `Nat8` of a `Nat32` into its own `Nat32`, and to shift into lower 8 bits.
|
|
65
|
+
|
|
66
|
+
// should this really be public?
|
|
67
|
+
// NB: Int.mo contains a local copy of hashNat8 (redefined to suppress the deprecation warning).
|
|
68
|
+
/// @deprecated This function may be removed or changed in future.
|
|
69
|
+
public func hashNat8(key : [Hash]) : Hash {
|
|
70
|
+
var hash : Nat32 = 0;
|
|
71
|
+
for (natOfKey in key.vals()) {
|
|
72
|
+
hash := hash +% natOfKey;
|
|
73
|
+
hash := hash +% hash << 10;
|
|
74
|
+
hash := hash ^ (hash >> 6)
|
|
75
|
+
};
|
|
76
|
+
hash := hash +% hash << 3;
|
|
77
|
+
hash := hash ^ (hash >> 11);
|
|
78
|
+
hash := hash +% hash << 15;
|
|
79
|
+
return hash
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
}
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
/// Class `HashMap<K, V>` provides a hashmap from keys of type `K` to values of type `V`.
|
|
2
|
+
|
|
3
|
+
/// The class is parameterized by the key's equality and hash functions,
|
|
4
|
+
/// and an initial capacity. However, the underlying allocation happens only when
|
|
5
|
+
/// the first key-value entry is inserted.
|
|
6
|
+
///
|
|
7
|
+
/// Internally, the map is represented as an array of `AssocList` (buckets).
|
|
8
|
+
/// The growth policy of the underyling array is very simple, for now: double
|
|
9
|
+
/// the current capacity when the expected bucket list size grows beyond a
|
|
10
|
+
/// certain constant.
|
|
11
|
+
///
|
|
12
|
+
/// WARNING: Certain operations are amortized O(1) time, such as `put`, but run
|
|
13
|
+
/// in worst case O(size) time. These worst case runtimes may exceed the cycles limit
|
|
14
|
+
/// per message if the size of the map is large enough. Further, this runtime analysis
|
|
15
|
+
/// assumes that the hash functions uniformly maps keys over the hash space. Grow these structures
|
|
16
|
+
/// with discretion, and with good hash functions. All amortized operations
|
|
17
|
+
/// below also list the worst case runtime.
|
|
18
|
+
///
|
|
19
|
+
/// For maps without amortization, see `TrieMap`.
|
|
20
|
+
///
|
|
21
|
+
/// Note on the constructor:
|
|
22
|
+
/// The argument `initCapacity` determines the initial number of buckets in the
|
|
23
|
+
/// underyling array. Also, the runtime and space anlyses in this documentation
|
|
24
|
+
/// assumes that the equality and hash functions for keys used to construct the
|
|
25
|
+
/// map run in O(1) time and space.
|
|
26
|
+
///
|
|
27
|
+
/// Example:
|
|
28
|
+
/// ```motoko name=initialize
|
|
29
|
+
/// import HashMap "mo:base/HashMap";
|
|
30
|
+
/// import Text "mo:base/Text";
|
|
31
|
+
///
|
|
32
|
+
/// let map = HashMap.HashMap<Text, Nat>(5, Text.equal, Text.hash);
|
|
33
|
+
/// ```
|
|
34
|
+
///
|
|
35
|
+
/// Runtime: O(1)
|
|
36
|
+
///
|
|
37
|
+
/// Space: O(1)
|
|
38
|
+
|
|
39
|
+
import Prim "mo:⛔";
|
|
40
|
+
import P "Prelude";
|
|
41
|
+
import A "Array";
|
|
42
|
+
import Hash "Hash";
|
|
43
|
+
import Iter "Iter";
|
|
44
|
+
import AssocList "AssocList";
|
|
45
|
+
import Nat32 "Nat32";
|
|
46
|
+
|
|
47
|
+
module {
|
|
48
|
+
|
|
49
|
+
// hash field avoids re-hashing the key when the array grows.
|
|
50
|
+
type Key<K> = (Hash.Hash, K);
|
|
51
|
+
|
|
52
|
+
// key-val list type
|
|
53
|
+
type KVs<K, V> = AssocList.AssocList<Key<K>, V>;
|
|
54
|
+
|
|
55
|
+
public class HashMap<K, V>(
|
|
56
|
+
initCapacity : Nat,
|
|
57
|
+
keyEq : (K, K) -> Bool,
|
|
58
|
+
keyHash : K -> Hash.Hash
|
|
59
|
+
) {
|
|
60
|
+
|
|
61
|
+
var table : [var KVs<K, V>] = [var];
|
|
62
|
+
var _count : Nat = 0;
|
|
63
|
+
|
|
64
|
+
/// Returns the current number of key-value entries in the map.
|
|
65
|
+
///
|
|
66
|
+
/// Example:
|
|
67
|
+
/// ```motoko include=initialize
|
|
68
|
+
/// map.size() // => 0
|
|
69
|
+
/// ```
|
|
70
|
+
///
|
|
71
|
+
/// Runtime: O(1)
|
|
72
|
+
///
|
|
73
|
+
/// Space: O(1)
|
|
74
|
+
public func size() : Nat = _count;
|
|
75
|
+
|
|
76
|
+
/// Returns the value assocaited with key `key` if present and `null` otherwise.
|
|
77
|
+
///
|
|
78
|
+
/// Example:
|
|
79
|
+
/// ```motoko include=initialize
|
|
80
|
+
/// map.put("key", 3);
|
|
81
|
+
/// map.get("key") // => ?3
|
|
82
|
+
/// ```
|
|
83
|
+
///
|
|
84
|
+
/// Expected Runtime: O(1), Worst Case Runtime: O(size)
|
|
85
|
+
///
|
|
86
|
+
/// Space: O(1)
|
|
87
|
+
public func get(key : K) : (value : ?V) {
|
|
88
|
+
let h = Prim.nat32ToNat(keyHash(key));
|
|
89
|
+
let m = table.size();
|
|
90
|
+
let v = if (m > 0) {
|
|
91
|
+
AssocList.find<Key<K>, V>(table[h % m], keyHash_(key), keyHashEq)
|
|
92
|
+
} else {
|
|
93
|
+
null
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/// Insert the value `value` with key `key`. Overwrites any existing entry with key `key`.
|
|
98
|
+
///
|
|
99
|
+
/// Example:
|
|
100
|
+
/// ```motoko include=initialize
|
|
101
|
+
/// map.put("key", 3);
|
|
102
|
+
/// map.get("key") // => ?3
|
|
103
|
+
/// ```
|
|
104
|
+
///
|
|
105
|
+
/// Expected Amortized Runtime: O(1), Worst Case Runtime: O(size)
|
|
106
|
+
///
|
|
107
|
+
/// Expected Amortized Space: O(1), Worst Case Space: O(size)
|
|
108
|
+
///
|
|
109
|
+
/// Note: If this is the first entry into this map, this operation will cause
|
|
110
|
+
/// the initial allocation of the underlying array.
|
|
111
|
+
public func put(key : K, value : V) = ignore replace(key, value);
|
|
112
|
+
|
|
113
|
+
/// Insert the value `value` with key `key`. Returns the previous value
|
|
114
|
+
/// associated with key `key` or `null` if no such value exists.
|
|
115
|
+
///
|
|
116
|
+
/// Example:
|
|
117
|
+
/// ```motoko include=initialize
|
|
118
|
+
/// map.put("key", 3);
|
|
119
|
+
/// ignore map.replace("key", 2); // => ?3
|
|
120
|
+
/// map.get("key") // => ?2
|
|
121
|
+
/// ```
|
|
122
|
+
///
|
|
123
|
+
/// Expected Amortized Runtime: O(1), Worst Case Runtime: O(size)
|
|
124
|
+
///
|
|
125
|
+
/// Expected Amortized Space: O(1), Worst Case Space: O(size)
|
|
126
|
+
///
|
|
127
|
+
/// Note: If this is the first entry into this map, this operation will cause
|
|
128
|
+
/// the initial allocation of the underlying array.
|
|
129
|
+
public func replace(key : K, value : V) : (oldValue : ?V) {
|
|
130
|
+
if (_count >= table.size()) {
|
|
131
|
+
let size = if (_count == 0) {
|
|
132
|
+
if (initCapacity > 0) {
|
|
133
|
+
initCapacity
|
|
134
|
+
} else {
|
|
135
|
+
1
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
table.size() * 2
|
|
139
|
+
};
|
|
140
|
+
let table2 = A.init<KVs<K, V>>(size, null);
|
|
141
|
+
for (i in table.keys()) {
|
|
142
|
+
var kvs = table[i];
|
|
143
|
+
label moveKeyVals : () loop {
|
|
144
|
+
switch kvs {
|
|
145
|
+
case null { break moveKeyVals };
|
|
146
|
+
case (?((k, v), kvsTail)) {
|
|
147
|
+
let pos2 = Nat32.toNat(k.0) % table2.size(); // critical: uses saved hash. no re-hash.
|
|
148
|
+
table2[pos2] := ?((k, v), table2[pos2]);
|
|
149
|
+
kvs := kvsTail
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
table := table2
|
|
155
|
+
};
|
|
156
|
+
let h = Prim.nat32ToNat(keyHash(key));
|
|
157
|
+
let pos = h % table.size();
|
|
158
|
+
let (kvs2, ov) = AssocList.replace<Key<K>, V>(table[pos], keyHash_(key), keyHashEq, ?value);
|
|
159
|
+
table[pos] := kvs2;
|
|
160
|
+
switch (ov) {
|
|
161
|
+
case null { _count += 1 };
|
|
162
|
+
case _ {}
|
|
163
|
+
};
|
|
164
|
+
ov
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/// Deletes the entry with the key `key`. Has no effect if `key` is not
|
|
168
|
+
/// present in the map.
|
|
169
|
+
///
|
|
170
|
+
/// Example:
|
|
171
|
+
/// ```motoko include=initialize
|
|
172
|
+
/// map.put("key", 3);
|
|
173
|
+
/// map.delete("key");
|
|
174
|
+
/// map.get("key"); // => null
|
|
175
|
+
/// ```
|
|
176
|
+
///
|
|
177
|
+
/// Expected Runtime: O(1), Worst Case Runtime: O(size)
|
|
178
|
+
///
|
|
179
|
+
/// Expected Space: O(1), Worst Case Space: O(size)
|
|
180
|
+
public func delete(key : K) = ignore remove(key);
|
|
181
|
+
|
|
182
|
+
func keyHash_(k : K) : Key<K> = (keyHash(k), k);
|
|
183
|
+
|
|
184
|
+
func keyHashEq(k1 : Key<K>, k2 : Key<K>) : Bool {
|
|
185
|
+
k1.0 == k2.0 and keyEq(k1.1, k2.1)
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/// Deletes the entry with the key `key`. Returns the previous value
|
|
189
|
+
/// associated with key `key` or `null` if no such value exists.
|
|
190
|
+
///
|
|
191
|
+
/// Example:
|
|
192
|
+
/// ```motoko include=initialize
|
|
193
|
+
/// map.put("key", 3);
|
|
194
|
+
/// map.remove("key"); // => ?3
|
|
195
|
+
/// ```
|
|
196
|
+
///
|
|
197
|
+
/// Expected Runtime: O(1), Worst Case Runtime: O(size)
|
|
198
|
+
///
|
|
199
|
+
/// Expected Space: O(1), Worst Case Space: O(size)
|
|
200
|
+
public func remove(key : K) : (oldValue : ?V) {
|
|
201
|
+
let m = table.size();
|
|
202
|
+
if (m > 0) {
|
|
203
|
+
let h = Prim.nat32ToNat(keyHash(key));
|
|
204
|
+
let pos = h % m;
|
|
205
|
+
let (kvs2, ov) = AssocList.replace<Key<K>, V>(table[pos], keyHash_(key), keyHashEq, null);
|
|
206
|
+
table[pos] := kvs2;
|
|
207
|
+
switch (ov) {
|
|
208
|
+
case null {};
|
|
209
|
+
case _ { _count -= 1 }
|
|
210
|
+
};
|
|
211
|
+
ov
|
|
212
|
+
} else {
|
|
213
|
+
null
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/// Returns an Iterator (`Iter`) over the keys of the map.
|
|
218
|
+
/// Iterator provides a single method `next()`, which returns
|
|
219
|
+
/// keys in no specific order, or `null` when out of keys to iterate over.
|
|
220
|
+
///
|
|
221
|
+
/// Example:
|
|
222
|
+
/// ```motoko include=initialize
|
|
223
|
+
///
|
|
224
|
+
/// map.put("key1", 1);
|
|
225
|
+
/// map.put("key2", 2);
|
|
226
|
+
/// map.put("key3", 3);
|
|
227
|
+
///
|
|
228
|
+
/// var keys = "";
|
|
229
|
+
/// for (key in map.keys()) {
|
|
230
|
+
/// keys := key # " " # keys
|
|
231
|
+
/// };
|
|
232
|
+
/// keys // => "key3 key2 key1 "
|
|
233
|
+
/// ```
|
|
234
|
+
///
|
|
235
|
+
/// Cost of iteration over all keys:
|
|
236
|
+
///
|
|
237
|
+
/// Runtime: O(size)
|
|
238
|
+
///
|
|
239
|
+
/// Space: O(1)
|
|
240
|
+
public func keys() : Iter.Iter<K> {
|
|
241
|
+
Iter.map(entries(), func(kv : (K, V)) : K { kv.0 })
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
/// Returns an Iterator (`Iter`) over the values of the map.
|
|
245
|
+
/// Iterator provides a single method `next()`, which returns
|
|
246
|
+
/// values in no specific order, or `null` when out of values to iterate over.
|
|
247
|
+
///
|
|
248
|
+
/// Example:
|
|
249
|
+
/// ```motoko include=initialize
|
|
250
|
+
///
|
|
251
|
+
/// map.put("key1", 1);
|
|
252
|
+
/// map.put("key2", 2);
|
|
253
|
+
/// map.put("key3", 3);
|
|
254
|
+
///
|
|
255
|
+
/// var sum = 0;
|
|
256
|
+
/// for (value in map.vals()) {
|
|
257
|
+
/// sum += value;
|
|
258
|
+
/// };
|
|
259
|
+
/// sum // => 6
|
|
260
|
+
/// ```
|
|
261
|
+
///
|
|
262
|
+
/// Cost of iteration over all values:
|
|
263
|
+
///
|
|
264
|
+
/// Runtime: O(size)
|
|
265
|
+
///
|
|
266
|
+
/// Space: O(1)
|
|
267
|
+
public func vals() : Iter.Iter<V> {
|
|
268
|
+
Iter.map(entries(), func(kv : (K, V)) : V { kv.1 })
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
/// Returns an Iterator (`Iter`) over the key-value pairs in the map.
|
|
272
|
+
/// Iterator provides a single method `next()`, which returns
|
|
273
|
+
/// pairs in no specific order, or `null` when out of pairs to iterate over.
|
|
274
|
+
///
|
|
275
|
+
/// Example:
|
|
276
|
+
/// ```motoko include=initialize
|
|
277
|
+
/// import Nat "mo:base/Nat";
|
|
278
|
+
///
|
|
279
|
+
/// map.put("key1", 1);
|
|
280
|
+
/// map.put("key2", 2);
|
|
281
|
+
/// map.put("key3", 3);
|
|
282
|
+
///
|
|
283
|
+
/// var pairs = "";
|
|
284
|
+
/// for ((key, value) in map.entries()) {
|
|
285
|
+
/// pairs := "(" # key # ", " # Nat.toText(value) # ") " # pairs
|
|
286
|
+
/// };
|
|
287
|
+
/// pairs // => "(key3, 3) (key2, 2) (key1, 1)"
|
|
288
|
+
/// ```
|
|
289
|
+
///
|
|
290
|
+
/// Cost of iteration over all pairs:
|
|
291
|
+
///
|
|
292
|
+
/// Runtime: O(size)
|
|
293
|
+
///
|
|
294
|
+
/// Space: O(1)
|
|
295
|
+
public func entries() : Iter.Iter<(K, V)> {
|
|
296
|
+
if (table.size() == 0) {
|
|
297
|
+
object { public func next() : ?(K, V) { null } }
|
|
298
|
+
} else {
|
|
299
|
+
object {
|
|
300
|
+
var kvs = table[0];
|
|
301
|
+
var nextTablePos = 1;
|
|
302
|
+
public func next() : ?(K, V) {
|
|
303
|
+
switch kvs {
|
|
304
|
+
case (?(kv, kvs2)) {
|
|
305
|
+
kvs := kvs2;
|
|
306
|
+
?(kv.0.1, kv.1)
|
|
307
|
+
};
|
|
308
|
+
case null {
|
|
309
|
+
if (nextTablePos < table.size()) {
|
|
310
|
+
kvs := table[nextTablePos];
|
|
311
|
+
nextTablePos += 1;
|
|
312
|
+
next()
|
|
313
|
+
} else {
|
|
314
|
+
null
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
/// Returns a copy of `map`, initializing the copy with the provided equality
|
|
326
|
+
/// and hash functions.
|
|
327
|
+
///
|
|
328
|
+
/// Example:
|
|
329
|
+
/// ```motoko include=initialize
|
|
330
|
+
/// map.put("key1", 1);
|
|
331
|
+
/// map.put("key2", 2);
|
|
332
|
+
/// map.put("key3", 3);
|
|
333
|
+
///
|
|
334
|
+
/// let map2 = HashMap.clone(map, Text.equal, Text.hash);
|
|
335
|
+
/// map2.get("key1") // => ?1
|
|
336
|
+
/// ```
|
|
337
|
+
///
|
|
338
|
+
/// Expected Runtime: O(size), Worst Case Runtime: O(size * size)
|
|
339
|
+
///
|
|
340
|
+
/// Expected Space: O(size), Worst Case Space: O(size)
|
|
341
|
+
public func clone<K, V>(
|
|
342
|
+
map : HashMap<K, V>,
|
|
343
|
+
keyEq : (K, K) -> Bool,
|
|
344
|
+
keyHash : K -> Hash.Hash
|
|
345
|
+
) : HashMap<K, V> {
|
|
346
|
+
let h2 = HashMap<K, V>(map.size(), keyEq, keyHash);
|
|
347
|
+
for ((k, v) in map.entries()) {
|
|
348
|
+
h2.put(k, v)
|
|
349
|
+
};
|
|
350
|
+
h2
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/// Returns a new map, containing all entries given by the iterator `iter`.
|
|
354
|
+
/// The new map is initialized with the provided initial capacity, equality,
|
|
355
|
+
/// and hash functions.
|
|
356
|
+
///
|
|
357
|
+
/// Example:
|
|
358
|
+
/// ```motoko include=initialize
|
|
359
|
+
/// let entries = [("key3", 3), ("key2", 2), ("key1", 1)];
|
|
360
|
+
/// let iter = entries.vals();
|
|
361
|
+
///
|
|
362
|
+
/// let map2 = HashMap.fromIter<Text, Nat>(iter, entries.size(), Text.equal, Text.hash);
|
|
363
|
+
/// map2.get("key1") // => ?1
|
|
364
|
+
/// ```
|
|
365
|
+
///
|
|
366
|
+
/// Expected Runtime: O(size), Worst Case Runtime: O(size * size)
|
|
367
|
+
///
|
|
368
|
+
/// Expected Space: O(size), Worst Case Space: O(size)
|
|
369
|
+
public func fromIter<K, V>(
|
|
370
|
+
iter : Iter.Iter<(K, V)>,
|
|
371
|
+
initCapacity : Nat,
|
|
372
|
+
keyEq : (K, K) -> Bool,
|
|
373
|
+
keyHash : K -> Hash.Hash
|
|
374
|
+
) : HashMap<K, V> {
|
|
375
|
+
let h = HashMap<K, V>(initCapacity, keyEq, keyHash);
|
|
376
|
+
for ((k, v) in iter) {
|
|
377
|
+
h.put(k, v)
|
|
378
|
+
};
|
|
379
|
+
h
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
/// Creates a new map by applying `f` to each entry in `hashMap`. Each entry
|
|
383
|
+
/// `(k, v)` in the old map is transformed into a new entry `(k, v2)`, where
|
|
384
|
+
/// the new value `v2` is created by applying `f` to `(k, v)`.
|
|
385
|
+
///
|
|
386
|
+
/// ```motoko include=initialize
|
|
387
|
+
/// map.put("key1", 1);
|
|
388
|
+
/// map.put("key2", 2);
|
|
389
|
+
/// map.put("key3", 3);
|
|
390
|
+
///
|
|
391
|
+
/// let map2 = HashMap.map<Text, Nat, Nat>(map, Text.equal, Text.hash, func (k, v) = v * 2);
|
|
392
|
+
/// map2.get("key2") // => ?4
|
|
393
|
+
/// ```
|
|
394
|
+
///
|
|
395
|
+
/// Expected Runtime: O(size), Worst Case Runtime: O(size * size)
|
|
396
|
+
///
|
|
397
|
+
/// Expected Space: O(size), Worst Case Space: O(size)
|
|
398
|
+
///
|
|
399
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
400
|
+
public func map<K, V1, V2>(
|
|
401
|
+
hashMap : HashMap<K, V1>,
|
|
402
|
+
keyEq : (K, K) -> Bool,
|
|
403
|
+
keyHash : K -> Hash.Hash,
|
|
404
|
+
f : (K, V1) -> V2
|
|
405
|
+
) : HashMap<K, V2> {
|
|
406
|
+
let h2 = HashMap<K, V2>(hashMap.size(), keyEq, keyHash);
|
|
407
|
+
for ((k, v1) in hashMap.entries()) {
|
|
408
|
+
let v2 = f(k, v1);
|
|
409
|
+
h2.put(k, v2)
|
|
410
|
+
};
|
|
411
|
+
h2
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
/// Creates a new map by applying `f` to each entry in `hashMap`. For each entry
|
|
415
|
+
/// `(k, v)` in the old map, if `f` evaluates to `null`, the entry is discarded.
|
|
416
|
+
/// Otherwise, the entry is transformed into a new entry `(k, v2)`, where
|
|
417
|
+
/// the new value `v2` is the result of applying `f` to `(k, v)`.
|
|
418
|
+
///
|
|
419
|
+
/// ```motoko include=initialize
|
|
420
|
+
/// map.put("key1", 1);
|
|
421
|
+
/// map.put("key2", 2);
|
|
422
|
+
/// map.put("key3", 3);
|
|
423
|
+
///
|
|
424
|
+
/// let map2 =
|
|
425
|
+
/// HashMap.mapFilter<Text, Nat, Nat>(
|
|
426
|
+
/// map,
|
|
427
|
+
/// Text.equal,
|
|
428
|
+
/// Text.hash,
|
|
429
|
+
/// func (k, v) = if (v == 2) { null } else { ?(v * 2)}
|
|
430
|
+
/// );
|
|
431
|
+
/// map2.get("key3") // => ?6
|
|
432
|
+
/// ```
|
|
433
|
+
///
|
|
434
|
+
/// Expected Runtime: O(size), Worst Case Runtime: O(size * size)
|
|
435
|
+
///
|
|
436
|
+
/// Expected Space: O(size), Worst Case Space: O(size)
|
|
437
|
+
///
|
|
438
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
439
|
+
public func mapFilter<K, V1, V2>(
|
|
440
|
+
hashMap : HashMap<K, V1>,
|
|
441
|
+
keyEq : (K, K) -> Bool,
|
|
442
|
+
keyHash : K -> Hash.Hash,
|
|
443
|
+
f : (K, V1) -> ?V2
|
|
444
|
+
) : HashMap<K, V2> {
|
|
445
|
+
let h2 = HashMap<K, V2>(hashMap.size(), keyEq, keyHash);
|
|
446
|
+
for ((k, v1) in hashMap.entries()) {
|
|
447
|
+
switch (f(k, v1)) {
|
|
448
|
+
case null {};
|
|
449
|
+
case (?v2) {
|
|
450
|
+
h2.put(k, v2)
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
h2
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
}
|