I’ve merged the changes I’ve done to use the Region instead of the ExperimentalStableMemory in the trunk. I made a few changes in the interfaces of the lib, I was inspired by the Map from @ZhenyaUsenko. The intended usage:
import BTree "mo:StableBTree/BTree"
// Arbitrary use of (Nat32, Text) for (key, value) types
let n32conv = BTree.n32conv;
let tconv = BTree.tconv(64); // Max 16 characters
stable let _btree = BTree.new<Nat32, Text>(n32conv, tconv);
let old = BTree.put(_btree, n32conv, 0, tconv, "hello");
let new = BTree.get(_btree, n32conv, 0, tconv);
let size = BTree.size(_btree);
assert Option.isNull(old);
assert Option.isSome(new);
assert size == 1;
Where the types are as follow:
type BTree<K, V> = {
region: Region;
key_nonce: K;
value_nonce: V;
};
type BytesConverter<T> = {
from_bytes: (Blob) -> T;
to_bytes: (T) -> Blob;
max_size: Nat32;
nonce: T;
};
The “nonces” (shall probably be renamed) are only useful to keep the initial template parameters, so that when a BTree is loaded from stable memory later, the compilation prevents loading it with different template parameters than the original one. It’s kind of a trick, but I don’t know how else to do to support template parameters otherwise.
The max_size is used at the initialization of the btree and directly stored in stable memory. If you every give a greater max size later it will have no effect, and inserting a key/value with a greater size than the original one will still trap.
If you guys have better ideas please share.
I’d like to create benchmarks for the lib before releasing it on mops. @ZhenyaUsenko I was wondering how did you come up with your performance metrics for your stable map?