ic-mops 0.8.4 → 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/network.txt +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,2660 @@
|
|
|
1
|
+
/// Class `Buffer<X>` provides a mutable list of elements of type `X`.
|
|
2
|
+
/// The class wraps and resizes an underyling array that holds the elements,
|
|
3
|
+
/// and thus is comparable to ArrayLists or Vectors in other languages.
|
|
4
|
+
///
|
|
5
|
+
/// When required, the current state of a buffer object can be converted to a fixed-size array of its elements.
|
|
6
|
+
/// This is recommended for example when storing a buffer to a stable variable.
|
|
7
|
+
///
|
|
8
|
+
/// Throughout this documentation, two terms come up that can be confused: `size`
|
|
9
|
+
/// and `capacity`. `size` is the length of the list that the buffer represents.
|
|
10
|
+
/// `capacity` is the length of the underyling array that backs this list.
|
|
11
|
+
/// `capacity` >= `size` is an invariant for this class.
|
|
12
|
+
///
|
|
13
|
+
/// Like arrays, elements in the buffer are ordered by indices from 0 to `size`-1.
|
|
14
|
+
///
|
|
15
|
+
/// WARNING: Certain operations are amortized O(1) time, such as `add`, but run
|
|
16
|
+
/// in worst case O(n) time. These worst case runtimes may exceed the cycles limit
|
|
17
|
+
/// per message if the size of the buffer is large enough. Grow these structures
|
|
18
|
+
/// with discretion. All amortized operations below also list the worst case runtime.
|
|
19
|
+
///
|
|
20
|
+
/// Constructor:
|
|
21
|
+
/// The argument `initCapacity` determines the initial capacity of the array.
|
|
22
|
+
/// The underlying array grows by a factor of 1.5 when its current capacity is
|
|
23
|
+
/// exceeded. Further, when the size of the buffer shrinks to be less than 1/4th
|
|
24
|
+
/// of the capacity, the underyling array is shrunk by a factor of 2.
|
|
25
|
+
///
|
|
26
|
+
/// Example:
|
|
27
|
+
/// ```motoko name=initialize
|
|
28
|
+
/// import Buffer "mo:base/Buffer";
|
|
29
|
+
///
|
|
30
|
+
/// let buffer = Buffer.Buffer<Nat>(3); // Creates a new Buffer
|
|
31
|
+
/// ```
|
|
32
|
+
///
|
|
33
|
+
/// Runtime: O(initCapacity)
|
|
34
|
+
///
|
|
35
|
+
/// Space: O(initCapacity)
|
|
36
|
+
|
|
37
|
+
import Prim "mo:⛔";
|
|
38
|
+
import Result "Result";
|
|
39
|
+
import Order "Order";
|
|
40
|
+
import Array "Array";
|
|
41
|
+
|
|
42
|
+
module {
|
|
43
|
+
type Order = Order.Order;
|
|
44
|
+
|
|
45
|
+
// The following constants are used to manage the capacity.
|
|
46
|
+
// The length of `elements` is increased by `INCREASE_FACTOR` when capacity is reached.
|
|
47
|
+
// The length of `elements` is decreased by `DECREASE_FACTOR` when capacity is strictly less than
|
|
48
|
+
// `DECREASE_THRESHOLD`.
|
|
49
|
+
|
|
50
|
+
// INCREASE_FACTOR = INCREASE_FACTOR_NUME / INCREASE_FACTOR_DENOM (with floating point division)
|
|
51
|
+
// Keep INCREASE_FACTOR low to minimize cycle limit problem
|
|
52
|
+
private let INCREASE_FACTOR_NUME = 3;
|
|
53
|
+
private let INCREASE_FACTOR_DENOM = 2;
|
|
54
|
+
private let DECREASE_THRESHOLD = 4; // Don't decrease capacity too early to avoid thrashing
|
|
55
|
+
private let DECREASE_FACTOR = 2;
|
|
56
|
+
private let DEFAULT_CAPACITY = 8;
|
|
57
|
+
|
|
58
|
+
private func newCapacity(oldCapacity : Nat) : Nat {
|
|
59
|
+
if (oldCapacity == 0) {
|
|
60
|
+
1
|
|
61
|
+
} else {
|
|
62
|
+
// calculates ceil(oldCapacity * INCREASE_FACTOR) without floats
|
|
63
|
+
((oldCapacity * INCREASE_FACTOR_NUME) + INCREASE_FACTOR_DENOM - 1) / INCREASE_FACTOR_DENOM
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
public class Buffer<X>(initCapacity : Nat) = this {
|
|
68
|
+
var _size : Nat = 0; // avoid name clash with `size()` method
|
|
69
|
+
var elements : [var ?X] = Prim.Array_init(initCapacity, null);
|
|
70
|
+
|
|
71
|
+
/// Returns the current number of elements in the buffer.
|
|
72
|
+
///
|
|
73
|
+
/// Example:
|
|
74
|
+
/// ```motoko include=initialize
|
|
75
|
+
/// buffer.size() // => 0
|
|
76
|
+
/// ```
|
|
77
|
+
///
|
|
78
|
+
/// Runtime: O(1)
|
|
79
|
+
///
|
|
80
|
+
/// Space: O(1)
|
|
81
|
+
public func size() : Nat = _size;
|
|
82
|
+
|
|
83
|
+
/// Adds a single element to the end of the buffer, doubling
|
|
84
|
+
/// the size of the array if capacity is exceeded.
|
|
85
|
+
///
|
|
86
|
+
/// Example:
|
|
87
|
+
/// ```motoko include=initialize
|
|
88
|
+
///
|
|
89
|
+
/// buffer.add(0); // add 0 to buffer
|
|
90
|
+
/// buffer.add(1);
|
|
91
|
+
/// buffer.add(2);
|
|
92
|
+
/// buffer.add(3); // causes underlying array to increase in capacity
|
|
93
|
+
/// Buffer.toArray(buffer) // => [0, 1, 2, 3]
|
|
94
|
+
/// ```
|
|
95
|
+
///
|
|
96
|
+
/// Amortized Runtime: O(1), Worst Case Runtime: O(size)
|
|
97
|
+
///
|
|
98
|
+
/// Amortized Space: O(1), Worst Case Space: O(size)
|
|
99
|
+
public func add(element : X) {
|
|
100
|
+
if (_size == elements.size()) {
|
|
101
|
+
reserve(newCapacity(elements.size()))
|
|
102
|
+
};
|
|
103
|
+
elements[_size] := ?element;
|
|
104
|
+
_size += 1
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/// Returns the element at index `index`. Traps if `index >= size`. Indexing is zero-based.
|
|
108
|
+
///
|
|
109
|
+
/// Example:
|
|
110
|
+
/// ```motoko include=initialize
|
|
111
|
+
///
|
|
112
|
+
/// buffer.add(10);
|
|
113
|
+
/// buffer.add(11);
|
|
114
|
+
/// buffer.get(0); // => 10
|
|
115
|
+
/// ```
|
|
116
|
+
///
|
|
117
|
+
/// Runtime: O(1)
|
|
118
|
+
///
|
|
119
|
+
/// Space: O(1)
|
|
120
|
+
public func get(index : Nat) : X {
|
|
121
|
+
switch (elements[index]) {
|
|
122
|
+
case (?element) element;
|
|
123
|
+
case null Prim.trap("Buffer index out of bounds in get")
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/// Returns the element at index `index` as an option.
|
|
128
|
+
/// Returns `null` when `index >= size`. Indexing is zero-based.
|
|
129
|
+
///
|
|
130
|
+
/// Example:
|
|
131
|
+
/// ```motoko include=initialize
|
|
132
|
+
///
|
|
133
|
+
/// buffer.add(10);
|
|
134
|
+
/// buffer.add(11);
|
|
135
|
+
/// let x = buffer.getOpt(0); // => ?10
|
|
136
|
+
/// let y = buffer.getOpt(2); // => null
|
|
137
|
+
/// ```
|
|
138
|
+
///
|
|
139
|
+
/// Runtime: O(1)
|
|
140
|
+
///
|
|
141
|
+
/// Space: O(1)
|
|
142
|
+
public func getOpt(index : Nat) : ?X {
|
|
143
|
+
if (index < _size) {
|
|
144
|
+
elements[index]
|
|
145
|
+
} else {
|
|
146
|
+
null
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/// Overwrites the current element at `index` with `element`. Traps if
|
|
151
|
+
/// `index` >= size. Indexing is zero-based.
|
|
152
|
+
///
|
|
153
|
+
/// Example:
|
|
154
|
+
/// ```motoko include=initialize
|
|
155
|
+
///
|
|
156
|
+
/// buffer.add(10);
|
|
157
|
+
/// buffer.put(0, 20); // overwrites 10 at index 0 with 20
|
|
158
|
+
/// Buffer.toArray(buffer) // => [20]
|
|
159
|
+
/// ```
|
|
160
|
+
///
|
|
161
|
+
/// Runtime: O(1)
|
|
162
|
+
///
|
|
163
|
+
/// Space: O(1)
|
|
164
|
+
public func put(index : Nat, element : X) {
|
|
165
|
+
if (index >= _size) {
|
|
166
|
+
Prim.trap "Buffer index out of bounds in put"
|
|
167
|
+
};
|
|
168
|
+
elements[index] := ?element
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/// Removes and returns the last item in the buffer or `null` if
|
|
172
|
+
/// the buffer is empty.
|
|
173
|
+
///
|
|
174
|
+
/// Example:
|
|
175
|
+
/// ```motoko include=initialize
|
|
176
|
+
///
|
|
177
|
+
/// buffer.add(10);
|
|
178
|
+
/// buffer.add(11);
|
|
179
|
+
/// buffer.removeLast(); // => ?11
|
|
180
|
+
/// ```
|
|
181
|
+
///
|
|
182
|
+
/// Amortized Runtime: O(1), Worst Case Runtime: O(size)
|
|
183
|
+
///
|
|
184
|
+
/// Amortized Space: O(1), Worst Case Space: O(size)
|
|
185
|
+
public func removeLast() : ?X {
|
|
186
|
+
if (_size == 0) {
|
|
187
|
+
return null
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
_size -= 1;
|
|
191
|
+
let lastElement = elements[_size];
|
|
192
|
+
elements[_size] := null;
|
|
193
|
+
|
|
194
|
+
if (_size < elements.size() / DECREASE_THRESHOLD) {
|
|
195
|
+
// FIXME should this new capacity be a function of _size
|
|
196
|
+
// instead of the current capacity? E.g. _size * INCREASE_FACTOR
|
|
197
|
+
reserve(elements.size() / DECREASE_FACTOR)
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
lastElement
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/// Removes and returns the element at `index` from the buffer.
|
|
204
|
+
/// All elements with index > `index` are shifted one position to the left.
|
|
205
|
+
/// This may cause a downsizing of the array.
|
|
206
|
+
///
|
|
207
|
+
/// Traps if index >= size.
|
|
208
|
+
///
|
|
209
|
+
/// WARNING: Repeated removal of elements using this method is ineffecient
|
|
210
|
+
/// and might be a sign that you should consider a different data-structure
|
|
211
|
+
/// for your use case.
|
|
212
|
+
///
|
|
213
|
+
/// Example:
|
|
214
|
+
/// ```motoko include=initialize
|
|
215
|
+
///
|
|
216
|
+
/// buffer.add(10);
|
|
217
|
+
/// buffer.add(11);
|
|
218
|
+
/// buffer.add(12);
|
|
219
|
+
/// let x = buffer.remove(1); // evaluates to 11. 11 no longer in list.
|
|
220
|
+
/// Buffer.toArray(buffer) // => [10, 12]
|
|
221
|
+
/// ```
|
|
222
|
+
///
|
|
223
|
+
/// Runtime: O(size)
|
|
224
|
+
///
|
|
225
|
+
/// Amortized Space: O(1), Worst Case Space: O(size)
|
|
226
|
+
public func remove(index : Nat) : X {
|
|
227
|
+
if (index >= _size) {
|
|
228
|
+
Prim.trap "Buffer index out of bounds in remove"
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
let element = elements[index];
|
|
232
|
+
|
|
233
|
+
// copy elements to new array and shift over in one pass
|
|
234
|
+
if ((_size - 1) : Nat < elements.size() / DECREASE_THRESHOLD) {
|
|
235
|
+
let elements2 = Prim.Array_init<?X>(elements.size() / DECREASE_FACTOR, null);
|
|
236
|
+
|
|
237
|
+
var i = 0;
|
|
238
|
+
var j = 0;
|
|
239
|
+
label l while (i < _size) {
|
|
240
|
+
if (i == index) {
|
|
241
|
+
i += 1;
|
|
242
|
+
continue l
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
elements2[j] := elements[i];
|
|
246
|
+
i += 1;
|
|
247
|
+
j += 1
|
|
248
|
+
};
|
|
249
|
+
elements := elements2
|
|
250
|
+
} else {
|
|
251
|
+
// just shift over elements
|
|
252
|
+
var i = index;
|
|
253
|
+
while (i < (_size - 1 : Nat)) {
|
|
254
|
+
elements[i] := elements[i + 1];
|
|
255
|
+
i += 1
|
|
256
|
+
};
|
|
257
|
+
elements[_size - 1] := null
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
_size -= 1;
|
|
261
|
+
|
|
262
|
+
switch (element) {
|
|
263
|
+
case (?element) {
|
|
264
|
+
element
|
|
265
|
+
};
|
|
266
|
+
case null {
|
|
267
|
+
Prim.trap "Malformed buffer in remove"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
/// Resets the buffer. Capacity is set to 8.
|
|
273
|
+
///
|
|
274
|
+
/// Example:
|
|
275
|
+
/// ```motoko include=initialize
|
|
276
|
+
///
|
|
277
|
+
/// buffer.add(10);
|
|
278
|
+
/// buffer.add(11);
|
|
279
|
+
/// buffer.add(12);
|
|
280
|
+
/// buffer.clear(); // buffer is now empty
|
|
281
|
+
/// Buffer.toArray(buffer) // => []
|
|
282
|
+
/// ```
|
|
283
|
+
///
|
|
284
|
+
/// Runtime: O(1)
|
|
285
|
+
///
|
|
286
|
+
/// Space: O(1)
|
|
287
|
+
public func clear() {
|
|
288
|
+
_size := 0;
|
|
289
|
+
reserve(DEFAULT_CAPACITY)
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
/// Removes all elements from the buffer for which the predicate returns false.
|
|
293
|
+
/// The predicate is given both the index of the element and the element itself.
|
|
294
|
+
/// This may cause a downsizing of the array.
|
|
295
|
+
///
|
|
296
|
+
/// Example:
|
|
297
|
+
/// ```motoko include=initialize
|
|
298
|
+
///
|
|
299
|
+
/// buffer.add(10);
|
|
300
|
+
/// buffer.add(11);
|
|
301
|
+
/// buffer.add(12);
|
|
302
|
+
/// buffer.filterEntries(func(_, x) = x % 2 == 0); // only keep even elements
|
|
303
|
+
/// Buffer.toArray(buffer) // => [10, 12]
|
|
304
|
+
/// ```
|
|
305
|
+
///
|
|
306
|
+
/// Runtime: O(size)
|
|
307
|
+
///
|
|
308
|
+
/// Amortized Space: O(1), Worst Case Space: O(size)
|
|
309
|
+
public func filterEntries(predicate : (Nat, X) -> Bool) {
|
|
310
|
+
var numRemoved = 0;
|
|
311
|
+
let keep = Prim.Array_tabulate<Bool>(
|
|
312
|
+
_size,
|
|
313
|
+
func i {
|
|
314
|
+
switch (elements[i]) {
|
|
315
|
+
case (?element) {
|
|
316
|
+
if (predicate(i, element)) {
|
|
317
|
+
true
|
|
318
|
+
} else {
|
|
319
|
+
numRemoved += 1;
|
|
320
|
+
false
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
case null {
|
|
324
|
+
Prim.trap "Malformed buffer in filter()"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
let capacity = elements.size();
|
|
331
|
+
|
|
332
|
+
if ((_size - numRemoved : Nat) < capacity / DECREASE_THRESHOLD) {
|
|
333
|
+
let elements2 = Prim.Array_init<?X>(capacity / DECREASE_FACTOR, null);
|
|
334
|
+
|
|
335
|
+
var i = 0;
|
|
336
|
+
var j = 0;
|
|
337
|
+
while (i < _size) {
|
|
338
|
+
if (keep[i]) {
|
|
339
|
+
elements2[j] := elements[i];
|
|
340
|
+
i += 1;
|
|
341
|
+
j += 1
|
|
342
|
+
} else {
|
|
343
|
+
i += 1
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
elements := elements2
|
|
348
|
+
} else {
|
|
349
|
+
var i = 0;
|
|
350
|
+
var j = 0;
|
|
351
|
+
while (i < _size) {
|
|
352
|
+
if (keep[i]) {
|
|
353
|
+
elements[j] := elements[i];
|
|
354
|
+
i += 1;
|
|
355
|
+
j += 1
|
|
356
|
+
} else {
|
|
357
|
+
i += 1
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
while (j < _size) {
|
|
362
|
+
elements[j] := null;
|
|
363
|
+
j += 1
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
_size -= numRemoved
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
/// Returns the capacity of the buffer (the length of the underlying array).
|
|
371
|
+
///
|
|
372
|
+
/// Example:
|
|
373
|
+
/// ```motoko include=initialize
|
|
374
|
+
///
|
|
375
|
+
/// let buffer = Buffer.Buffer<Nat>(2); // underlying array has capacity 2
|
|
376
|
+
/// buffer.add(10);
|
|
377
|
+
/// let c1 = buffer.capacity(); // => 2
|
|
378
|
+
/// buffer.add(11);
|
|
379
|
+
/// buffer.add(12); // causes capacity to increase by factor of 1.5
|
|
380
|
+
/// let c2 = buffer.capacity(); // => 3
|
|
381
|
+
/// ```
|
|
382
|
+
///
|
|
383
|
+
/// Runtime: O(1)
|
|
384
|
+
///
|
|
385
|
+
/// Space: O(1)
|
|
386
|
+
public func capacity() : Nat = elements.size();
|
|
387
|
+
|
|
388
|
+
/// Changes the capacity to `capacity`. Traps if `capacity` < `size`.
|
|
389
|
+
///
|
|
390
|
+
/// ```motoko include=initialize
|
|
391
|
+
///
|
|
392
|
+
/// buffer.reserve(4);
|
|
393
|
+
/// buffer.add(10);
|
|
394
|
+
/// buffer.add(11);
|
|
395
|
+
/// buffer.capacity(); // => 4
|
|
396
|
+
/// ```
|
|
397
|
+
///
|
|
398
|
+
/// Runtime: O(capacity)
|
|
399
|
+
///
|
|
400
|
+
/// Space: O(capacity)
|
|
401
|
+
public func reserve(capacity : Nat) {
|
|
402
|
+
if (capacity < _size) {
|
|
403
|
+
Prim.trap "capacity must be >= size in reserve"
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
let elements2 = Prim.Array_init<?X>(capacity, null);
|
|
407
|
+
|
|
408
|
+
var i = 0;
|
|
409
|
+
while (i < _size) {
|
|
410
|
+
elements2[i] := elements[i];
|
|
411
|
+
i += 1
|
|
412
|
+
};
|
|
413
|
+
elements := elements2
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
/// Adds all elements in buffer `b` to this buffer.
|
|
417
|
+
///
|
|
418
|
+
/// ```motoko include=initialize
|
|
419
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
420
|
+
/// let buffer2 = Buffer.Buffer<Nat>(2);
|
|
421
|
+
/// buffer1.add(10);
|
|
422
|
+
/// buffer1.add(11);
|
|
423
|
+
/// buffer2.add(12);
|
|
424
|
+
/// buffer2.add(13);
|
|
425
|
+
/// buffer1.append(buffer2); // adds elements from buffer2 to buffer1
|
|
426
|
+
/// Buffer.toArray(buffer1) // => [10, 11, 12, 13]
|
|
427
|
+
/// ```
|
|
428
|
+
///
|
|
429
|
+
/// Amortized Runtime: O(size2), Worst Case Runtime: O(size1 + size2)
|
|
430
|
+
///
|
|
431
|
+
/// Amortized Space: O(1), Worst Case Space: O(size1 + size2)
|
|
432
|
+
public func append(buffer2 : Buffer<X>) {
|
|
433
|
+
let size2 = buffer2.size();
|
|
434
|
+
// Make sure you only allocate a new array at most once
|
|
435
|
+
if (_size + size2 > elements.size()) {
|
|
436
|
+
// FIXME would be nice to have a tabulate for var arrays here
|
|
437
|
+
reserve(newCapacity(_size + size2))
|
|
438
|
+
};
|
|
439
|
+
var i = 0;
|
|
440
|
+
while (i < size2) {
|
|
441
|
+
elements[_size + i] := buffer2.getOpt i;
|
|
442
|
+
i += 1
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
_size += size2
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
/// Inserts `element` at `index`, shifts all elements to the right of
|
|
449
|
+
/// `index` over by one index. Traps if `index` is greater than size.
|
|
450
|
+
///
|
|
451
|
+
/// ```motoko include=initialize
|
|
452
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
453
|
+
/// let buffer2 = Buffer.Buffer<Nat>(2);
|
|
454
|
+
/// buffer.add(10);
|
|
455
|
+
/// buffer.add(11);
|
|
456
|
+
/// buffer.insert(1, 9);
|
|
457
|
+
/// Buffer.toArray(buffer) // => [10, 9, 11]
|
|
458
|
+
/// ```
|
|
459
|
+
///
|
|
460
|
+
/// Runtime: O(size)
|
|
461
|
+
///
|
|
462
|
+
/// Amortized Space: O(1), Worst Case Space: O(size)
|
|
463
|
+
public func insert(index : Nat, element : X) {
|
|
464
|
+
if (index > _size) {
|
|
465
|
+
Prim.trap "Buffer index out of bounds in insert"
|
|
466
|
+
};
|
|
467
|
+
let capacity = elements.size();
|
|
468
|
+
|
|
469
|
+
if (_size + 1 > capacity) {
|
|
470
|
+
let capacity = elements.size();
|
|
471
|
+
let elements2 = Prim.Array_init<?X>(newCapacity capacity, null);
|
|
472
|
+
var i = 0;
|
|
473
|
+
while (i < _size + 1) {
|
|
474
|
+
if (i < index) {
|
|
475
|
+
elements2[i] := elements[i]
|
|
476
|
+
} else if (i == index) {
|
|
477
|
+
elements2[i] := ?element
|
|
478
|
+
} else {
|
|
479
|
+
elements2[i] := elements[i - 1]
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
i += 1
|
|
483
|
+
};
|
|
484
|
+
elements := elements2
|
|
485
|
+
} else {
|
|
486
|
+
var i : Nat = _size;
|
|
487
|
+
while (i > index) {
|
|
488
|
+
elements[i] := elements[i - 1];
|
|
489
|
+
i -= 1
|
|
490
|
+
};
|
|
491
|
+
elements[index] := ?element
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
_size += 1
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
/// Inserts `buffer2` at `index`, and shifts all elements to the right of
|
|
498
|
+
/// `index` over by size2. Traps if `index` is greater than size.
|
|
499
|
+
///
|
|
500
|
+
/// ```motoko include=initialize
|
|
501
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
502
|
+
/// let buffer2 = Buffer.Buffer<Nat>(2);
|
|
503
|
+
/// buffer1.add(10);
|
|
504
|
+
/// buffer1.add(11);
|
|
505
|
+
/// buffer2.add(12);
|
|
506
|
+
/// buffer2.add(13);
|
|
507
|
+
/// buffer1.insertBuffer(1, buffer2);
|
|
508
|
+
/// Buffer.toArray(buffer1) // => [10, 12, 13, 11]
|
|
509
|
+
/// ```
|
|
510
|
+
///
|
|
511
|
+
/// Runtime: O(size)
|
|
512
|
+
///
|
|
513
|
+
/// Amortized Space: O(1), Worst Case Space: O(size1 + size2)
|
|
514
|
+
public func insertBuffer(index : Nat, buffer2 : Buffer<X>) {
|
|
515
|
+
if (index > _size) {
|
|
516
|
+
Prim.trap "Buffer index out of bounds in insertBuffer"
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
let size2 = buffer2.size();
|
|
520
|
+
let capacity = elements.size();
|
|
521
|
+
|
|
522
|
+
// copy elements to new array and shift over in one pass
|
|
523
|
+
if (_size + size2 > capacity) {
|
|
524
|
+
let elements2 = Prim.Array_init<?X>(newCapacity(_size + size2), null);
|
|
525
|
+
var i = 0;
|
|
526
|
+
for (element in elements.vals()) {
|
|
527
|
+
if (i == index) {
|
|
528
|
+
i += size2
|
|
529
|
+
};
|
|
530
|
+
elements2[i] := element;
|
|
531
|
+
i += 1
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
i := 0;
|
|
535
|
+
while (i < size2) {
|
|
536
|
+
elements2[i + index] := buffer2.getOpt(i);
|
|
537
|
+
i += 1
|
|
538
|
+
};
|
|
539
|
+
elements := elements2
|
|
540
|
+
} // just insert
|
|
541
|
+
else {
|
|
542
|
+
var i = index;
|
|
543
|
+
while (i < index + size2) {
|
|
544
|
+
if (i < _size) {
|
|
545
|
+
elements[i + size2] := elements[i]
|
|
546
|
+
};
|
|
547
|
+
elements[i] := buffer2.getOpt(i - index);
|
|
548
|
+
|
|
549
|
+
i += 1
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
_size += size2
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
/// Sorts the elements in the buffer according to `compare`.
|
|
557
|
+
/// Sort is deterministic, stable, and in-place.
|
|
558
|
+
///
|
|
559
|
+
/// ```motoko include=initialize
|
|
560
|
+
///
|
|
561
|
+
/// import Nat "mo:base/Nat";
|
|
562
|
+
///
|
|
563
|
+
/// buffer.add(11);
|
|
564
|
+
/// buffer.add(12);
|
|
565
|
+
/// buffer.add(10);
|
|
566
|
+
/// buffer.sort(Nat.compare);
|
|
567
|
+
/// Buffer.toArray(buffer) // => [10, 11, 12]
|
|
568
|
+
/// ```
|
|
569
|
+
///
|
|
570
|
+
/// Runtime: O(size * log(size))
|
|
571
|
+
///
|
|
572
|
+
/// Space: O(size)
|
|
573
|
+
public func sort(compare : (X, X) -> Order.Order) {
|
|
574
|
+
// Stable merge sort in a bottom-up iterative style
|
|
575
|
+
if (_size == 0) {
|
|
576
|
+
return
|
|
577
|
+
};
|
|
578
|
+
let scratchSpace = Prim.Array_init<?X>(_size, null);
|
|
579
|
+
|
|
580
|
+
let sizeDec = _size - 1 : Nat;
|
|
581
|
+
var currSize = 1; // current size of the subarrays being merged
|
|
582
|
+
// when the current size == size, the array has been merged into a single sorted array
|
|
583
|
+
while (currSize < _size) {
|
|
584
|
+
var leftStart = 0; // selects the current left subarray being merged
|
|
585
|
+
while (leftStart < sizeDec) {
|
|
586
|
+
let mid : Nat = if (leftStart + currSize - 1 : Nat < sizeDec) {
|
|
587
|
+
leftStart + currSize - 1
|
|
588
|
+
} else { sizeDec };
|
|
589
|
+
let rightEnd : Nat = if (leftStart + (2 * currSize) - 1 : Nat < sizeDec) {
|
|
590
|
+
leftStart + (2 * currSize) - 1
|
|
591
|
+
} else { sizeDec };
|
|
592
|
+
|
|
593
|
+
// Merge subarrays elements[leftStart...mid] and elements[mid+1...rightEnd]
|
|
594
|
+
var left = leftStart;
|
|
595
|
+
var right = mid + 1;
|
|
596
|
+
var nextSorted = leftStart;
|
|
597
|
+
while (left < mid + 1 and right < rightEnd + 1) {
|
|
598
|
+
let leftOpt = elements[left];
|
|
599
|
+
let rightOpt = elements[right];
|
|
600
|
+
switch (leftOpt, rightOpt) {
|
|
601
|
+
case (?leftElement, ?rightElement) {
|
|
602
|
+
switch (compare(leftElement, rightElement)) {
|
|
603
|
+
case (#less or #equal) {
|
|
604
|
+
scratchSpace[nextSorted] := leftOpt;
|
|
605
|
+
left += 1
|
|
606
|
+
};
|
|
607
|
+
case (#greater) {
|
|
608
|
+
scratchSpace[nextSorted] := rightOpt;
|
|
609
|
+
right += 1
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
case (_, _) {
|
|
614
|
+
// only sorting non-null items
|
|
615
|
+
Prim.trap "Malformed buffer in sort"
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
nextSorted += 1
|
|
619
|
+
};
|
|
620
|
+
while (left < mid + 1) {
|
|
621
|
+
scratchSpace[nextSorted] := elements[left];
|
|
622
|
+
nextSorted += 1;
|
|
623
|
+
left += 1
|
|
624
|
+
};
|
|
625
|
+
while (right < rightEnd + 1) {
|
|
626
|
+
scratchSpace[nextSorted] := elements[right];
|
|
627
|
+
nextSorted += 1;
|
|
628
|
+
right += 1
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
// Copy over merged elements
|
|
632
|
+
var i = leftStart;
|
|
633
|
+
while (i < rightEnd + 1) {
|
|
634
|
+
elements[i] := scratchSpace[i];
|
|
635
|
+
i += 1
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
leftStart += 2 * currSize
|
|
639
|
+
};
|
|
640
|
+
currSize *= 2
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
/// Returns an Iterator (`Iter`) over the elements of this buffer.
|
|
645
|
+
/// Iterator provides a single method `next()`, which returns
|
|
646
|
+
/// elements in order, or `null` when out of elements to iterate over.
|
|
647
|
+
///
|
|
648
|
+
/// ```motoko include=initialize
|
|
649
|
+
///
|
|
650
|
+
/// buffer.add(10);
|
|
651
|
+
/// buffer.add(11);
|
|
652
|
+
/// buffer.add(12);
|
|
653
|
+
///
|
|
654
|
+
/// var sum = 0;
|
|
655
|
+
/// for (element in buffer.vals()) {
|
|
656
|
+
/// sum += element;
|
|
657
|
+
/// };
|
|
658
|
+
/// sum // => 33
|
|
659
|
+
/// ```
|
|
660
|
+
///
|
|
661
|
+
/// Runtime: O(1)
|
|
662
|
+
///
|
|
663
|
+
/// Space: O(1)
|
|
664
|
+
public func vals() : { next : () -> ?X } = object {
|
|
665
|
+
// FIXME either handle modification to underlying list
|
|
666
|
+
// or explicitly warn users in documentation
|
|
667
|
+
var nextIndex = 0;
|
|
668
|
+
public func next() : ?X {
|
|
669
|
+
if (nextIndex >= _size) {
|
|
670
|
+
return null
|
|
671
|
+
};
|
|
672
|
+
let nextElement = elements[nextIndex];
|
|
673
|
+
nextIndex += 1;
|
|
674
|
+
nextElement
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
// FOLLOWING METHODS ARE DEPRECATED
|
|
679
|
+
|
|
680
|
+
/// @deprecated Use static library function instead.
|
|
681
|
+
public func clone() : Buffer<X> {
|
|
682
|
+
let newBuffer = Buffer<X>(elements.size());
|
|
683
|
+
for (element in vals()) {
|
|
684
|
+
newBuffer.add(element)
|
|
685
|
+
};
|
|
686
|
+
newBuffer
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
/// @deprecated Use static library function instead.
|
|
690
|
+
public func toArray() : [X] =
|
|
691
|
+
// immutable clone of array
|
|
692
|
+
Prim.Array_tabulate<X>(
|
|
693
|
+
_size,
|
|
694
|
+
func(i : Nat) : X { get i }
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
/// @deprecated Use static library function instead.
|
|
698
|
+
public func toVarArray() : [var X] {
|
|
699
|
+
if (_size == 0) { [var] } else {
|
|
700
|
+
let newArray = Prim.Array_init<X>(_size, get 0);
|
|
701
|
+
var i = 0;
|
|
702
|
+
for (element in vals()) {
|
|
703
|
+
newArray[i] := element;
|
|
704
|
+
i += 1
|
|
705
|
+
};
|
|
706
|
+
newArray
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
/// Returns true if and only if the buffer is empty.
|
|
712
|
+
///
|
|
713
|
+
/// Example:
|
|
714
|
+
/// ```motoko include=initialize
|
|
715
|
+
/// buffer.add(2);
|
|
716
|
+
/// buffer.add(0);
|
|
717
|
+
/// buffer.add(3);
|
|
718
|
+
/// Buffer.isEmpty(buffer); // => false
|
|
719
|
+
/// ```
|
|
720
|
+
///
|
|
721
|
+
/// ```motoko include=initialize
|
|
722
|
+
/// Buffer.isEmpty(buffer); // => true
|
|
723
|
+
/// ```
|
|
724
|
+
///
|
|
725
|
+
/// Runtime: O(1)
|
|
726
|
+
///
|
|
727
|
+
/// Space: O(1)
|
|
728
|
+
public func isEmpty<X>(buffer : Buffer<X>) : Bool = buffer.size() == 0;
|
|
729
|
+
|
|
730
|
+
/// Returns true iff `buffer` contains `element` with respect to equality
|
|
731
|
+
/// defined by `equal`.
|
|
732
|
+
///
|
|
733
|
+
///
|
|
734
|
+
/// Example:
|
|
735
|
+
/// ```motoko include=initialize
|
|
736
|
+
/// import Nat "mo:base/Nat";
|
|
737
|
+
///
|
|
738
|
+
/// buffer.add(2);
|
|
739
|
+
/// buffer.add(0);
|
|
740
|
+
/// buffer.add(3);
|
|
741
|
+
/// Buffer.contains<Nat>(buffer, 2, Nat.equal); // => true
|
|
742
|
+
/// ```
|
|
743
|
+
///
|
|
744
|
+
/// Runtime: O(size)
|
|
745
|
+
///
|
|
746
|
+
/// Space: O(1)
|
|
747
|
+
///
|
|
748
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
749
|
+
public func contains<X>(buffer : Buffer<X>, element : X, equal : (X, X) -> Bool) : Bool {
|
|
750
|
+
for (current in buffer.vals()) {
|
|
751
|
+
if (equal(current, element)) {
|
|
752
|
+
return true
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
false
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
/// Returns a copy of `buffer`, with the same capacity.
|
|
760
|
+
///
|
|
761
|
+
///
|
|
762
|
+
/// Example:
|
|
763
|
+
/// ```motoko include=initialize
|
|
764
|
+
///
|
|
765
|
+
/// buffer.add(1);
|
|
766
|
+
///
|
|
767
|
+
/// let clone = Buffer.clone(buffer);
|
|
768
|
+
/// Buffer.toArray(clone); // => [1]
|
|
769
|
+
/// ```
|
|
770
|
+
///
|
|
771
|
+
/// Runtime: O(size)
|
|
772
|
+
///
|
|
773
|
+
/// Space: O(size)
|
|
774
|
+
public func clone<X>(buffer : Buffer<X>) : Buffer<X> {
|
|
775
|
+
let newBuffer = Buffer<X>(buffer.capacity());
|
|
776
|
+
for (element in buffer.vals()) {
|
|
777
|
+
newBuffer.add(element)
|
|
778
|
+
};
|
|
779
|
+
newBuffer
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/// Finds the greatest element in `buffer` defined by `compare`.
|
|
783
|
+
/// Returns `null` if `buffer` is empty.
|
|
784
|
+
///
|
|
785
|
+
///
|
|
786
|
+
/// Example:
|
|
787
|
+
/// ```motoko include=initialize
|
|
788
|
+
/// import Nat "mo:base/Nat";
|
|
789
|
+
///
|
|
790
|
+
/// buffer.add(1);
|
|
791
|
+
/// buffer.add(2);
|
|
792
|
+
///
|
|
793
|
+
/// Buffer.max(buffer, Nat.compare); // => ?2
|
|
794
|
+
/// ```
|
|
795
|
+
///
|
|
796
|
+
/// Runtime: O(size)
|
|
797
|
+
///
|
|
798
|
+
/// Space: O(1)
|
|
799
|
+
///
|
|
800
|
+
/// *Runtime and space assumes that `compare` runs in O(1) time and space.
|
|
801
|
+
public func max<X>(buffer : Buffer<X>, compare : (X, X) -> Order) : ?X {
|
|
802
|
+
if (buffer.size() == 0) {
|
|
803
|
+
return null
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
var maxSoFar = buffer.get(0);
|
|
807
|
+
for (current in buffer.vals()) {
|
|
808
|
+
switch (compare(current, maxSoFar)) {
|
|
809
|
+
case (#greater) {
|
|
810
|
+
maxSoFar := current
|
|
811
|
+
};
|
|
812
|
+
case _ {}
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
?maxSoFar
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
/// Finds the least element in `buffer` defined by `compare`.
|
|
820
|
+
/// Returns `null` if `buffer` is empty.
|
|
821
|
+
///
|
|
822
|
+
/// Example:
|
|
823
|
+
/// ```motoko include=initialize
|
|
824
|
+
/// import Nat "mo:base/Nat";
|
|
825
|
+
///
|
|
826
|
+
/// buffer.add(1);
|
|
827
|
+
/// buffer.add(2);
|
|
828
|
+
///
|
|
829
|
+
/// Buffer.min(buffer, Nat.compare); // => ?1
|
|
830
|
+
/// ```
|
|
831
|
+
///
|
|
832
|
+
/// Runtime: O(size)
|
|
833
|
+
///
|
|
834
|
+
/// Space: O(1)
|
|
835
|
+
///
|
|
836
|
+
/// *Runtime and space assumes that `compare` runs in O(1) time and space.
|
|
837
|
+
public func min<X>(buffer : Buffer<X>, compare : (X, X) -> Order) : ?X {
|
|
838
|
+
if (buffer.size() == 0) {
|
|
839
|
+
return null
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
var minSoFar = buffer.get(0);
|
|
843
|
+
for (current in buffer.vals()) {
|
|
844
|
+
switch (compare(current, minSoFar)) {
|
|
845
|
+
case (#less) {
|
|
846
|
+
minSoFar := current
|
|
847
|
+
};
|
|
848
|
+
case _ {}
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
?minSoFar
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
/// Defines equality for two buffers, using `equal` to recursively compare elements in the
|
|
856
|
+
/// buffers. Returns true iff the two buffers are of the same size, and `equal`
|
|
857
|
+
/// evaluates to true for every pair of elements in the two buffers of the same
|
|
858
|
+
/// index.
|
|
859
|
+
///
|
|
860
|
+
///
|
|
861
|
+
/// Example:
|
|
862
|
+
/// ```motoko include=initialize
|
|
863
|
+
/// import Nat "mo:base/Nat";
|
|
864
|
+
///
|
|
865
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
866
|
+
/// buffer1.add(1);
|
|
867
|
+
/// buffer1.add(2);
|
|
868
|
+
///
|
|
869
|
+
/// let buffer2 = Buffer.Buffer<Nat>(5);
|
|
870
|
+
/// buffer2.add(1);
|
|
871
|
+
/// buffer2.add(2);
|
|
872
|
+
///
|
|
873
|
+
/// Buffer.equal(buffer1, buffer2, Nat.equal); // => true
|
|
874
|
+
/// ```
|
|
875
|
+
///
|
|
876
|
+
/// Runtime: O(size)
|
|
877
|
+
///
|
|
878
|
+
/// Space: O(1)
|
|
879
|
+
///
|
|
880
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
881
|
+
public func equal<X>(buffer1 : Buffer<X>, buffer2 : Buffer<X>, equal : (X, X) -> Bool) : Bool {
|
|
882
|
+
let size1 = buffer1.size();
|
|
883
|
+
|
|
884
|
+
if (size1 != buffer2.size()) {
|
|
885
|
+
return false
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
var i = 0;
|
|
889
|
+
while (i < size1) {
|
|
890
|
+
if (not equal(buffer1.get(i), buffer2.get(i))) {
|
|
891
|
+
return false
|
|
892
|
+
};
|
|
893
|
+
i += 1
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
true
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
/// Defines comparison for two buffers, using `compare` to recursively compare elements in the
|
|
900
|
+
/// buffers. Comparison is defined lexicographically.
|
|
901
|
+
///
|
|
902
|
+
///
|
|
903
|
+
/// Example:
|
|
904
|
+
/// ```motoko include=initialize
|
|
905
|
+
/// import Nat "mo:base/Nat";
|
|
906
|
+
///
|
|
907
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
908
|
+
/// buffer1.add(1);
|
|
909
|
+
/// buffer1.add(2);
|
|
910
|
+
///
|
|
911
|
+
/// let buffer2 = Buffer.Buffer<Nat>(3);
|
|
912
|
+
/// buffer2.add(3);
|
|
913
|
+
/// buffer2.add(4);
|
|
914
|
+
///
|
|
915
|
+
/// Buffer.compare<Nat>(buffer1, buffer2, Nat.compare); // => #less
|
|
916
|
+
/// ```
|
|
917
|
+
///
|
|
918
|
+
/// Runtime: O(size)
|
|
919
|
+
///
|
|
920
|
+
/// Space: O(1)
|
|
921
|
+
///
|
|
922
|
+
/// *Runtime and space assumes that `compare` runs in O(1) time and space.
|
|
923
|
+
public func compare<X>(buffer1 : Buffer<X>, buffer2 : Buffer<X>, compare : (X, X) -> Order.Order) : Order.Order {
|
|
924
|
+
let size1 = buffer1.size();
|
|
925
|
+
let size2 = buffer2.size();
|
|
926
|
+
let minSize = if (size1 < size2) { size1 } else { size2 };
|
|
927
|
+
|
|
928
|
+
var i = 0;
|
|
929
|
+
while (i < minSize) {
|
|
930
|
+
switch (compare(buffer1.get(i), buffer2.get(i))) {
|
|
931
|
+
case (#less) {
|
|
932
|
+
return #less
|
|
933
|
+
};
|
|
934
|
+
case (#greater) {
|
|
935
|
+
return #greater
|
|
936
|
+
};
|
|
937
|
+
case _ {}
|
|
938
|
+
};
|
|
939
|
+
i += 1
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
if (size1 < size2) {
|
|
943
|
+
#less
|
|
944
|
+
} else if (size1 == size2) {
|
|
945
|
+
#equal
|
|
946
|
+
} else {
|
|
947
|
+
#greater
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
/// Creates a textual representation of `buffer`, using `toText` to recursively
|
|
952
|
+
/// convert the elements into Text.
|
|
953
|
+
///
|
|
954
|
+
/// Example:
|
|
955
|
+
/// ```motoko include=initialize
|
|
956
|
+
/// import Nat "mo:base/Nat";
|
|
957
|
+
///
|
|
958
|
+
/// buffer.add(1);
|
|
959
|
+
/// buffer.add(2);
|
|
960
|
+
/// buffer.add(3);
|
|
961
|
+
/// buffer.add(4);
|
|
962
|
+
///
|
|
963
|
+
/// Buffer.toText(buffer, Nat.toText); // => "[1, 2, 3, 4]"
|
|
964
|
+
/// ```
|
|
965
|
+
///
|
|
966
|
+
/// Runtime: O(size)
|
|
967
|
+
///
|
|
968
|
+
/// Space: O(size)
|
|
969
|
+
///
|
|
970
|
+
/// *Runtime and space assumes that `toText` runs in O(1) time and space.
|
|
971
|
+
public func toText<X>(buffer : Buffer<X>, toText : X -> Text) : Text {
|
|
972
|
+
let size : Int = buffer.size();
|
|
973
|
+
var i = 0;
|
|
974
|
+
var text = "";
|
|
975
|
+
while (i < size - 1) {
|
|
976
|
+
text := text # toText(buffer.get(i)) # ", "; // Text implemented as rope
|
|
977
|
+
i += 1
|
|
978
|
+
};
|
|
979
|
+
if (size > 0) {
|
|
980
|
+
// avoid the trailing comma
|
|
981
|
+
text := text # toText(buffer.get(i))
|
|
982
|
+
};
|
|
983
|
+
|
|
984
|
+
"[" # text # "]"
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
/// Hashes `buffer` using `hash` to hash the underlying elements.
|
|
988
|
+
/// The deterministic hash function is a function of the elements in the Buffer, as well
|
|
989
|
+
/// as their ordering.
|
|
990
|
+
///
|
|
991
|
+
/// Example:
|
|
992
|
+
/// ```motoko include=initialize
|
|
993
|
+
/// import Hash "mo:base/Hash";
|
|
994
|
+
///
|
|
995
|
+
/// buffer.add(1);
|
|
996
|
+
/// buffer.add(2);
|
|
997
|
+
/// buffer.add(3);
|
|
998
|
+
/// buffer.add(1000);
|
|
999
|
+
///
|
|
1000
|
+
/// Buffer.hash<Nat>(buffer, Hash.hash); // => 2_872_640_342
|
|
1001
|
+
/// ```
|
|
1002
|
+
///
|
|
1003
|
+
/// Runtime: O(size)
|
|
1004
|
+
///
|
|
1005
|
+
/// Space: O(1)
|
|
1006
|
+
///
|
|
1007
|
+
/// *Runtime and space assumes that `hash` runs in O(1) time and space.
|
|
1008
|
+
public func hash<X>(buffer : Buffer<X>, hash : X -> Nat32) : Nat32 {
|
|
1009
|
+
let size = buffer.size();
|
|
1010
|
+
var i = 0;
|
|
1011
|
+
var accHash : Nat32 = 0;
|
|
1012
|
+
|
|
1013
|
+
while (i < size) {
|
|
1014
|
+
accHash := Prim.intToNat32Wrap(i) ^ accHash ^ hash(buffer.get(i));
|
|
1015
|
+
i += 1
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
accHash
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
/// Finds the first index of `element` in `buffer` using equality of elements defined
|
|
1022
|
+
/// by `equal`. Returns `null` if `element` is not found.
|
|
1023
|
+
///
|
|
1024
|
+
/// Example:
|
|
1025
|
+
/// ```motoko include=initialize
|
|
1026
|
+
/// import Nat "mo:base/Nat";
|
|
1027
|
+
///
|
|
1028
|
+
/// buffer.add(1);
|
|
1029
|
+
/// buffer.add(2);
|
|
1030
|
+
/// buffer.add(3);
|
|
1031
|
+
/// buffer.add(4);
|
|
1032
|
+
///
|
|
1033
|
+
/// Buffer.indexOf<Nat>(3, buffer, Nat.equal); // => ?2
|
|
1034
|
+
/// ```
|
|
1035
|
+
///
|
|
1036
|
+
/// Runtime: O(size)
|
|
1037
|
+
///
|
|
1038
|
+
/// Space: O(size)
|
|
1039
|
+
///
|
|
1040
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1041
|
+
public func indexOf<X>(element : X, buffer : Buffer<X>, equal : (X, X) -> Bool) : ?Nat {
|
|
1042
|
+
let size = buffer.size();
|
|
1043
|
+
var i = 0;
|
|
1044
|
+
while (i < size) {
|
|
1045
|
+
if (equal(buffer.get(i), element)) {
|
|
1046
|
+
return ?i
|
|
1047
|
+
};
|
|
1048
|
+
i += 1
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
null
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
/// Finds the last index of `element` in `buffer` using equality of elements defined
|
|
1055
|
+
/// by `equal`. Returns `null` if `element` is not found.
|
|
1056
|
+
///
|
|
1057
|
+
/// Example:
|
|
1058
|
+
/// ```motoko include=initialize
|
|
1059
|
+
/// import Nat "mo:base/Nat";
|
|
1060
|
+
///
|
|
1061
|
+
/// buffer.add(1);
|
|
1062
|
+
/// buffer.add(2);
|
|
1063
|
+
/// buffer.add(3);
|
|
1064
|
+
/// buffer.add(4);
|
|
1065
|
+
/// buffer.add(2);
|
|
1066
|
+
/// buffer.add(2);
|
|
1067
|
+
///
|
|
1068
|
+
/// Buffer.lastIndexOf<Nat>(2, buffer, Nat.equal); // => ?5
|
|
1069
|
+
/// ```
|
|
1070
|
+
///
|
|
1071
|
+
/// Runtime: O(size)
|
|
1072
|
+
///
|
|
1073
|
+
/// Space: O(size)
|
|
1074
|
+
///
|
|
1075
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1076
|
+
public func lastIndexOf<X>(element : X, buffer : Buffer<X>, equal : (X, X) -> Bool) : ?Nat {
|
|
1077
|
+
let size = buffer.size();
|
|
1078
|
+
if (size == 0) {
|
|
1079
|
+
return null
|
|
1080
|
+
};
|
|
1081
|
+
var i = size;
|
|
1082
|
+
while (i >= 1) {
|
|
1083
|
+
i -= 1;
|
|
1084
|
+
if (equal(buffer.get(i), element)) {
|
|
1085
|
+
return ?i
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
|
|
1089
|
+
null
|
|
1090
|
+
};
|
|
1091
|
+
|
|
1092
|
+
/// Searches for `subBuffer` in `buffer`, and returns the starting index if it is found.
|
|
1093
|
+
///
|
|
1094
|
+
/// Example:
|
|
1095
|
+
/// ```motoko include=initialize
|
|
1096
|
+
/// import Nat "mo:base/Nat";
|
|
1097
|
+
///
|
|
1098
|
+
/// buffer.add(1);
|
|
1099
|
+
/// buffer.add(2);
|
|
1100
|
+
/// buffer.add(3);
|
|
1101
|
+
/// buffer.add(4);
|
|
1102
|
+
/// buffer.add(5);
|
|
1103
|
+
/// buffer.add(6);
|
|
1104
|
+
///
|
|
1105
|
+
/// let sub = Buffer.Buffer<Nat>(2);
|
|
1106
|
+
/// sub.add(4);
|
|
1107
|
+
/// sub.add(5);
|
|
1108
|
+
/// sub.add(6);
|
|
1109
|
+
///
|
|
1110
|
+
/// Buffer.indexOfBuffer<Nat>(sub, buffer, Nat.equal); // => ?3
|
|
1111
|
+
/// ```
|
|
1112
|
+
///
|
|
1113
|
+
/// Runtime: O(size of buffer + size of subBuffer)
|
|
1114
|
+
///
|
|
1115
|
+
/// Space: O(size of subBuffer)
|
|
1116
|
+
///
|
|
1117
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1118
|
+
public func indexOfBuffer<X>(subBuffer : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : ?Nat {
|
|
1119
|
+
// Uses the KMP substring search algorithm
|
|
1120
|
+
// Implementation from: https://www.educative.io/answers/what-is-the-knuth-morris-pratt-algorithm
|
|
1121
|
+
let size = buffer.size();
|
|
1122
|
+
let subSize = subBuffer.size();
|
|
1123
|
+
if (subSize > size or subSize == 0) {
|
|
1124
|
+
return null
|
|
1125
|
+
};
|
|
1126
|
+
|
|
1127
|
+
// precompute lps
|
|
1128
|
+
let lps = Prim.Array_init<Nat>(subSize, 0);
|
|
1129
|
+
var i = 0;
|
|
1130
|
+
var j = 1;
|
|
1131
|
+
|
|
1132
|
+
while (j < subSize) {
|
|
1133
|
+
if (equal(subBuffer.get(i), subBuffer.get(j))) {
|
|
1134
|
+
i += 1;
|
|
1135
|
+
lps[j] := i;
|
|
1136
|
+
j += 1
|
|
1137
|
+
} else if (i == 0) {
|
|
1138
|
+
lps[j] := 0;
|
|
1139
|
+
j += 1
|
|
1140
|
+
} else {
|
|
1141
|
+
i := lps[i - 1]
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1144
|
+
|
|
1145
|
+
// start search
|
|
1146
|
+
i := 0;
|
|
1147
|
+
j := 0;
|
|
1148
|
+
let subSizeDec = subSize - 1 : Nat; // hoisting loop invariant
|
|
1149
|
+
while (i < subSize and j < size) {
|
|
1150
|
+
if (equal(subBuffer.get(i), buffer.get(j)) and i == subSizeDec) {
|
|
1151
|
+
return ?(j - i)
|
|
1152
|
+
} else if (equal(subBuffer.get(i), buffer.get(j))) {
|
|
1153
|
+
i += 1;
|
|
1154
|
+
j += 1
|
|
1155
|
+
} else {
|
|
1156
|
+
if (i != 0) {
|
|
1157
|
+
i := lps[i - 1]
|
|
1158
|
+
} else {
|
|
1159
|
+
j += 1
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
|
|
1164
|
+
null
|
|
1165
|
+
};
|
|
1166
|
+
|
|
1167
|
+
/// Similar to indexOf, but runs in logarithmic time. Assumes that `buffer` is sorted.
|
|
1168
|
+
/// Behavior is undefined if `buffer` is not sorted. Uses `compare` to
|
|
1169
|
+
/// perform the search. Returns an index of `element` if it is found.
|
|
1170
|
+
///
|
|
1171
|
+
/// Example:
|
|
1172
|
+
/// ```motoko include=initialize
|
|
1173
|
+
/// import Nat "mo:base/Nat";
|
|
1174
|
+
///
|
|
1175
|
+
/// buffer.add(1);
|
|
1176
|
+
/// buffer.add(4);
|
|
1177
|
+
/// buffer.add(5);
|
|
1178
|
+
/// buffer.add(6);
|
|
1179
|
+
///
|
|
1180
|
+
/// Buffer.binarySearch<Nat>(5, buffer, Nat.compare); // => ?2
|
|
1181
|
+
/// ```
|
|
1182
|
+
///
|
|
1183
|
+
/// Runtime: O(log(size))
|
|
1184
|
+
///
|
|
1185
|
+
/// Space: O(1)
|
|
1186
|
+
///
|
|
1187
|
+
/// *Runtime and space assumes that `compare` runs in O(1) time and space.
|
|
1188
|
+
public func binarySearch<X>(element : X, buffer : Buffer<X>, compare : (X, X) -> Order.Order) : ?Nat {
|
|
1189
|
+
var low = 0;
|
|
1190
|
+
var high = buffer.size();
|
|
1191
|
+
|
|
1192
|
+
while (low < high) {
|
|
1193
|
+
let mid = (low + high) / 2;
|
|
1194
|
+
let current = buffer.get(mid);
|
|
1195
|
+
switch (compare(element, current)) {
|
|
1196
|
+
case (#equal) {
|
|
1197
|
+
return ?mid
|
|
1198
|
+
};
|
|
1199
|
+
case (#less) {
|
|
1200
|
+
high := mid
|
|
1201
|
+
};
|
|
1202
|
+
case (#greater) {
|
|
1203
|
+
low := mid + 1
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
};
|
|
1207
|
+
|
|
1208
|
+
null
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1211
|
+
/// Returns the sub-buffer of `buffer` starting at index `start`
|
|
1212
|
+
/// of length `length`. Traps if `start` is out of bounds, or `start + length`
|
|
1213
|
+
/// is greater than the size of `buffer`.
|
|
1214
|
+
///
|
|
1215
|
+
/// Example:
|
|
1216
|
+
/// ```motoko include=initialize
|
|
1217
|
+
/// import Nat "mo:base/Nat";
|
|
1218
|
+
///
|
|
1219
|
+
/// buffer.add(1);
|
|
1220
|
+
/// buffer.add(2);
|
|
1221
|
+
/// buffer.add(3);
|
|
1222
|
+
/// buffer.add(4);
|
|
1223
|
+
/// buffer.add(5);
|
|
1224
|
+
/// buffer.add(6);
|
|
1225
|
+
///
|
|
1226
|
+
/// let sub = Buffer.subBuffer(buffer, 3, 2);
|
|
1227
|
+
/// Buffer.toText(sub, Nat.toText); // => [4, 5]
|
|
1228
|
+
/// ```
|
|
1229
|
+
///
|
|
1230
|
+
/// Runtime: O(length)
|
|
1231
|
+
///
|
|
1232
|
+
/// Space: O(length)
|
|
1233
|
+
public func subBuffer<X>(buffer : Buffer<X>, start : Nat, length : Nat) : Buffer<X> {
|
|
1234
|
+
let size = buffer.size();
|
|
1235
|
+
let end = start + length; // exclusive
|
|
1236
|
+
if (start >= size or end > size) {
|
|
1237
|
+
Prim.trap "Buffer index out of bounds in subBuffer"
|
|
1238
|
+
};
|
|
1239
|
+
|
|
1240
|
+
let newBuffer = Buffer<X>(newCapacity length);
|
|
1241
|
+
|
|
1242
|
+
var i = start;
|
|
1243
|
+
while (i < end) {
|
|
1244
|
+
newBuffer.add(buffer.get(i));
|
|
1245
|
+
|
|
1246
|
+
i += 1
|
|
1247
|
+
};
|
|
1248
|
+
|
|
1249
|
+
newBuffer
|
|
1250
|
+
};
|
|
1251
|
+
|
|
1252
|
+
/// Checks if `subBuffer` is a sub-Buffer of `buffer`. Uses `equal` to
|
|
1253
|
+
/// compare elements.
|
|
1254
|
+
///
|
|
1255
|
+
/// Example:
|
|
1256
|
+
/// ```motoko include=initialize
|
|
1257
|
+
/// import Nat "mo:base/Nat";
|
|
1258
|
+
///
|
|
1259
|
+
/// buffer.add(1);
|
|
1260
|
+
/// buffer.add(2);
|
|
1261
|
+
/// buffer.add(3);
|
|
1262
|
+
/// buffer.add(4);
|
|
1263
|
+
/// buffer.add(5);
|
|
1264
|
+
/// buffer.add(6);
|
|
1265
|
+
///
|
|
1266
|
+
/// let sub = Buffer.Buffer<Nat>(2);
|
|
1267
|
+
/// sub.add(2);
|
|
1268
|
+
/// sub.add(3);
|
|
1269
|
+
/// Buffer.isSubBufferOf(sub, buffer, Nat.equal); // => true
|
|
1270
|
+
/// ```
|
|
1271
|
+
///
|
|
1272
|
+
/// Runtime: O(size of subBuffer + size of buffer)
|
|
1273
|
+
///
|
|
1274
|
+
/// Space: O(size of subBuffer)
|
|
1275
|
+
///
|
|
1276
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1277
|
+
public func isSubBufferOf<X>(subBuffer : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : Bool {
|
|
1278
|
+
switch (indexOfBuffer(subBuffer, buffer, equal)) {
|
|
1279
|
+
case null subBuffer.size() == 0;
|
|
1280
|
+
case _ true
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
|
|
1284
|
+
/// Checks if `subBuffer` is a strict subBuffer of `buffer`, i.e. `subBuffer` must be
|
|
1285
|
+
/// strictly contained inside both the first and last indices of `buffer`.
|
|
1286
|
+
/// Uses `equal` to compare elements.
|
|
1287
|
+
///
|
|
1288
|
+
/// Example:
|
|
1289
|
+
/// ```motoko include=initialize
|
|
1290
|
+
/// import Nat "mo:base/Nat";
|
|
1291
|
+
///
|
|
1292
|
+
/// buffer.add(1);
|
|
1293
|
+
/// buffer.add(2);
|
|
1294
|
+
/// buffer.add(3);
|
|
1295
|
+
/// buffer.add(4);
|
|
1296
|
+
///
|
|
1297
|
+
/// let sub = Buffer.Buffer<Nat>(2);
|
|
1298
|
+
/// sub.add(2);
|
|
1299
|
+
/// sub.add(3);
|
|
1300
|
+
/// Buffer.isStrictSubBufferOf(sub, buffer, Nat.equal); // => true
|
|
1301
|
+
/// ```
|
|
1302
|
+
///
|
|
1303
|
+
/// Runtime: O(size of subBuffer + size of buffer)
|
|
1304
|
+
///
|
|
1305
|
+
/// Space: O(size of subBuffer)
|
|
1306
|
+
///
|
|
1307
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1308
|
+
public func isStrictSubBufferOf<X>(subBuffer : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : Bool {
|
|
1309
|
+
let subBufferSize = subBuffer.size();
|
|
1310
|
+
|
|
1311
|
+
switch (indexOfBuffer(subBuffer, buffer, equal)) {
|
|
1312
|
+
case (?index) {
|
|
1313
|
+
index != 0 and index != (buffer.size() - subBufferSize : Nat) // enforce strictness
|
|
1314
|
+
};
|
|
1315
|
+
case null {
|
|
1316
|
+
subBufferSize == 0 and subBufferSize != buffer.size()
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
|
|
1321
|
+
/// Returns the prefix of `buffer` of length `length`. Traps if `length`
|
|
1322
|
+
/// is greater than the size of `buffer`.
|
|
1323
|
+
///
|
|
1324
|
+
/// Example:
|
|
1325
|
+
/// ```motoko include=initialize
|
|
1326
|
+
/// import Nat "mo:base/Nat";
|
|
1327
|
+
///
|
|
1328
|
+
/// buffer.add(1);
|
|
1329
|
+
/// buffer.add(2);
|
|
1330
|
+
/// buffer.add(3);
|
|
1331
|
+
/// buffer.add(4);
|
|
1332
|
+
///
|
|
1333
|
+
/// let pre = Buffer.prefix(buffer, 3); // => [1, 2, 3]
|
|
1334
|
+
/// Buffer.toText(pre, Nat.toText);
|
|
1335
|
+
/// ```
|
|
1336
|
+
///
|
|
1337
|
+
/// Runtime: O(length)
|
|
1338
|
+
///
|
|
1339
|
+
/// Space: O(length)
|
|
1340
|
+
public func prefix<X>(buffer : Buffer<X>, length : Nat) : Buffer<X> {
|
|
1341
|
+
let size = buffer.size();
|
|
1342
|
+
if (length > size) {
|
|
1343
|
+
Prim.trap "Buffer index out of bounds in prefix"
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1346
|
+
let newBuffer = Buffer<X>(newCapacity length);
|
|
1347
|
+
|
|
1348
|
+
var i = 0;
|
|
1349
|
+
while (i < length) {
|
|
1350
|
+
newBuffer.add(buffer.get(i));
|
|
1351
|
+
i += 1
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
newBuffer
|
|
1355
|
+
};
|
|
1356
|
+
|
|
1357
|
+
/// Checks if `prefix` is a prefix of `buffer`. Uses `equal` to
|
|
1358
|
+
/// compare elements.
|
|
1359
|
+
///
|
|
1360
|
+
/// Example:
|
|
1361
|
+
/// ```motoko include=initialize
|
|
1362
|
+
/// import Nat "mo:base/Nat";
|
|
1363
|
+
///
|
|
1364
|
+
/// buffer.add(1);
|
|
1365
|
+
/// buffer.add(2);
|
|
1366
|
+
/// buffer.add(3);
|
|
1367
|
+
/// buffer.add(4);
|
|
1368
|
+
///
|
|
1369
|
+
/// let pre = Buffer.Buffer<Nat>(2);
|
|
1370
|
+
/// pre.add(1);
|
|
1371
|
+
/// pre.add(2);
|
|
1372
|
+
/// Buffer.isPrefixOf(pre, buffer, Nat.equal); // => true
|
|
1373
|
+
/// ```
|
|
1374
|
+
///
|
|
1375
|
+
/// Runtime: O(size of prefix)
|
|
1376
|
+
///
|
|
1377
|
+
/// Space: O(size of prefix)
|
|
1378
|
+
///
|
|
1379
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1380
|
+
public func isPrefixOf<X>(prefix : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : Bool {
|
|
1381
|
+
let sizePrefix = prefix.size();
|
|
1382
|
+
if (buffer.size() < sizePrefix) {
|
|
1383
|
+
return false
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
var i = 0;
|
|
1387
|
+
while (i < sizePrefix) {
|
|
1388
|
+
if (not equal(buffer.get(i), prefix.get(i))) {
|
|
1389
|
+
return false
|
|
1390
|
+
};
|
|
1391
|
+
|
|
1392
|
+
i += 1
|
|
1393
|
+
};
|
|
1394
|
+
|
|
1395
|
+
return true
|
|
1396
|
+
};
|
|
1397
|
+
|
|
1398
|
+
/// Checks if `prefix` is a strict prefix of `buffer`. Uses `equal` to
|
|
1399
|
+
/// compare elements.
|
|
1400
|
+
///
|
|
1401
|
+
/// Example:
|
|
1402
|
+
/// ```motoko include=initialize
|
|
1403
|
+
/// import Nat "mo:base/Nat";
|
|
1404
|
+
///
|
|
1405
|
+
/// buffer.add(1);
|
|
1406
|
+
/// buffer.add(2);
|
|
1407
|
+
/// buffer.add(3);
|
|
1408
|
+
/// buffer.add(4);
|
|
1409
|
+
///
|
|
1410
|
+
/// let pre = Buffer.Buffer<Nat>(3);
|
|
1411
|
+
/// pre.add(1);
|
|
1412
|
+
/// pre.add(2);
|
|
1413
|
+
/// pre.add(3);
|
|
1414
|
+
/// Buffer.isStrictPrefixOf(pre, buffer, Nat.equal); // => true
|
|
1415
|
+
/// ```
|
|
1416
|
+
///
|
|
1417
|
+
/// Runtime: O(size of prefix)
|
|
1418
|
+
///
|
|
1419
|
+
/// Space: O(size of prefix)
|
|
1420
|
+
///
|
|
1421
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1422
|
+
public func isStrictPrefixOf<X>(prefix : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : Bool {
|
|
1423
|
+
if (buffer.size() <= prefix.size()) {
|
|
1424
|
+
return false
|
|
1425
|
+
};
|
|
1426
|
+
isPrefixOf(prefix, buffer, equal)
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
/// Returns the suffix of `buffer` of length `length`.
|
|
1430
|
+
/// Traps if `length`is greater than the size of `buffer`.
|
|
1431
|
+
///
|
|
1432
|
+
/// Example:
|
|
1433
|
+
/// ```motoko include=initialize
|
|
1434
|
+
/// import Nat "mo:base/Nat";
|
|
1435
|
+
///
|
|
1436
|
+
/// buffer.add(1);
|
|
1437
|
+
/// buffer.add(2);
|
|
1438
|
+
/// buffer.add(3);
|
|
1439
|
+
/// buffer.add(4);
|
|
1440
|
+
///
|
|
1441
|
+
/// let suf = Buffer.suffix(buffer, 3); // => [2, 3, 4]
|
|
1442
|
+
/// Buffer.toText(suf, Nat.toText);
|
|
1443
|
+
/// ```
|
|
1444
|
+
///
|
|
1445
|
+
/// Runtime: O(length)
|
|
1446
|
+
///
|
|
1447
|
+
/// Space: O(length)
|
|
1448
|
+
public func suffix<X>(buffer : Buffer<X>, length : Nat) : Buffer<X> {
|
|
1449
|
+
let size = buffer.size();
|
|
1450
|
+
|
|
1451
|
+
if (length > size) {
|
|
1452
|
+
Prim.trap "Buffer index out of bounds in suffix"
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
let newBuffer = Buffer<X>(newCapacity length);
|
|
1456
|
+
|
|
1457
|
+
var i = size - length : Nat;
|
|
1458
|
+
while (i < size) {
|
|
1459
|
+
newBuffer.add(buffer.get(i));
|
|
1460
|
+
|
|
1461
|
+
i += 1
|
|
1462
|
+
};
|
|
1463
|
+
|
|
1464
|
+
newBuffer
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
/// Checks if `suffix` is a suffix of `buffer`. Uses `equal` to compare
|
|
1468
|
+
/// elements.
|
|
1469
|
+
///
|
|
1470
|
+
/// Example:
|
|
1471
|
+
/// ```motoko include=initialize
|
|
1472
|
+
/// import Nat "mo:base/Nat";
|
|
1473
|
+
///
|
|
1474
|
+
/// buffer.add(1);
|
|
1475
|
+
/// buffer.add(2);
|
|
1476
|
+
/// buffer.add(3);
|
|
1477
|
+
/// buffer.add(4);
|
|
1478
|
+
///
|
|
1479
|
+
/// let suf = Buffer.Buffer<Nat>(3);
|
|
1480
|
+
/// suf.add(2);
|
|
1481
|
+
/// suf.add(3);
|
|
1482
|
+
/// suf.add(4);
|
|
1483
|
+
/// Buffer.isSuffixOf(suf, buffer, Nat.equal); // => true
|
|
1484
|
+
/// ```
|
|
1485
|
+
///
|
|
1486
|
+
/// Runtime: O(length of suffix)
|
|
1487
|
+
///
|
|
1488
|
+
/// Space: O(length of suffix)
|
|
1489
|
+
///
|
|
1490
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1491
|
+
public func isSuffixOf<X>(suffix : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : Bool {
|
|
1492
|
+
let suffixSize = suffix.size();
|
|
1493
|
+
let bufferSize = buffer.size();
|
|
1494
|
+
if (bufferSize < suffixSize) {
|
|
1495
|
+
return false
|
|
1496
|
+
};
|
|
1497
|
+
|
|
1498
|
+
var i = bufferSize;
|
|
1499
|
+
var j = suffixSize;
|
|
1500
|
+
while (i >= 1 and j >= 1) {
|
|
1501
|
+
i -= 1;
|
|
1502
|
+
j -= 1;
|
|
1503
|
+
if (not equal(buffer.get(i), suffix.get(j))) {
|
|
1504
|
+
return false
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1508
|
+
return true
|
|
1509
|
+
};
|
|
1510
|
+
|
|
1511
|
+
/// Checks if `suffix` is a strict suffix of `buffer`. Uses `equal` to compare
|
|
1512
|
+
/// elements.
|
|
1513
|
+
///
|
|
1514
|
+
/// Example:
|
|
1515
|
+
/// ```motoko include=initialize
|
|
1516
|
+
/// import Nat "mo:base/Nat";
|
|
1517
|
+
///
|
|
1518
|
+
/// buffer.add(1);
|
|
1519
|
+
/// buffer.add(2);
|
|
1520
|
+
/// buffer.add(3);
|
|
1521
|
+
/// buffer.add(4);
|
|
1522
|
+
///
|
|
1523
|
+
/// let suf = Buffer.Buffer<Nat>(3);
|
|
1524
|
+
/// suf.add(2);
|
|
1525
|
+
/// suf.add(3);
|
|
1526
|
+
/// suf.add(4);
|
|
1527
|
+
/// Buffer.isStrictSuffixOf(suf, buffer, Nat.equal); // => true
|
|
1528
|
+
/// ```
|
|
1529
|
+
///
|
|
1530
|
+
/// Runtime: O(length of suffix)
|
|
1531
|
+
///
|
|
1532
|
+
/// Space: O(length of suffix)
|
|
1533
|
+
///
|
|
1534
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
1535
|
+
public func isStrictSuffixOf<X>(suffix : Buffer<X>, buffer : Buffer<X>, equal : (X, X) -> Bool) : Bool {
|
|
1536
|
+
if (buffer.size() <= suffix.size()) {
|
|
1537
|
+
return false
|
|
1538
|
+
};
|
|
1539
|
+
isSuffixOf(suffix, buffer, equal)
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
/// Returns true iff every element in `buffer` satisfies `predicate`.
|
|
1543
|
+
///
|
|
1544
|
+
/// Example:
|
|
1545
|
+
/// ```motoko include=initialize
|
|
1546
|
+
///
|
|
1547
|
+
/// buffer.add(2);
|
|
1548
|
+
/// buffer.add(3);
|
|
1549
|
+
/// buffer.add(4);
|
|
1550
|
+
///
|
|
1551
|
+
/// Buffer.forAll<Nat>(buffer, func x { x > 1 }); // => true
|
|
1552
|
+
/// ```
|
|
1553
|
+
///
|
|
1554
|
+
/// Runtime: O(size)
|
|
1555
|
+
///
|
|
1556
|
+
/// Space: O(1)
|
|
1557
|
+
///
|
|
1558
|
+
/// *Runtime and space assumes that `predicate` runs in O(1) time and space.
|
|
1559
|
+
public func forAll<X>(buffer : Buffer<X>, predicate : X -> Bool) : Bool {
|
|
1560
|
+
for (element in buffer.vals()) {
|
|
1561
|
+
if (not predicate element) {
|
|
1562
|
+
return false
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
true
|
|
1567
|
+
};
|
|
1568
|
+
|
|
1569
|
+
/// Returns true iff some element in `buffer` satisfies `predicate`.
|
|
1570
|
+
///
|
|
1571
|
+
/// Example:
|
|
1572
|
+
/// ```motoko include=initialize
|
|
1573
|
+
///
|
|
1574
|
+
/// buffer.add(2);
|
|
1575
|
+
/// buffer.add(3);
|
|
1576
|
+
/// buffer.add(4);
|
|
1577
|
+
///
|
|
1578
|
+
/// Buffer.forSome<Nat>(buffer, func x { x > 3 }); // => true
|
|
1579
|
+
/// ```
|
|
1580
|
+
///
|
|
1581
|
+
/// Runtime: O(size)
|
|
1582
|
+
///
|
|
1583
|
+
/// Space: O(1)
|
|
1584
|
+
///
|
|
1585
|
+
/// *Runtime and space assumes that `predicate` runs in O(1) time and space.
|
|
1586
|
+
public func forSome<X>(buffer : Buffer<X>, predicate : X -> Bool) : Bool {
|
|
1587
|
+
for (element in buffer.vals()) {
|
|
1588
|
+
if (predicate element) {
|
|
1589
|
+
return true
|
|
1590
|
+
}
|
|
1591
|
+
};
|
|
1592
|
+
|
|
1593
|
+
false
|
|
1594
|
+
};
|
|
1595
|
+
|
|
1596
|
+
/// Returns true iff no element in `buffer` satisfies `predicate`.
|
|
1597
|
+
///
|
|
1598
|
+
/// Example:
|
|
1599
|
+
/// ```motoko include=initialize
|
|
1600
|
+
///
|
|
1601
|
+
/// buffer.add(2);
|
|
1602
|
+
/// buffer.add(3);
|
|
1603
|
+
/// buffer.add(4);
|
|
1604
|
+
///
|
|
1605
|
+
/// Buffer.forNone<Nat>(buffer, func x { x == 0 }); // => true
|
|
1606
|
+
/// ```
|
|
1607
|
+
///
|
|
1608
|
+
/// Runtime: O(size)
|
|
1609
|
+
///
|
|
1610
|
+
/// Space: O(1)
|
|
1611
|
+
///
|
|
1612
|
+
/// *Runtime and space assumes that `predicate` runs in O(1) time and space.
|
|
1613
|
+
public func forNone<X>(buffer : Buffer<X>, predicate : X -> Bool) : Bool {
|
|
1614
|
+
for (element in buffer.vals()) {
|
|
1615
|
+
if (predicate element) {
|
|
1616
|
+
return false
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
|
|
1620
|
+
true
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1623
|
+
/// Creates an array containing elements from `buffer`.
|
|
1624
|
+
///
|
|
1625
|
+
/// Example:
|
|
1626
|
+
/// ```motoko include=initialize
|
|
1627
|
+
///
|
|
1628
|
+
/// buffer.add(1);
|
|
1629
|
+
/// buffer.add(2);
|
|
1630
|
+
/// buffer.add(3);
|
|
1631
|
+
///
|
|
1632
|
+
/// Buffer.toArray<Nat>(buffer); // => [1, 2, 3]
|
|
1633
|
+
///
|
|
1634
|
+
/// ```
|
|
1635
|
+
///
|
|
1636
|
+
/// Runtime: O(size)
|
|
1637
|
+
///
|
|
1638
|
+
/// Space: O(size)
|
|
1639
|
+
public func toArray<X>(buffer : Buffer<X>) : [X] =
|
|
1640
|
+
// immutable clone of array
|
|
1641
|
+
Prim.Array_tabulate<X>(
|
|
1642
|
+
buffer.size(),
|
|
1643
|
+
func(i : Nat) : X { buffer.get(i) }
|
|
1644
|
+
);
|
|
1645
|
+
|
|
1646
|
+
/// Creates a mutable array containing elements from `buffer`.
|
|
1647
|
+
///
|
|
1648
|
+
/// Example:
|
|
1649
|
+
/// ```motoko include=initialize
|
|
1650
|
+
///
|
|
1651
|
+
/// buffer.add(1);
|
|
1652
|
+
/// buffer.add(2);
|
|
1653
|
+
/// buffer.add(3);
|
|
1654
|
+
///
|
|
1655
|
+
/// Buffer.toVarArray<Nat>(buffer); // => [1, 2, 3]
|
|
1656
|
+
/// ```
|
|
1657
|
+
///
|
|
1658
|
+
/// Runtime: O(size)
|
|
1659
|
+
///
|
|
1660
|
+
/// Space: O(size)
|
|
1661
|
+
public func toVarArray<X>(buffer : Buffer<X>) : [var X] {
|
|
1662
|
+
let size = buffer.size();
|
|
1663
|
+
if (size == 0) { [var] } else {
|
|
1664
|
+
let newArray = Prim.Array_init<X>(size, buffer.get(0));
|
|
1665
|
+
var i = 1;
|
|
1666
|
+
while (i < size) {
|
|
1667
|
+
newArray[i] := buffer.get(i);
|
|
1668
|
+
i += 1
|
|
1669
|
+
};
|
|
1670
|
+
newArray
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
|
|
1674
|
+
/// Creates a buffer containing elements from `array`.
|
|
1675
|
+
///
|
|
1676
|
+
/// Example:
|
|
1677
|
+
/// ```motoko include=initialize
|
|
1678
|
+
/// import Nat "mo:base/Nat";
|
|
1679
|
+
///
|
|
1680
|
+
/// let array = [2, 3];
|
|
1681
|
+
///
|
|
1682
|
+
/// let buf = Buffer.fromArray<Nat>(array); // => [2, 3]
|
|
1683
|
+
/// Buffer.toText(buf, Nat.toText);
|
|
1684
|
+
/// ```
|
|
1685
|
+
///
|
|
1686
|
+
/// Runtime: O(size)
|
|
1687
|
+
///
|
|
1688
|
+
/// Space: O(size)
|
|
1689
|
+
public func fromArray<X>(array : [X]) : Buffer<X> {
|
|
1690
|
+
// When returning new buffer, if possible, set the capacity
|
|
1691
|
+
// to the capacity of the old buffer. Otherwise, return them
|
|
1692
|
+
// at 2/3 capacity (like in this case). Alternative is to
|
|
1693
|
+
// calculate what the size would be if the elements were
|
|
1694
|
+
// sequentially added using `add`. This current strategy (2/3)
|
|
1695
|
+
// is the upper bound of that calculation (if the last element
|
|
1696
|
+
// added caused a capacity increase).
|
|
1697
|
+
let newBuffer = Buffer<X>(newCapacity(array.size()));
|
|
1698
|
+
|
|
1699
|
+
for (element in array.vals()) {
|
|
1700
|
+
newBuffer.add(element)
|
|
1701
|
+
};
|
|
1702
|
+
|
|
1703
|
+
newBuffer
|
|
1704
|
+
};
|
|
1705
|
+
|
|
1706
|
+
/// Creates a buffer containing elements from `array`.
|
|
1707
|
+
///
|
|
1708
|
+
/// Example:
|
|
1709
|
+
/// ```motoko include=initialize
|
|
1710
|
+
/// import Nat "mo:base/Nat";
|
|
1711
|
+
///
|
|
1712
|
+
/// let array = [var 1, 2, 3];
|
|
1713
|
+
///
|
|
1714
|
+
/// let buf = Buffer.fromVarArray<Nat>(array); // => [1, 2, 3]
|
|
1715
|
+
/// Buffer.toText(buf, Nat.toText);
|
|
1716
|
+
/// ```
|
|
1717
|
+
///
|
|
1718
|
+
/// Runtime: O(size)
|
|
1719
|
+
///
|
|
1720
|
+
/// Space: O(size)
|
|
1721
|
+
public func fromVarArray<X>(array : [var X]) : Buffer<X> {
|
|
1722
|
+
let newBuffer = Buffer<X>(newCapacity(array.size()));
|
|
1723
|
+
|
|
1724
|
+
for (element in array.vals()) {
|
|
1725
|
+
newBuffer.add(element)
|
|
1726
|
+
};
|
|
1727
|
+
|
|
1728
|
+
newBuffer
|
|
1729
|
+
};
|
|
1730
|
+
|
|
1731
|
+
/// Creates a buffer containing elements from `iter`.
|
|
1732
|
+
///
|
|
1733
|
+
/// Example:
|
|
1734
|
+
/// ```motoko include=initialize
|
|
1735
|
+
/// import Nat "mo:base/Nat";
|
|
1736
|
+
///
|
|
1737
|
+
/// let array = [1, 1, 1];
|
|
1738
|
+
/// let iter = array.vals();
|
|
1739
|
+
///
|
|
1740
|
+
/// let buf = Buffer.fromIter<Nat>(iter); // => [1, 1, 1]
|
|
1741
|
+
/// Buffer.toText(buf, Nat.toText);
|
|
1742
|
+
/// ```
|
|
1743
|
+
///
|
|
1744
|
+
/// Runtime: O(size)
|
|
1745
|
+
///
|
|
1746
|
+
/// Space: O(size)
|
|
1747
|
+
public func fromIter<X>(iter : { next : () -> ?X }) : Buffer<X> {
|
|
1748
|
+
let newBuffer = Buffer<X>(DEFAULT_CAPACITY); // can't get size from `iter`
|
|
1749
|
+
|
|
1750
|
+
for (element in iter) {
|
|
1751
|
+
newBuffer.add(element)
|
|
1752
|
+
};
|
|
1753
|
+
|
|
1754
|
+
newBuffer
|
|
1755
|
+
};
|
|
1756
|
+
|
|
1757
|
+
/// Reallocates the array underlying `buffer` such that capacity == size.
|
|
1758
|
+
///
|
|
1759
|
+
/// Example:
|
|
1760
|
+
/// ```motoko include=initialize
|
|
1761
|
+
///
|
|
1762
|
+
/// let buffer = Buffer.Buffer<Nat>(10);
|
|
1763
|
+
/// buffer.add(1);
|
|
1764
|
+
/// buffer.add(2);
|
|
1765
|
+
/// buffer.add(3);
|
|
1766
|
+
///
|
|
1767
|
+
/// Buffer.trimToSize<Nat>(buffer);
|
|
1768
|
+
/// buffer.capacity(); // => 3
|
|
1769
|
+
/// ```
|
|
1770
|
+
///
|
|
1771
|
+
/// Runtime: O(size)
|
|
1772
|
+
///
|
|
1773
|
+
/// Space: O(size)
|
|
1774
|
+
public func trimToSize<X>(buffer : Buffer<X>) {
|
|
1775
|
+
let size = buffer.size();
|
|
1776
|
+
if (size < buffer.capacity()) {
|
|
1777
|
+
buffer.reserve(size)
|
|
1778
|
+
}
|
|
1779
|
+
};
|
|
1780
|
+
|
|
1781
|
+
/// Creates a new buffer by applying `f` to each element in `buffer`.
|
|
1782
|
+
///
|
|
1783
|
+
/// Example:
|
|
1784
|
+
/// ```motoko include=initialize
|
|
1785
|
+
/// import Nat "mo:base/Nat";
|
|
1786
|
+
///
|
|
1787
|
+
/// buffer.add(1);
|
|
1788
|
+
/// buffer.add(2);
|
|
1789
|
+
/// buffer.add(3);
|
|
1790
|
+
///
|
|
1791
|
+
/// let newBuf = Buffer.map<Nat, Nat>(buffer, func (x) { x + 1 });
|
|
1792
|
+
/// Buffer.toText(newBuf, Nat.toText); // => [2, 3, 4]
|
|
1793
|
+
/// ```
|
|
1794
|
+
///
|
|
1795
|
+
/// Runtime: O(size)
|
|
1796
|
+
///
|
|
1797
|
+
/// Space: O(size)
|
|
1798
|
+
///
|
|
1799
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
1800
|
+
public func map<X, Y>(buffer : Buffer<X>, f : X -> Y) : Buffer<Y> {
|
|
1801
|
+
let newBuffer = Buffer<Y>(buffer.capacity());
|
|
1802
|
+
|
|
1803
|
+
for (element in buffer.vals()) {
|
|
1804
|
+
newBuffer.add(f element)
|
|
1805
|
+
};
|
|
1806
|
+
|
|
1807
|
+
newBuffer
|
|
1808
|
+
};
|
|
1809
|
+
|
|
1810
|
+
/// Applies `f` to each element in `buffer`.
|
|
1811
|
+
///
|
|
1812
|
+
/// Example:
|
|
1813
|
+
/// ```motoko include=initialize
|
|
1814
|
+
/// import Nat "mo:base/Nat";
|
|
1815
|
+
/// import Debug "mo:base/Debug";
|
|
1816
|
+
///
|
|
1817
|
+
/// buffer.add(1);
|
|
1818
|
+
/// buffer.add(2);
|
|
1819
|
+
/// buffer.add(3);
|
|
1820
|
+
///
|
|
1821
|
+
/// Buffer.iterate<Nat>(buffer, func (x) {
|
|
1822
|
+
/// Debug.print(Nat.toText(x)); // prints each element in buffer
|
|
1823
|
+
/// });
|
|
1824
|
+
/// ```
|
|
1825
|
+
///
|
|
1826
|
+
/// Runtime: O(size)
|
|
1827
|
+
///
|
|
1828
|
+
/// Space: O(size)
|
|
1829
|
+
///
|
|
1830
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
1831
|
+
public func iterate<X>(buffer : Buffer<X>, f : X -> ()) {
|
|
1832
|
+
for (element in buffer.vals()) {
|
|
1833
|
+
f element
|
|
1834
|
+
}
|
|
1835
|
+
};
|
|
1836
|
+
|
|
1837
|
+
/// Applies `f` to each element in `buffer` and its index.
|
|
1838
|
+
///
|
|
1839
|
+
/// Example:
|
|
1840
|
+
/// ```motoko include=initialize
|
|
1841
|
+
/// import Nat "mo:base/Nat";
|
|
1842
|
+
///
|
|
1843
|
+
/// buffer.add(1);
|
|
1844
|
+
/// buffer.add(2);
|
|
1845
|
+
/// buffer.add(3);
|
|
1846
|
+
///
|
|
1847
|
+
/// let newBuf = Buffer.mapEntries<Nat, Nat>(buffer, func (x, i) { x + i + 1 });
|
|
1848
|
+
/// Buffer.toText(newBuf, Nat.toText); // => [2, 4, 6]
|
|
1849
|
+
/// ```
|
|
1850
|
+
///
|
|
1851
|
+
/// Runtime: O(size)
|
|
1852
|
+
///
|
|
1853
|
+
/// Space: O(size)
|
|
1854
|
+
///
|
|
1855
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
1856
|
+
public func mapEntries<X, Y>(buffer : Buffer<X>, f : (Nat, X) -> Y) : Buffer<Y> {
|
|
1857
|
+
let newBuffer = Buffer<Y>(buffer.capacity());
|
|
1858
|
+
|
|
1859
|
+
var i = 0;
|
|
1860
|
+
let size = buffer.size();
|
|
1861
|
+
while (i < size) {
|
|
1862
|
+
newBuffer.add(f(i, buffer.get(i)));
|
|
1863
|
+
i += 1
|
|
1864
|
+
};
|
|
1865
|
+
|
|
1866
|
+
newBuffer
|
|
1867
|
+
};
|
|
1868
|
+
|
|
1869
|
+
/// Creates a new buffer by applying `f` to each element in `buffer`,
|
|
1870
|
+
/// and keeping all non-null elements.
|
|
1871
|
+
///
|
|
1872
|
+
/// Example:
|
|
1873
|
+
/// ```motoko include=initialize
|
|
1874
|
+
/// import Nat "mo:base/Nat";
|
|
1875
|
+
///
|
|
1876
|
+
/// buffer.add(1);
|
|
1877
|
+
/// buffer.add(2);
|
|
1878
|
+
/// buffer.add(3);
|
|
1879
|
+
///
|
|
1880
|
+
/// let newBuf = Buffer.mapFilter<Nat, Nat>(buffer, func (x) {
|
|
1881
|
+
/// if (x > 1) {
|
|
1882
|
+
/// ?(x * 2);
|
|
1883
|
+
/// } else {
|
|
1884
|
+
/// null;
|
|
1885
|
+
/// }
|
|
1886
|
+
/// });
|
|
1887
|
+
/// Buffer.toText(newBuf, Nat.toText); // => [4, 6]
|
|
1888
|
+
/// ```
|
|
1889
|
+
///
|
|
1890
|
+
/// Runtime: O(size)
|
|
1891
|
+
///
|
|
1892
|
+
/// Space: O(size)
|
|
1893
|
+
///
|
|
1894
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
1895
|
+
public func mapFilter<X, Y>(buffer : Buffer<X>, f : X -> ?Y) : Buffer<Y> {
|
|
1896
|
+
let newBuffer = Buffer<Y>(buffer.capacity());
|
|
1897
|
+
|
|
1898
|
+
for (element in buffer.vals()) {
|
|
1899
|
+
switch (f element) {
|
|
1900
|
+
case (?element) {
|
|
1901
|
+
newBuffer.add(element)
|
|
1902
|
+
};
|
|
1903
|
+
case _ {}
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1906
|
+
|
|
1907
|
+
newBuffer
|
|
1908
|
+
};
|
|
1909
|
+
|
|
1910
|
+
/// Creates a new buffer by applying `f` to each element in `buffer`.
|
|
1911
|
+
/// If any invocation of `f` produces an `#err`, returns an `#err`. Otherwise
|
|
1912
|
+
/// Returns an `#ok` containing the new buffer.
|
|
1913
|
+
///
|
|
1914
|
+
/// Example:
|
|
1915
|
+
/// ```motoko include=initialize
|
|
1916
|
+
/// import Result "mo:base/Result";
|
|
1917
|
+
///
|
|
1918
|
+
/// buffer.add(1);
|
|
1919
|
+
/// buffer.add(2);
|
|
1920
|
+
/// buffer.add(3);
|
|
1921
|
+
///
|
|
1922
|
+
/// let result = Buffer.mapResult<Nat, Nat, Text>(buffer, func (k) {
|
|
1923
|
+
/// if (k > 0) {
|
|
1924
|
+
/// #ok(k);
|
|
1925
|
+
/// } else {
|
|
1926
|
+
/// #err("One or more elements are zero.");
|
|
1927
|
+
/// }
|
|
1928
|
+
/// });
|
|
1929
|
+
///
|
|
1930
|
+
/// Result.mapOk<Buffer.Buffer<Nat>, [Nat], Text>(result, func buffer = Buffer.toArray(buffer)) // => #ok([1, 2, 3])
|
|
1931
|
+
/// ```
|
|
1932
|
+
///
|
|
1933
|
+
/// Runtime: O(size)
|
|
1934
|
+
///
|
|
1935
|
+
/// Space: O(size)
|
|
1936
|
+
///
|
|
1937
|
+
/// *Runtime and space assumes that `f` runs in O(1) time and space.
|
|
1938
|
+
public func mapResult<X, Y, E>(buffer : Buffer<X>, f : X -> Result.Result<Y, E>) : Result.Result<Buffer<Y>, E> {
|
|
1939
|
+
let newBuffer = Buffer<Y>(buffer.capacity());
|
|
1940
|
+
|
|
1941
|
+
for (element in buffer.vals()) {
|
|
1942
|
+
switch (f element) {
|
|
1943
|
+
case (#ok result) {
|
|
1944
|
+
newBuffer.add(result)
|
|
1945
|
+
};
|
|
1946
|
+
case (#err e) {
|
|
1947
|
+
return #err e
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
};
|
|
1951
|
+
|
|
1952
|
+
#ok newBuffer
|
|
1953
|
+
};
|
|
1954
|
+
|
|
1955
|
+
/// Creates a new buffer by applying `k` to each element in `buffer`,
|
|
1956
|
+
/// and concatenating the resulting buffers in order. This operation
|
|
1957
|
+
/// is similar to what in other functional languages is known as monadic bind.
|
|
1958
|
+
///
|
|
1959
|
+
/// Example:
|
|
1960
|
+
/// ```motoko include=initialize
|
|
1961
|
+
/// import Nat "mo:base/Nat";
|
|
1962
|
+
///
|
|
1963
|
+
/// buffer.add(1);
|
|
1964
|
+
/// buffer.add(2);
|
|
1965
|
+
/// buffer.add(3);
|
|
1966
|
+
///
|
|
1967
|
+
/// let chain = Buffer.chain<Nat, Nat>(buffer, func (x) {
|
|
1968
|
+
/// let b = Buffer.Buffer<Nat>(2);
|
|
1969
|
+
/// b.add(x);
|
|
1970
|
+
/// b.add(x * 2);
|
|
1971
|
+
/// return b;
|
|
1972
|
+
/// });
|
|
1973
|
+
/// Buffer.toText(chain, Nat.toText); // => [1, 2, 2, 4, 3, 6]
|
|
1974
|
+
/// ```
|
|
1975
|
+
///
|
|
1976
|
+
/// Runtime: O(size)
|
|
1977
|
+
///
|
|
1978
|
+
/// Space: O(size)
|
|
1979
|
+
///
|
|
1980
|
+
/// *Runtime and space assumes that `k` runs in O(1) time and space.
|
|
1981
|
+
public func chain<X, Y>(buffer : Buffer<X>, k : X -> Buffer<Y>) : Buffer<Y> {
|
|
1982
|
+
let newBuffer = Buffer<Y>(buffer.size() * 4);
|
|
1983
|
+
|
|
1984
|
+
for (element in buffer.vals()) {
|
|
1985
|
+
newBuffer.append(k element)
|
|
1986
|
+
};
|
|
1987
|
+
|
|
1988
|
+
newBuffer
|
|
1989
|
+
};
|
|
1990
|
+
|
|
1991
|
+
/// Collapses the elements in `buffer` into a single value by starting with `base`
|
|
1992
|
+
/// and progessively combining elements into `base` with `combine`. Iteration runs
|
|
1993
|
+
/// left to right.
|
|
1994
|
+
///
|
|
1995
|
+
/// Example:
|
|
1996
|
+
/// ```motoko include=initialize
|
|
1997
|
+
/// import Nat "mo:base/Nat";
|
|
1998
|
+
///
|
|
1999
|
+
/// buffer.add(1);
|
|
2000
|
+
/// buffer.add(2);
|
|
2001
|
+
/// buffer.add(3);
|
|
2002
|
+
///
|
|
2003
|
+
/// Buffer.foldLeft<Text, Nat>(buffer, "", func (acc, x) { acc # Nat.toText(x)}); // => "123"
|
|
2004
|
+
/// ```
|
|
2005
|
+
///
|
|
2006
|
+
/// Runtime: O(size)
|
|
2007
|
+
///
|
|
2008
|
+
/// Space: O(1)
|
|
2009
|
+
///
|
|
2010
|
+
/// *Runtime and space assumes that `combine` runs in O(1) time and space.
|
|
2011
|
+
public func foldLeft<A, X>(buffer : Buffer<X>, base : A, combine : (A, X) -> A) : A {
|
|
2012
|
+
var accumulation = base;
|
|
2013
|
+
|
|
2014
|
+
for (element in buffer.vals()) {
|
|
2015
|
+
accumulation := combine(accumulation, element)
|
|
2016
|
+
};
|
|
2017
|
+
|
|
2018
|
+
accumulation
|
|
2019
|
+
};
|
|
2020
|
+
|
|
2021
|
+
/// Collapses the elements in `buffer` into a single value by starting with `base`
|
|
2022
|
+
/// and progessively combining elements into `base` with `combine`. Iteration runs
|
|
2023
|
+
/// right to left.
|
|
2024
|
+
///
|
|
2025
|
+
/// Example:
|
|
2026
|
+
/// ```motoko include=initialize
|
|
2027
|
+
/// import Nat "mo:base/Nat";
|
|
2028
|
+
///
|
|
2029
|
+
/// buffer.add(1);
|
|
2030
|
+
/// buffer.add(2);
|
|
2031
|
+
/// buffer.add(3);
|
|
2032
|
+
///
|
|
2033
|
+
/// Buffer.foldRight<Nat, Text>(buffer, "", func (x, acc) { Nat.toText(x) # acc }); // => "123"
|
|
2034
|
+
/// ```
|
|
2035
|
+
///
|
|
2036
|
+
/// Runtime: O(size)
|
|
2037
|
+
///
|
|
2038
|
+
/// Space: O(1)
|
|
2039
|
+
///
|
|
2040
|
+
/// *Runtime and space assumes that `combine` runs in O(1) time and space.
|
|
2041
|
+
public func foldRight<X, A>(buffer : Buffer<X>, base : A, combine : (X, A) -> A) : A {
|
|
2042
|
+
let size = buffer.size();
|
|
2043
|
+
if (size == 0) {
|
|
2044
|
+
return base
|
|
2045
|
+
};
|
|
2046
|
+
var accumulation = base;
|
|
2047
|
+
|
|
2048
|
+
var i = size;
|
|
2049
|
+
while (i >= 1) {
|
|
2050
|
+
i -= 1; // to avoid Nat underflow, subtract first and stop iteration at 1
|
|
2051
|
+
accumulation := combine(buffer.get(i), accumulation)
|
|
2052
|
+
};
|
|
2053
|
+
|
|
2054
|
+
accumulation
|
|
2055
|
+
};
|
|
2056
|
+
|
|
2057
|
+
/// Returns the first element of `buffer`. Traps if `buffer` is empty.
|
|
2058
|
+
///
|
|
2059
|
+
/// Example:
|
|
2060
|
+
/// ```motoko include=initialize
|
|
2061
|
+
///
|
|
2062
|
+
/// buffer.add(1);
|
|
2063
|
+
/// buffer.add(2);
|
|
2064
|
+
/// buffer.add(3);
|
|
2065
|
+
///
|
|
2066
|
+
/// Buffer.first(buffer); // => 1
|
|
2067
|
+
/// ```
|
|
2068
|
+
///
|
|
2069
|
+
/// Runtime: O(1)
|
|
2070
|
+
///
|
|
2071
|
+
/// Space: O(1)
|
|
2072
|
+
public func first<X>(buffer : Buffer<X>) : X = buffer.get(0);
|
|
2073
|
+
|
|
2074
|
+
/// Returns the last element of `buffer`. Traps if `buffer` is empty.
|
|
2075
|
+
///
|
|
2076
|
+
/// Example:
|
|
2077
|
+
/// ```motoko include=initialize
|
|
2078
|
+
///
|
|
2079
|
+
/// buffer.add(1);
|
|
2080
|
+
/// buffer.add(2);
|
|
2081
|
+
/// buffer.add(3);
|
|
2082
|
+
///
|
|
2083
|
+
/// Buffer.last(buffer); // => 3
|
|
2084
|
+
/// ```
|
|
2085
|
+
///
|
|
2086
|
+
/// Runtime: O(1)
|
|
2087
|
+
///
|
|
2088
|
+
/// Space: O(1)
|
|
2089
|
+
public func last<X>(buffer : Buffer<X>) : X = buffer.get(buffer.size() - 1);
|
|
2090
|
+
|
|
2091
|
+
/// Returns a new buffer with capacity and size 1, containing `element`.
|
|
2092
|
+
///
|
|
2093
|
+
/// Example:
|
|
2094
|
+
/// ```motoko include=initialize
|
|
2095
|
+
/// import Nat "mo:base/Nat";
|
|
2096
|
+
///
|
|
2097
|
+
/// let buffer = Buffer.make<Nat>(1);
|
|
2098
|
+
/// Buffer.toText(buffer, Nat.toText); // => [1]
|
|
2099
|
+
/// ```
|
|
2100
|
+
///
|
|
2101
|
+
/// Runtime: O(1)
|
|
2102
|
+
///
|
|
2103
|
+
/// Space: O(1)
|
|
2104
|
+
public func make<X>(element : X) : Buffer<X> {
|
|
2105
|
+
let newBuffer = Buffer<X>(1);
|
|
2106
|
+
newBuffer.add(element);
|
|
2107
|
+
newBuffer
|
|
2108
|
+
};
|
|
2109
|
+
|
|
2110
|
+
/// Reverses the order of elements in `buffer`.
|
|
2111
|
+
///
|
|
2112
|
+
/// Example:
|
|
2113
|
+
/// ```motoko include=initialize
|
|
2114
|
+
/// import Nat "mo:base/Nat";
|
|
2115
|
+
///
|
|
2116
|
+
/// buffer.add(1);
|
|
2117
|
+
/// buffer.add(2);
|
|
2118
|
+
/// buffer.add(3);
|
|
2119
|
+
///
|
|
2120
|
+
/// Buffer.reverse(buffer);
|
|
2121
|
+
/// Buffer.toText(buffer, Nat.toText); // => [3, 2, 1]
|
|
2122
|
+
/// ```
|
|
2123
|
+
///
|
|
2124
|
+
/// Runtime: O(size)
|
|
2125
|
+
///
|
|
2126
|
+
/// Space: O(1)
|
|
2127
|
+
public func reverse<X>(buffer : Buffer<X>) {
|
|
2128
|
+
let size = buffer.size();
|
|
2129
|
+
if (size == 0) {
|
|
2130
|
+
return
|
|
2131
|
+
};
|
|
2132
|
+
|
|
2133
|
+
var i = 0;
|
|
2134
|
+
var j = size - 1 : Nat;
|
|
2135
|
+
var temp = buffer.get(0);
|
|
2136
|
+
while (i < size / 2) {
|
|
2137
|
+
temp := buffer.get(j);
|
|
2138
|
+
buffer.put(j, buffer.get(i));
|
|
2139
|
+
buffer.put(i, temp);
|
|
2140
|
+
i += 1;
|
|
2141
|
+
j -= 1
|
|
2142
|
+
}
|
|
2143
|
+
};
|
|
2144
|
+
|
|
2145
|
+
/// Merges two sorted buffers into a single sorted buffer, using `compare` to define
|
|
2146
|
+
/// the ordering. The final ordering is stable. Behavior is undefined if either
|
|
2147
|
+
/// `buffer1` or `buffer2` is not sorted.
|
|
2148
|
+
///
|
|
2149
|
+
/// Example:
|
|
2150
|
+
/// ```motoko include=initialize
|
|
2151
|
+
/// import Nat "mo:base/Nat";
|
|
2152
|
+
///
|
|
2153
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
2154
|
+
/// buffer1.add(1);
|
|
2155
|
+
/// buffer1.add(2);
|
|
2156
|
+
/// buffer1.add(4);
|
|
2157
|
+
///
|
|
2158
|
+
/// let buffer2 = Buffer.Buffer<Nat>(2);
|
|
2159
|
+
/// buffer2.add(2);
|
|
2160
|
+
/// buffer2.add(4);
|
|
2161
|
+
/// buffer2.add(6);
|
|
2162
|
+
///
|
|
2163
|
+
/// let merged = Buffer.merge<Nat>(buffer1, buffer2, Nat.compare);
|
|
2164
|
+
/// Buffer.toText(merged, Nat.toText); // => [1, 2, 2, 4, 4, 6]
|
|
2165
|
+
/// ```
|
|
2166
|
+
///
|
|
2167
|
+
/// Runtime: O(size1 + size2)
|
|
2168
|
+
///
|
|
2169
|
+
/// Space: O(size1 + size2)
|
|
2170
|
+
///
|
|
2171
|
+
/// *Runtime and space assumes that `compare` runs in O(1) time and space.
|
|
2172
|
+
public func merge<X>(buffer1 : Buffer<X>, buffer2 : Buffer<X>, compare : (X, X) -> Order) : Buffer<X> {
|
|
2173
|
+
let size1 = buffer1.size();
|
|
2174
|
+
let size2 = buffer2.size();
|
|
2175
|
+
|
|
2176
|
+
let newBuffer = Buffer<X>(newCapacity(size1 + size2));
|
|
2177
|
+
|
|
2178
|
+
var pointer1 = 0;
|
|
2179
|
+
var pointer2 = 0;
|
|
2180
|
+
|
|
2181
|
+
while (pointer1 < size1 and pointer2 < size2) {
|
|
2182
|
+
let current1 = buffer1.get(pointer1);
|
|
2183
|
+
let current2 = buffer2.get(pointer2);
|
|
2184
|
+
|
|
2185
|
+
switch (compare(current1, current2)) {
|
|
2186
|
+
case (#less) {
|
|
2187
|
+
newBuffer.add(current1);
|
|
2188
|
+
pointer1 += 1
|
|
2189
|
+
};
|
|
2190
|
+
case _ {
|
|
2191
|
+
newBuffer.add(current2);
|
|
2192
|
+
pointer2 += 1
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
};
|
|
2196
|
+
|
|
2197
|
+
while (pointer1 < size1) {
|
|
2198
|
+
newBuffer.add(buffer1.get(pointer1));
|
|
2199
|
+
pointer1 += 1
|
|
2200
|
+
};
|
|
2201
|
+
|
|
2202
|
+
while (pointer2 < size2) {
|
|
2203
|
+
newBuffer.add(buffer2.get(pointer2));
|
|
2204
|
+
pointer2 += 1
|
|
2205
|
+
};
|
|
2206
|
+
|
|
2207
|
+
newBuffer
|
|
2208
|
+
};
|
|
2209
|
+
|
|
2210
|
+
/// Eliminates all duplicate elements in `buffer` as defined by `compare`.
|
|
2211
|
+
/// Elimination is stable with respect to the original ordering of the elements.
|
|
2212
|
+
///
|
|
2213
|
+
/// Example:
|
|
2214
|
+
/// ```motoko include=initialize
|
|
2215
|
+
/// import Nat "mo:base/Nat";
|
|
2216
|
+
///
|
|
2217
|
+
/// buffer.add(1);
|
|
2218
|
+
/// buffer.add(2);
|
|
2219
|
+
/// buffer.add(3);
|
|
2220
|
+
/// buffer.add(1);
|
|
2221
|
+
/// buffer.add(2);
|
|
2222
|
+
/// buffer.add(3);
|
|
2223
|
+
///
|
|
2224
|
+
/// Buffer.removeDuplicates<Nat>(buffer, Nat.compare);
|
|
2225
|
+
/// Buffer.toText(buffer, Nat.toText); // => [1, 2, 3]
|
|
2226
|
+
/// ```
|
|
2227
|
+
///
|
|
2228
|
+
/// Runtime: O(size * log(size))
|
|
2229
|
+
///
|
|
2230
|
+
/// Space: O(size)
|
|
2231
|
+
public func removeDuplicates<X>(buffer : Buffer<X>, compare : (X, X) -> Order) {
|
|
2232
|
+
let size = buffer.size();
|
|
2233
|
+
let indices = Prim.Array_tabulate<(Nat, X)>(size, func i = (i, buffer.get(i)));
|
|
2234
|
+
// Sort based on element, while carrying original index information
|
|
2235
|
+
// This groups together the duplicate elements
|
|
2236
|
+
let sorted = Array.sort<(Nat, X)>(indices, func(pair1, pair2) = compare(pair1.1, pair2.1));
|
|
2237
|
+
let uniques = Buffer<(Nat, X)>(size);
|
|
2238
|
+
|
|
2239
|
+
// Iterate over elements
|
|
2240
|
+
var i = 0;
|
|
2241
|
+
while (i < size) {
|
|
2242
|
+
var j = i;
|
|
2243
|
+
// Iterate over duplicate elements, and find the smallest index among them (for stability)
|
|
2244
|
+
var minIndex = sorted[j];
|
|
2245
|
+
label duplicates while (j < (size - 1 : Nat)) {
|
|
2246
|
+
let pair1 = sorted[j];
|
|
2247
|
+
let pair2 = sorted[j + 1];
|
|
2248
|
+
switch (compare(pair1.1, pair2.1)) {
|
|
2249
|
+
case (#equal) {
|
|
2250
|
+
if (pair2.0 < pair1.0) {
|
|
2251
|
+
minIndex := pair2
|
|
2252
|
+
};
|
|
2253
|
+
j += 1
|
|
2254
|
+
};
|
|
2255
|
+
case _ {
|
|
2256
|
+
break duplicates
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
};
|
|
2260
|
+
|
|
2261
|
+
uniques.add(minIndex);
|
|
2262
|
+
i := j + 1
|
|
2263
|
+
};
|
|
2264
|
+
|
|
2265
|
+
// resort based on original ordering and place back in buffer
|
|
2266
|
+
uniques.sort(
|
|
2267
|
+
func(pair1, pair2) {
|
|
2268
|
+
if (pair1.0 < pair2.0) {
|
|
2269
|
+
#less
|
|
2270
|
+
} else if (pair1.0 == pair2.0) {
|
|
2271
|
+
#equal
|
|
2272
|
+
} else {
|
|
2273
|
+
#greater
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
);
|
|
2277
|
+
|
|
2278
|
+
buffer.clear();
|
|
2279
|
+
buffer.reserve(uniques.size());
|
|
2280
|
+
for (element in uniques.vals()) {
|
|
2281
|
+
buffer.add(element.1)
|
|
2282
|
+
}
|
|
2283
|
+
};
|
|
2284
|
+
|
|
2285
|
+
/// Splits `buffer` into a pair of buffers where all elements in the left
|
|
2286
|
+
/// buffer satisfy `predicate` and all elements in the right buffer do not.
|
|
2287
|
+
///
|
|
2288
|
+
/// Example:
|
|
2289
|
+
/// ```motoko include=initialize
|
|
2290
|
+
/// import Nat "mo:base/Nat";
|
|
2291
|
+
///
|
|
2292
|
+
/// buffer.add(1);
|
|
2293
|
+
/// buffer.add(2);
|
|
2294
|
+
/// buffer.add(3);
|
|
2295
|
+
/// buffer.add(4);
|
|
2296
|
+
/// buffer.add(5);
|
|
2297
|
+
/// buffer.add(6);
|
|
2298
|
+
///
|
|
2299
|
+
/// let partitions = Buffer.partition<Nat>(buffer, func (x) { x % 2 == 0 });
|
|
2300
|
+
/// (Buffer.toArray(partitions.0), Buffer.toArray(partitions.1)) // => ([2, 4, 6], [1, 3, 5])
|
|
2301
|
+
/// ```
|
|
2302
|
+
///
|
|
2303
|
+
/// Runtime: O(size)
|
|
2304
|
+
///
|
|
2305
|
+
/// Space: O(size)
|
|
2306
|
+
///
|
|
2307
|
+
/// *Runtime and space assumes that `predicate` runs in O(1) time and space.
|
|
2308
|
+
public func partition<X>(buffer : Buffer<X>, predicate : X -> Bool) : (Buffer<X>, Buffer<X>) {
|
|
2309
|
+
let size = buffer.size();
|
|
2310
|
+
let trueBuffer = Buffer<X>(size);
|
|
2311
|
+
let falseBuffer = Buffer<X>(size);
|
|
2312
|
+
|
|
2313
|
+
for (element in buffer.vals()) {
|
|
2314
|
+
if (predicate element) {
|
|
2315
|
+
trueBuffer.add(element)
|
|
2316
|
+
} else {
|
|
2317
|
+
falseBuffer.add(element)
|
|
2318
|
+
}
|
|
2319
|
+
};
|
|
2320
|
+
|
|
2321
|
+
(trueBuffer, falseBuffer)
|
|
2322
|
+
};
|
|
2323
|
+
|
|
2324
|
+
/// Splits the buffer into two buffers at `index`, where the left buffer contains
|
|
2325
|
+
/// all elements with indices less than `index`, and the right buffer contains all
|
|
2326
|
+
/// elements with indices greater than or equal to `index`. Traps if `index` is out
|
|
2327
|
+
/// of bounds.
|
|
2328
|
+
///
|
|
2329
|
+
/// Example:
|
|
2330
|
+
/// ```motoko include=initialize
|
|
2331
|
+
/// import Nat "mo:base/Nat";
|
|
2332
|
+
///
|
|
2333
|
+
/// buffer.add(1);
|
|
2334
|
+
/// buffer.add(2);
|
|
2335
|
+
/// buffer.add(3);
|
|
2336
|
+
/// buffer.add(4);
|
|
2337
|
+
/// buffer.add(5);
|
|
2338
|
+
/// buffer.add(6);
|
|
2339
|
+
///
|
|
2340
|
+
/// let split = Buffer.split<Nat>(buffer, 3);
|
|
2341
|
+
/// (Buffer.toArray(split.0), Buffer.toArray(split.1)) // => ([1, 2, 3], [4, 5, 6])
|
|
2342
|
+
/// ```
|
|
2343
|
+
///
|
|
2344
|
+
/// Runtime: O(size)
|
|
2345
|
+
///
|
|
2346
|
+
/// Space: O(size)
|
|
2347
|
+
///
|
|
2348
|
+
/// *Runtime and space assumes that `compare` runs in O(1) time and space.
|
|
2349
|
+
public func split<X>(buffer : Buffer<X>, index : Nat) : (Buffer<X>, Buffer<X>) {
|
|
2350
|
+
let size = buffer.size();
|
|
2351
|
+
|
|
2352
|
+
if (index < 0 or index > size) {
|
|
2353
|
+
Prim.trap "Index out of bounds in split"
|
|
2354
|
+
};
|
|
2355
|
+
|
|
2356
|
+
let buffer1 = Buffer<X>(newCapacity index);
|
|
2357
|
+
let buffer2 = Buffer<X>(newCapacity(size - index));
|
|
2358
|
+
|
|
2359
|
+
var i = 0;
|
|
2360
|
+
while (i < index) {
|
|
2361
|
+
buffer1.add(buffer.get(i));
|
|
2362
|
+
i += 1
|
|
2363
|
+
};
|
|
2364
|
+
while (i < size) {
|
|
2365
|
+
buffer2.add(buffer.get(i));
|
|
2366
|
+
i += 1
|
|
2367
|
+
};
|
|
2368
|
+
|
|
2369
|
+
(buffer1, buffer2)
|
|
2370
|
+
};
|
|
2371
|
+
|
|
2372
|
+
/// Breaks up `buffer` into buffers of size `size`. The last chunk may
|
|
2373
|
+
/// have less than `size` elements if the number of elements is not divisible
|
|
2374
|
+
/// by the chunk size.
|
|
2375
|
+
///
|
|
2376
|
+
/// Example:
|
|
2377
|
+
/// ```motoko include=initialize
|
|
2378
|
+
/// import Nat "mo:base/Nat";
|
|
2379
|
+
///
|
|
2380
|
+
/// buffer.add(1);
|
|
2381
|
+
/// buffer.add(2);
|
|
2382
|
+
/// buffer.add(3);
|
|
2383
|
+
/// buffer.add(4);
|
|
2384
|
+
/// buffer.add(5);
|
|
2385
|
+
/// buffer.add(6);
|
|
2386
|
+
///
|
|
2387
|
+
/// let chunks = Buffer.chunk<Nat>(buffer, 3);
|
|
2388
|
+
/// Buffer.toText<Buffer.Buffer<Nat>>(chunks, func buf = Buffer.toText(buf, Nat.toText)); // => [[1, 2, 3], [4, 5, 6]]
|
|
2389
|
+
/// ```
|
|
2390
|
+
///
|
|
2391
|
+
/// Runtime: O(number of elements in buffer)
|
|
2392
|
+
///
|
|
2393
|
+
/// Space: O(number of elements in buffer)
|
|
2394
|
+
public func chunk<X>(buffer : Buffer<X>, size : Nat) : Buffer<Buffer<X>> {
|
|
2395
|
+
if (size == 0) {
|
|
2396
|
+
Prim.trap "Chunk size must be non-zero in chunk"
|
|
2397
|
+
};
|
|
2398
|
+
|
|
2399
|
+
// ceil(buffer.size() / size)
|
|
2400
|
+
let newBuffer = Buffer<Buffer<X>>((buffer.size() + size - 1) / size);
|
|
2401
|
+
|
|
2402
|
+
var newInnerBuffer = Buffer<X>(newCapacity size);
|
|
2403
|
+
var innerSize = 0;
|
|
2404
|
+
for (element in buffer.vals()) {
|
|
2405
|
+
if (innerSize == size) {
|
|
2406
|
+
newBuffer.add(newInnerBuffer);
|
|
2407
|
+
newInnerBuffer := Buffer<X>(newCapacity size);
|
|
2408
|
+
innerSize := 0
|
|
2409
|
+
};
|
|
2410
|
+
newInnerBuffer.add(element);
|
|
2411
|
+
innerSize += 1
|
|
2412
|
+
};
|
|
2413
|
+
if (innerSize > 0) {
|
|
2414
|
+
newBuffer.add(newInnerBuffer)
|
|
2415
|
+
};
|
|
2416
|
+
|
|
2417
|
+
newBuffer
|
|
2418
|
+
};
|
|
2419
|
+
|
|
2420
|
+
/// Groups equal and adjacent elements in the list into sub lists.
|
|
2421
|
+
///
|
|
2422
|
+
/// Example:
|
|
2423
|
+
/// ```motoko include=initialize
|
|
2424
|
+
/// import Nat "mo:base/Nat";
|
|
2425
|
+
///
|
|
2426
|
+
/// buffer.add(1);
|
|
2427
|
+
/// buffer.add(2);
|
|
2428
|
+
/// buffer.add(2);
|
|
2429
|
+
/// buffer.add(4);
|
|
2430
|
+
/// buffer.add(5);
|
|
2431
|
+
/// buffer.add(5);
|
|
2432
|
+
///
|
|
2433
|
+
/// let grouped = Buffer.groupBy<Nat>(buffer, func (x, y) { x == y });
|
|
2434
|
+
/// Buffer.toText<Buffer.Buffer<Nat>>(grouped, func buf = Buffer.toText(buf, Nat.toText)); // => [[1], [2, 2], [4], [5, 5]]
|
|
2435
|
+
/// ```
|
|
2436
|
+
///
|
|
2437
|
+
/// Runtime: O(size)
|
|
2438
|
+
///
|
|
2439
|
+
/// Space: O(size)
|
|
2440
|
+
///
|
|
2441
|
+
/// *Runtime and space assumes that `equal` runs in O(1) time and space.
|
|
2442
|
+
public func groupBy<X>(buffer : Buffer<X>, equal : (X, X) -> Bool) : Buffer<Buffer<X>> {
|
|
2443
|
+
let size = buffer.size();
|
|
2444
|
+
let newBuffer = Buffer<Buffer<X>>(size);
|
|
2445
|
+
if (size == 0) {
|
|
2446
|
+
return newBuffer
|
|
2447
|
+
};
|
|
2448
|
+
|
|
2449
|
+
var i = 0;
|
|
2450
|
+
var baseElement = buffer.get(0);
|
|
2451
|
+
var newInnerBuffer = Buffer<X>(size);
|
|
2452
|
+
while (i < size) {
|
|
2453
|
+
let element = buffer.get(i);
|
|
2454
|
+
|
|
2455
|
+
if (equal(baseElement, element)) {
|
|
2456
|
+
newInnerBuffer.add(element)
|
|
2457
|
+
} else {
|
|
2458
|
+
newBuffer.add(newInnerBuffer);
|
|
2459
|
+
baseElement := element;
|
|
2460
|
+
newInnerBuffer := Buffer<X>(size - i);
|
|
2461
|
+
newInnerBuffer.add(element)
|
|
2462
|
+
};
|
|
2463
|
+
i += 1
|
|
2464
|
+
};
|
|
2465
|
+
if (newInnerBuffer.size() > 0) {
|
|
2466
|
+
newBuffer.add(newInnerBuffer)
|
|
2467
|
+
};
|
|
2468
|
+
|
|
2469
|
+
newBuffer
|
|
2470
|
+
};
|
|
2471
|
+
|
|
2472
|
+
/// Flattens the buffer of buffers into a single buffer.
|
|
2473
|
+
///
|
|
2474
|
+
/// Example:
|
|
2475
|
+
/// ```motoko include=initialize
|
|
2476
|
+
/// import Nat "mo:base/Nat";
|
|
2477
|
+
///
|
|
2478
|
+
/// let buffer = Buffer.Buffer<Buffer.Buffer<Nat>>(1);
|
|
2479
|
+
///
|
|
2480
|
+
/// let inner1 = Buffer.Buffer<Nat>(2);
|
|
2481
|
+
/// inner1.add(1);
|
|
2482
|
+
/// inner1.add(2);
|
|
2483
|
+
///
|
|
2484
|
+
/// let inner2 = Buffer.Buffer<Nat>(2);
|
|
2485
|
+
/// inner2.add(3);
|
|
2486
|
+
/// inner2.add(4);
|
|
2487
|
+
///
|
|
2488
|
+
/// buffer.add(inner1);
|
|
2489
|
+
/// buffer.add(inner2);
|
|
2490
|
+
/// // buffer = [[1, 2], [3, 4]]
|
|
2491
|
+
///
|
|
2492
|
+
/// let flat = Buffer.flatten<Nat>(buffer);
|
|
2493
|
+
/// Buffer.toText<Nat>(flat, Nat.toText); // => [1, 2, 3, 4]
|
|
2494
|
+
/// ```
|
|
2495
|
+
///
|
|
2496
|
+
/// Runtime: O(number of elements in buffer)
|
|
2497
|
+
///
|
|
2498
|
+
/// Space: O(number of elements in buffer)
|
|
2499
|
+
public func flatten<X>(buffer : Buffer<Buffer<X>>) : Buffer<X> {
|
|
2500
|
+
let size = buffer.size();
|
|
2501
|
+
if (size == 0) {
|
|
2502
|
+
return Buffer<X>(0)
|
|
2503
|
+
};
|
|
2504
|
+
|
|
2505
|
+
let newBuffer = Buffer<X>(
|
|
2506
|
+
if (buffer.get(0).size() != 0) {
|
|
2507
|
+
newCapacity(buffer.get(0).size() * size)
|
|
2508
|
+
} else {
|
|
2509
|
+
newCapacity(size)
|
|
2510
|
+
}
|
|
2511
|
+
);
|
|
2512
|
+
|
|
2513
|
+
for (innerBuffer in buffer.vals()) {
|
|
2514
|
+
for (innerElement in innerBuffer.vals()) {
|
|
2515
|
+
newBuffer.add(innerElement)
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
|
|
2519
|
+
newBuffer
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2522
|
+
/// Combines the two buffers into a single buffer of pairs, pairing together
|
|
2523
|
+
/// elements with the same index. If one buffer is longer than the other, the
|
|
2524
|
+
/// remaining elements from the longer buffer are not included.
|
|
2525
|
+
///
|
|
2526
|
+
/// Example:
|
|
2527
|
+
/// ```motoko include=initialize
|
|
2528
|
+
///
|
|
2529
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
2530
|
+
/// buffer1.add(1);
|
|
2531
|
+
/// buffer1.add(2);
|
|
2532
|
+
/// buffer1.add(3);
|
|
2533
|
+
///
|
|
2534
|
+
/// let buffer2 = Buffer.Buffer<Nat>(2);
|
|
2535
|
+
/// buffer2.add(4);
|
|
2536
|
+
/// buffer2.add(5);
|
|
2537
|
+
///
|
|
2538
|
+
/// let zipped = Buffer.zip(buffer1, buffer2);
|
|
2539
|
+
/// Buffer.toArray(zipped); // => [(1, 4), (2, 5)]
|
|
2540
|
+
/// ```
|
|
2541
|
+
///
|
|
2542
|
+
/// Runtime: O(min(size1, size2))
|
|
2543
|
+
///
|
|
2544
|
+
/// Space: O(min(size1, size2))
|
|
2545
|
+
public func zip<X, Y>(buffer1 : Buffer<X>, buffer2 : Buffer<Y>) : Buffer<(X, Y)> {
|
|
2546
|
+
// compiler should pull lamda out as a static function since it is fully closed
|
|
2547
|
+
zipWith<X, Y, (X, Y)>(buffer1, buffer2, func(x, y) = (x, y))
|
|
2548
|
+
};
|
|
2549
|
+
|
|
2550
|
+
/// Combines the two buffers into a single buffer, pairing together
|
|
2551
|
+
/// elements with the same index and combining them using `zip`. If
|
|
2552
|
+
/// one buffer is longer than the other, the remaining elements from
|
|
2553
|
+
/// the longer buffer are not included.
|
|
2554
|
+
///
|
|
2555
|
+
/// Example:
|
|
2556
|
+
/// ```motoko include=initialize
|
|
2557
|
+
///
|
|
2558
|
+
/// let buffer1 = Buffer.Buffer<Nat>(2);
|
|
2559
|
+
/// buffer1.add(1);
|
|
2560
|
+
/// buffer1.add(2);
|
|
2561
|
+
/// buffer1.add(3);
|
|
2562
|
+
///
|
|
2563
|
+
/// let buffer2 = Buffer.Buffer<Nat>(2);
|
|
2564
|
+
/// buffer2.add(4);
|
|
2565
|
+
/// buffer2.add(5);
|
|
2566
|
+
/// buffer2.add(6);
|
|
2567
|
+
///
|
|
2568
|
+
/// let zipped = Buffer.zipWith<Nat, Nat, Nat>(buffer1, buffer2, func (x, y) { x + y });
|
|
2569
|
+
/// Buffer.toArray(zipped) // => [5, 7, 9]
|
|
2570
|
+
/// ```
|
|
2571
|
+
///
|
|
2572
|
+
/// Runtime: O(min(size1, size2))
|
|
2573
|
+
///
|
|
2574
|
+
/// Space: O(min(size1, size2))
|
|
2575
|
+
///
|
|
2576
|
+
/// *Runtime and space assumes that `zip` runs in O(1) time and space.
|
|
2577
|
+
public func zipWith<X, Y, Z>(buffer1 : Buffer<X>, buffer2 : Buffer<Y>, zip : (X, Y) -> Z) : Buffer<Z> {
|
|
2578
|
+
let size1 = buffer1.size();
|
|
2579
|
+
let size2 = buffer2.size();
|
|
2580
|
+
let minSize = if (size1 < size2) { size1 } else { size2 };
|
|
2581
|
+
|
|
2582
|
+
var i = 0;
|
|
2583
|
+
let newBuffer = Buffer<Z>(newCapacity minSize);
|
|
2584
|
+
while (i < minSize) {
|
|
2585
|
+
newBuffer.add(zip(buffer1.get(i), buffer2.get(i)));
|
|
2586
|
+
i += 1
|
|
2587
|
+
};
|
|
2588
|
+
newBuffer
|
|
2589
|
+
};
|
|
2590
|
+
|
|
2591
|
+
/// Creates a new buffer taking elements in order from `buffer` until predicate
|
|
2592
|
+
/// returns false.
|
|
2593
|
+
///
|
|
2594
|
+
/// Example:
|
|
2595
|
+
/// ```motoko include=initialize
|
|
2596
|
+
/// import Nat "mo:base/Nat";
|
|
2597
|
+
///
|
|
2598
|
+
/// buffer.add(1);
|
|
2599
|
+
/// buffer.add(2);
|
|
2600
|
+
/// buffer.add(3);
|
|
2601
|
+
///
|
|
2602
|
+
/// let newBuf = Buffer.takeWhile<Nat>(buffer, func (x) { x < 3 });
|
|
2603
|
+
/// Buffer.toText(newBuf, Nat.toText); // => [1, 2]
|
|
2604
|
+
/// ```
|
|
2605
|
+
///
|
|
2606
|
+
/// Runtime: O(size)
|
|
2607
|
+
///
|
|
2608
|
+
/// Space: O(size)
|
|
2609
|
+
///
|
|
2610
|
+
/// *Runtime and space assumes that `predicate` runs in O(1) time and space.
|
|
2611
|
+
public func takeWhile<X>(buffer : Buffer<X>, predicate : X -> Bool) : Buffer<X> {
|
|
2612
|
+
let newBuffer = Buffer<X>(buffer.size());
|
|
2613
|
+
|
|
2614
|
+
for (element in buffer.vals()) {
|
|
2615
|
+
if (not predicate element) {
|
|
2616
|
+
return newBuffer
|
|
2617
|
+
};
|
|
2618
|
+
newBuffer.add(element)
|
|
2619
|
+
};
|
|
2620
|
+
|
|
2621
|
+
newBuffer
|
|
2622
|
+
};
|
|
2623
|
+
|
|
2624
|
+
/// Creates a new buffer excluding elements in order from `buffer` until predicate
|
|
2625
|
+
/// returns false.
|
|
2626
|
+
///
|
|
2627
|
+
/// Example:
|
|
2628
|
+
/// ```motoko include=initialize
|
|
2629
|
+
/// import Nat "mo:base/Nat";
|
|
2630
|
+
///
|
|
2631
|
+
/// buffer.add(1);
|
|
2632
|
+
/// buffer.add(2);
|
|
2633
|
+
/// buffer.add(3);
|
|
2634
|
+
///
|
|
2635
|
+
/// let newBuf = Buffer.dropWhile<Nat>(buffer, func x { x < 3 }); // => [3]
|
|
2636
|
+
/// Buffer.toText(newBuf, Nat.toText);
|
|
2637
|
+
/// ```
|
|
2638
|
+
///
|
|
2639
|
+
/// Runtime: O(size)
|
|
2640
|
+
///
|
|
2641
|
+
/// Space: O(size)
|
|
2642
|
+
///
|
|
2643
|
+
/// *Runtime and space assumes that `predicate` runs in O(1) time and space.
|
|
2644
|
+
public func dropWhile<X>(buffer : Buffer<X>, predicate : X -> Bool) : Buffer<X> {
|
|
2645
|
+
let size = buffer.size();
|
|
2646
|
+
let newBuffer = Buffer<X>(size);
|
|
2647
|
+
|
|
2648
|
+
var i = 0;
|
|
2649
|
+
var take = false;
|
|
2650
|
+
label iter for (element in buffer.vals()) {
|
|
2651
|
+
if (not (take or predicate element)) {
|
|
2652
|
+
take := true
|
|
2653
|
+
};
|
|
2654
|
+
if (take) {
|
|
2655
|
+
newBuffer.add(element)
|
|
2656
|
+
}
|
|
2657
|
+
};
|
|
2658
|
+
newBuffer
|
|
2659
|
+
}
|
|
2660
|
+
}
|