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.
Files changed (99) hide show
  1. package/.mops/base@0.7.4/LICENSE +208 -0
  2. package/.mops/base@0.7.4/README.md +64 -0
  3. package/.mops/base@0.7.4/mops.toml +5 -0
  4. package/.mops/base@0.7.4/src/Array.mo +686 -0
  5. package/.mops/base@0.7.4/src/AssocList.mo +203 -0
  6. package/.mops/base@0.7.4/src/Blob.mo +55 -0
  7. package/.mops/base@0.7.4/src/Bool.mo +44 -0
  8. package/.mops/base@0.7.4/src/Buffer.mo +1937 -0
  9. package/.mops/base@0.7.4/src/CertifiedData.mo +29 -0
  10. package/.mops/base@0.7.4/src/Char.mo +67 -0
  11. package/.mops/base@0.7.4/src/Debug.mo +15 -0
  12. package/.mops/base@0.7.4/src/Deque.mo +75 -0
  13. package/.mops/base@0.7.4/src/Error.mo +41 -0
  14. package/.mops/base@0.7.4/src/ExperimentalCycles.mo +51 -0
  15. package/.mops/base@0.7.4/src/ExperimentalInternetComputer.mo +36 -0
  16. package/.mops/base@0.7.4/src/ExperimentalStableMemory.mo +121 -0
  17. package/.mops/base@0.7.4/src/Float.mo +150 -0
  18. package/.mops/base@0.7.4/src/Func.mo +38 -0
  19. package/.mops/base@0.7.4/src/Hash.mo +83 -0
  20. package/.mops/base@0.7.4/src/HashMap.mo +229 -0
  21. package/.mops/base@0.7.4/src/Heap.mo +113 -0
  22. package/.mops/base@0.7.4/src/Int.mo +150 -0
  23. package/.mops/base@0.7.4/src/Int16.mo +159 -0
  24. package/.mops/base@0.7.4/src/Int32.mo +160 -0
  25. package/.mops/base@0.7.4/src/Int64.mo +161 -0
  26. package/.mops/base@0.7.4/src/Int8.mo +160 -0
  27. package/.mops/base@0.7.4/src/Iter.mo +220 -0
  28. package/.mops/base@0.7.4/src/IterType.mo +7 -0
  29. package/.mops/base@0.7.4/src/List.mo +433 -0
  30. package/.mops/base@0.7.4/src/Nat.mo +75 -0
  31. package/.mops/base@0.7.4/src/Nat16.mo +146 -0
  32. package/.mops/base@0.7.4/src/Nat32.mo +146 -0
  33. package/.mops/base@0.7.4/src/Nat64.mo +146 -0
  34. package/.mops/base@0.7.4/src/Nat8.mo +146 -0
  35. package/.mops/base@0.7.4/src/None.mo +19 -0
  36. package/.mops/base@0.7.4/src/Option.mo +160 -0
  37. package/.mops/base@0.7.4/src/Order.mo +46 -0
  38. package/.mops/base@0.7.4/src/Prelude.mo +33 -0
  39. package/.mops/base@0.7.4/src/Principal.mo +58 -0
  40. package/.mops/base@0.7.4/src/RBTree.mo +218 -0
  41. package/.mops/base@0.7.4/src/Random.mo +188 -0
  42. package/.mops/base@0.7.4/src/Result.mo +210 -0
  43. package/.mops/base@0.7.4/src/Stack.mo +40 -0
  44. package/.mops/base@0.7.4/src/Text.mo +615 -0
  45. package/.mops/base@0.7.4/src/Time.mo +37 -0
  46. package/.mops/base@0.7.4/src/Trie.mo +1200 -0
  47. package/.mops/base@0.7.4/src/TrieMap.mo +180 -0
  48. package/.mops/base@0.7.4/src/TrieSet.mo +97 -0
  49. package/.mops/base@0.8.3/LICENSE +208 -0
  50. package/.mops/base@0.8.3/README.md +64 -0
  51. package/.mops/base@0.8.3/mops.toml +6 -0
  52. package/.mops/base@0.8.3/src/Array.mo +717 -0
  53. package/.mops/base@0.8.3/src/AssocList.mo +404 -0
  54. package/.mops/base@0.8.3/src/Blob.mo +212 -0
  55. package/.mops/base@0.8.3/src/Bool.mo +44 -0
  56. package/.mops/base@0.8.3/src/Buffer.mo +2660 -0
  57. package/.mops/base@0.8.3/src/CertifiedData.mo +53 -0
  58. package/.mops/base@0.8.3/src/Char.mo +65 -0
  59. package/.mops/base@0.8.3/src/Debug.mo +56 -0
  60. package/.mops/base@0.8.3/src/Deque.mo +243 -0
  61. package/.mops/base@0.8.3/src/Error.mo +68 -0
  62. package/.mops/base@0.8.3/src/ExperimentalCycles.mo +151 -0
  63. package/.mops/base@0.8.3/src/ExperimentalInternetComputer.mo +60 -0
  64. package/.mops/base@0.8.3/src/ExperimentalStableMemory.mo +348 -0
  65. package/.mops/base@0.8.3/src/Float.mo +843 -0
  66. package/.mops/base@0.8.3/src/Func.mo +46 -0
  67. package/.mops/base@0.8.3/src/Hash.mo +82 -0
  68. package/.mops/base@0.8.3/src/HashMap.mo +457 -0
  69. package/.mops/base@0.8.3/src/Heap.mo +233 -0
  70. package/.mops/base@0.8.3/src/Int.mo +365 -0
  71. package/.mops/base@0.8.3/src/Int16.mo +521 -0
  72. package/.mops/base@0.8.3/src/Int32.mo +522 -0
  73. package/.mops/base@0.8.3/src/Int64.mo +522 -0
  74. package/.mops/base@0.8.3/src/Int8.mo +522 -0
  75. package/.mops/base@0.8.3/src/Iter.mo +227 -0
  76. package/.mops/base@0.8.3/src/IterType.mo +7 -0
  77. package/.mops/base@0.8.3/src/List.mo +930 -0
  78. package/.mops/base@0.8.3/src/Nat.mo +305 -0
  79. package/.mops/base@0.8.3/src/Nat16.mo +144 -0
  80. package/.mops/base@0.8.3/src/Nat32.mo +144 -0
  81. package/.mops/base@0.8.3/src/Nat64.mo +144 -0
  82. package/.mops/base@0.8.3/src/Nat8.mo +144 -0
  83. package/.mops/base@0.8.3/src/None.mo +19 -0
  84. package/.mops/base@0.8.3/src/Option.mo +154 -0
  85. package/.mops/base@0.8.3/src/Order.mo +46 -0
  86. package/.mops/base@0.8.3/src/Prelude.mo +33 -0
  87. package/.mops/base@0.8.3/src/Principal.mo +249 -0
  88. package/.mops/base@0.8.3/src/RBTree.mo +681 -0
  89. package/.mops/base@0.8.3/src/Random.mo +270 -0
  90. package/.mops/base@0.8.3/src/Result.mo +209 -0
  91. package/.mops/base@0.8.3/src/Stack.mo +93 -0
  92. package/.mops/base@0.8.3/src/Text.mo +761 -0
  93. package/.mops/base@0.8.3/src/Time.mo +36 -0
  94. package/.mops/base@0.8.3/src/Timer.mo +62 -0
  95. package/.mops/base@0.8.3/src/Trie.mo +1603 -0
  96. package/.mops/base@0.8.3/src/TrieMap.mo +392 -0
  97. package/.mops/base@0.8.3/src/TrieSet.mo +148 -0
  98. package/network.txt +1 -0
  99. 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
+ }