From d548252ee80c8ec086a55f1b64490ada43cf6f42 Mon Sep 17 00:00:00 2001 From: Tomi Jaga Date: Sat, 19 Jul 2025 10:35:21 -0700 Subject: [PATCH 1/4] Update median_key to separator_key --- src/MemoryBTree/Base.mo | 12 +++---- src/MemoryBTree/modules/Branch.mo | 54 ++++++++++++++-------------- src/MemoryBTree/modules/Methods.mo | 56 +++++++++++++++--------------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/MemoryBTree/Base.mo b/src/MemoryBTree/Base.mo index 6c2e2ad..b8d9722 100644 --- a/src/MemoryBTree/Base.mo +++ b/src/MemoryBTree/Base.mo @@ -376,7 +376,7 @@ module { var right_index = Leaf.get_index(btree, right_node_address); let ?first_key_address = Leaf.get_kv_address(btree, right_node_address, 0) else Debug.trap("insert: first_key_address accessed a null value"); - var median_key_address = first_key_address; + var separator_key_address = first_key_address; // assert Leaf.get_count(btree, left_node_address) == (btree.node_capacity / 2) + 1; // assert Leaf.get_count(btree, right_node_address) == (btree.node_capacity / 2); @@ -392,7 +392,7 @@ module { // Debug.print("found branch with enough space"); // Debug.print("parent before insert: " # debug_show Branch.from_memory(btree, parent_address)); - Branch.insert(btree, parent_address, right_index, median_key_address, right_node_address); + Branch.insert(btree, parent_address, right_index, separator_key_address, right_node_address); update_count(btree, btree.count + 1); // Debug.print("parent after insert: " # debug_show Branch.from_memory(btree, parent_address)); @@ -402,12 +402,12 @@ module { // otherwise split parent left_node_address := parent_address; - right_node_address := Branch.split(btree, left_node_address, right_index, median_key_address, right_node_address); + right_node_address := Branch.split(btree, left_node_address, right_index, separator_key_address, right_node_address); update_branch_count(btree, btree.branch_count + 1); let ?first_key_address = Branch.get_key_address(btree, right_node_address, btree.node_capacity - 2) else Debug.trap("4. insert: accessed a null value in first key of branch"); Branch.set_key_address_to_null(btree, right_node_address, btree.node_capacity - 2); - median_key_address := first_key_address; + separator_key_address := first_key_address; right_index := Branch.get_index(btree, right_node_address); opt_parent := Branch.get_parent(btree, right_node_address); @@ -423,7 +423,7 @@ module { Branch.update_depth(btree, new_root, new_depth); assert Branch.get_depth(btree, new_root) == new_depth; - Branch.put_key_address(btree, new_root, 0, median_key_address); + Branch.put_key_address(btree, new_root, 0, separator_key_address); Branch.add_child(btree, new_root, left_node_address); Branch.add_child(btree, new_root, right_node_address); @@ -723,7 +723,7 @@ module { if (elem_index == 0) { // if the first element is removed then update the parent key let ?next_key_address = Leaf.get_kv_address(btree, leaf_address, 0) else Debug.trap("remove: next_key_block is null"); - Branch.update_median_key_address(btree, parent, leaf_index, next_key_address); + Branch.update_separator_key_address(btree, parent, leaf_index, next_key_address); }; let min_count = btree.node_capacity / 2; diff --git a/src/MemoryBTree/modules/Branch.mo b/src/MemoryBTree/modules/Branch.mo index 7fae09b..fd69db8 100644 --- a/src/MemoryBTree/modules/Branch.mo +++ b/src/MemoryBTree/modules/Branch.mo @@ -601,7 +601,7 @@ module Branch { MemoryRegion.storeNat64(btree.branches, branch_address + MC.PARENT_START, parent); }; - public func update_median_key_address(btree : MemoryBTree, parent_address : Nat, child_index : Nat, new_key_address : UniqueId) { + public func update_separator_key_address(btree : MemoryBTree, parent_address : Nat, child_index : Nat, new_key_address : UniqueId) { var curr_address = parent_address; var i = child_index; @@ -630,7 +630,7 @@ module Branch { // elements inserted are always nodes created as a result of split // so their index is always greater than one as new nodes created from // a split operation are always inserted at the right - // update_median_key_address(btree, branch, i, key); + // update_separator_key_address(btree, branch, i, key); // Debug.trap("Branch.insert(): inserting at index 0 is not allowed"); } else { let key_offset = get_node_key_offset(branch_address, i - 1); @@ -681,7 +681,7 @@ module Branch { let is_elem_added_to_right = child_index >= median; - var median_key_address = ?child_key_address; + var separator_key_address = ?child_key_address; var offset = if (is_elem_added_to_right) 0 else 1; var already_inserted = false; @@ -698,7 +698,7 @@ module Branch { if (not is_elem_added_to_right) { let j = i + median - offset : Nat; - median_key_address := Branch.get_key_address(btree, branch_address, j - 1); + separator_key_address := Branch.get_key_address(btree, branch_address, j - 1); let start_key = get_node_key_offset(branch_address, j); let end_key = get_node_key_offset(branch_address, arr_len - 1); @@ -751,7 +751,7 @@ module Branch { child; } else { if (i == 0) { - median_key_address := Branch.get_key_address(btree, branch_address, j - 1); + separator_key_address := Branch.get_key_address(btree, branch_address, j - 1); } else { let ?shifted_key_address = Branch.get_key_address(btree, branch_address, j - 1) else Debug.trap("Branch.split: accessed a null value"); @@ -799,8 +799,8 @@ module Branch { // store the first key of the right node at the end of the keys in left node // no need to delete as the value will get overwritten because it exceeds the count position - let ?_median_key_address = median_key_address else Debug.trap("Branch.split: median key_block is null"); - Branch.put_key_address(btree, right_address, btree.node_capacity - 2, _median_key_address); + let ?_separator_key_address = separator_key_address else Debug.trap("Branch.split: median key_block is null"); + Branch.put_key_address(btree, right_address, btree.node_capacity - 2, _separator_key_address); right_address; }; @@ -932,8 +932,8 @@ module Branch { if (neighbour_index < branch_index) { // Debug.print("redistribute: left neighbour"); // move data from the left neighbour to the right branch - let ?_median_key_address = Branch.get_key_address(btree, parent, neighbour_index) else return Debug.trap("Branch.redistribute: median_key_address should not be null"); - var median_key_address = _median_key_address; + let ?_separator_key_address = Branch.get_key_address(btree, parent, neighbour_index) else return Debug.trap("Branch.redistribute: separator_key_address should not be null"); + var separator_key_address = _separator_key_address; Branch.shift(btree, branch, 0, branch_count, data_to_move); @@ -945,39 +945,39 @@ module Branch { let ?child = Branch.get_child(btree, neighbour, j) else return Debug.trap("Branch.redistribute: child should not be null"); Branch.remove(btree, neighbour, j); - // Debug.print("median_key_address: " # debug_show median_key_address); + // Debug.print("separator_key_address: " # debug_show separator_key_address); let new_index = data_to_move - i - 1 : Nat; - Branch.put_key_address(btree, branch, new_index, median_key_address); + Branch.put_key_address(btree, branch, new_index, separator_key_address); Branch.put_child(btree, branch, new_index, child); let child_subtree_size = if (branch_has_leaves) Leaf.get_count(btree, child) else Branch.get_subtree_size(btree, child); moved_subtree_size += child_subtree_size; - median_key_address := key_address; + separator_key_address := key_address; i += 1; }; - // Debug.print("parent median_key_address: " # debug_show median_key_address); - // Debug.print("parent median_key_blob: " # debug_show median_key_blob); + // Debug.print("parent separator_key_address: " # debug_show separator_key_address); + // Debug.print("parent separator_key_blob: " # debug_show separator_key_blob); - Branch.put_key_address(btree, parent, neighbour_index, median_key_address); + Branch.put_key_address(btree, parent, neighbour_index, separator_key_address); } else { // Debug.print("redistribute: right neighbour"); // move data from the right neighbour to the left branch - let ?_median_key_address = Branch.get_key_address(btree, parent, branch_index) else return Debug.trap("Branch.redistribute: median_key_address should not be null"); - var median_key_address = _median_key_address; + let ?_separator_key_address = Branch.get_key_address(btree, parent, branch_index) else return Debug.trap("Branch.redistribute: separator_key_address should not be null"); + var separator_key_address = _separator_key_address; var i = 0; while (i < data_to_move) { - // Debug.print("median_key_address: " # debug_show median_key_address); + // Debug.print("separator_key_address: " # debug_show separator_key_address); let ?child = Branch.get_child(btree, neighbour, i) else return Debug.trap("Branch.redistribute: child should not be null"); - Branch.insert(btree, branch, branch_count + i, median_key_address, child); + Branch.insert(btree, branch, branch_count + i, separator_key_address, child); let child_subtree_size = if (branch_has_leaves) Leaf.get_count(btree, child) else Branch.get_subtree_size(btree, child); moved_subtree_size += child_subtree_size; @@ -985,12 +985,12 @@ module Branch { let ?key_block = Branch.get_key_address(btree, neighbour, i) else return Debug.trap("Branch.redistribute: key_block should not be null"); let ?key_blob = Branch.get_key_blob(btree, neighbour, i) else return Debug.trap("Branch.redistribute: key_blob should not be null"); - median_key_address := key_block; + separator_key_address := key_block; i += 1; }; - // Debug.print("parent median_key_address: " # debug_show median_key_address); + // Debug.print("parent separator_key_address: " # debug_show separator_key_address); // shift keys and children in the right neighbour // since we can't shift to the first child index, @@ -1001,7 +1001,7 @@ module Branch { Branch.put_child(btree, neighbour, 0, first_child); // update median key in parent - Branch.put_key_address(btree, parent, branch_index, median_key_address); + Branch.put_key_address(btree, parent, branch_index, separator_key_address); }; Branch.update_count(btree, branch, branch_count + data_to_move); @@ -1039,21 +1039,21 @@ module Branch { let left_subtree_size = Branch.get_subtree_size(btree, left); let right_subtree_size = Branch.get_subtree_size(btree, right); - let ?_median_key_address = Branch.get_key_address(btree, parent, right_index - 1) else Debug.trap("Branch.merge: median_key_address should not be null"); - var median_key_address = _median_key_address; + let ?_separator_key_address = Branch.get_key_address(btree, parent, right_index - 1) else Debug.trap("Branch.merge: separator_key_address should not be null"); + var separator_key_address = _separator_key_address; // Debug.print("left branch before merge: " # debug_show Branch.from_memory(btree, left)); // Debug.print("right branch before merge: " # debug_show Branch.from_memory(btree, right)); var i = 0; label while_loop while (i < right_count) { - // Debug.print("median_key_address: " # debug_show median_key_address); + // Debug.print("separator_key_address: " # debug_show separator_key_address); let ?child = Branch.get_child(btree, right, i) else return Debug.trap("Branch.merge: child should not be null"); - Branch.insert(btree, left, left_count + i, median_key_address, child); + Branch.insert(btree, left, left_count + i, separator_key_address, child); if (i < (right_count - 1 : Nat)) { let ?key_block = Branch.get_key_address(btree, right, i) else return Debug.trap("Branch.merge: key_block should not be null"); - median_key_address := key_block; + separator_key_address := key_block; }; i += 1; diff --git a/src/MemoryBTree/modules/Methods.mo b/src/MemoryBTree/modules/Methods.mo index 601aad1..1b9c584 100644 --- a/src/MemoryBTree/modules/Methods.mo +++ b/src/MemoryBTree/modules/Methods.mo @@ -733,26 +733,26 @@ module Methods { assert address == leaf.0 [Leaf.AC.ADDRESS]; assert depth == 1; - let (left_median_key, right_median_key) = switch (Leaf.get_parent(btree, address)) { + let (left_separator_key, right_separator_key) = switch (Leaf.get_parent(btree, address)) { case (?parent) { - var left_median_key : ?Nat = null; - var right_median_key : ?Nat = null; + var left_separator_key : ?Nat = null; + var right_separator_key : ?Nat = null; if (index > 0) { - let ?left_median_key_blob = Branch.get_key_blob(btree, parent, index - 1) else Debug.trap("1. validate: accessed a null value"); - left_median_key := ?btree_utils.key.blobify.from_blob(left_median_key_blob); + let ?left_separator_key_blob = Branch.get_key_blob(btree, parent, index - 1) else Debug.trap("1. validate: accessed a null value"); + left_separator_key := ?btree_utils.key.blobify.from_blob(left_separator_key_blob); }; let parent_count = Branch.get_count(btree, parent); if (index + 1 < parent_count) { - let ?right_median_key_blob = Branch.get_key_blob(btree, parent, index) else Debug.trap("2. validate: accessed a null value"); - right_median_key := ?btree_utils.key.blobify.from_blob(right_median_key_blob); + let ?right_separator_key_blob = Branch.get_key_blob(btree, parent, index) else Debug.trap("2. validate: accessed a null value"); + right_separator_key := ?btree_utils.key.blobify.from_blob(right_separator_key_blob); }; - (left_median_key, right_median_key); + (left_separator_key, right_separator_key); }; case (null) (null, null); @@ -783,16 +783,16 @@ module Methods { }; }; - switch (left_median_key) { - case (?left_median_key) { - assert left_median_key <= key; + switch (left_separator_key) { + case (?left_separator_key) { + assert left_separator_key <= key; }; case (null) {}; }; - switch (right_median_key) { - case (?right_median_key) { - assert key < right_median_key; + switch (right_separator_key) { + case (?right_separator_key) { + assert key < right_separator_key; }; case (null) {}; }; @@ -820,26 +820,26 @@ module Methods { assert address == branch.0 [Branch.AC.ADDRESS]; assert subtree_size == branch.0 [Branch.AC.SUBTREE_SIZE]; - let (left_median_key, right_median_key) = switch (Branch.get_parent(btree, address)) { + let (left_separator_key, right_separator_key) = switch (Branch.get_parent(btree, address)) { case (?parent) { - var left_median_key : ?Nat = null; - var right_median_key : ?Nat = null; + var left_separator_key : ?Nat = null; + var right_separator_key : ?Nat = null; if (index > 0) { - let ?left_median_key_blob = Branch.get_key_blob(btree, parent, index - 1) else Debug.trap("7. validate: accessed a null value"); - left_median_key := ?btree_utils.key.blobify.from_blob(left_median_key_blob); + let ?left_separator_key_blob = Branch.get_key_blob(btree, parent, index - 1) else Debug.trap("7. validate: accessed a null value"); + left_separator_key := ?btree_utils.key.blobify.from_blob(left_separator_key_blob); }; let parent_count = Branch.get_count(btree, parent); if (index + 1 < parent_count) { - let ?right_median_key_blob = Branch.get_key_blob(btree, parent, index) else Debug.trap("8. validate: accessed a null value"); - right_median_key := ?btree_utils.key.blobify.from_blob(right_median_key_blob); + let ?right_separator_key_blob = Branch.get_key_blob(btree, parent, index) else Debug.trap("8. validate: accessed a null value"); + right_separator_key := ?btree_utils.key.blobify.from_blob(right_separator_key_blob); }; - (left_median_key, right_median_key); + (left_separator_key, right_separator_key); }; case (null) (null, null); @@ -868,16 +868,16 @@ module Methods { }; }; - switch (left_median_key) { - case (?left_median_key) { - assert left_median_key <= key; + switch (left_separator_key) { + case (?left_separator_key) { + assert left_separator_key <= key; }; case (null) {}; }; - switch (right_median_key) { - case (?right_median_key) { - assert key < right_median_key; + switch (right_separator_key) { + case (?right_separator_key) { + assert key < right_separator_key; }; case (null) {}; }; From b3bf9234bfff04bd973238386241ab9b6031ba14 Mon Sep 17 00:00:00 2001 From: Tomi Jaga Date: Sun, 10 Aug 2025 14:42:47 -0700 Subject: [PATCH 2/4] fix memory-buffer pointer bug caused by an error in the MemoryRegion allocating the same memory block twice. --- bench/MemoryBTree/BTree-specific-fns.bench.mo | 36 +- bench/MemoryBTree/BTree.Types.bench.mo | 38 +- bench/MemoryBTree/MemoryBTree.bench.mo | 81 +-- .../MemoryBTree.node-capacity.bench.mo | 42 +- ...fer.Blob.mo => MemoryBuffer.Blob.bench.mo} | 62 +-- bench/MemoryBuffer/MemoryBuffer.Nat.Test.mo | 327 ------------ bench/MemoryBuffer/MemoryBuffer.Text.mo | 326 ------------ bench/MemoryQueue/MemoryQueue.bench.mo | 34 +- example/MemoryBTree.mo | 8 +- example/MemoryBuffer.mo | 2 +- example/MemoryQueue.mo | 12 +- example/txs/backend/Backend.mo | 32 +- example/txs/backend/BlockUtils.mo | 16 +- mops.toml | 21 +- src/MemoryBTree/Base.mo | 51 +- src/MemoryBTree/Migrations/V0.mo | 8 +- src/MemoryBTree/Migrations/V0_0_1.mo | 8 +- src/MemoryBTree/Migrations/lib.mo | 6 +- src/MemoryBTree/Migrations/upgrades.mo | 18 +- src/MemoryBTree/Stable.mo | 2 +- src/MemoryBTree/lib.mo | 2 +- src/MemoryBTree/modules/Branch.mo | 28 +- src/MemoryBTree/modules/Leaf.mo | 20 +- src/MemoryBTree/modules/MemoryBlock.mo | 20 +- src/MemoryBTree/modules/MemoryFns.mo | 6 +- src/MemoryBTree/modules/Methods.mo | 22 +- src/MemoryBTree/modules/Types.mo | 6 +- src/MemoryBTreeSet/lib.mo | 4 +- src/MemoryBuffer/Base.mo | 34 +- src/MemoryBuffer/Migrations.mo | 10 +- src/MemoryBuffer/Stable.mo | 12 +- src/MemoryBuffer/lib.mo | 8 +- src/MemoryQueue/Base.mo | 22 +- src/MemoryQueue/Stable.mo | 2 +- src/MemoryQueue/lib.mo | 6 +- src/MemoryQueue/migrations/V0.mo | 2 +- src/MemoryQueue/migrations/lib.mo | 2 +- src/TypeUtils/Blobify.mo | 38 +- src/TypeUtils/Int8Cmp.mo | 2 +- src/TypeUtils/MemoryCmp.mo | 2 +- src/TypeUtils/WyHash64.mo | 16 +- src/Utils.mo | 22 +- tests/MemoryBTree/MemoryBTree.Load.Test.mo | 481 ++++++++++++++++++ .../MemoryBTree.Migrations.Test.mo | 20 +- tests/MemoryBTree/MemoryBTree.Test.mo | 44 +- tests/MemoryBTree/MotokoStableBTre.mo | 91 ---- tests/MemoryBuffer/MemoryBuffer.Load.Test.mo | 336 ++++++++++++ ...est.mo => MemoryBuffer.Migrations.Test.mo} | 2 +- tests/MemoryBuffer/MemoryBuffer.Test.mo | 47 +- tests/MemoryQueue/MemoryQueue.Test.mo | 16 +- 50 files changed, 1158 insertions(+), 1295 deletions(-) rename bench/MemoryBuffer/{MemoryBuffer.Blob.mo => MemoryBuffer.Blob.bench.mo} (72%) delete mode 100644 bench/MemoryBuffer/MemoryBuffer.Nat.Test.mo delete mode 100644 bench/MemoryBuffer/MemoryBuffer.Text.mo create mode 100644 tests/MemoryBTree/MemoryBTree.Load.Test.mo delete mode 100644 tests/MemoryBTree/MotokoStableBTre.mo create mode 100644 tests/MemoryBuffer/MemoryBuffer.Load.Test.mo rename tests/MemoryBuffer/{Migrations.Test.mo => MemoryBuffer.Migrations.Test.mo} (94%) diff --git a/bench/MemoryBTree/BTree-specific-fns.bench.mo b/bench/MemoryBTree/BTree-specific-fns.bench.mo index 4a122c6..f330894 100644 --- a/bench/MemoryBTree/BTree-specific-fns.bench.mo +++ b/bench/MemoryBTree/BTree-specific-fns.bench.mo @@ -1,13 +1,13 @@ -import Iter "mo:base/Iter"; -import Debug "mo:base/Debug"; -import Nat "mo:base/Nat"; -import Buffer "mo:base/Buffer"; -import Nat64 "mo:base/Nat64"; +import Iter "mo:base@.v0.14.11/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat "mo:base@.v0.14.11/Nat"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Nat64 "mo:base@.v0.14.11/Nat64"; -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; +import Bench "mo:bench@.v1.0.0"; +import Fuzz "mo:fuzz@.v1.0.0"; -import { BpTree; Cmp } "mo:augmented-btrees"; +import { BpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; import MemoryBTree "../../src/MemoryBTree/Base"; import TypeUtils "../../src/TypeUtils"; @@ -16,25 +16,7 @@ module { type MemoryBTree = MemoryBTree.MemoryBTree; public func init() : Bench.Bench { - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); + let fuzz = Fuzz.fromSeed(0xdeadbeef); let bench = Bench.Bench(); bench.name("Comparing B+Tree and MemoryBTree"); diff --git a/bench/MemoryBTree/BTree.Types.bench.mo b/bench/MemoryBTree/BTree.Types.bench.mo index 70feefd..bfa139b 100644 --- a/bench/MemoryBTree/BTree.Types.bench.mo +++ b/bench/MemoryBTree/BTree.Types.bench.mo @@ -1,12 +1,12 @@ -import Iter "mo:base/Iter"; -import Debug "mo:base/Debug"; -import Buffer "mo:base/Buffer"; -import Text "mo:base/Text"; -import Nat "mo:base/Nat"; -import Nat64 "mo:base/Nat64"; - -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; +import Iter "mo:base@.v0.14.11/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Text "mo:base@.v0.14.11/Text"; +import Nat "mo:base@.v0.14.11/Nat"; +import Nat64 "mo:base@.v0.14.11/Nat64"; + +import Bench "mo:bench@.v1.0.0"; +import Fuzz "mo:fuzz@.v1.0.0"; import MotokoStableBTree "mo:MotokoStableBTree/BTree"; import MemoryBTree "../../src/MemoryBTree/Base"; @@ -20,25 +20,7 @@ module { type Buffer = Buffer.Buffer; public func init() : Bench.Bench { - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); + let fuzz = Fuzz.fromSeed(0xdeadbeef); let bench = Bench.Bench(); bench.name("Comparing B+Tree and Memory B+Tree with different serialization formats and comparison functions"); diff --git a/bench/MemoryBTree/MemoryBTree.bench.mo b/bench/MemoryBTree/MemoryBTree.bench.mo index e4e73fd..284e8b5 100644 --- a/bench/MemoryBTree/MemoryBTree.bench.mo +++ b/bench/MemoryBTree/MemoryBTree.bench.mo @@ -1,19 +1,16 @@ -import Iter "mo:base/Iter"; -import Debug "mo:base/Debug"; -import Nat64 "mo:base/Nat64"; -import Region "mo:base/Region"; -import Buffer "mo:base/Buffer"; -import Text "mo:base/Text"; -import RBTree "mo:base/RBTree"; +import Iter "mo:base@.v0.14.11/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Region "mo:base@.v0.14.11/Region"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Text "mo:base@.v0.14.11/Text"; +import RBTree "mo:base@.v0.14.11/RBTree"; -import BTree "mo:stableheapbtreemap/BTree"; -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; -import MotokoStableBTree "mo:MotokoStableBTree/BTree"; -import BTreeMap "mo:MotokoStableBTree/modules/btreemap"; -import BTreeMapMemory "mo:MotokoStableBTree/modules/memory"; +import BTree "mo:stableheapbtreemap@.v1.5.0/BTree"; +import Bench "mo:bench@.v1.0.0"; +import Fuzz "mo:fuzz@.v1.0.0"; -import { BpTree; Cmp } "mo:augmented-btrees"; +import { BpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; import MemoryBTree "../../src/MemoryBTree/Base"; import TypeUtils "../../src/TypeUtils"; @@ -24,25 +21,7 @@ module { type BTreeUtils = MemoryBTree.BTreeUtils; public func init() : Bench.Bench { - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); + let fuzz = Fuzz.fromSeed(0xdeadbeef); let bench = Bench.Bench(); bench.name("Comparing RBTree, BTree and B+Tree (BpTree)"); @@ -66,13 +45,9 @@ module { let limit = 10_000; - let { n64conv; tconv } = MotokoStableBTree; - - let tconv_10 = tconv(10); let rbtree = RBTree.RBTree(Text.compare); let btree = BTree.init(?32); let bptree = BpTree.new(?128); - let stable_btree = BTreeMap.new(BTreeMapMemory.RegionMemory(Region.new()), tconv_10, tconv_10); let mem_btree = MemoryBTree.new(?128); let mem_btree_blob_cmp = MemoryBTree.new(?128); @@ -242,38 +217,6 @@ module { }; }; - case ("MotokoStableBTree", "insert()") { - for ((key, val) in entries.vals()) { - ignore stable_btree.insert(key, tconv_10, val, tconv_10); - }; - }; - case ("MotokoStableBTree", "replace()") { - for ((key, val) in entries.vals()) { - ignore stable_btree.insert(key, tconv_10, val, tconv_10); - }; - }; - case ("MotokoStableBTree", "get()") { - for (i in Iter.range(0, limit - 1)) { - let (key, val) = entries.get(i); - ignore stable_btree.get(key, tconv_10, tconv_10); - }; - }; - case ("MotokoStableBTree", "entries()") { - var i = 0; - for (kv in stable_btree.iter(tconv_10, tconv_10)) { - i += 1; - }; - - assert Nat64.fromNat(i) == stable_btree.getLength(); - Debug.print("Size: " # debug_show (i, stable_btree.getLength())); - }; - case ("MotokoStableBTree", "scan()") {}; - case ("MotokoStableBTree", "remove()") { - for ((k, v) in entries.vals()) { - ignore stable_btree.remove(k, tconv_10, tconv_10); - }; - }; - case ("Memory B+Tree (#BlobCmp)", category) { run_bench("Memory B+Tree", category, mem_btree_blob_cmp, btree_utils); }; diff --git a/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo b/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo index 2cc0c65..40ac632 100644 --- a/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo +++ b/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo @@ -1,18 +1,18 @@ -import Iter "mo:base/Iter"; -import Debug "mo:base/Debug"; -import Nat "mo:base/Nat"; -import Nat64 "mo:base/Nat64"; -import Region "mo:base/Region"; -import Buffer "mo:base/Buffer"; -import Text "mo:base/Text"; - -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; +import Iter "mo:base@.v0.14.11/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat "mo:base@.v0.14.11/Nat"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Region "mo:base@.v0.14.11/Region"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Text "mo:base@.v0.14.11/Text"; + +import Bench "mo:bench@.v1.0.0"; +import Fuzz "mo:fuzz@.v1.0.0"; import MotokoStableBTree "mo:MotokoStableBTree/BTree"; import BTreeMap "mo:MotokoStableBTree/modules/btreemap"; import BTreeMapMemory "mo:MotokoStableBTree/modules/memory"; -import { BpTree; Cmp } "mo:augmented-btrees"; +import { BpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; import MemoryBTree "../../src/MemoryBTree/Base"; import TypeUtils "../../src/TypeUtils"; @@ -22,25 +22,7 @@ module { type MemoryBTree = MemoryBTree.MemoryBTree; public func init() : Bench.Bench { - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); + let fuzz = Fuzz.fromSeed(0xdeadbeef); let bench = Bench.Bench(); bench.name("Comparing the Memory B+Tree with different node capacities"); diff --git a/bench/MemoryBuffer/MemoryBuffer.Blob.mo b/bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo similarity index 72% rename from bench/MemoryBuffer/MemoryBuffer.Blob.mo rename to bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo index d6cdea1..c81ec5f 100644 --- a/bench/MemoryBuffer/MemoryBuffer.Blob.mo +++ b/bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo @@ -1,12 +1,12 @@ -import Iter "mo:base/Iter"; -import Buffer "mo:base/Buffer"; -import Nat "mo:base/Nat"; -import Blob "mo:base/Blob"; -import Debug "mo:base/Debug"; -import Nat64 "mo:base/Nat64"; +import Iter "mo:base@.v0.14.11/Iter"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Nat "mo:base@.v0.14.11/Nat"; +import Blob "mo:base@.v0.14.11/Blob"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat64 "mo:base@.v0.14.11/Nat64"; -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; +import Bench "mo:bench@.v1.0.0"; +import Fuzz "mo:fuzz@.v1.0.0"; import MemoryBuffer "../../src/MemoryBuffer/Base"; @@ -45,25 +45,7 @@ module { let limit = 10_000; - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); + let fuzz = Fuzz.fromSeed(0xdeadbeef); let buffer = Buffer.Buffer(limit); let mbuffer = MemoryBuffer.new(); @@ -75,10 +57,12 @@ module { let less = Buffer.Buffer(limit); for (i in Iter.range(0, limit - 1)) { - let blob = fuzz.blob.randomBlob(10); - let blob2 = fuzz.blob.randomBlob(10); - let higher = fuzz.blob.randomBlob(20); - let lower = fuzz.blob.randomBlob(5); + let size = fuzz.nat.randomRange(25, 50); + + let blob = fuzz.blob.randomBlob(size); + let blob2 = fuzz.blob.randomBlob(size); + let higher = fuzz.blob.randomBlob(fuzz.nat.randomRange(50, 100)); + let lower = fuzz.blob.randomBlob(fuzz.nat.randomRange(0, 25)); order.add(i); values.add(blob); @@ -155,10 +139,6 @@ module { MemoryBuffer.add(mbuffer, TypeUtils.Blob, val); }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - }; case ("MemoryBuffer", "get()") { for (i in Iter.range(0, limit - 1)) { @@ -171,9 +151,6 @@ module { let val = values2.get(i); MemoryBuffer.put(mbuffer, TypeUtils.Blob, i, val); }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); }; case ("MemoryBuffer", "put() (new > prev)") { @@ -181,9 +158,6 @@ module { let val = greater.get(i); MemoryBuffer.put(mbuffer, TypeUtils.Blob, i, val); }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); }; case ("MemoryBuffer", "put() (new < prev)") { @@ -191,9 +165,6 @@ module { let val = less.get(i); MemoryBuffer.put(mbuffer, TypeUtils.Blob, i, val); }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); }; case ("MemoryBuffer", "remove()") { @@ -202,9 +173,6 @@ module { ignore MemoryBuffer.remove(mbuffer, TypeUtils.Blob, j); }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); }; case ("MemoryBuffer", "insert()") { diff --git a/bench/MemoryBuffer/MemoryBuffer.Nat.Test.mo b/bench/MemoryBuffer/MemoryBuffer.Nat.Test.mo deleted file mode 100644 index 5b4682d..0000000 --- a/bench/MemoryBuffer/MemoryBuffer.Nat.Test.mo +++ /dev/null @@ -1,327 +0,0 @@ -import Iter "mo:base/Iter"; -import Buffer "mo:base/Buffer"; -import Int "mo:base/Int"; -import Nat "mo:base/Nat"; -import Nat64 "mo:base/Nat64"; -import Debug "mo:base/Debug"; -import Float "mo:base/Float"; - -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; - -import MemoryBuffer "../../src/MemoryBuffer/Base"; -import Cmp "../../src/TypeUtils/Int8Cmp"; -import TypeUtils "../../src/TypeUtils"; - -module { - - let candid_blobify = TypeUtils.Candid.Nat; - - public func init() : Bench.Bench { - let bench = Bench.Bench(); - - bench.name("Buffer vs MemoryBuffer"); - bench.description("Benchmarking the performance with 10k entries"); - - bench.cols([ - "Buffer", - "MemoryBuffer (with Blobify)", - "MemoryBuffer (encode to candid)", - ]); - - bench.rows([ - "add()", - "get()", - "put() (new == prev)", - "put() (new > prev)", - "put() (new < prev)", - "add() reallocation", - "removeLast()", - "reverse()", - "remove()", - "insert()", - "shuffle()", - "sortUnstable() #GenCmp", - "shuffle()", - "sortUnstable() #BlobCmp", - ]); - - let limit = 10_000; - - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); - - let buffer = Buffer.Buffer(limit); - let mbuffer = MemoryBuffer.new(); - let cbuffer = MemoryBuffer.new(); - - let order = Buffer.Buffer(limit); - let values = Buffer.Buffer(limit); - let values2 = Buffer.Buffer(limit); - let greater = Buffer.Buffer(limit); - let less = Buffer.Buffer(limit); - - func logn(number : Float, base : Float) : Float { - Float.log(number) / Float.log(base); - }; - - for (i in Iter.range(0, limit - 1)) { - let n1 = fuzz.nat.randomRange(0, limit * 100); - let n2 = fuzz.nat.randomRange(0, limit * 100); - - order.add(i); - values.add(n1); - values2.add(n2); - greater.add(Nat64.toNat(Nat64.fromNat(n1) << 16) * 2); - - let log : Nat = logn(Float.fromInt(n1), 2) - |> Float.toInt(_) - |> Int.abs(_); - less.add(log); - }; - - fuzz.buffer.shuffle(order); - - bench.runner( - func(row, col) = switch (col, row) { - - case ("Buffer", "add()" or "add() reallocation") { - for (i in Iter.range(0, limit - 1)) { - let val = values.get(i); - buffer.add(val); - }; - }; - case ("Buffer", "get()") { - for (i in Iter.range(0, limit - 1)) { - ignore buffer.get(i); - }; - }; - case ("Buffer", "put() (new == prev)") { - for (i in Iter.range(0, limit - 1)) { - let val = values2.get(i); - buffer.put(i, val); - }; - }; - case ("Buffer", "put() (new > prev)") { - for (i in order.vals()) { - let val = greater.get(i); - buffer.put(i, val); - }; - }; - case ("Buffer", "put() (new < prev)") { - for (i in order.vals()) { - let val = less.get(i); - buffer.put(i, val); - }; - }; - case ("Buffer", "remove()") { - for (i in order.vals()) { - ignore buffer.remove(Nat.min(i, buffer.size() - 1)); - }; - }; - case ("Buffer", "insert()") { - for (i in order.vals()) { - buffer.insert(Nat.min(i, buffer.size()), i); - }; - }; - case ("Buffer", "reverse()") { - Buffer.reverse(buffer); - }; - case ("Buffer", "sortUnstable() #GenCmp") { - buffer.sort(Nat.compare); - }; - case ("Buffer", "sortUnstable() #BlobCmp") {}; - case ("Buffer", "shuffle()") { - // fuzz.buffer.shuffle(buffer); - }; - case ("Buffer", "removeLast()") { - for (_ in Iter.range(0, limit - 1)) { - ignore buffer.removeLast(); - }; - }; - - case ("MemoryBuffer (encode to candid)", "add()" or "add() reallocation") { - for (i in Iter.range(0, limit - 1)) { - let val = values.get(i); - MemoryBuffer.add(cbuffer, candid_blobify, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "get()") { - for (i in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.get(cbuffer, candid_blobify, i); - }; - - }; - case ("MemoryBuffer (encode to candid)", "put() (new == prev)") { - for (i in order.vals()) { - let val = values2.get(i); - MemoryBuffer.put(cbuffer, candid_blobify, i, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "put() (new > prev)") { - for (i in order.vals()) { - let val = greater.get(i); - MemoryBuffer.put(cbuffer, candid_blobify, i, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "put() (new < prev)") { - for (i in order.vals()) { - let val = less.get(i); - MemoryBuffer.put(cbuffer, candid_blobify, i, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "remove()") { - for (i in order.vals()) { - let j = Nat.min(i, MemoryBuffer.size(cbuffer) - 1); - - ignore MemoryBuffer.remove(cbuffer, candid_blobify, j); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "insert()") { - for (i in order.vals()) { - MemoryBuffer.insert(cbuffer, candid_blobify, Nat.min(i, MemoryBuffer.size(cbuffer)), i ** 3); - }; - }; - case ("MemoryBuffer (encode to candid)", "reverse()") { - MemoryBuffer.reverse(cbuffer); - }; - case ("MemoryBuffer (encode to candid)", "sortUnstable() #GenCmp") { - MemoryBuffer.sortUnstable(cbuffer, candid_blobify, #GenCmp(Cmp.Nat)); - }; - case ("MemoryBuffer (encode to candid)", "sortUnstable() #BlobCmp") {}; - case ("MemoryBuffer (encode to candid)", "shuffle()") { - MemoryBuffer.shuffle(cbuffer); - }; - case ("MemoryBuffer (encode to candid)", "removeLast()") { - for (_ in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.removeLast(cbuffer, candid_blobify); - }; - }; - - case ("MemoryBuffer (with Blobify)", "add()" or "add() reallocation") { - for (i in Iter.range(0, limit - 1)) { - let val = values.get(i); - MemoryBuffer.add(mbuffer, TypeUtils.Nat, val); - }; - - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "get()") { - for (i in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.get(mbuffer, TypeUtils.Nat, i); - }; - - }; - case ("MemoryBuffer (with Blobify)", "put() (new == prev)") { - for (i in order.vals()) { - let val = values2.get(i); - MemoryBuffer.put(mbuffer, TypeUtils.Nat, i, val); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "put() (new > prev)") { - for (i in order.vals()) { - let val = greater.get(i); - MemoryBuffer.put(mbuffer, TypeUtils.Nat, i, val); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "put() (new < prev)") { - for (i in order.vals()) { - let val = less.get(i); - MemoryBuffer.put(mbuffer, TypeUtils.Nat, i, val); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "remove()") { - for (i in order.vals()) { - let j = Nat.min(i, MemoryBuffer.size(mbuffer) - 1); - - ignore MemoryBuffer.remove(mbuffer, TypeUtils.Nat, j); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "insert()") { - for (i in order.vals()) { - MemoryBuffer.insert(mbuffer, TypeUtils.Nat, Nat.min(i, MemoryBuffer.size(mbuffer)), i ** 3); - }; - }; - case ("MemoryBuffer (with Blobify)", "reverse()") { - MemoryBuffer.reverse(mbuffer); - }; - case ("MemoryBuffer (with Blobify)", "sortUnstable() #GenCmp") { - MemoryBuffer.sortUnstable(mbuffer, TypeUtils.Nat, #GenCmp(Cmp.Nat)); - }; - case ("MemoryBuffer (with Blobify)", "shuffle()") { - MemoryBuffer.shuffle(mbuffer); - }; - case ("MemoryBuffer (with Blobify)", "sortUnstable() #BlobCmp") { - MemoryBuffer.sortUnstable(mbuffer, TypeUtils.Nat, #BlobCmp(Cmp.Blob)); - }; - case ("MemoryBuffer (with Blobify)", "removeLast()") { - for (_ in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.removeLast(mbuffer, TypeUtils.Nat); - }; - }; - - case (_) { - Debug.trap("Should not reach with row = " # debug_show row # " and col = " # debug_show col); - }; - } - ); - - bench; - }; -}; diff --git a/bench/MemoryBuffer/MemoryBuffer.Text.mo b/bench/MemoryBuffer/MemoryBuffer.Text.mo deleted file mode 100644 index dc30600..0000000 --- a/bench/MemoryBuffer/MemoryBuffer.Text.mo +++ /dev/null @@ -1,326 +0,0 @@ -import Iter "mo:base/Iter"; -import Buffer "mo:base/Buffer"; -import Nat "mo:base/Nat"; -import Text "mo:base/Text"; -import Debug "mo:base/Debug"; -import Float "mo:base/Float"; -import Nat64 "mo:base/Nat64"; - -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; - -import MemoryBuffer "../../src/MemoryBuffer/Base"; -import Cmp "../../src/TypeUtils/Int8Cmp"; -import TypeUtils "../../src/TypeUtils"; - -module { - - let candid_blobify = TypeUtils.Candid.Text; - - public func init() : Bench.Bench { - let bench = Bench.Bench(); - - bench.name("Buffer vs MemoryBuffer"); - bench.description("Benchmarking the performance with 10k entries"); - - bench.cols([ - "Buffer", - "MemoryBuffer (with Blobify)", - "MemoryBuffer (encode to candid)", - ]); - - bench.rows([ - "add()", - "get()", - "put() (new == prev)", - "put() (new > prev)", - "put() (new < prev)", - "add() reallocation", - "removeLast()", - "reverse()", - "remove()", - "insert()", - "shuffle()", - "sortUnstable() #GenCmp", - "shuffle()", - "sortUnstable() #BlobCmp", - ]); - - let limit = 10_000; - - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); - - let buffer = Buffer.Buffer(limit); - let mbuffer = MemoryBuffer.new(); - let cbuffer = MemoryBuffer.new(); - - let order = Buffer.Buffer(limit); - let values = Buffer.Buffer(limit); - let values2 = Buffer.Buffer(limit); - let greater = Buffer.Buffer(limit); - let less = Buffer.Buffer(limit); - - func logn(number : Float, base : Float) : Float { - Float.log(number) / Float.log(base); - }; - - for (i in Iter.range(0, limit - 1)) { - let n1 = fuzz.text.randomAlphanumeric(10); - let n2 = fuzz.text.randomAlphanumeric(10); - - let l = fuzz.text.randomAlphanumeric(5); - let g = fuzz.text.randomAlphanumeric(15); - - order.add(i); - values.add(n1); - values2.add(n2); - greater.add(g); - less.add(l); - }; - - fuzz.buffer.shuffle(order); - - bench.runner( - func(row, col) = switch (col, row) { - - case ("Buffer", "add()" or "add() reallocation") { - for (i in Iter.range(0, limit - 1)) { - let val = values.get(i); - buffer.add(val); - }; - }; - case ("Buffer", "get()") { - for (i in Iter.range(0, limit - 1)) { - ignore buffer.get(i); - }; - }; - case ("Buffer", "put() (new == prev)") { - for (i in Iter.range(0, limit - 1)) { - let val = values2.get(i); - buffer.put(i, val); - }; - }; - case ("Buffer", "put() (new > prev)") { - for (i in order.vals()) { - let val = greater.get(i); - buffer.put(i, val); - }; - }; - case ("Buffer", "put() (new < prev)") { - for (i in order.vals()) { - let val = less.get(i); - buffer.put(i, val); - }; - }; - case ("Buffer", "remove()") { - for (i in order.vals()) { - ignore buffer.remove(Nat.min(i, buffer.size() - 1)); - }; - }; - case ("Buffer", "insert()") { - for (i in order.vals()) { - buffer.insert(Nat.min(i, buffer.size()), values.get(i)); - }; - }; - case ("Buffer", "reverse()") { - Buffer.reverse(buffer); - }; - case ("Buffer", "sortUnstable() #GenCmp") { - buffer.sort(Text.compare); - }; - case ("Buffer", "sortUnstable() #BlobCmp") {}; - case ("Buffer", "shuffle()") { - // fuzz.buffer.shuffle(buffer); - }; - case ("Buffer", "removeLast()") { - for (_ in Iter.range(0, limit - 1)) { - ignore buffer.removeLast(); - }; - }; - - case ("MemoryBuffer (encode to candid)", "add()" or "add() reallocation") { - for (i in Iter.range(0, limit - 1)) { - let val = values.get(i); - MemoryBuffer.add(cbuffer, candid_blobify, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "get()") { - for (i in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.get(cbuffer, candid_blobify, i); - }; - - }; - case ("MemoryBuffer (encode to candid)", "put() (new == prev)") { - for (i in order.vals()) { - let val = values2.get(i); - MemoryBuffer.put(cbuffer, candid_blobify, i, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "put() (new > prev)") { - for (i in order.vals()) { - let val = greater.get(i); - MemoryBuffer.put(cbuffer, candid_blobify, i, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "put() (new < prev)") { - for (i in order.vals()) { - let val = less.get(i); - MemoryBuffer.put(cbuffer, candid_blobify, i, val); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "remove()") { - for (i in order.vals()) { - let j = Nat.min(i, MemoryBuffer.size(cbuffer) - 1); - - ignore MemoryBuffer.remove(cbuffer, candid_blobify, j); - }; - Debug.print("cbuffer bytes: " # debug_show MemoryBuffer.bytes(cbuffer)); - Debug.print("cbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(cbuffer)); - Debug.print("cbuffer capacity: " # debug_show MemoryBuffer.capacity(cbuffer)); - - }; - case ("MemoryBuffer (encode to candid)", "insert()") { - for (i in order.vals()) { - MemoryBuffer.insert(cbuffer, candid_blobify, Nat.min(i, MemoryBuffer.size(cbuffer)), values.get(i)); - }; - }; - case ("MemoryBuffer (encode to candid)", "reverse()") { - MemoryBuffer.reverse(cbuffer); - }; - case ("MemoryBuffer (encode to candid)", "sortUnstable() #GenCmp") { - MemoryBuffer.sortUnstable(cbuffer, candid_blobify, #GenCmp(Cmp.Text)); - }; - case ("MemoryBuffer (encode to candid)", "sortUnstable() #BlobCmp") {}; - case ("MemoryBuffer (encode to candid)", "shuffle()") { - MemoryBuffer.shuffle(cbuffer); - }; - case ("MemoryBuffer (encode to candid)", "removeLast()") { - for (_ in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.removeLast(cbuffer, candid_blobify); - }; - }; - - case ("MemoryBuffer (with Blobify)", "add()" or "add() reallocation") { - for (i in Iter.range(0, limit - 1)) { - let val = values.get(i); - MemoryBuffer.add(mbuffer, TypeUtils.Text, val); - }; - - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "get()") { - for (i in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.get(mbuffer, TypeUtils.Text, i); - }; - - }; - case ("MemoryBuffer (with Blobify)", "put() (new == prev)") { - for (i in order.vals()) { - let val = values2.get(i); - MemoryBuffer.put(mbuffer, TypeUtils.Text, i, val); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "put() (new > prev)") { - for (i in order.vals()) { - let val = greater.get(i); - MemoryBuffer.put(mbuffer, TypeUtils.Text, i, val); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "put() (new < prev)") { - for (i in order.vals()) { - let val = less.get(i); - MemoryBuffer.put(mbuffer, TypeUtils.Text, i, val); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "remove()") { - for (i in order.vals()) { - let j = Nat.min(i, MemoryBuffer.size(mbuffer) - 1); - - ignore MemoryBuffer.remove(mbuffer, TypeUtils.Text, j); - }; - Debug.print("mbuffer bytes: " # debug_show MemoryBuffer.bytes(mbuffer)); - Debug.print("mbuffer metadataBytes: " # debug_show MemoryBuffer.metadataBytes(mbuffer)); - Debug.print("mbuffer capacity: " # debug_show MemoryBuffer.capacity(mbuffer)); - - }; - case ("MemoryBuffer (with Blobify)", "insert()") { - for (i in order.vals()) { - MemoryBuffer.insert(mbuffer, TypeUtils.Text, Nat.min(i, MemoryBuffer.size(mbuffer)), values.get(i)); - }; - }; - case ("MemoryBuffer (with Blobify)", "reverse()") { - MemoryBuffer.reverse(mbuffer); - }; - case ("MemoryBuffer (with Blobify)", "sortUnstable() #GenCmp") { - MemoryBuffer.sortUnstable(mbuffer, TypeUtils.Text, #GenCmp(Cmp.Text)); - }; - case ("MemoryBuffer (with Blobify)", "shuffle()") { - MemoryBuffer.shuffle(mbuffer); - }; - case ("MemoryBuffer (with Blobify)", "sortUnstable() #BlobCmp") { - MemoryBuffer.sortUnstable(mbuffer, TypeUtils.Text, #BlobCmp(Cmp.Blob)); - }; - case ("MemoryBuffer (with Blobify)", "removeLast()") { - for (_ in Iter.range(0, limit - 1)) { - ignore MemoryBuffer.removeLast(mbuffer, TypeUtils.Text); - }; - }; - - case (_) { - Debug.trap("Should not reach with row = " # debug_show row # " and col = " # debug_show col); - }; - } - ); - - bench; - }; -}; diff --git a/bench/MemoryQueue/MemoryQueue.bench.mo b/bench/MemoryQueue/MemoryQueue.bench.mo index 8d32043..6465bbb 100644 --- a/bench/MemoryQueue/MemoryQueue.bench.mo +++ b/bench/MemoryQueue/MemoryQueue.bench.mo @@ -1,11 +1,11 @@ -import Iter "mo:base/Iter"; -import Debug "mo:base/Debug"; -import Buffer "mo:base/Buffer"; -import Nat64 "mo:base/Nat64"; +import Iter "mo:base@.v0.14.11/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Nat64 "mo:base@.v0.14.11/Nat64"; -import Bench "mo:bench"; -import Fuzz "mo:fuzz"; -import Itertools "mo:itertools/Iter"; +import Bench "mo:bench@.v1.0.0"; +import Fuzz "mo:fuzz@.v1.0.0"; +import Itertools "mo:itertools@.v0.2.2/Iter"; import MemoryQueue "../../src/MemoryQueue"; import TypeUtils "../../src/TypeUtils"; @@ -25,25 +25,7 @@ module { "random add()/pop()", ]); - func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; - }; - - let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); + let fuzz = Fuzz.fromSeed(0xdeadbeef); let limit = 10_000; diff --git a/example/MemoryBTree.mo b/example/MemoryBTree.mo index a91679b..e1b6545 100644 --- a/example/MemoryBTree.mo +++ b/example/MemoryBTree.mo @@ -1,7 +1,7 @@ -import Debug "mo:base/Debug"; -import Time "mo:base/Time"; -import Float "mo:base/Float"; -import Iter "mo:base/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Time "mo:base@.v0.14.11/Time"; +import Float "mo:base@.v0.14.11/Float"; +import Iter "mo:base@.v0.14.11/Iter"; import MemoryBTree "../src/MemoryBTree"; // "mo:memory_collection/MemoryBTree" import TypeUtils "../src/TypeUtils"; // "mo:memory_collection/TypeUtils" diff --git a/example/MemoryBuffer.mo b/example/MemoryBuffer.mo index d9a0153..147c69c 100644 --- a/example/MemoryBuffer.mo +++ b/example/MemoryBuffer.mo @@ -1,4 +1,4 @@ -import Debug "mo:base/Debug"; +import Debug "mo:base@.v0.14.11/Debug"; import MemoryBuffer "../src/MemoryBuffer"; // "mo:memory_collection/MemoryBuffer" import TypeUtils "../src/TypeUtils"; // "mo:memory_collection/TypeUtils" diff --git a/example/MemoryQueue.mo b/example/MemoryQueue.mo index 41501a6..3bb76e7 100644 --- a/example/MemoryQueue.mo +++ b/example/MemoryQueue.mo @@ -1,9 +1,9 @@ -import Buffer "mo:base/Buffer"; -import Principal "mo:base/Principal"; -import Timer "mo:base/Timer"; -import Debug "mo:base/Debug"; -import Iter "mo:base/Iter"; -import Nat "mo:base/Nat"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Principal "mo:base@.v0.14.11/Principal"; +import Timer "mo:base@.v0.14.11/Timer"; +import Debug "mo:base@.v0.14.11/Debug"; +import Iter "mo:base@.v0.14.11/Iter"; +import Nat "mo:base@.v0.14.11/Nat"; import Map "mo:map/Map"; diff --git a/example/txs/backend/Backend.mo b/example/txs/backend/Backend.mo index 94748ed..40783f1 100644 --- a/example/txs/backend/Backend.mo +++ b/example/txs/backend/Backend.mo @@ -1,23 +1,23 @@ import Prim "mo:prim"; -import Array "mo:base/Array"; -import Iter "mo:base/Iter"; -import IC "mo:base/ExperimentalInternetComputer"; -import Principal "mo:base/Principal"; -import Debug "mo:base/Debug"; -import Nat64 "mo:base/Nat64"; -import Nat "mo:base/Nat"; -import Cycles "mo:base/ExperimentalCycles"; -import Buffer "mo:base/Buffer"; -import Option "mo:base/Option"; -import Time "mo:base/Time"; -import Blob "mo:base/Blob"; -import Nat8 "mo:base/Nat8"; -import Int "mo:base/Int"; +import Array "mo:base@.v0.14.11/Array"; +import Iter "mo:base@.v0.14.11/Iter"; +import IC "mo:base@.v0.14.11/ExperimentalInternetComputer"; +import Principal "mo:base@.v0.14.11/Principal"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Nat "mo:base@.v0.14.11/Nat"; +import Cycles "mo:base@.v0.14.11/ExperimentalCycles"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Option "mo:base@.v0.14.11/Option"; +import Time "mo:base@.v0.14.11/Time"; +import Blob "mo:base@.v0.14.11/Blob"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Int "mo:base@.v0.14.11/Int"; import Vector "mo:vector"; -import Itertools "mo:itertools/Iter"; -import RevIter "mo:itertools/RevIter"; +import Itertools "mo:itertools@.v0.2.2/Iter"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import Ledger "ledger"; import MemoryBTree "mo:memory-collection/MemoryBTree"; diff --git a/example/txs/backend/BlockUtils.mo b/example/txs/backend/BlockUtils.mo index 52aaf9e..bbb0bdc 100644 --- a/example/txs/backend/BlockUtils.mo +++ b/example/txs/backend/BlockUtils.mo @@ -1,13 +1,13 @@ -import Array "mo:base/Array"; -import Principal "mo:base/Principal"; -import Debug "mo:base/Debug"; -import Nat64 "mo:base/Nat64"; -import Nat "mo:base/Nat"; -import Cycles "mo:base/ExperimentalCycles"; -import Buffer "mo:base/Buffer"; +import Array "mo:base@.v0.14.11/Array"; +import Principal "mo:base@.v0.14.11/Principal"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Nat "mo:base@.v0.14.11/Nat"; +import Cycles "mo:base@.v0.14.11/ExperimentalCycles"; +import Buffer "mo:base@.v0.14.11/Buffer"; import Vector "mo:vector"; -import Itertools "mo:itertools/Iter"; +import Itertools "mo:itertools@.v0.2.2/Iter"; import Ledger "ledger"; import T "Types"; diff --git a/mops.toml b/mops.toml index 56dbf0a..92aaa3d 100644 --- a/mops.toml +++ b/mops.toml @@ -7,19 +7,18 @@ keywords = ["stable-memory", "encoding", "persistent"] license = "MIT" [dependencies] -base = "0.14.11" -itertools = "0.2.2" -memory-region = "1.2.4" -buffer-deque = "0.1.0" -byte-utils = "0.0.1" +"base@.v0.14.11" = "0.14.11" +"itertools@.v0.2.2" = "0.2.2" +"memory-region@.v1.3.2" = "1.3.2" +"buffer-deque@.v0.1.0" = "0.1.0" +"byte-utils@.v0.0.1" = "0.0.1" [dev-dependencies] -test = "2.1.1" -bench = "1.0.0" -augmented-btrees = "0.5.2" -fuzz = "1.0.0" -MotokoStableBTree = "https://github.com/sardariuss/MotokoStableBTree#master@b590ede4489c2d4b2189299c3a2cc35dc4faa3fc" -memory-collection-btree-v0-v0_0_1_migration = "https://github.com/NatLabs/memory-collection#master@bdba9e30ad95048634f23fe9c45c1e93c7787ce0" +"test@.v2.1.1" = "2.1.1" +"bench@.v1.0.0" = "1.0.0" +"augmented-btrees@.v0.7.1" = "0.7.1" +"fuzz@.v1.0.0" = "1.0.0" +"stableheapbtreemap@.v1.5.0" = "1.5.0" [toolchain] wasmtime = "14.0.4" diff --git a/src/MemoryBTree/Base.mo b/src/MemoryBTree/Base.mo index b8d9722..27fc837 100644 --- a/src/MemoryBTree/Base.mo +++ b/src/MemoryBTree/Base.mo @@ -1,16 +1,16 @@ -import Debug "mo:base/Debug"; -import Iter "mo:base/Iter"; -import Int "mo:base/Int"; -import Nat "mo:base/Nat"; -import Option "mo:base/Option"; -import Nat8 "mo:base/Nat8"; -import Nat16 "mo:base/Nat16"; -import Nat32 "mo:base/Nat32"; -import Nat64 "mo:base/Nat64"; -import Blob "mo:base/Blob"; - -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Iter "mo:base@.v0.14.11/Iter"; +import Int "mo:base@.v0.14.11/Int"; +import Nat "mo:base@.v0.14.11/Nat"; +import Option "mo:base@.v0.14.11/Option"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat16 "mo:base@.v0.14.11/Nat16"; +import Nat32 "mo:base@.v0.14.11/Nat32"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Blob "mo:base@.v0.14.11/Blob"; + +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import Find "mo:map/Map/modules/find"; import MemoryCmp "../TypeUtils/MemoryCmp"; @@ -636,9 +636,13 @@ module { public func clear(btree : MemoryBTree) { // the first leaf node should be at the address where the header ends + // Leaf.validate() checks that the leaf_address the specified leaf_address is valid (i.e the start of the leaf node) let leaf_address = MC.REGION_HEADER_SIZE; assert Leaf.validate(btree, leaf_address); + // remove all key-value pairs from the leaf + // this will also deallocate the key and value blocks + // but not the leaf node itself Leaf.clear(btree, leaf_address); assert Leaf.validate(btree, leaf_address); @@ -650,28 +654,25 @@ module { update_leaf_count(btree, 1); let leaf_memory_size = Leaf.get_memory_size(btree.node_capacity); - let everything_after_leaf = leaf_address + leaf_memory_size; + let leaf_memory_end = leaf_address + leaf_memory_size; let leaves_region_size = MemoryRegion.size(btree.leaves); - MemoryRegion.deallocateRange(btree.leaves, everything_after_leaf, leaves_region_size); + MemoryRegion.deallocateRange(btree.leaves, leaf_memory_end, leaves_region_size); - assert MemoryRegion.allocated(btree.leaves) == everything_after_leaf; - assert MemoryRegion.size(btree.leaves) == everything_after_leaf; - assert MemoryRegion.deallocated(btree.leaves) == 0; - assert [] == Iter.toArray(MemoryRegion.deallocatedBlocksInRange(btree.leaves, 0, leaves_region_size)); + assert MemoryRegion.allocated(btree.leaves) == leaf_memory_end; + assert MemoryRegion.size(btree.leaves) == MemoryRegion.allocated(btree.leaves) + MemoryRegion.deallocated(btree.leaves); + assert [(leaf_memory_end, MemoryRegion.size(btree.leaves) - leaf_memory_end)] == MemoryRegion.getFreeMemory(btree.leaves); let branches_memory_size = MemoryRegion.size(btree.branches); MemoryRegion.deallocateRange(btree.branches, MC.REGION_HEADER_SIZE, branches_memory_size); assert MemoryRegion.allocated(btree.branches) == MC.REGION_HEADER_SIZE; - assert MemoryRegion.size(btree.branches) == MC.REGION_HEADER_SIZE; - assert MemoryRegion.deallocated(btree.branches) == 0; - assert [] == Iter.toArray(MemoryRegion.deallocatedBlocksInRange(btree.branches, 0, branches_memory_size)); + assert MemoryRegion.size(btree.branches) == MemoryRegion.allocated(btree.branches) + MemoryRegion.deallocated(btree.branches); + assert [(MC.REGION_HEADER_SIZE, MemoryRegion.size(btree.branches) - MC.REGION_HEADER_SIZE)] == MemoryRegion.getFreeMemory(btree.branches); let data_memory_size = MemoryRegion.size(btree.data); MemoryRegion.deallocateRange(btree.data, MC.REGION_HEADER_SIZE, data_memory_size); assert MemoryRegion.allocated(btree.data) == MC.REGION_HEADER_SIZE; - assert MemoryRegion.size(btree.data) == MC.REGION_HEADER_SIZE; - assert MemoryRegion.deallocated(btree.data) == 0; - assert [] == Iter.toArray(MemoryRegion.deallocatedBlocksInRange(btree.data, 0, data_memory_size)); + assert MemoryRegion.size(btree.data) == MemoryRegion.allocated(btree.data) + MemoryRegion.deallocated(btree.data); + assert [(MC.REGION_HEADER_SIZE, MemoryRegion.size(btree.data) - MC.REGION_HEADER_SIZE)] == MemoryRegion.getFreeMemory(btree.data); }; diff --git a/src/MemoryBTree/Migrations/V0.mo b/src/MemoryBTree/Migrations/V0.mo index 20b6e52..dcf3a39 100644 --- a/src/MemoryBTree/Migrations/V0.mo +++ b/src/MemoryBTree/Migrations/V0.mo @@ -1,8 +1,8 @@ -import Nat "mo:base/Nat"; +import Nat "mo:base@.v0.14.11/Nat"; -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; -// import Branch "mo:augmented-btrees/BpTree/Branch"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; +// import Branch "mo:augmented-btrees@.v0.7.1/BpTree/Branch"; import Blobify "../../TypeUtils/Blobify"; import MemoryCmp "../../TypeUtils/MemoryCmp"; diff --git a/src/MemoryBTree/Migrations/V0_0_1.mo b/src/MemoryBTree/Migrations/V0_0_1.mo index 68155b4..dba2102 100644 --- a/src/MemoryBTree/Migrations/V0_0_1.mo +++ b/src/MemoryBTree/Migrations/V0_0_1.mo @@ -1,8 +1,8 @@ -import Nat "mo:base/Nat"; +import Nat "mo:base@.v0.14.11/Nat"; -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; -// import Branch "mo:augmented-btrees/BpTree/Branch"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; +// import Branch "mo:augmented-btrees@.v0.7.1/BpTree/Branch"; import Blobify "../../TypeUtils/Blobify"; import MemoryCmp "../../TypeUtils/MemoryCmp"; diff --git a/src/MemoryBTree/Migrations/lib.mo b/src/MemoryBTree/Migrations/lib.mo index 72af6dd..380e016 100644 --- a/src/MemoryBTree/Migrations/lib.mo +++ b/src/MemoryBTree/Migrations/lib.mo @@ -1,7 +1,7 @@ -import Debug "mo:base/Debug"; -import Nat32 "mo:base/Nat32"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat32 "mo:base@.v0.14.11/Nat32"; -import MemoryRegion "mo:memory-region/MemoryRegion"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; import V0 "V0"; import V0_0_1 "V0_0_1"; diff --git a/src/MemoryBTree/Migrations/upgrades.mo b/src/MemoryBTree/Migrations/upgrades.mo index d39923b..641ceb7 100644 --- a/src/MemoryBTree/Migrations/upgrades.mo +++ b/src/MemoryBTree/Migrations/upgrades.mo @@ -1,12 +1,12 @@ -import Debug "mo:base/Debug"; -import Nat32 "mo:base/Nat32"; -import Nat16 "mo:base/Nat16"; -import Nat64 "mo:base/Nat64"; -import Nat8 "mo:base/Nat8"; -import Iter "mo:base/Iter"; - -import MemoryRegion "mo:memory-region/MemoryRegion"; -import Itertools "mo:itertools/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Nat32 "mo:base@.v0.14.11/Nat32"; +import Nat16 "mo:base@.v0.14.11/Nat16"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Iter "mo:base@.v0.14.11/Iter"; + +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import Itertools "mo:itertools@.v0.2.2/Iter"; import V0 "V0"; import V0_0_1 "V0_0_1"; diff --git a/src/MemoryBTree/Stable.mo b/src/MemoryBTree/Stable.mo index 65c4f4e..95d7ad1 100644 --- a/src/MemoryBTree/Stable.mo +++ b/src/MemoryBTree/Stable.mo @@ -1,4 +1,4 @@ -import RevIter "mo:itertools/RevIter"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import Migrations "Migrations"; import MemoryBTree "Base"; diff --git a/src/MemoryBTree/lib.mo b/src/MemoryBTree/lib.mo index a367fac..1d20079 100644 --- a/src/MemoryBTree/lib.mo +++ b/src/MemoryBTree/lib.mo @@ -1,4 +1,4 @@ -import RevIter "mo:itertools/RevIter"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import Migrations "Migrations"; import BaseMemoryBTree "Base"; diff --git a/src/MemoryBTree/modules/Branch.mo b/src/MemoryBTree/modules/Branch.mo index fd69db8..8d755ee 100644 --- a/src/MemoryBTree/modules/Branch.mo +++ b/src/MemoryBTree/modules/Branch.mo @@ -1,19 +1,19 @@ /// Branch Node Operations -import Debug "mo:base/Debug"; -import Array "mo:base/Array"; -import Int "mo:base/Int"; -import Nat "mo:base/Nat"; -import Nat8 "mo:base/Nat8"; -import Nat16 "mo:base/Nat16"; -import Nat64 "mo:base/Nat64"; -import Blob "mo:base/Blob"; -import Bool "mo:base/Bool"; -import Float "mo:base/Float"; - -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; -// import Branch "mo:augmented-btrees/BpTree/Branch"; +import Debug "mo:base@.v0.14.11/Debug"; +import Array "mo:base@.v0.14.11/Array"; +import Int "mo:base@.v0.14.11/Int"; +import Nat "mo:base@.v0.14.11/Nat"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat16 "mo:base@.v0.14.11/Nat16"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Blob "mo:base@.v0.14.11/Blob"; +import Bool "mo:base@.v0.14.11/Bool"; +import Float "mo:base@.v0.14.11/Float"; + +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; +// import Branch "mo:augmented-btrees@.v0.7.1/BpTree/Branch"; import MemoryFns "MemoryFns"; import T "Types"; diff --git a/src/MemoryBTree/modules/Leaf.mo b/src/MemoryBTree/modules/Leaf.mo index f4a51ea..55095bb 100644 --- a/src/MemoryBTree/modules/Leaf.mo +++ b/src/MemoryBTree/modules/Leaf.mo @@ -1,15 +1,15 @@ /// Leaf Node Operations -import Debug "mo:base/Debug"; -import Array "mo:base/Array"; -import Nat "mo:base/Nat"; -import Nat8 "mo:base/Nat8"; -import Nat16 "mo:base/Nat16"; -import Nat64 "mo:base/Nat64"; -import Int "mo:base/Int"; -import Float "mo:base/Float"; - -import MemoryRegion "mo:memory-region/MemoryRegion"; +import Debug "mo:base@.v0.14.11/Debug"; +import Array "mo:base@.v0.14.11/Array"; +import Nat "mo:base@.v0.14.11/Nat"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat16 "mo:base@.v0.14.11/Nat16"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Int "mo:base@.v0.14.11/Int"; +import Float "mo:base@.v0.14.11/Float"; + +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; import MemoryFns "MemoryFns"; import MemoryBlock "MemoryBlock"; diff --git a/src/MemoryBTree/modules/MemoryBlock.mo b/src/MemoryBTree/modules/MemoryBlock.mo index 624ac7f..3f44ce8 100644 --- a/src/MemoryBTree/modules/MemoryBlock.mo +++ b/src/MemoryBTree/modules/MemoryBlock.mo @@ -1,13 +1,13 @@ -import Nat "mo:base/Nat"; -import Blob "mo:base/Blob"; -import Nat64 "mo:base/Nat64"; -import Nat16 "mo:base/Nat16"; -import Nat8 "mo:base/Nat8"; -import Nat32 "mo:base/Nat32"; -import Debug "mo:base/Debug"; +import Nat "mo:base@.v0.14.11/Nat"; +import Blob "mo:base@.v0.14.11/Blob"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Nat16 "mo:base@.v0.14.11/Nat16"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat32 "mo:base@.v0.14.11/Nat32"; +import Debug "mo:base@.v0.14.11/Debug"; -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import Migrations "../Migrations"; import T "Types"; @@ -43,7 +43,7 @@ module MemoryBlock { let KEY_BLOB_START = 15; public func id_exists(btree : MemoryBTree, block_address : UniqueId) : Bool { - MemoryRegion.isAllocated(btree.data, block_address); + MemoryRegion.isAllocated(btree.data, block_address, 0); }; public func store(btree : MemoryBTree, key : Blob, val : Blob) : UniqueId { diff --git a/src/MemoryBTree/modules/MemoryFns.mo b/src/MemoryBTree/modules/MemoryFns.mo index 6e91eff..f3253ab 100644 --- a/src/MemoryBTree/modules/MemoryFns.mo +++ b/src/MemoryBTree/modules/MemoryFns.mo @@ -1,6 +1,6 @@ -import Int "mo:base/Int"; -import Region "mo:base/Region"; -import Nat64 "mo:base/Nat64"; +import Int "mo:base@.v0.14.11/Int"; +import Region "mo:base@.v0.14.11/Region"; +import Nat64 "mo:base@.v0.14.11/Nat64"; module { diff --git a/src/MemoryBTree/modules/Methods.mo b/src/MemoryBTree/modules/Methods.mo index 1b9c584..4013ac6 100644 --- a/src/MemoryBTree/modules/Methods.mo +++ b/src/MemoryBTree/modules/Methods.mo @@ -1,14 +1,14 @@ -import Debug "mo:base/Debug"; -import Array "mo:base/Array"; -import Iter "mo:base/Iter"; -import Int "mo:base/Int"; -import Nat "mo:base/Nat"; -import Blob "mo:base/Blob"; -import Buffer "mo:base/Buffer"; - -import RevIter "mo:itertools/RevIter"; -import BufferDeque "mo:buffer-deque/BufferDeque"; -// import Branch "mo:augmented-btrees/BpTree/Branch"; +import Debug "mo:base@.v0.14.11/Debug"; +import Array "mo:base@.v0.14.11/Array"; +import Iter "mo:base@.v0.14.11/Iter"; +import Int "mo:base@.v0.14.11/Int"; +import Nat "mo:base@.v0.14.11/Nat"; +import Blob "mo:base@.v0.14.11/Blob"; +import Buffer "mo:base@.v0.14.11/Buffer"; + +import RevIter "mo:itertools@.v0.2.2/RevIter"; +import BufferDeque "mo:buffer-deque@.v0.1.0/BufferDeque"; +// import Branch "mo:augmented-btrees@.v0.7.1/BpTree/Branch"; import T "Types"; import Leaf "Leaf"; diff --git a/src/MemoryBTree/modules/Types.mo b/src/MemoryBTree/modules/Types.mo index ed2ed73..0ba6c5b 100644 --- a/src/MemoryBTree/modules/Types.mo +++ b/src/MemoryBTree/modules/Types.mo @@ -1,7 +1,7 @@ -import Nat "mo:base/Nat"; +import Nat "mo:base@.v0.14.11/Nat"; -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import Blobify "../../TypeUtils/Blobify"; import MemoryCmp "../../TypeUtils/MemoryCmp"; diff --git a/src/MemoryBTreeSet/lib.mo b/src/MemoryBTreeSet/lib.mo index 0b5ca3e..9d3c752 100644 --- a/src/MemoryBTreeSet/lib.mo +++ b/src/MemoryBTreeSet/lib.mo @@ -1,5 +1,5 @@ -import RevIter "mo:itertools/RevIter"; -import Option "mo:base/Option"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; +import Option "mo:base@.v0.14.11/Option"; import Migrations "../MemoryBTree/Migrations"; import BaseMemoryBTree "../MemoryBTree/Base"; diff --git a/src/MemoryBuffer/Base.mo b/src/MemoryBuffer/Base.mo index e67f34a..586f9e9 100644 --- a/src/MemoryBuffer/Base.mo +++ b/src/MemoryBuffer/Base.mo @@ -1,20 +1,20 @@ /// A memory buffer is a data structure that stores a sequence of values in memory. -import Debug "mo:base/Debug"; -import Array "mo:base/Array"; -import Iter "mo:base/Iter"; -import Int "mo:base/Int"; -import Nat "mo:base/Nat"; -import Nat8 "mo:base/Nat8"; -import Nat32 "mo:base/Nat32"; -import Nat64 "mo:base/Nat64"; -import Blob "mo:base/Blob"; -import Result "mo:base/Result"; -import Order "mo:base/Order"; - -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; -import Itertools "mo:itertools/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Array "mo:base@.v0.14.11/Array"; +import Iter "mo:base@.v0.14.11/Iter"; +import Int "mo:base@.v0.14.11/Int"; +import Nat "mo:base@.v0.14.11/Nat"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat32 "mo:base@.v0.14.11/Nat32"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Blob "mo:base@.v0.14.11/Blob"; +import Result "mo:base@.v0.14.11/Result"; +import Order "mo:base@.v0.14.11/Order"; + +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; +import Itertools "mo:itertools@.v0.2.2/Iter"; import Migrations "Migrations"; import MemoryCmp "../TypeUtils/MemoryCmp"; @@ -92,7 +92,7 @@ module MemoryBuffer { MemoryRegion.storeBlob(m_region.blobs, C.MAGIC_NUMBER_ADDRESS, "BLB"); MemoryRegion.storeNat8(m_region.blobs, C.LAYOUT_VERSION_ADDRESS, Nat8.fromNat(LAYOUT_VERSION)); MemoryRegion.storeNat32(m_region.blobs, C.REGION_ID_ADDRESS, Nat32.fromNat(MemoryRegion.id(m_region.pointers))); // store the pointers region id in the blob region - assert MemoryRegion.size(m_region.blobs) == REGION_HEADER_SIZE; + assert MemoryRegion.allocated(m_region.blobs) == REGION_HEADER_SIZE; // Initialize the Pointer Region Header ignore MemoryRegion.allocate(m_region.pointers, REGION_HEADER_SIZE); // Reserved Space for the Region Header @@ -101,7 +101,7 @@ module MemoryBuffer { MemoryRegion.storeNat32(m_region.pointers, C.REGION_ID_ADDRESS, Nat32.fromNat(MemoryRegion.id(m_region.blobs))); // store the blobs region id in the pointers region MemoryRegion.storeNat64(m_region.pointers, C.COUNT_ADDRESS, 0); - assert MemoryRegion.size(m_region.pointers) == REGION_HEADER_SIZE; + assert MemoryRegion.allocated(m_region.pointers) == REGION_HEADER_SIZE; }; func update_count(self : MemoryBuffer, count : Nat) { diff --git a/src/MemoryBuffer/Migrations.mo b/src/MemoryBuffer/Migrations.mo index 54dd3ea..1b392fa 100644 --- a/src/MemoryBuffer/Migrations.mo +++ b/src/MemoryBuffer/Migrations.mo @@ -1,11 +1,11 @@ /// A memory buffer is a data structure that stores a sequence of values in memory. -import Iter "mo:base/Iter"; -import Nat "mo:base/Nat"; -import Result "mo:base/Result"; -import Order "mo:base/Order"; +import Iter "mo:base@.v0.14.11/Iter"; +import Nat "mo:base@.v0.14.11/Nat"; +import Result "mo:base@.v0.14.11/Result"; +import Order "mo:base@.v0.14.11/Order"; -import MemoryRegion "mo:memory-region/MemoryRegion"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; module Migrations { type Iter = Iter.Iter; diff --git a/src/MemoryBuffer/Stable.mo b/src/MemoryBuffer/Stable.mo index 15f4b13..14e7b7c 100644 --- a/src/MemoryBuffer/Stable.mo +++ b/src/MemoryBuffer/Stable.mo @@ -1,10 +1,10 @@ -import Iter "mo:base/Iter"; -import Nat "mo:base/Nat"; -import Result "mo:base/Result"; -import Order "mo:base/Order"; +import Iter "mo:base@.v0.14.11/Iter"; +import Nat "mo:base@.v0.14.11/Nat"; +import Result "mo:base@.v0.14.11/Result"; +import Order "mo:base@.v0.14.11/Order"; -import MemoryRegion "mo:memory-region/MemoryRegion"; -import RevIter "mo:itertools/RevIter"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import MemoryBuffer "Base"; import Migrations "Migrations"; diff --git a/src/MemoryBuffer/lib.mo b/src/MemoryBuffer/lib.mo index b6d6881..87f03e4 100644 --- a/src/MemoryBuffer/lib.mo +++ b/src/MemoryBuffer/lib.mo @@ -27,11 +27,11 @@ /// assert buffer.removeLast() == ?9; /// ``` -import Iter "mo:base/Iter"; -import Order "mo:base/Order"; -import Nat "mo:base/Nat"; +import Iter "mo:base@.v0.14.11/Iter"; +import Order "mo:base@.v0.14.11/Order"; +import Nat "mo:base@.v0.14.11/Nat"; -import RevIter "mo:itertools/RevIter"; +import RevIter "mo:itertools@.v0.2.2/RevIter"; import BaseMemoryBuffer "Base"; import StableMemoryBuffer "Stable"; diff --git a/src/MemoryQueue/Base.mo b/src/MemoryQueue/Base.mo index e022889..1ebeb3e 100644 --- a/src/MemoryQueue/Base.mo +++ b/src/MemoryQueue/Base.mo @@ -1,11 +1,11 @@ -import Array "mo:base/Array"; -import Debug "mo:base/Debug"; -import Iter "mo:base/Iter"; -import Nat8 "mo:base/Nat8"; -import Nat32 "mo:base/Nat32"; -import Nat64 "mo:base/Nat64"; +import Array "mo:base@.v0.14.11/Array"; +import Debug "mo:base@.v0.14.11/Debug"; +import Iter "mo:base@.v0.14.11/Iter"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat32 "mo:base@.v0.14.11/Nat32"; +import Nat64 "mo:base@.v0.14.11/Nat64"; -import MemoryRegion "mo:memory-region/MemoryRegion"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; import Blobify "../TypeUtils/Blobify"; import TypeUtils "../TypeUtils"; @@ -80,7 +80,7 @@ module MemoryQueue { MemoryRegion.storeNat64(mem_queue.region, C.COUNT_ADDRESS, 0); MemoryRegion.storeNat64(mem_queue.region, C.HEAD_START, Nat64.fromNat(C.NULL_ADDRESS)); MemoryRegion.storeNat64(mem_queue.region, C.TAIL_START, Nat64.fromNat(C.NULL_ADDRESS)); - assert MemoryRegion.size(mem_queue.region) == C.REGION_HEADER_SIZE; + assert MemoryRegion.allocated(mem_queue.region) == C.REGION_HEADER_SIZE; }; func update_count(mem_queue : MemoryQueue, count : Nat) { @@ -213,8 +213,10 @@ module MemoryQueue { /// Removes all the elements from the memory queue. public func clear(mem_queue : MemoryQueue) { - MemoryRegion.clear(mem_queue.region); - init_region_header(mem_queue); + MemoryRegion.deallocateRange(mem_queue.region, C.REGION_HEADER_SIZE, MemoryRegion.size(mem_queue.region)); + update_count(mem_queue, 0); + update_head(mem_queue, C.NULL_ADDRESS); + update_tail(mem_queue, C.NULL_ADDRESS); }; }; diff --git a/src/MemoryQueue/Stable.mo b/src/MemoryQueue/Stable.mo index 7b3cb55..494a927 100644 --- a/src/MemoryQueue/Stable.mo +++ b/src/MemoryQueue/Stable.mo @@ -1,4 +1,4 @@ -import Iter "mo:base/Iter"; +import Iter "mo:base@.v0.14.11/Iter"; import Migrations "migrations"; import BaseMemoryQueue "Base"; diff --git a/src/MemoryQueue/lib.mo b/src/MemoryQueue/lib.mo index 219fcfb..5b303ec 100644 --- a/src/MemoryQueue/lib.mo +++ b/src/MemoryQueue/lib.mo @@ -15,10 +15,10 @@ /// import TypeUtils "mo:memory-collections/TypeUtils"; /// ``` -import Iter "mo:base/Iter"; -import Nat "mo:base/Nat"; +import Iter "mo:base@.v0.14.11/Iter"; +import Nat "mo:base@.v0.14.11/Nat"; -import MemoryRegion "mo:memory-region/MemoryRegion"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; import BaseMemoryQueue "Base"; import StableMemoryQueue "Stable"; diff --git a/src/MemoryQueue/migrations/V0.mo b/src/MemoryQueue/migrations/V0.mo index 8742792..c7aec6d 100644 --- a/src/MemoryQueue/migrations/V0.mo +++ b/src/MemoryQueue/migrations/V0.mo @@ -1,4 +1,4 @@ -import MemoryRegion "mo:memory-region/MemoryRegion"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; module V0 { type MemoryRegionV1 = MemoryRegion.MemoryRegionV1; diff --git a/src/MemoryQueue/migrations/lib.mo b/src/MemoryQueue/migrations/lib.mo index f40fcb8..9c2b989 100644 --- a/src/MemoryQueue/migrations/lib.mo +++ b/src/MemoryQueue/migrations/lib.mo @@ -1,4 +1,4 @@ -import Debug "mo:base/Debug"; +import Debug "mo:base@.v0.14.11/Debug"; import V0 "V0"; diff --git a/src/TypeUtils/Blobify.mo b/src/TypeUtils/Blobify.mo index ab072d2..cda50e1 100644 --- a/src/TypeUtils/Blobify.mo +++ b/src/TypeUtils/Blobify.mo @@ -4,25 +4,25 @@ /// and deserializing values that will be stored in persistent stable memory. /// -import TextModule "mo:base/Text"; -import CharModule "mo:base/Char"; -import BlobModule "mo:base/Blob"; -import ArrayModule "mo:base/Array"; -import NatModule "mo:base/Nat"; -import Nat8Module "mo:base/Nat8"; -import Nat16Module "mo:base/Nat16"; -import Nat32Module "mo:base/Nat32"; -import Nat64Module "mo:base/Nat64"; -import IntModule "mo:base/Int"; -import Int8Module "mo:base/Int8"; -import Int16Module "mo:base/Int16"; -import Int32Module "mo:base/Int32"; -import Int64Module "mo:base/Int64"; -import PrincipalModule "mo:base/Principal"; -import TimeModule "mo:base/Time"; -import Debug "mo:base/Debug"; - -import ByteUtils "mo:byte-utils"; +import TextModule "mo:base@.v0.14.11/Text"; +import CharModule "mo:base@.v0.14.11/Char"; +import BlobModule "mo:base@.v0.14.11/Blob"; +import ArrayModule "mo:base@.v0.14.11/Array"; +import NatModule "mo:base@.v0.14.11/Nat"; +import Nat8Module "mo:base@.v0.14.11/Nat8"; +import Nat16Module "mo:base@.v0.14.11/Nat16"; +import Nat32Module "mo:base@.v0.14.11/Nat32"; +import Nat64Module "mo:base@.v0.14.11/Nat64"; +import IntModule "mo:base@.v0.14.11/Int"; +import Int8Module "mo:base@.v0.14.11/Int8"; +import Int16Module "mo:base@.v0.14.11/Int16"; +import Int32Module "mo:base@.v0.14.11/Int32"; +import Int64Module "mo:base@.v0.14.11/Int64"; +import PrincipalModule "mo:base@.v0.14.11/Principal"; +import TimeModule "mo:base@.v0.14.11/Time"; +import Debug "mo:base@.v0.14.11/Debug"; + +import ByteUtils "mo:byte-utils@.v0.0.1"; import Utils "../Utils"; diff --git a/src/TypeUtils/Int8Cmp.mo b/src/TypeUtils/Int8Cmp.mo index c7f015e..c5ea45e 100644 --- a/src/TypeUtils/Int8Cmp.mo +++ b/src/TypeUtils/Int8Cmp.mo @@ -1,5 +1,5 @@ import Prim "mo:prim"; -import FloatModule "mo:base/Float"; +import FloatModule "mo:base@.v0.14.11/Float"; /// ## `Int8` Comparators /// Comparators that return an `Int8` type instead of an `Order` variant diff --git a/src/TypeUtils/MemoryCmp.mo b/src/TypeUtils/MemoryCmp.mo index aaa7793..1755abd 100644 --- a/src/TypeUtils/MemoryCmp.mo +++ b/src/TypeUtils/MemoryCmp.mo @@ -4,7 +4,7 @@ import Prim "mo:prim"; -import Blob "mo:base/Blob"; +import Blob "mo:base@.v0.14.11/Blob"; import Int8Cmp "Int8Cmp"; module { diff --git a/src/TypeUtils/WyHash64.mo b/src/TypeUtils/WyHash64.mo index 79bca24..b88dfae 100644 --- a/src/TypeUtils/WyHash64.mo +++ b/src/TypeUtils/WyHash64.mo @@ -1,11 +1,11 @@ -import Iter "mo:base/Iter"; -import Nat8 "mo:base/Nat8"; -import Nat64 "mo:base/Nat64"; -import Debug "mo:base/Debug"; -import Blob "mo:base/Blob"; -import TextModule "mo:base/Text"; - -import Itertools "mo:itertools/Iter"; +import Iter "mo:base@.v0.14.11/Iter"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Debug "mo:base@.v0.14.11/Debug"; +import Blob "mo:base@.v0.14.11/Blob"; +import TextModule "mo:base@.v0.14.11/Text"; + +import Itertools "mo:itertools@.v0.2.2/Iter"; import Blobify "../TypeUtils/Blobify"; module WyHash { diff --git a/src/Utils.mo b/src/Utils.mo index 77d45ee..9db6711 100644 --- a/src/Utils.mo +++ b/src/Utils.mo @@ -1,14 +1,14 @@ -import Blob "mo:base/Blob"; -import Buffer "mo:base/Buffer"; -import Array "mo:base/Array"; -import Nat8 "mo:base/Nat8"; -import Nat64 "mo:base/Nat64"; -import Prelude "mo:base/Prelude"; -import Iter "mo:base/Iter"; -import Debug "mo:base/Debug"; -import Result "mo:base/Result"; - -import Itertools "mo:itertools/Iter"; +import Blob "mo:base@.v0.14.11/Blob"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Array "mo:base@.v0.14.11/Array"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Prelude "mo:base@.v0.14.11/Prelude"; +import Iter "mo:base@.v0.14.11/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; +import Result "mo:base@.v0.14.11/Result"; + +import Itertools "mo:itertools@.v0.2.2/Iter"; module { type Buffer = Buffer.Buffer; diff --git a/tests/MemoryBTree/MemoryBTree.Load.Test.mo b/tests/MemoryBTree/MemoryBTree.Load.Test.mo new file mode 100644 index 0000000..9c0003b --- /dev/null +++ b/tests/MemoryBTree/MemoryBTree.Load.Test.mo @@ -0,0 +1,481 @@ +// @testmode wasi +import { test; suite } "mo:test@.v2.1.1"; +import Debug "mo:base@.v0.14.11/Debug"; +import Iter "mo:base@.v0.14.11/Iter"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Nat "mo:base@.v0.14.11/Nat"; +import Blob "mo:base@.v0.14.11/Blob"; +import Order "mo:base@.v0.14.11/Order"; + +import Fuzz "mo:fuzz@.v1.0.0"; +import Itertools "mo:itertools@.v0.2.2/Iter"; +import Map "mo:map/Map"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import { MaxBpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; +import MaxBpTreeMethods "mo:augmented-btrees@.v0.7.1/MaxBpTree/Methods"; +import BpTree "mo:augmented-btrees@.v0.7.1/BpTree"; + +import MemoryBTree "../../src/MemoryBTree/Base"; +import TypeUtils "../../src/TypeUtils"; +import Utils "../../src/Utils"; +import Branch "../../src/MemoryBTree/modules/Branch"; +import Leaf "../../src/MemoryBTree/modules/Leaf"; +import Methods "../../src/MemoryBTree/modules/Methods"; + +type Buffer = Buffer.Buffer; +type Iter = Iter.Iter; +type Order = Order.Order; +type MemoryBlock = MemoryBTree.MemoryBlock; + +let limit = 10_000; +let fuzz = Fuzz.fromSeed(0xcafebabe); + +// Create input arrays for different blob test scenarios +let order = Buffer.Buffer(limit); +let blob_keys = Buffer.Buffer(limit); +let initial_blob_values = Buffer.Buffer(limit); +let equal_size_blob_values = Buffer.Buffer(limit); +let greater_size_blob_values = Buffer.Buffer(limit); +let less_size_blob_values = Buffer.Buffer(limit); + +for (i in Iter.range(0, limit - 1)) { + order.add(i); + + // Generate fixed keys - these will remain constant throughout the test + let key_size = fuzz.nat.randomRange(16, 32); + let key_blob = fuzz.blob.randomBlob(key_size); + blob_keys.add(key_blob); + + // Generate values of varying sizes + let val_size_a = fuzz.nat.randomRange(8, 24); + let val_blob_a = fuzz.blob.randomBlob(val_size_a); + less_size_blob_values.add(val_blob_a); + + let val_size_b = fuzz.nat.randomRange(val_size_a, 48); + let val_blob_b = fuzz.blob.randomBlob(val_size_b); + initial_blob_values.add(val_blob_b); + + let val_blob_c = fuzz.blob.randomBlob(val_size_b); + equal_size_blob_values.add(val_blob_c); + + let val_size_d = fuzz.nat.randomRange(val_size_b, 96); + let val_blob_d = fuzz.blob.randomBlob(val_size_d); + greater_size_blob_values.add(val_blob_d); +}; + +fuzz.buffer.shuffle(order); + +// Current expected values - will be updated as we modify the btree +let current_values = Buffer.Buffer(limit); +for (i in Iter.range(0, limit - 1)) { + current_values.add(initial_blob_values.get(i)); +}; + +// Helper function to validate all entries match expected values +let run_blob_validation_test = func(btree : MemoryBTree.MemoryBTree, btree_utils : MemoryBTree.BTreeUtils, expected_values : Buffer.Buffer) { + test( + "validate all blob entries", + func() { + for (i in Iter.range(0, limit - 1)) { + let expected_key = blob_keys.get(i); + let expected_value = expected_values.get(i); + let retrieved = MemoryBTree.get(btree, btree_utils, expected_key); + + if (retrieved != ?expected_value) { + Debug.print("validation mismatch at index " # debug_show i); + Debug.print("expected: " # debug_show expected_value); + Debug.print("retrieved: " # debug_show retrieved); + assert false; + }; + }; + }, + ); +}; + +// Helper function to validate memory regions +func validate_btree_memory_regions(btree : MemoryBTree.MemoryBTree) { + if (not MaxBpTreeMethods.validate_max_path(btree.data.free_memory, Cmp.Nat)) { + Debug.print("invalid max path discovered in data region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.data.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.data.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_subtree_size(btree.data.free_memory)) { + Debug.print("invalid subtree size in data region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.data.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.data.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_max_path(btree.leaves.free_memory, Cmp.Nat)) { + Debug.print("invalid max path discovered in keys region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.leaves.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.leaves.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_subtree_size(btree.leaves.free_memory)) { + Debug.print("invalid subtree size in keys region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.leaves.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.leaves.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_max_path(btree.branches.free_memory, Cmp.Nat)) { + Debug.print("invalid max path discovered in keys region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.branches.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.branches.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_subtree_size(btree.branches.free_memory)) { + Debug.print("invalid subtree size in keys region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.branches.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.branches.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_max_path(btree.values.free_memory, Cmp.Nat)) { + Debug.print("invalid max path discovered in values region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.values.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.values.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_subtree_size(btree.values.free_memory)) { + Debug.print("invalid subtree size in values region"); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(btree.values.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(btree.values.free_memory))); + assert false; + }; +}; + +// Track memory blocks to detect overlaps (similar to MemoryBuffer.Load.Test.mo) +class MemoryBlocksMap() { + let memory_blocks = BpTree.new<(Nat, Nat), Nat>(null); + + func compare(a : (Nat, Nat), b : (Nat, Nat)) : Int8 { + if (a.0 < b.0 and a.1 <= b.0) { + -1; + } else if (a.0 >= b.1 and a.1 > b.0) { + 1; + } else { + 0; + }; + }; + + public func add(_block : (Nat, Nat), index : Nat) : Bool { + if (_block.1 == 0) return true; + + let block = (_block.0, _block.0 + _block.1); + + switch (BpTree.getEntry(memory_blocks, compare, block)) { + case (?(existing_block, prev_index)) { + Debug.print("Memory block already exists at index " # debug_show prev_index # ", current index: " # debug_show index); + Debug.print("Existing block: " # debug_show existing_block # ", New block: " # debug_show block); + return false; + }; + case (null) { + ignore BpTree.insert(memory_blocks, compare, block, index); + return true; + }; + }; + }; + + public func remove(_block : (Nat, Nat)) : Bool { + if (_block.1 == 0) return true; + + let block = (_block.0, _block.0 + _block.1); + + switch (BpTree.remove(memory_blocks, compare, block)) { + case (?_) true; + case (null) { + Debug.print("Failed to remove block: " # debug_show block); + false; + }; + }; + }; + +}; + +suite( + "MemoryBTree Blob Memory Load Tests", + func() { + let btree = MemoryBTree._new_with_options(?8, ?0, false); + let btree_utils = MemoryBTree.createUtils(TypeUtils.Blob, TypeUtils.Blob); + + test( + "insert initial blob entries", + func() { + for (i in Iter.range(0, limit - 1)) { + let key = blob_keys.get(i); + let value = initial_blob_values.get(i); + + ignore MemoryBTree.insert(btree, btree_utils, key, value); + assert MemoryBTree.size(btree) == i + 1; + + // Validate memory regions after each insert + validate_btree_memory_regions(btree); + + // Verify the entry can be retrieved + let retrieved = MemoryBTree.get(btree, btree_utils, key); + if (retrieved != ?value) { + Debug.print("mismatch after insert: " # debug_show (i, retrieved)); + assert false; + }; + }; + + validate_btree_memory_regions(btree); + }, + ); + + run_blob_validation_test(btree, btree_utils, initial_blob_values); + + test( + "replace with equal size blob values", + func() { + let memory_blocks_map = MemoryBlocksMap(); + + for (index in order.vals()) { + let key = blob_keys.get(index); + let old_value = initial_blob_values.get(index); + let new_value = equal_size_blob_values.get(index); + + // Verify old entry exists + assert MemoryBTree.get(btree, btree_utils, key) == ?old_value; + + // Get memory block info before replacement + let ?old_id = MemoryBTree.getId(btree, btree_utils, key); + let ?old_mem_block = MemoryBTree._lookup_mem_block(btree, old_id); + let ?old_key_blob = MemoryBTree._lookup_key_blob(btree, old_id); + let ?old_val_blob = MemoryBTree._lookup_val_blob(btree, old_id); + + // Verify the blobs match + assert old_key_blob == key; + assert old_val_blob == old_value; + + // Check memory is allocated + if (old_mem_block.0.1 > 0) { + assert MemoryRegion.isAllocated(btree.data, old_mem_block.0.0, old_mem_block.0.1); + }; + if (old_mem_block.1.1 > 0) { + assert MemoryRegion.isAllocated(btree.values, old_mem_block.1.0, old_mem_block.1.1); + }; + + // Replace with equal size value (using insert which replaces if key exists) + let replaced = MemoryBTree.insert(btree, btree_utils, key, new_value); + assert replaced == ?old_value; + + // Get new memory block info + let ?new_id = MemoryBTree.getId(btree, btree_utils, key); + let ?new_mem_block = MemoryBTree._lookup_mem_block(btree, new_id); + let ?new_key_blob = MemoryBTree._lookup_key_blob(btree, new_id); + let ?new_val_blob = MemoryBTree._lookup_val_blob(btree, new_id); + + // Verify new blobs match + assert new_key_blob == key; + assert new_val_blob == new_value; + + // Check new memory is allocated + if (new_mem_block.1.1 > 0) { + assert MemoryRegion.isAllocated(btree.values, new_mem_block.1.0, new_mem_block.1.1); + assert memory_blocks_map.add(new_mem_block.1, index); + }; + + // Validate memory regions + validate_btree_memory_regions(btree); + }; + + validate_btree_memory_regions(btree); + }, + ); + + run_blob_validation_test(btree, btree_utils, equal_size_blob_values); + + test( + "replace with greater size blob values", + func() { + let memory_blocks_map = MemoryBlocksMap(); + + for (index in order.vals()) { + let key = blob_keys.get(index); + let old_value = equal_size_blob_values.get(index); + let new_value = greater_size_blob_values.get(index); + + // Verify old entry exists + assert MemoryBTree.get(btree, btree_utils, key) == ?old_value; + + // Get memory info before replacement + let ?old_id = MemoryBTree.getId(btree, btree_utils, key); + let ?old_mem_block = MemoryBTree._lookup_mem_block(btree, old_id); + + // Check memory is allocated before replacement + let old_key_allocated = old_mem_block.0.1 > 0 and MemoryRegion.isAllocated(btree.data, old_mem_block.0.0, old_mem_block.0.1); + let old_val_allocated = old_mem_block.1.1 > 0 and MemoryRegion.isAllocated(btree.values, old_mem_block.1.0, old_mem_block.1.1); + + // Replace with larger value + let replaced = MemoryBTree.insert(btree, btree_utils, key, new_value); + assert replaced == ?old_value; + + // Get new memory info + let ?new_id = MemoryBTree.getId(btree, btree_utils, key); + let ?new_mem_block = MemoryBTree._lookup_mem_block(btree, new_id); + let ?new_key_blob = MemoryBTree._lookup_key_blob(btree, new_id); + let ?new_val_blob = MemoryBTree._lookup_val_blob(btree, new_id); + + // Verify larger value is correctly stored + assert new_key_blob == key; + assert new_val_blob == new_value; + assert new_value.size() >= old_value.size(); + + // Check memory allocation + if (new_mem_block.1.1 > 0) { + assert MemoryRegion.isAllocated(btree.values, new_mem_block.1.0, new_mem_block.1.1); + assert memory_blocks_map.add(new_mem_block.1, index); + }; + + validate_btree_memory_regions(btree); + }; + + validate_btree_memory_regions(btree); + }, + ); + + run_blob_validation_test(btree, btree_utils, greater_size_blob_values); + + test( + "replace with smaller size blob values", + func() { + for (index in order.vals()) { + let key = blob_keys.get(index); + let old_value = greater_size_blob_values.get(index); + let new_value = less_size_blob_values.get(index); + + // Verify old entry exists + assert MemoryBTree.get(btree, btree_utils, key) == ?old_value; + + // Get memory info before replacement + let ?old_id = MemoryBTree.getId(btree, btree_utils, key); + let ?old_mem_block = MemoryBTree._lookup_mem_block(btree, old_id); + + // Replace with smaller value + let replaced = MemoryBTree.insert(btree, btree_utils, key, new_value); + assert replaced == ?old_value; + + // Get new memory info + let ?new_id = MemoryBTree.getId(btree, btree_utils, key); + let ?new_mem_block = MemoryBTree._lookup_mem_block(btree, new_id); + let ?new_key_blob = MemoryBTree._lookup_key_blob(btree, new_id); + let ?new_val_blob = MemoryBTree._lookup_val_blob(btree, new_id); + + // Verify smaller value is correctly stored + assert new_key_blob == key; + assert new_val_blob == new_value; + assert new_value.size() <= old_value.size(); + + // Check memory allocation + if (new_mem_block.0.1 > 0) { + assert MemoryRegion.isAllocated(btree.data, new_mem_block.0.0, new_mem_block.0.1); + }; + if (new_mem_block.1.1 > 0) { + assert MemoryRegion.isAllocated(btree.values, new_mem_block.1.0, new_mem_block.1.1); + }; + + validate_btree_memory_regions(btree); + }; + + validate_btree_memory_regions(btree); + }, + ); + + run_blob_validation_test(btree, btree_utils, less_size_blob_values); + + test( + "verify memory consistency after all operations", + func() { + // Final verification that all current entries are accessible + for (i in Iter.range(0, limit - 1)) { + let expected_key = blob_keys.get(i); + let expected_value = less_size_blob_values.get(i); + + let ?id = MemoryBTree.getId(btree, btree_utils, expected_key); + let ?mem_block = MemoryBTree._lookup_mem_block(btree, id); + let ?key_blob = MemoryBTree._lookup_key_blob(btree, id); + let ?val_blob = MemoryBTree._lookup_val_blob(btree, id); + + // Verify blobs match expected + assert key_blob == expected_key; + assert val_blob == expected_value; + + // Verify memory allocation + if (mem_block.0.1 > 0) { + assert MemoryRegion.isAllocated(btree.data, mem_block.0.0, mem_block.0.1); + }; + if (mem_block.1.1 > 0) { + assert MemoryRegion.isAllocated(btree.values, mem_block.1.0, mem_block.1.1); + }; + + // Verify retrieval works + let retrieved = MemoryBTree.get(btree, btree_utils, expected_key); + if (retrieved != ?expected_value) { + Debug.print("final verification mismatch: " # debug_show i); + assert false; + }; + }; + + // Final memory validation + validate_btree_memory_regions(btree); + }, + ); + + test( + "test btree operations on blob data", + func() { + // Test some of the original MemoryBTree operations with blob data + assert MemoryBTree.size(btree) == limit; + + // Test entries iteration + var count = 0; + for ((key, value) in MemoryBTree.entries(btree, btree_utils)) { + count += 1; + // Verify this entry exists + assert MemoryBTree.get(btree, btree_utils, key) == ?value; + }; + assert count == limit; + + // Test scan functionality with a subset of keys + if (limit > 10) { + let start_key = blob_keys.get(5); + let end_key = blob_keys.get(15); + + var scan_count = 0; + for ((key, value) in MemoryBTree.scan(btree, btree_utils, ?start_key, ?end_key)) { + scan_count += 1; + assert MemoryBTree.get(btree, btree_utils, key) == ?value; + }; + assert scan_count > 0; // Should have found some entries + }; + + validate_btree_memory_regions(btree); + }, + ); + + test( + "clear blob btree", + func() { + MemoryBTree.clear(btree); + assert MemoryBTree.size(btree) == 0; + + // Verify all entries are gone + for (i in Iter.range(0, limit - 1)) { + let key = blob_keys.get(i); + assert MemoryBTree.get(btree, btree_utils, key) == null; + }; + + // Validate memory regions after clearing + validate_btree_memory_regions(btree); + }, + ); + }, +); diff --git a/tests/MemoryBTree/MemoryBTree.Migrations.Test.mo b/tests/MemoryBTree/MemoryBTree.Migrations.Test.mo index bed87fe..fedbba3 100644 --- a/tests/MemoryBTree/MemoryBTree.Migrations.Test.mo +++ b/tests/MemoryBTree/MemoryBTree.Migrations.Test.mo @@ -1,9 +1,8 @@ // @testmode wasi -import { test; suite } "mo:test"; +import { test; suite } "mo:test@.v2.1.1"; import MemoryBTree "../../src/MemoryBTree/Base"; import StableMemoryBTree "../../src/MemoryBTree/Stable"; import Migrations "../../src/MemoryBTree/Migrations"; -import OldMemoryBTree "mo:memory-collection-btree-v0-v0_0_1_migration/MemoryBTree/Stable"; import TypeUtils "../../src/TypeUtils"; suite( @@ -20,22 +19,5 @@ suite( ignore Migrations.getCurrentVersion(version); // should not trap }, ); - // test( - // "#v0 -> #v0_0_1", - // func() { - // let old_btree = OldMemoryBTree.new(?32); - // let btree_utils = MemoryBTree.createUtils(TypeUtils.Nat, TypeUtils.Nat); - - // ignore OldMemoryBTree.insert(old_btree, btree_utils, 0, 0); - // ignore OldMemoryBTree.insert(old_btree, btree_utils, 1, 1); - // ignore OldMemoryBTree.insert(old_btree, btree_utils, 2, 2); - - // let new_btree = Migrations.upgrade(old_btree); - - // assert StableMemoryBTree.get(new_btree, btree_utils, 0) == ?0; - // assert StableMemoryBTree.toArray(new_btree, btree_utils) == [(0, 0), (1, 1), (2, 2)]; - - // }, - // ); }, ); diff --git a/tests/MemoryBTree/MemoryBTree.Test.mo b/tests/MemoryBTree/MemoryBTree.Test.mo index 7ed3df8..0a85a47 100644 --- a/tests/MemoryBTree/MemoryBTree.Test.mo +++ b/tests/MemoryBTree/MemoryBTree.Test.mo @@ -1,17 +1,17 @@ // @testmode wasi -import { test; suite } "mo:test"; -import Debug "mo:base/Debug"; -import Iter "mo:base/Iter"; -import Buffer "mo:base/Buffer"; -import Nat32 "mo:base/Nat32"; -import Nat64 "mo:base/Nat64"; -import Nat "mo:base/Nat"; -import Order "mo:base/Order"; - -import Fuzz "mo:fuzz"; -import Itertools "mo:itertools/Iter"; +import { test; suite } "mo:test@.v2.1.1"; +import Debug "mo:base@.v0.14.11/Debug"; +import Iter "mo:base@.v0.14.11/Iter"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Nat32 "mo:base@.v0.14.11/Nat32"; +import Nat64 "mo:base@.v0.14.11/Nat64"; +import Nat "mo:base@.v0.14.11/Nat"; +import Order "mo:base@.v0.14.11/Order"; + +import Fuzz "mo:fuzz@.v1.0.0"; +import Itertools "mo:itertools@.v0.2.2/Iter"; import Map "mo:map/Map"; -import MemoryRegion "mo:memory-region/MemoryRegion"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; import MemoryBTree "../../src/MemoryBTree/Base"; import TypeUtils "../../src/TypeUtils"; @@ -26,25 +26,7 @@ type Order = Order.Order; type MemoryBlock = MemoryBTree.MemoryBlock; let { nhash } = Map; -func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; -}; - -let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); +let fuzz = Fuzz.fromSeed(0xdeadbeef); let limit = 10_000; diff --git a/tests/MemoryBTree/MotokoStableBTre.mo b/tests/MemoryBTree/MotokoStableBTre.mo deleted file mode 100644 index 0aafc78..0000000 --- a/tests/MemoryBTree/MotokoStableBTre.mo +++ /dev/null @@ -1,91 +0,0 @@ -// @testmode wasi -import { test; suite } "mo:test"; -import Debug "mo:base/Debug"; -import Iter "mo:base/Iter"; -import Buffer "mo:base/Buffer"; -import Nat32 "mo:base/Nat32"; -import Nat "mo:base/Nat"; -import Nat64 "mo:base/Nat64"; -import Region "mo:base/Region"; - -import Fuzz "mo:fuzz"; -import Itertools "mo:itertools/Iter"; -import Map "mo:map/Map"; - -import MotokoStableBTree "mo:MotokoStableBTree/BTree"; -import BTreeMap "mo:MotokoStableBTree/modules/btreemap"; -import BTreeMapMemory "mo:MotokoStableBTree/modules/memory"; - -type Buffer = Buffer.Buffer; -type Iter = Iter.Iter; - -let { nconv; tconv } = MotokoStableBTree; -let tconv_20 = tconv(20); -let nconv_32 = nconv(32); - -let stable_btree = BTreeMap.new(BTreeMapMemory.RegionMemory(Region.new()), nconv_32, nconv_32); - -let { nhash } = Map; -func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; -}; - -let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); - -let limit = 10_000; - -let nat_gen_iter : Iter = { - next = func() : ?Nat = ?fuzz.nat.randomRange(1, limit * 10); -}; -let unique_iter = Itertools.unique(nat_gen_iter, Nat32.fromNat, Nat.equal); -let random = Itertools.toBuffer(Itertools.take(unique_iter, limit)); -let sorted = Buffer.clone(random); -sorted.sort(Nat.compare); - -suite( - "MotokoStableBTree", - func() { - test( - "insert ", - func() { - for (n in random.vals()) { - ignore stable_btree.insert(n, nconv_32, n, nconv_32); - }; - - for (n in random.vals()) { - assert ?n == stable_btree.get(n, nconv_32, nconv_32); - }; - }, - ); - - test( - "entries", - func() { - var i = 0; - for ((n, (k, v)) in Itertools.zip(sorted.vals(), stable_btree.iter(nconv_32, nconv_32))) { - i += 1; - if (not (n == k and n == v)) { - Debug.print("mismatch " # debug_show (n, (k, v))); - assert false; - }; - }; - - assert i == random.size(); // fails to return all entries - }, - ); - }, -); diff --git a/tests/MemoryBuffer/MemoryBuffer.Load.Test.mo b/tests/MemoryBuffer/MemoryBuffer.Load.Test.mo new file mode 100644 index 0000000..c3c12e1 --- /dev/null +++ b/tests/MemoryBuffer/MemoryBuffer.Load.Test.mo @@ -0,0 +1,336 @@ +// @testmode wasi +import Buffer "mo:base@.v0.14.11/Buffer"; +import Debug "mo:base@.v0.14.11/Debug"; +import Iter "mo:base@.v0.14.11/Iter"; +import Nat "mo:base@.v0.14.11/Nat"; +import Result "mo:base@.v0.14.11/Result"; + +import { test; suite } "mo:test@.v2.1.1"; +import Fuzz "mo:fuzz@.v1.0.0"; +import { MaxBpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import Itertools "mo:itertools@.v0.2.2/Iter"; +import MaxBpTreeMethods "mo:augmented-btrees@.v0.7.1/MaxBpTree/Methods"; +import BpTree "mo:augmented-btrees@.v0.7.1/BpTree"; + +import MemoryBuffer "../../src/MemoryBuffer/Base"; + +import TypeUtils "../../src/TypeUtils"; + +let limit = 10_000; +let fuzz = Fuzz.fromSeed(0xdeadbeef); + +// Create input arrays for different test scenarios +let order = Buffer.Buffer(limit); +let initial_values = Buffer.Buffer(limit); +let equal_size_values = Buffer.Buffer(limit); +let greater_size_values = Buffer.Buffer(limit); +let less_size_values = Buffer.Buffer(limit); + +for (i in Iter.range(0, limit - 1)) { + order.add(i); + + let size_a = fuzz.nat.randomRange(0, 25); + let text_a = fuzz.text.randomAlphanumeric(size_a); + + // Less size values: shorter text strings + less_size_values.add(text_a); + + let size_b = fuzz.nat.randomRange(size_a, 50); + let text_b = fuzz.text.randomAlphanumeric(size_b); + + // Initial values: short text strings + initial_values.add(text_b); + + let text_c = fuzz.text.randomAlphanumeric(size_b); + + // Equal size values: same length as initial + equal_size_values.add(text_c); + + let size_d = fuzz.nat.randomRange(size_b, 100); + let text_d = fuzz.text.randomAlphanumeric(size_d); + + // Greater size values: longer text strings + greater_size_values.add(text_d); + +}; + +fuzz.buffer.shuffle(order); + +type MemoryRegion = MemoryRegion.MemoryRegion; + +func validate_region(memory_region : MemoryRegion) { + if (not MaxBpTreeMethods.validate_max_path(memory_region.free_memory, Cmp.Nat)) { + Debug.print("invalid max path discovered at index "); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(memory_region.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(memory_region.free_memory))); + assert false; + }; + + if (not MaxBpTreeMethods.validate_subtree_size(memory_region.free_memory)) { + Debug.print("invalid subtree size at index "); + Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(memory_region.free_memory))); + Debug.print("node leaves: " # debug_show (MaxBpTree.toLeafNodes(memory_region.free_memory))); + assert false; + }; +}; + +class MemoryBlocksMap(mbuffer : MemoryBuffer.MemoryBuffer) { + let memory_blocks = BpTree.new<(Nat, Nat), Nat>(null); + + func compare(a : (Nat, Nat), b : (Nat, Nat)) : Int8 { + if (a.0 < b.0 and a.1 <= b.0) { + -1; + } else if (a.0 >= b.1 and a.1 > b.0) { + 1; + } else { + 0; + }; + }; + + public func add(_block : (Nat, Nat), index : Nat) : Bool { + let block = (_block.0, _block.0 + _block.1); + + switch (BpTree.getEntry(memory_blocks, compare, block)) { + case (?(existing_block, prev_index)) { + Debug.print("Memory block already exists at index " # debug_show prev_index # ", current index: " # debug_show index); + Debug.print("Existing block: " # debug_show existing_block # ", New block: " # debug_show block); + Debug.print("Actual memory block at prev index: " # debug_show MemoryBuffer._get_memory_block(mbuffer, prev_index)); + false; + }; + case (null) { + ignore BpTree.insert(memory_blocks, compare, block, index); + true; + }; + }; + }; + +}; + +suite( + "Memory Buffer", + func() { + let mbuffer = MemoryBuffer.new(); + + test( + "add() to Buffer", + func() { + for (i in Iter.range(0, limit - 1)) { + let value = initial_values.get(i); + MemoryBuffer.add(mbuffer, TypeUtils.Text, value); + + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == value; + assert MemoryBuffer.size(mbuffer) == i + 1; + + assert MemoryRegion.size(mbuffer.pointers) == 64 + (MemoryBuffer.size(mbuffer) * 12); + }; + + let total_blob_size = Itertools.sum( + Iter.map( + MemoryBuffer.blocks(mbuffer), + func((_address, size) : (Nat, Nat)) : Nat = size, + ), + Nat.add, + ); + + switch (total_blob_size) { + case (?sum) { + let blob_size = MemoryRegion.size(mbuffer.blobs); + assert blob_size == sum + 64; + }; + case null { + let blob_size = MemoryRegion.size(mbuffer.blobs); + assert blob_size == 64; + }; + }; + }, + ); + + test( + "get() from Buffer", + func() { + for (i in Iter.range(0, limit - 1)) { + let expected_value = initial_values.get(i); + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == expected_value; + }; + }, + ); + + test( + "put() (new == prev) in Buffer", + func() { + for (i in order.vals()) { + let initial_value = initial_values.get(i); + let equal_value = equal_size_values.get(i); + + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == initial_value; + + MemoryBuffer.put(mbuffer, TypeUtils.Text, i, equal_value); + validate_region(mbuffer.blobs); + validate_region(mbuffer.pointers); + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == equal_value; + }; + + // After putting equal values, the memory region should not change + assert MemoryRegion.getFreeMemory(mbuffer.blobs) == []; + assert MemoryRegion.getFreeMemory(mbuffer.pointers) == []; + }, + ); + + test( + "get() from Buffer", + func() { + for (i in Iter.range(0, limit - 1)) { + let expected_value = equal_size_values.get(i); + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == expected_value; + }; + }, + ); + + test( + "put() new > old", + func() { + + let memory_blocks_map = MemoryBlocksMap(mbuffer); + + for (i in order.vals()) { + let equal_value = equal_size_values.get(i); + let greater_value = greater_size_values.get(i); + + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == equal_value; // ensures the previous value did not get overwritten + + let _pointer = MemoryBuffer._get_pointer(mbuffer, i); + let _memory_block = MemoryBuffer._get_memory_block(mbuffer, i); + let blob = MemoryBuffer._get_blob(mbuffer, i); + // Debug.print("old " # debug_show (i, pointer, memory_block, blob, TypeUtils.Text.blobify.to_blob(equal_value))); + assert blob == TypeUtils.Text.blobify.to_blob(equal_value); + + let prev_block_free_memory = MemoryRegion.getFreeMemory(mbuffer.blobs); + if (_memory_block.1 > 0) { + // Debug.print("previous memory region free memory: " # debug_show (prev_block_free_memory)); + // assert MemoryRegion.isAllocated(mbuffer.blobs, _memory_block.0); + if (not MemoryRegion.isAllocated(mbuffer.blobs, _memory_block.0, _memory_block.1)) { + Debug.print("Memory block was not allocated at index " # debug_show i); + Debug.print("Memory block: " # debug_show _memory_block); + Debug.print("Pointer: " # debug_show _pointer); + Debug.print("Blob: " # debug_show blob); + Debug.print("prev memory region free memory: " # debug_show (prev_block_free_memory)); + assert false; + }; + + if (MemoryRegion.isFreed(mbuffer.blobs, _memory_block.0, _memory_block.1) != #ok(false)) { + Debug.print("isFreed response: " # debug_show (MemoryRegion.isFreed(mbuffer.blobs, _memory_block.0, _memory_block.1))); + Debug.print("Memory block was freed unexpectedly at index " # debug_show i); + Debug.print("Memory block: " # debug_show _memory_block); + Debug.print("Pointer: " # debug_show _pointer); + Debug.print("Blob: " # debug_show blob); + Debug.print("memory region free memory: " # debug_show (MemoryRegion.getFreeMemory(mbuffer.blobs))); + assert false; + }; + assert MemoryRegion.isFreed(mbuffer.blobs, _memory_block.0, _memory_block.1) == #ok(false); + + }; + + // Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(mbuffer.blobs.free_memory))); + // Debug.print("leaf nodes: " # debug_show (MaxBpTree.toLeafNodes(mbuffer.blobs.free_memory))); + MemoryBuffer.put(mbuffer, TypeUtils.Text, i, greater_value); + + validate_region(mbuffer.blobs); + validate_region(mbuffer.pointers); + + let serialized = TypeUtils.Text.blobify.to_blob(greater_value); + + let new_pointer = MemoryBuffer._get_pointer(mbuffer, i); + let new_memory_block = MemoryBuffer._get_memory_block(mbuffer, i); + let new_blob = MemoryBuffer._get_blob(mbuffer, i); + + if (new_memory_block.1 > 0) { + if (not MemoryRegion.isAllocated(mbuffer.blobs, new_memory_block.0, new_memory_block.1)) { + Debug.print("Memory block was not allocated at index " # debug_show i); + Debug.print("Memory block: " # debug_show new_memory_block); + Debug.print("Pointer: " # debug_show new_pointer); + Debug.print("Blob: " # debug_show new_blob); + Debug.print("previous memory region free memory: " # debug_show (prev_block_free_memory)); + Debug.print("current memory region free memory: " # debug_show (MemoryRegion.getFreeMemory(mbuffer.blobs))); + assert false; + }; + + if (not memory_blocks_map.add(new_memory_block, i)) { + Debug.print("i = " # debug_show i # ", greater_value = " # debug_show greater_value # ", received = " # debug_show MemoryBuffer.get(mbuffer, TypeUtils.Text, i)); + Debug.print("old blob: " # debug_show blob); + Debug.print("new blob: " # debug_show new_blob); + + Debug.print("old pointer: " # debug_show _pointer); + Debug.print("new pointer: " # debug_show MemoryBuffer._get_pointer(mbuffer, i)); + + Debug.print("old memory block: " # debug_show _memory_block); + Debug.print("new memory block: " # debug_show MemoryBuffer._get_memory_block(mbuffer, i)); + + Debug.print("blobs free memory: " # debug_show (prev_block_free_memory)); + Debug.print("pointers free memory: " # debug_show (MemoryRegion.getFreeMemory(mbuffer.pointers))); + + assert false; + + }; + + }; + + // Debug.print("new " # debug_show (i, new_pointer, new_memory_block, new_blob)); + // Debug.print("expected " # debug_show serialized); + assert new_blob == serialized; + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == greater_value; + + }; + }, + ); + + test( + "get() from Buffer", + func() { + for (i in Iter.range(0, limit - 1)) { + let expected_value = greater_size_values.get(i); + + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == expected_value; + }; + }, + ); + + test( + "put() (new < prev) in Buffer", + func() { + + for (i in order.vals()) { + let greater_value = greater_size_values.get(i); + let less_value = less_size_values.get(i); + + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == greater_value; // ensures the previous value did not get overwritten + + MemoryBuffer.put(mbuffer, TypeUtils.Text, i, less_value); + // Debug.print("node keys: " # debug_show (MaxBpTree.toNodeKeys(mbuffer.blobs.free_memory))); + // Debug.print("leaf nodes: " # debug_show (MaxBpTree.toLeafNodes(mbuffer.blobs.free_memory))); + validate_region(mbuffer.blobs); + validate_region(mbuffer.pointers); + let received = MemoryBuffer.get(mbuffer, TypeUtils.Text, i); + if (received != less_value) { + Debug.print("mismatch at i = " # debug_show i); + Debug.print("(expected, received) -> " # debug_show (less_value, received)); + + assert false; + }; + }; + }, + ); + + test( + "get() from Buffer", + func() { + + for (i in Iter.range(0, limit - 1)) { + let expected_value = less_size_values.get(i); + assert MemoryBuffer.get(mbuffer, TypeUtils.Text, i) == expected_value; + }; + }, + ); + + }, +); diff --git a/tests/MemoryBuffer/Migrations.Test.mo b/tests/MemoryBuffer/MemoryBuffer.Migrations.Test.mo similarity index 94% rename from tests/MemoryBuffer/Migrations.Test.mo rename to tests/MemoryBuffer/MemoryBuffer.Migrations.Test.mo index 0bffa59..1f908a2 100644 --- a/tests/MemoryBuffer/Migrations.Test.mo +++ b/tests/MemoryBuffer/MemoryBuffer.Migrations.Test.mo @@ -1,5 +1,5 @@ // @testmode wasi -import { test; suite } "mo:test"; +import { test; suite } "mo:test@.v2.1.1"; import MemoryBuffer "../../src/MemoryBuffer/Base"; import StableMemoryBuffer "../../src/MemoryBuffer/Stable"; import Migrations "../../src/MemoryBuffer/Migrations"; diff --git a/tests/MemoryBuffer/MemoryBuffer.Test.mo b/tests/MemoryBuffer/MemoryBuffer.Test.mo index 8f399cb..37ed4ef 100644 --- a/tests/MemoryBuffer/MemoryBuffer.Test.mo +++ b/tests/MemoryBuffer/MemoryBuffer.Test.mo @@ -1,18 +1,18 @@ // @testmode wasi -import Buffer "mo:base/Buffer"; -import Debug "mo:base/Debug"; -import Iter "mo:base/Iter"; -import Prelude "mo:base/Prelude"; -import Nat "mo:base/Nat"; -import Array "mo:base/Array"; -import Nat64 "mo:base/Nat64"; - -import { test; suite } "mo:test"; -import Fuzz "mo:fuzz"; -import { MaxBpTree; Cmp } "mo:augmented-btrees"; -import MemoryRegion "mo:memory-region/MemoryRegion"; -import Itertools "mo:itertools/Iter"; -import MaxBpTreeMethods "mo:augmented-btrees/MaxBpTree/Methods"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Debug "mo:base@.v0.14.11/Debug"; +import Iter "mo:base@.v0.14.11/Iter"; +import Prelude "mo:base@.v0.14.11/Prelude"; +import Nat "mo:base@.v0.14.11/Nat"; +import Array "mo:base@.v0.14.11/Array"; +import Nat64 "mo:base@.v0.14.11/Nat64"; + +import { test; suite } "mo:test@.v2.1.1"; +import Fuzz "mo:fuzz@.v1.0.0"; +import { MaxBpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import Itertools "mo:itertools@.v0.2.2/Iter"; +import MaxBpTreeMethods "mo:augmented-btrees@.v0.7.1/MaxBpTree/Methods"; import MemoryBuffer "../../src/MemoryBuffer/Base"; @@ -29,25 +29,8 @@ for (i in Iter.range(0, limit - 1)) { order.add(i); }; -func xorshift128plus(seed : Nat) : { next() : Nat } { - var state0 : Nat64 = Nat64.fromNat(seed); - var state1 : Nat64 = Nat64.fromNat(seed + 1); - if (state0 == 0) state0 := 1; - if (state1 == 0) state1 := 2; - - { - next = func() : Nat { - var s1 = state0; - let s0 = state1; - state0 := s0; - s1 ^= s1 << 23 : Nat64; - state1 := s1 ^ s0 ^ (s1 >> 18 : Nat64) ^ (s0 >> 5 : Nat64); - Nat64.toNat(state1 +% s0); // Use wrapping addition - }; - }; -}; +let fuzz = Fuzz.fromSeed(0xdeadbeef); -let fuzz = Fuzz.create(xorshift128plus(0xdeadbeef)); fuzz.buffer.shuffle(order); // Utils.shuffle_buffer(fuzz, order); diff --git a/tests/MemoryQueue/MemoryQueue.Test.mo b/tests/MemoryQueue/MemoryQueue.Test.mo index bbc4f95..9dfd1b2 100644 --- a/tests/MemoryQueue/MemoryQueue.Test.mo +++ b/tests/MemoryQueue/MemoryQueue.Test.mo @@ -1,10 +1,10 @@ // @testmode wasi -import Buffer "mo:base/Buffer"; -import Iter "mo:base/Iter"; -import Debug "mo:base/Debug"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import Iter "mo:base@.v0.14.11/Iter"; +import Debug "mo:base@.v0.14.11/Debug"; -import MemoryRegion "mo:memory-region/MemoryRegion"; -import { test; suite } "mo:test"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; +import { test; suite } "mo:test@.v2.1.1"; import MemoryQueue "../../src/MemoryQueue/Base"; import TypeUtils "../../src/TypeUtils"; @@ -54,7 +54,9 @@ suite( "clear()", func() { MemoryQueue.clear(mem_queue); - assert MemoryRegion.size(mem_queue.region) == 64; + assert MemoryRegion.allocated(mem_queue.region) == 64; + assert MemoryRegion.getFreeMemory(mem_queue.region) == [(64, MemoryRegion.size(mem_queue.region) - 64)]; + assert MemoryQueue.size(mem_queue) == 0; }, ); @@ -83,7 +85,7 @@ suite( assert null == MemoryQueue.peek(mem_queue, queue_utils); assert null == MemoryQueue.pop(mem_queue, queue_utils); - assert MemoryRegion.size(mem_queue.region) == 64; + assert MemoryRegion.allocated(mem_queue.region) == 64; }, ); From bf57267bc37c40b9aecbb35f2e83efd6e38b1efe Mon Sep 17 00:00:00 2001 From: Tomi Jaga Date: Sun, 10 Aug 2025 15:02:39 -0700 Subject: [PATCH 3/4] revert version tagged bench dependency --- bench/MemoryBTree/BTree-specific-fns.bench.mo | 2 +- bench/MemoryBTree/BTree.Types.bench.mo | 7 +--- bench/MemoryBTree/MemoryBTree.bench.mo | 2 +- .../MemoryBTree.node-capacity.bench.mo | 42 +------------------ bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo | 2 +- bench/MemoryQueue/MemoryQueue.bench.mo | 2 +- mops.toml | 2 +- 7 files changed, 7 insertions(+), 52 deletions(-) diff --git a/bench/MemoryBTree/BTree-specific-fns.bench.mo b/bench/MemoryBTree/BTree-specific-fns.bench.mo index f330894..83cd491 100644 --- a/bench/MemoryBTree/BTree-specific-fns.bench.mo +++ b/bench/MemoryBTree/BTree-specific-fns.bench.mo @@ -4,7 +4,7 @@ import Nat "mo:base@.v0.14.11/Nat"; import Buffer "mo:base@.v0.14.11/Buffer"; import Nat64 "mo:base@.v0.14.11/Nat64"; -import Bench "mo:bench@.v1.0.0"; +import Bench "mo:bench"; import Fuzz "mo:fuzz@.v1.0.0"; import { BpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; diff --git a/bench/MemoryBTree/BTree.Types.bench.mo b/bench/MemoryBTree/BTree.Types.bench.mo index bfa139b..a61253d 100644 --- a/bench/MemoryBTree/BTree.Types.bench.mo +++ b/bench/MemoryBTree/BTree.Types.bench.mo @@ -5,9 +5,8 @@ import Text "mo:base@.v0.14.11/Text"; import Nat "mo:base@.v0.14.11/Nat"; import Nat64 "mo:base@.v0.14.11/Nat64"; -import Bench "mo:bench@.v1.0.0"; +import Bench "mo:bench"; import Fuzz "mo:fuzz@.v1.0.0"; -import MotokoStableBTree "mo:MotokoStableBTree/BTree"; import MemoryBTree "../../src/MemoryBTree/Base"; import TypeUtils "../../src/TypeUtils"; @@ -47,10 +46,6 @@ module { let limit = 10_000; - let { n64conv; tconv } = MotokoStableBTree; - - let tconv_10 = tconv(10); - let mem_btree_text_gen_cmp = MemoryBTree.new(?128); let mem_btree_text_blob_cmp = MemoryBTree.new(?128); let mem_btree_candid_text_gen_cmp = MemoryBTree.new(?128); diff --git a/bench/MemoryBTree/MemoryBTree.bench.mo b/bench/MemoryBTree/MemoryBTree.bench.mo index 284e8b5..0d5e9ce 100644 --- a/bench/MemoryBTree/MemoryBTree.bench.mo +++ b/bench/MemoryBTree/MemoryBTree.bench.mo @@ -7,7 +7,7 @@ import Text "mo:base@.v0.14.11/Text"; import RBTree "mo:base@.v0.14.11/RBTree"; import BTree "mo:stableheapbtreemap@.v1.5.0/BTree"; -import Bench "mo:bench@.v1.0.0"; +import Bench "mo:bench"; import Fuzz "mo:fuzz@.v1.0.0"; import { BpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; diff --git a/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo b/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo index 40ac632..c08e3a2 100644 --- a/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo +++ b/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo @@ -6,11 +6,8 @@ import Region "mo:base@.v0.14.11/Region"; import Buffer "mo:base@.v0.14.11/Buffer"; import Text "mo:base@.v0.14.11/Text"; -import Bench "mo:bench@.v1.0.0"; +import Bench "mo:bench"; import Fuzz "mo:fuzz@.v1.0.0"; -import MotokoStableBTree "mo:MotokoStableBTree/BTree"; -import BTreeMap "mo:MotokoStableBTree/modules/btreemap"; -import BTreeMapMemory "mo:MotokoStableBTree/modules/memory"; import { BpTree; Cmp } "mo:augmented-btrees@.v0.7.1"; @@ -51,12 +48,7 @@ module { let limit = 10_000; - let { n64conv; tconv } = MotokoStableBTree; - - let tconv_10 = tconv(10); - let bptree = BpTree.new(?32); - let stable_btree = BTreeMap.new(BTreeMapMemory.RegionMemory(Region.new()), tconv_10, tconv_10); let mem_btree_order_4 = MemoryBTree.new(?4); let mem_btree_order_32 = MemoryBTree.new(?32); let mem_btree_order_64 = MemoryBTree.new(?64); @@ -207,38 +199,6 @@ module { }; }; - case ("MotokoStableBTree", "insert()") { - for ((key, val) in entries.vals()) { - ignore stable_btree.insert(key, tconv_10, val, tconv_10); - }; - }; - case ("MotokoStableBTree", "replace()") { - for ((key, val) in replacements.vals()) { - ignore stable_btree.insert(key, tconv_10, val, tconv_10); - }; - }; - case ("MotokoStableBTree", "get()") { - for (i in Iter.range(0, limit - 1)) { - let (key, val) = entries.get(i); - ignore stable_btree.get(key, tconv_10, tconv_10); - }; - }; - case ("MotokoStableBTree", "entries()") { - var i = 0; - for (kv in stable_btree.iter(tconv_10, tconv_10)) { - i += 1; - }; - - assert Nat64.fromNat(i) == stable_btree.getLength(); - Debug.print("Size: " # debug_show (i, stable_btree.getLength())); - }; - case ("MotokoStableBTree", "scan()") {}; - case ("MotokoStableBTree", "remove()") { - for ((k, v) in entries.vals()) { - ignore stable_btree.remove(k, tconv_10, tconv_10); - }; - }; - case ("Memory B+Tree (4)", category) { run_bench("Memory B+Tree", category, mem_btree_order_4); }; diff --git a/bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo b/bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo index c81ec5f..06e1b7f 100644 --- a/bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo +++ b/bench/MemoryBuffer/MemoryBuffer.Blob.bench.mo @@ -5,7 +5,7 @@ import Blob "mo:base@.v0.14.11/Blob"; import Debug "mo:base@.v0.14.11/Debug"; import Nat64 "mo:base@.v0.14.11/Nat64"; -import Bench "mo:bench@.v1.0.0"; +import Bench "mo:bench"; import Fuzz "mo:fuzz@.v1.0.0"; import MemoryBuffer "../../src/MemoryBuffer/Base"; diff --git a/bench/MemoryQueue/MemoryQueue.bench.mo b/bench/MemoryQueue/MemoryQueue.bench.mo index 6465bbb..1153468 100644 --- a/bench/MemoryQueue/MemoryQueue.bench.mo +++ b/bench/MemoryQueue/MemoryQueue.bench.mo @@ -3,7 +3,7 @@ import Debug "mo:base@.v0.14.11/Debug"; import Buffer "mo:base@.v0.14.11/Buffer"; import Nat64 "mo:base@.v0.14.11/Nat64"; -import Bench "mo:bench@.v1.0.0"; +import Bench "mo:bench"; import Fuzz "mo:fuzz@.v1.0.0"; import Itertools "mo:itertools@.v0.2.2/Iter"; diff --git a/mops.toml b/mops.toml index 92aaa3d..da7d6fc 100644 --- a/mops.toml +++ b/mops.toml @@ -15,7 +15,7 @@ license = "MIT" [dev-dependencies] "test@.v2.1.1" = "2.1.1" -"bench@.v1.0.0" = "1.0.0" +bench = "1.0.0" "augmented-btrees@.v0.7.1" = "0.7.1" "fuzz@.v1.0.0" = "1.0.0" "stableheapbtreemap@.v1.5.0" = "1.5.0" From 472c8f22c1cb924a229ee68dd7cc5637ad471438 Mon Sep 17 00:00:00 2001 From: Tomi Jaga Date: Sun, 10 Aug 2025 17:06:30 -0700 Subject: [PATCH 4/4] added legacy TypeUtils functions from v0.4.0 back into the lib for backward compatibility --- bench/MemoryBTree/BTree.Types.bench.mo | 23 - example/MemoryQueue.mo | 2 +- mops.toml | 1 + src/MemoryBTree/Base.mo | 1 - src/TypeUtils/Blobify.mo | 282 ++++-- src/TypeUtils/MemoryCmp.mo | 37 + src/TypeUtils/lib.mo | 97 +- tests/MemoryBTree/MemoryBTree.Load.Test.mo | 533 ++++++----- tests/MemoryBTree/MemoryBTree.Test.mo | 903 +++++++++--------- .../BigEndian.BackwardCompatible.Nat.Test.mo | 67 ++ 10 files changed, 1039 insertions(+), 907 deletions(-) create mode 100644 tests/MemoryBTree/TypeUtils/BigEndian.BackwardCompatible.Nat.Test.mo diff --git a/bench/MemoryBTree/BTree.Types.bench.mo b/bench/MemoryBTree/BTree.Types.bench.mo index a61253d..0f607d3 100644 --- a/bench/MemoryBTree/BTree.Types.bench.mo +++ b/bench/MemoryBTree/BTree.Types.bench.mo @@ -28,11 +28,8 @@ module { bench.rows([ "Memory B+Tree - Text (#BlobCmp)", "Memory B+Tree - Text (#GenCmp)", - "Memory B+Tree - Candid Text (#BlobCmp)", - "Memory B+Tree - Candid Text (#GenCmp)", "Memory B+Tree - Nat (#BlobCmp)", "Memory B+Tree - Nat (#GenCmp)", - "Memory B+Tree - Candid Nat (#GenCmp)", ]); bench.cols([ @@ -48,13 +45,9 @@ module { let mem_btree_text_gen_cmp = MemoryBTree.new(?128); let mem_btree_text_blob_cmp = MemoryBTree.new(?128); - let mem_btree_candid_text_gen_cmp = MemoryBTree.new(?128); - let mem_btree_candid_text_blob_cmp = MemoryBTree.new(?128); let mem_btree_nat_gen_cmp = MemoryBTree.new(?128); let mem_btree_nat_blob_cmp = MemoryBTree.new(?128); - let mem_btree_candid_nat_gen_cmp = MemoryBTree.new(?128); - let mem_btree_candid_nat_blob_cmp = MemoryBTree.new(?128); let entries = Buffer.Buffer<(Text, Text)>(limit); let nat_entries = Buffer.Buffer<(Nat, Nat)>(limit); @@ -115,17 +108,12 @@ module { let btree_utils = MemoryBTree.createUtils(TypeUtils.Text, TypeUtils.Text); let gen_cmp_text_utils = MemoryBTree.createUtils({ TypeUtils.Text with cmp = #GenCmp(Int8Cmp.Text) }, TypeUtils.Text); - let candid_text_utils = MemoryBTree.createUtils({ TypeUtils.Text with cmp = TypeUtils.MemoryCmp.Default }, TypeUtils.Candid.Text); - let candid_text_gen_cmp_utils = MemoryBTree.createUtils({ TypeUtils.Candid.Text with cmp = #GenCmp(Int8Cmp.Text) }, TypeUtils.Candid.Text); - let nat_btree_utils = MemoryBTree.createUtils({ TypeUtils.Nat with cmp = TypeUtils.MemoryCmp.Default }, TypeUtils.Nat); let nat_gen_cmp_utils = MemoryBTree.createUtils( { TypeUtils.Nat with cmp = #GenCmp(Int8Cmp.Nat) }, TypeUtils.Nat, ); - let candid_nat_utils = MemoryBTree.createUtils(TypeUtils.Candid.Nat, TypeUtils.Candid.Nat); - bench.runner( func(col, row) = switch (col, row) { @@ -137,14 +125,6 @@ module { run_bench("Memory B+Tree", category, mem_btree_text_gen_cmp, gen_cmp_text_utils, entries, Text.equal); }; - case ("Memory B+Tree - Candid Text (#BlobCmp)", category) { - run_bench("Memory B+Tree", category, mem_btree_candid_text_blob_cmp, candid_text_utils, entries, Text.equal); - }; - - case ("Memory B+Tree - Candid Text (#GenCmp)", category) { - run_bench("Memory B+Tree", category, mem_btree_candid_text_gen_cmp, candid_text_gen_cmp_utils, entries, Text.equal); - }; - case ("Memory B+Tree - Nat (#BlobCmp)", category) { run_bench("Memory B+Tree", category, mem_btree_nat_blob_cmp, nat_btree_utils, nat_entries, Nat.equal); }; @@ -153,9 +133,6 @@ module { run_bench("Memory B+Tree", category, mem_btree_nat_gen_cmp, nat_gen_cmp_utils, nat_entries, Nat.equal); }; - case ("Memory B+Tree - Candid Nat (#GenCmp)", category) { - run_bench("Memory B+Tree", category, mem_btree_candid_nat_gen_cmp, candid_nat_utils, nat_entries, Nat.equal); - }; case (_) { Debug.trap("Should not reach with row = " # debug_show row # " and col = " # debug_show col); }; diff --git a/example/MemoryQueue.mo b/example/MemoryQueue.mo index 3bb76e7..d85d2c1 100644 --- a/example/MemoryQueue.mo +++ b/example/MemoryQueue.mo @@ -5,7 +5,7 @@ import Debug "mo:base@.v0.14.11/Debug"; import Iter "mo:base@.v0.14.11/Iter"; import Nat "mo:base@.v0.14.11/Nat"; -import Map "mo:map/Map"; +import Map "mo:map@.v9.0.1/Map"; import MemoryQueue "../src/MemoryQueue"; // "mo:memory_collection/MemoryQueue" import TypeUtils "../src/TypeUtils"; // "mo:memory_collection/TypeUtils" diff --git a/mops.toml b/mops.toml index da7d6fc..ef5eb97 100644 --- a/mops.toml +++ b/mops.toml @@ -19,6 +19,7 @@ bench = "1.0.0" "augmented-btrees@.v0.7.1" = "0.7.1" "fuzz@.v1.0.0" = "1.0.0" "stableheapbtreemap@.v1.5.0" = "1.5.0" +'map@.v9.0.1' = "9.0.1" [toolchain] wasmtime = "14.0.4" diff --git a/src/MemoryBTree/Base.mo b/src/MemoryBTree/Base.mo index 27fc837..7797018 100644 --- a/src/MemoryBTree/Base.mo +++ b/src/MemoryBTree/Base.mo @@ -11,7 +11,6 @@ import Blob "mo:base@.v0.14.11/Blob"; import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; import RevIter "mo:itertools@.v0.2.2/RevIter"; -import Find "mo:map/Map/modules/find"; import MemoryCmp "../TypeUtils/MemoryCmp"; import Blobify "../TypeUtils/Blobify"; diff --git a/src/TypeUtils/Blobify.mo b/src/TypeUtils/Blobify.mo index cda50e1..8aede49 100644 --- a/src/TypeUtils/Blobify.mo +++ b/src/TypeUtils/Blobify.mo @@ -189,135 +189,207 @@ module Blobify { public let Time : Blobify