Generic, extensible buffers
StableBuffer<X> is adapted directly from https://github.com/dfinity/motoko-base/blob/master/src/Buffer.mo,
ripping all functions and instance variables out of the Buffer class in order to make a stable, persistent
buffer.
Generic, mutable sequences that grow to accommodate arbitrary numbers of elements.
StableBuffer<X> provides extensible, mutable sequences of elements of type X.
that can be efficiently produced and consumed with imperative code.
A buffer object can be extended by a single element or the contents of another buffer object.
When required, the current state of a buffer object can be converted to a fixed-size array of its elements.
Buffers complement Motoko's non-extensible array types (arrays do not support efficient extension, because the size of an array is determined at construction and cannot be changed).
public func initPresized<X>(initCapacity : Nat) : StableBuffer<X>Initializes a buffer of given initial capacity. Note that this capacity is not realized until an element is added to the buffer.
public func init<X>() : StableBuffer<X>Initializes a buffer of initial capacity 0. When the first element is added the size will grow to one
public func add<X>(buffer : StableBuffer<X>, element : X)Adds a single element to the end of the buffer, doubling the size of the array if capacity is exceeded.
Example:
motoko include=initialize
StableBuffer.add(buffer, 0); // add 0 to buffer
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3); // causes underlying array to increase in capacity
StableBuffer.toArray(buffer) // => [0, 1, 2, 3]Amortized Runtime: O(1), Worst Case Runtime: O(size)
Amortized Space: O(1), Worst Case Space: O(size)
public func remove<X>(buffer : StableBuffer<X>, index : Nat) : XRemoves and returns the element at index from the buffer.
All elements with index > index are shifted one position to the left.
This may cause a downsizing of the array.
Traps if index >= size.
WARNING: Repeated removal of elements using this method is ineffecient and might be a sign that you should consider a different data-structure for your use case.
Example:
motoko include=initialize
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
StableBuffer.add(buffer, 12);
let x = StableBuffer.remove(buffer, 1); // evaluates to 11. 11 no longer in list.
StableBuffer.toArray(buffer) // => [10, 12]Runtime: O(size)
Amortized Space: O(1), Worst Case Space: O(size)
public func removeLast<X>(buffer : StableBuffer<X>) : ?XRemoves and returns the last item in the buffer or null if
the buffer is empty.
Example:
motoko include=initialize
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
StableBuffer.removeLast(buffer); // => ?11Amortized Runtime: O(1), Worst Case Runtime: O(size)
Amortized Space: O(1), Worst Case Space: O(size)
public func append<X>(buffer : StableBuffer<X>, buffer2 : StableBuffer<X>)Adds all elements in buffer b to this buffer.
motoko include=initialize
let buffer1 = StableBuffer.initPresized<Nat>(2);
let buffer2 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer1, 10);
StableBuffer.add(buffer1, 11);
StableBuffer.add(buffer2, 12);
StableBuffer.add(buffer2, 13);
StableBuffer.append(buffer1, buffer2); // adds elements from buffer2 to buffer1
StableBuffer.toArray(buffer1) // => [10, 11, 12, 13]Amortized Runtime: O(size2), Worst Case Runtime: O(size1 + size2)
Amortized Space: O(1), Worst Case Space: O(size1 + size2)
public func size<X>(buffer : StableBuffer<X>) : NatReturns the current number of elements in the buffer.
Example:
motoko include=initialize
size(buffer) // => 0Runtime: O(1)
Space: O(1)
public func capacity<X>(buffer : StableBuffer<X>) : NatReturns the capacity of the buffer (the length of the underlying array).
Example:
motoko include=initialize
let buffer = StableBuffer.initPresized<Nat>(2); // underlying array has capacity 2
StableBuffer.add(buffer, 10);
let c1 = StableBuffer.capacity(buffer); // => 2
StableBuffer.add(buffer, 11);
StableBuffer.add(buffer, 12); // causes capacity to increase by factor of 1.5
let c2 = StableBuffer.capacity(buffer); // => 3Runtime: O(1)
Space: O(1)
public func reserve<X>(buffer : StableBuffer<X>, capacity : Nat)Changes the capacity to capacity. Traps if capacity < size.
motoko include=initialize
StableBuffer.reserve(buffer, 4);
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
StableBuffer.capacity(buffer); // => 4Runtime: O(capacity)
Space: O(capacity)
public func clear<X>(buffer : StableBuffer<X>)Resets the buffer. Capacity is set to 8.
Example:
motoko include=initialize
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
StableBuffer.add(buffer, 12);
StableBuffer.clear(buffer, ); // buffer is now empty
StableBuffer.toArray(buffer) // => []Runtime: O(1)
Space: O(1)
public func clone<X>(buffer : StableBuffer<X>) : StableBuffer<X>Returns a copy of buffer, with the same capacity.
Example:
motoko include=initialize
StableBuffer.add(buffer, 1);
let clone = StableBuffer.clone(buffer);
StableBuffer.toArray(clone); // => [1]Runtime: O(size)
Space: O(size)
public func vals<X>(buffer : StableBuffer<X>) : { next : () -> ?X }Returns an Iterator (Iter) over the elements of this buffer.
Iterator provides a single method next(), which returns
elements in order, or null when out of elements to iterate over.
motoko include=initialize
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
StableBuffer.add(buffer, 12);
var sum = 0;
for (element in StableBuffer.vals(buffer, )) {
  sum += element;
};
sum // => 33Runtime: O(1)
Space: O(1)
public func fromArray<X>(array : [X]) : StableBuffer<X>Creates a buffer containing elements from array.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let array = [2, 3];
let buf = StableBuffer.fromArray<Nat>(array); // => [2, 3]
StableBuffer.toText(buf, Nat.toText);Runtime: O(size)
Space: O(size)
public func toArray<X>(buffer : StableBuffer<X>) : [X]Creates an array containing elements from buffer.
Example:
motoko include=initialize
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.toArray<Nat>(buffer); // => [1, 2, 3]
Runtime: O(size)
Space: O(size)
public func toVarArray<X>(buffer : StableBuffer<X>) : [var X]Creates a mutable array containing elements from buffer.
Example:
motoko include=initialize
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.toVarArray<Nat>(buffer); // => [1, 2, 3]Runtime: O(size)
Space: O(size)
public func get<X>(buffer : StableBuffer<X>, index : Nat) : XReturns the element at index index. Traps if  index >= size. Indexing is zero-based.
Example:
motoko include=initialize
StableBuffer.add(buffer,10);
StableBuffer.add(buffer,11);
StableBuffer.get(buffer,0); // => 10Runtime: O(1)
Space: O(1)
public func getOpt<X>(buffer : StableBuffer<X>, index : Nat) : ?XReturns the element at index index as an option.
Returns null when index >= size. Indexing is zero-based.
Example:
motoko include=initialize
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
let x = StableBuffer.getOpt(buffer, 0); // => ?10
let y = StableBuffer.getOpt(buffer, 2); // => nullRuntime: O(1)
Space: O(1)
public func put<X>(
  buffer : StableBuffer<X>, 
  index : Nat, 
  element : X
)Overwrites the current element at index with element. Traps if
index >= size. Indexing is zero-based.
Example:
motoko include=initialize
StableBuffer.add(buffer, 10);
StableBuffer.put(buffer, 0, 20); // overwrites 10 at index 0 with 20
StableBuffer.toArray(Buffer, buffer) // => [20]Runtime: O(1)
Space: O(1)
public func contains<X>(
  buffer : StableBuffer<X>, 
  element : X, 
  equal : (X, X) -> Bool
) : BoolReturns true iff buffer contains element with respect to equality
defined by equal.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 0);
StableBuffer.add(buffer, 3);
StableBuffer.contains<Nat>(buffer, 2, Nat.equal); // => trueRuntime: O(size)
Space: O(1)
*Runtime and space assumes that equal runs in O(1) time and space.
public func indexOf<X>(
  element : X, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : ?NatFinds the first index of element in buffer using equality of elements defined
by equal. Returns null if element is not found.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.indexOf<Nat>(3, buffer, Nat.equal); // => ?2Runtime: O(size)
Space: O(size)
*Runtime and space assumes that equal runs in O(1) time and space.
public func filterEntries<X>(buffer : StableBuffer<X>, predicate : (Nat, X) -> Bool)Removes all elements from the buffer for which the predicate returns false. The predicate is given both the index of the element and the element itself. This may cause a downsizing of the array.
Example:
motoko include=initialize
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
StableBuffer.add(buffer, 12);
StableBuffer.filterEntries(buffer, func(_, x) = x % 2 == 0); // only keep even elements
StableBuffer.toArray(buffer) // => [10, 12]Runtime: O(size)
Amortized Space: O(1), Worst Case Space: O(size)
public func insert<X>(
  buffer : StableBuffer<X>, 
  index : Nat, 
  element : X
)Inserts element at index, shifts all elements to the right of
index over by one index. Traps if index is greater than size.
motoko include=initialize
let buffer1 = StableBuffer.initPresized<Nat>(2);
let buffer2 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer, 10);
StableBuffer.add(buffer, 11);
StableBuffer.insert(buffer, 1, 9);
StableBuffer.toArray(buffer) // => [10, 9, 11]Runtime: O(size)
Amortized Space: O(1), Worst Case Space: O(size)
public func insertBuffer<X>(
  buffer : StableBuffer<X>, 
  index : Nat, 
  buffer2 : StableBuffer<X>
)Inserts buffer2 at index, and shifts all elements to the right of
index over by size2. Traps if index is greater than size.
motoko include=initialize
let buffer1 = StableBuffer.initPresized<Nat>(2);
let buffer2 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer1, 10);
StableBuffer.add(buffer1, 11);
StableBuffer.add(buffer2, 12);
StableBuffer.add(buffer2, 13);
StableBuffer.insertBuffer(buffer1, 1, buffer2);
StableBuffer.toArray(buffer1) // => [10, 12, 13, 11]Runtime: O(size)
Amortized Space: O(1), Worst Case Space: O(size1 + size2)
public func sort<X>(buffer : StableBuffer<X>, compare : (X, X) -> Order.Order)Sorts the elements in the buffer according to compare.
Sort is deterministic, stable, and in-place.
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 11);
StableBuffer.add(buffer, 12);
StableBuffer.add(buffer, 10);
StableBuffer.sort(buffer, Nat.compare);
StableBuffer.toArray(buffer) // => [10, 11, 12]Runtime: O(size * log(size))
Space: O(size)
public func isEmpty<X>(buffer : StableBuffer<X>) : BoolReturns true if and only if the buffer is empty.
Example:
motoko include=initialize
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 0);
StableBuffer.add(buffer, 3);
StableBuffer.isEmpty(buffer); // => falsemotoko include=initialize
Buffer.isEmpty(buffer); // => trueRuntime: O(1)
Space: O(1)
public func max<X>(buffer : StableBuffer<X>, compare : (X, X) -> Order) : ?XFinds the greatest element in buffer defined by compare.
Returns null if buffer is empty.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.max(buffer, Nat.compare); // => ?2Runtime: O(size)
Space: O(1)
*Runtime and space assumes that compare runs in O(1) time and space.
public func min<X>(buffer : StableBuffer<X>, compare : (X, X) -> Order) : ?XFinds the least element in buffer defined by compare.
Returns null if buffer is empty.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.min(buffer, Nat.compare); // => ?1Runtime: O(size)
Space: O(1)
*Runtime and space assumes that compare runs in O(1) time and space.
public func equal<X>(
  buffer1 : StableBuffer<X>, 
  buffer2 : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : BoolDefines equality for two buffers, using equal to recursively compare elements in the
buffers. Returns true iff the two buffers are of the same size, and equal
evaluates to true for every pair of elements in the two buffers of the same
index.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let buffer1 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer1, 1);
StableBuffer.add(buffer1, 2);
let buffer2 = StableBuffer.initPresized<Nat>(5);
StableBuffer.add(buffer2, 1);
StableBuffer.add(buffer2, 2);
StableBuffer.equal(buffer1, buffer2, Nat.equal); // => trueRuntime: O(size)
Space: O(1)
*Runtime and space assumes that equal runs in O(1) time and space.
public func compare<X>(
  buffer1 : StableBuffer<X>, 
  buffer2 : StableBuffer<X>, 
  compare : (X, X) -> Order.Order
) : Order.OrderDefines comparison for two buffers, using compare to recursively compare elements in the
buffers. Comparison is defined lexicographically.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let buffer1 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer1, 1);
StableBuffer.add(buffer1, 2);
let buffer2 = StableBuffer.initPresized<Nat>(3);
StableBuffer.add(buffer2, 3);
StableBuffer.add(buffer2, 4);
StableBuffer.compare<Nat>(buffer1, buffer2, Nat.compare); // => #lessRuntime: O(size)
Space: O(1)
*Runtime and space assumes that compare runs in O(1) time and space.
public func toText<X>(buffer : StableBuffer<X>, toText : X -> Text) : TextCreates a textual representation of buffer, using toText to recursively
convert the elements into Text.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.toText(buffer, Nat.toText); // => "[1, 2, 3, 4]"Runtime: O(size)
Space: O(size)
*Runtime and space assumes that toText runs in O(1) time and space.
public func hash<X>(buffer : StableBuffer<X>, hash : X -> Nat32) : Nat32Hashes buffer using hash to hash the underlying elements.
The deterministic hash function is a function of the elements in the Buffer, as well
as their ordering.
Example:
motoko include=initialize
import Hash "mo:base/Hash";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 1000);
StableBuffer.hash<Nat>(buffer, Hash.hash); // => 2_872_640_342Runtime: O(size)
Space: O(1)
*Runtime and space assumes that hash runs in O(1) time and space.
public func lastIndexOf<X>(
  element : X, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : ?NatFinds the last index of element in buffer using equality of elements defined
by equal. Returns null if element is not found.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 2);
StableBuffer.lastIndexOf<Nat>(2, buffer, Nat.equal); // => ?5Runtime: O(size)
Space: O(size)
*Runtime and space assumes that equal runs in O(1) time and space.
public func indexOfBuffer<X>(
  subBuffer : StableBuffer<X>, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : ?NatSearches for subBuffer in buffer, and returns the starting index if it is found.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 6);
let sub = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(sub, 4);
StableBuffer.add(sub, 5);
StableBuffer.add(sub, 6);
StableBuffer.indexOfBuffer<Nat>(sub, buffer, Nat.equal); // => ?3Runtime: O(size of buffer + size of subBuffer)
Space: O(size of subBuffer)
*Runtime and space assumes that equal runs in O(1) time and space.
public func binarySearch<X>(
  element : X, 
  buffer : StableBuffer<X>, 
  compare : (X, X) -> Order.Order
) : ?NatSimilar to indexOf, but runs in logarithmic time. Assumes that buffer is sorted.
Behavior is undefined if buffer is not sorted. Uses compare to
perform the search. Returns an index of element if it is found.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 6);
StableBuffer.binarySearch<Nat>(5, buffer, Nat.compare); // => ?2Runtime: O(log(size))
Space: O(1)
*Runtime and space assumes that compare runs in O(1) time and space.
public func subBuffer<X>(
  buffer : StableBuffer<X>, 
  start : Nat, 
  length : Nat
) : StableBuffer<X>Returns the sub-buffer of buffer starting at index start
of length length. Traps if start is out of bounds, or start + length
is greater than the size of buffer.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 6);
let sub = StableBuffer.subBuffer(buffer, 3, 2);
StableBuffer.toText(sub, Nat.toText); // => [4, 5]Runtime: O(length)
Space: O(length)
public func isSubBufferOf<X>(
  subBuffer : StableBuffer<X>, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : BoolChecks if subBuffer is a sub-Buffer of buffer. Uses equal to
compare elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 6);
let sub = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(sub, 2);
StableBuffer.add(sub, 3);
StableBuffer.isSubBufferOf(sub, buffer, Nat.equal); // => trueRuntime: O(size of subBuffer + size of buffer)
Space: O(size of subBuffer)
*Runtime and space assumes that equal runs in O(1) time and space.
public func isStrictSubBufferOf<X>(
  subBuffer : StableBuffer<X>, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : BoolChecks if subBuffer is a strict subBuffer of buffer, i.e. subBuffer must be
strictly contained inside both the first and last indices of buffer.
Uses equal to compare elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
let sub = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(sub, 2);
StableBuffer.add(sub, 3);
StableBuffer.isStrictSubBufferOf(sub, buffer, Nat.equal); // => trueRuntime: O(size of subBuffer + size of buffer)
Space: O(size of subBuffer)
*Runtime and space assumes that equal runs in O(1) time and space.
public func prefix<X>(buffer : StableBuffer<X>, length : Nat) : StableBuffer<X>Returns the prefix of buffer of length length. Traps if length
is greater than the size of buffer.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
let pre = StableBuffer.prefix(buffer, 3); // => [1, 2, 3]
StableBuffer.toText(pre, Nat.toText);Runtime: O(length)
Space: O(length)
public func isPrefixOf<X>(
  prefix : StableBuffer<X>, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : BoolChecks if prefix is a prefix of buffer. Uses equal to
compare elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
let pre = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(pre, 1);
StableBuffer.add(pre, 2);
StableBuffer.isPrefixOf(pre, buffer, Nat.equal); // => trueRuntime: O(size of prefix)
Space: O(size of prefix)
*Runtime and space assumes that equal runs in O(1) time and space.
public func isStrictPrefixOf<X>(
  prefix : StableBuffer<X>, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : BoolChecks if prefix is a strict prefix of buffer. Uses equal to
compare elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
let pre = StableBuffer.initPresized<Nat>(3);
StableBuffer.add(pre, 1);
StableBuffer.add(pre, 2);
StableBuffer.add(pre, 3);
StableBuffer.isStrictPrefixOf(pre, buffer, Nat.equal); // => trueRuntime: O(size of prefix)
Space: O(size of prefix)
*Runtime and space assumes that equal runs in O(1) time and space.
public func suffix<X>(buffer : StableBuffer<X>, length : Nat) : StableBuffer<X>Returns the suffix of buffer of length length.
Traps if lengthis greater than the size of buffer.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
let suf = StableBuffer.suffix(buffer, 3); // => [2, 3, 4]
StableBuffer.toText(suf, Nat.toText);Runtime: O(length)
Space: O(length)
public func isSuffixOf<X>(
  suffix : StableBuffer<X>, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : BoolChecks if suffix is a suffix of buffer. Uses equal to compare
elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
let suf = StableBuffer.initPresized<Nat>(3);
StableBuffer.add(suf, 2);
StableBuffer.add(suf, 3);
StableBuffer.add(suf, 4);
StableBuffer.isSuffixOf(suf, buffer, Nat.equal); // => trueRuntime: O(length of suffix)
Space: O(length of suffix)
*Runtime and space assumes that equal runs in O(1) time and space.
public func isStrictSuffixOf<X>(
  suffix : StableBuffer<X>, 
  buffer : StableBuffer<X>, 
  equal : (X, X) -> Bool
) : BoolChecks if suffix is a strict suffix of buffer. Uses equal to compare
elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
let suf = StableBuffer.initPresized<Nat>(3);
StableBuffer.add(suf, 2);
StableBuffer.add(suf, 3);
StableBuffer.add(suf, 4);
StableBuffer.isStrictSuffixOf(suf, buffer, Nat.equal); // => trueRuntime: O(length of suffix)
Space: O(length of suffix)
*Runtime and space assumes that equal runs in O(1) time and space.
public func forAll<X>(buffer : StableBuffer<X>, predicate : X -> Bool) : BoolReturns true iff every element in buffer satisfies predicate.
Example:
motoko include=initialize
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.forAll<Nat>(buffer, func x { x > 1 }); // => trueRuntime: O(size)
Space: O(1)
*Runtime and space assumes that predicate runs in O(1) time and space.
public func forSome<X>(buffer : StableBuffer<X>, predicate : X -> Bool) : BoolReturns true iff some element in buffer satisfies predicate.
Example:
motoko include=initialize
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.forSome<Nat>(buffer, func x { x > 3 }); // => trueRuntime: O(size)
Space: O(1)
*Runtime and space assumes that predicate runs in O(1) time and space.
public func forNone<X>(buffer : StableBuffer<X>, predicate : X -> Bool) : BoolReturns true iff no element in buffer satisfies predicate.
Example:
motoko include=initialize
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.forNone<Nat>(buffer, func x { x == 0 }); // => trueRuntime: O(size)
Space: O(1)
*Runtime and space assumes that predicate runs in O(1) time and space.
public func fromVarArray<X>(array : [var X]) : StableBuffer<X>Creates a buffer containing elements from array.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let array = [var 1, 2, 3];
let buf = StableBuffer.fromVarArray<Nat>(array); // => [1, 2, 3]
StableBuffer.toText(buf, Nat.toText);Runtime: O(size)
Space: O(size)
public func fromIter<X>(iter : { next : () -> ?X }) : StableBuffer<X>Creates a buffer containing elements from iter.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let array = [1, 1, 1];
let iter = array.vals();
let buf = StableBuffer.fromIter<Nat>(iter); // => [1, 1, 1]
StableBuffer.toText(buf, Nat.toText);Runtime: O(size)
Space: O(size)
public func trimToSize<X>(buffer : StableBuffer<X>)Reallocates the array underlying buffer such that capacity == size.
Example:
motoko include=initialize
let buffer = StableBuffer.initPresized<Nat>(10);
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.trimToSize<Nat>(buffer);
StableBuffer.capacity(buffer); // => 3Runtime: O(size)
Space: O(size)
public func map<X, Y>(buffer : StableBuffer<X>, f : X -> Y) : StableBuffer<Y>Creates a new buffer by applying f to each element in buffer.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
let newBuf = StableBuffer.map<Nat, Nat>(buffer, func (x) { x + 1 });
StableBuffer.toText(newBuf, Nat.toText); // => [2, 3, 4]Runtime: O(size)
Space: O(size)
*Runtime and space assumes that f runs in O(1) time and space.
public func iterate<X>(buffer : StableBuffer<X>, f : X -> ())Applies f to each element in buffer.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
import Debug "mo:base/Debug";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.iterate<Nat>(buffer, func (x) {
  Debug.print(Nat.toText(x)); // prints each element in buffer
});Runtime: O(size)
Space: O(size)
*Runtime and space assumes that f runs in O(1) time and space.
public func mapEntries<X, Y>(buffer : StableBuffer<X>, f : (Nat, X) -> Y) : StableBuffer<Y>Applies f to each element in buffer and its index.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
let newBuf = StableBuffer.mapEntries<Nat, Nat>(buffer, func (x, i) { x + i + 1 });
StableBuffer.toText(newBuf, Nat.toText); // => [2, 4, 6]Runtime: O(size)
Space: O(size)
*Runtime and space assumes that f runs in O(1) time and space.
public func mapFilter<X, Y>(buffer : StableBuffer<X>, f : X -> ?Y) : StableBuffer<Y>Creates a new buffer by applying f to each element in buffer,
and keeping all non-null elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
let newBuf = StableBuffer.mapFilter<Nat, Nat>(buffer, func (x) {
  if (x > 1) {
    ?(x * 2);
  } else {
    null;
  }
});
StableBuffer.toText(newBuf, Nat.toText); // => [4, 6]Runtime: O(size)
Space: O(size)
*Runtime and space assumes that f runs in O(1) time and space.
public func mapResult<X, Y, E>(buffer : StableBuffer<X>, f : X -> Result.Result<Y, E>) : Result.Result<StableBuffer<Y>, E>Creates a new buffer by applying f to each element in buffer.
If any invocation of f produces an #err, returns an #err. Otherwise
Returns an #ok containing the new buffer.
Example:
motoko include=initialize
import Result "mo:base/Result";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
let result = StableBuffer.mapResult<Nat, Nat, Text>(buffer, func (k) {
  if (k > 0) {
    #ok(k);
  } else {
    #err("One or more elements are zero.");
  }
});
Result.mapOk<StableBuffer.StableBuffer<Nat>, [Nat], Text>(result, func buffer = StableBuffer.toArray(buffer)) // => #ok([1, 2, 3])Runtime: O(size)
Space: O(size)
*Runtime and space assumes that f runs in O(1) time and space.
public func chain<X, Y>(buffer : StableBuffer<X>, k : X -> StableBuffer<Y>) : StableBuffer<Y>Creates a new buffer by applying k to each element in buffer,
and concatenating the resulting buffers in order. This operation
is similar to what in other functional languages is known as monadic bind.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
let chain = StableBuffer.chain<Nat, Nat>(buffer, func (x) {
  let b = StableBuffer.initPresized<Nat>(2);
  b.add(x);
  b.add(x * 2);
  return b;
});
Buffer.toText(chain, Nat.toText); // => [1, 2, 2, 4, 3, 6]Runtime: O(size)
Space: O(size)
*Runtime and space assumes that k runs in O(1) time and space.
public func foldLeft<A, X>(
  buffer : StableBuffer<X>, 
  base : A, 
  combine : (A, X) -> A
) : ACollapses the elements in buffer into a single value by starting with base
and progessively combining elements into base with combine. Iteration runs
left to right.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
buffer.add(1);
buffer.add(2);
buffer.add(3);
Buffer.foldLeft<Text, Nat>(buffer, "", func (acc, x) { acc # Nat.toText(x)}); // => "123"Runtime: O(size)
Space: O(1)
*Runtime and space assumes that combine runs in O(1) time and space.
public func foldRight<X, A>(
  buffer : StableBuffer<X>, 
  base : A, 
  combine : (X, A) -> A
) : ACollapses the elements in buffer into a single value by starting with base
and progessively combining elements into base with combine. Iteration runs
right to left.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
buffer.add(1);
buffer.add(2);
buffer.add(3);
Buffer.foldRight<Nat, Text>(buffer, "", func (x, acc) { Nat.toText(x) # acc }); // => "123"Runtime: O(size)
Space: O(1)
*Runtime and space assumes that combine runs in O(1) time and space.
public func first<X>(buffer : StableBuffer<X>) : XReturns the first element of buffer. Traps if buffer is empty.
Example:
motoko include=initialize
buffer.add(1);
buffer.add(2);
buffer.add(3);
Buffer.first(buffer); // => 1Runtime: O(1)
Space: O(1)
public func last<X>(buffer : StableBuffer<X>) : XReturns the last element of buffer. Traps if buffer is empty.
Example:
motoko include=initialize
buffer.add(1);
buffer.add(2);
buffer.add(3);
Buffer.last(buffer); // => 3Runtime: O(1)
Space: O(1)
public func make<X>(element : X) : StableBuffer<X>Returns a new buffer with capacity and size 1, containing element.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let buffer = Buffer.make<Nat>(1);
Buffer.toText(buffer, Nat.toText); // => [1]Runtime: O(1)
Space: O(1)
public func reverse<X>(buffer : StableBuffer<X>)Reverses the order of elements in buffer.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
buffer.add(1);
buffer.add(2);
buffer.add(3);
Buffer.reverse(buffer);
Buffer.toText(buffer, Nat.toText); // => [3, 2, 1]Runtime: O(size)
Space: O(1)
public func merge<X>(
  buffer1 : StableBuffer<X>, 
  buffer2 : StableBuffer<X>, 
  compare : (X, X) -> Order
) : StableBuffer<X>Merges two sorted buffers into a single sorted buffer, using compare to define
the ordering. The final ordering is stable. Behavior is undefined if either
buffer1 or buffer2 is not sorted.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let buffer1 = Buffer.Buffer<Nat>(2);
buffer1.add(1);
buffer1.add(2);
buffer1.add(4);
let buffer2 = Buffer.Buffer<Nat>(2);
buffer2.add(2);
buffer2.add(4);
buffer2.add(6);
let merged = Buffer.merge<Nat>(buffer1, buffer2, Nat.compare);
Buffer.toText(merged, Nat.toText); // => [1, 2, 2, 4, 4, 6]Runtime: O(size1 + size2)
Space: O(size1 + size2)
*Runtime and space assumes that compare runs in O(1) time and space.
public func removeDuplicates<X>(buffer : StableBuffer<X>, compare : (X, X) -> Order)Eliminates all duplicate elements in buffer as defined by compare.
Elimination is stable with respect to the original ordering of the elements.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
buffer.add(1);
buffer.add(2);
buffer.add(3);
buffer.add(1);
buffer.add(2);
buffer.add(3);
Buffer.removeDuplicates<Nat>(buffer, Nat.compare);
Buffer.toText(buffer, Nat.toText); // => [1, 2, 3]Runtime: O(size * log(size))
Space: O(size)
public func partition<X>(buffer : StableBuffer<X>, predicate : X -> Bool) : (StableBuffer<X>, StableBuffer<X>)Splits buffer into a pair of buffers where all elements in the left
buffer satisfy predicate and all elements in the right buffer do not.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 6);
let partitions = StableBuffer.partition<Nat>(buffer, func (x) { x % 2 == 0 });
(StableBuffer.toArray(partitions.0), StableBuffer.toArray(partitions.1)) // => ([2, 4, 6], [1, 3, 5])Runtime: O(size)
Space: O(size)
*Runtime and space assumes that predicate runs in O(1) time and space.
public func split<X>(buffer : StableBuffer<X>, index : Nat) : (StableBuffer<X>, StableBuffer<X>)Splits the buffer into two buffers at index, where the left buffer contains
all elements with indices less than index, and the right buffer contains all
elements with indices greater than or equal to index. Traps if index is out
of bounds.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 6);
let split = Buffer.split<Nat>(buffer, 3);
(Buffer.toArray(split.0), Buffer.toArray(split.1)) // => ([1, 2, 3], [4, 5, 6])Runtime: O(size)
Space: O(size)
*Runtime and space assumes that compare runs in O(1) time and space.
public func chunk<X>(buffer : StableBuffer<X>, count : Nat) : StableBuffer<StableBuffer<X>>Breaks up buffer into buffers of size size. The last chunk may
have less than size elements if the number of elements is not divisible
by the chunk size.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 6);
let chunks = StableBuffer.chunk<Nat>(buffer, 3);
StableBuffer.toText<StableBuffer.StableBuffer<Nat>>(chunks, func buf = StableBuffer.toText(buf, Nat.toText)); // => [[1, 2, 3], [4, 5, 6]]Runtime: O(number of elements in buffer)
Space: O(number of elements in buffer)
public func groupBy<X>(buffer : StableBuffer<X>, equal : (X, X) -> Bool) : StableBuffer<StableBuffer<X>>Groups equal and adjacent elements in the list into sub lists.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 4);
StableBuffer.add(buffer, 5);
StableBuffer.add(buffer, 5);
let grouped = StableBuffer.groupBy<Nat>(buffer, func (x, y) { x == y });
StableBuffer.toText<StableBuffer.StableBuffer<Nat>>(grouped, func buf = StableBuffer.toText(buf, Nat.toText)); // => [[1], [2, 2], [4], [5, 5]]Runtime: O(size)
Space: O(size)
*Runtime and space assumes that equal runs in O(1) time and space.
public func flatten<X>(buffer : StableBuffer<StableBuffer<X>>) : StableBuffer<X>Flattens the buffer of buffers into a single buffer.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
let buffer = StableBuffer.initPresized<StableBuffer.StableBuffer<Nat>>(1);
let inner1 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(inner1, 1);
StableBuffer.add(inner1, 2);
let inner2 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(inner2, 3);
StableBuffer.add(inner2, 4);
StableBuffer.add(buffer, inner1);
StableBuffer.add(buffer, inner2);
// buffer = [[1, 2], [3, 4]]
let flat = StableBuffer.flatten<Nat>(buffer);
StableBuffer.toText<Nat>(flat, Nat.toText); // => [1, 2, 3, 4]Runtime: O(number of elements in buffer)
Space: O(number of elements in buffer)
public func zip<X, Y>(buffer1 : StableBuffer<X>, buffer2 : StableBuffer<Y>) : StableBuffer<(X, Y)>Combines the two buffers into a single buffer of pairs, pairing together elements with the same index. If one buffer is longer than the other, the remaining elements from the longer buffer are not included.
Example:
motoko include=initialize
let buffer1 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer1, 1);
StableBuffer.add(buffer1, 2);
StableBuffer.add(buffer1, 3);
let buffer2 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer2, 4);
StableBuffer.add(buffer2, 5);
let zipped = StableBuffer.zip(buffer1, buffer2);
StableBuffer.toArray(zipped); // => [(1, 4), (2, 5)]Runtime: O(min(size1, size2))
Space: O(min(size1, size2))
public func zipWith<X, Y, Z>(
  buffer1 : StableBuffer<X>, 
  buffer2 : StableBuffer<Y>, 
  zip : (X, Y) -> Z
) : StableBuffer<Z>Combines the two buffers into a single buffer, pairing together
elements with the same index and combining them using zip. If
one buffer is longer than the other, the remaining elements from
the longer buffer are not included.
Example:
motoko include=initialize
let buffer1 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer1, 1);
StableBuffer.add(buffer1, 2);
StableBuffer.add(buffer1, 3);
let buffer2 = StableBuffer.initPresized<Nat>(2);
StableBuffer.add(buffer2, 4);
StableBuffer.add(buffer2, 5);
StableBuffer.add(buffer2, 6);
let zipped = StableBuffer.zipWith<Nat, Nat, Nat>(buffer1, buffer2, func (x, y) { x + y });
StableBuffer.toArray(zipped) // => [5, 7, 9]Runtime: O(min(size1, size2))
Space: O(min(size1, size2))
*Runtime and space assumes that zip runs in O(1) time and space.
public func takeWhile<X>(buffer : StableBuffer<X>, predicate : X -> Bool) : StableBuffer<X>Creates a new buffer taking elements in order from buffer until predicate
returns false.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
let newBuf = StableBuffer.takeWhile<Nat>(buffer, func (x) { x < 3 });
StableBuffer.toText(newBuf, Nat.toText); // => [1, 2]Runtime: O(size)
Space: O(size)
*Runtime and space assumes that predicate runs in O(1) time and space.
public func dropWhile<X>(buffer : StableBuffer<X>, predicate : X -> Bool) : StableBuffer<X>Creates a new buffer excluding elements in order from buffer until predicate
returns false.
Example:
motoko include=initialize
import Nat "mo:base/Nat";
StableBuffer.add(buffer, 1);
StableBuffer.add(buffer, 2);
StableBuffer.add(buffer, 3);
let newBuf = StableBuffer.dropWhile<Nat>(buffer, func x { x < 3 }); // => [3]
StableBuffer.toText(newBuf, Nat.toText);Runtime: O(size)
Space: O(size)
*Runtime and space assumes that predicate runs in O(1) time and space.