diff --git a/bench/MemoryBTree/BTree-specific-fns.bench.mo b/bench/MemoryBTree/BTree-specific-fns.bench.mo index 4a122c6..83cd491 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 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..0f607d3 100644 --- a/bench/MemoryBTree/BTree.Types.bench.mo +++ b/bench/MemoryBTree/BTree.Types.bench.mo @@ -1,13 +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 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"; -import Fuzz "mo:fuzz"; -import MotokoStableBTree "mo:MotokoStableBTree/BTree"; +import Fuzz "mo:fuzz@.v1.0.0"; import MemoryBTree "../../src/MemoryBTree/Base"; import TypeUtils "../../src/TypeUtils"; @@ -20,25 +19,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"); @@ -47,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([ @@ -65,19 +43,11 @@ 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); - 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); @@ -138,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) { @@ -160,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); }; @@ -176,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/bench/MemoryBTree/MemoryBTree.bench.mo b/bench/MemoryBTree/MemoryBTree.bench.mo index e4e73fd..0d5e9ce 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 BTree "mo:stableheapbtreemap/BTree"; +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@.v1.5.0/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 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..c08e3a2 100644 --- a/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo +++ b/bench/MemoryBTree/MemoryBTree.node-capacity.bench.mo @@ -1,18 +1,15 @@ -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 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"; -import Fuzz "mo:fuzz"; -import MotokoStableBTree "mo:MotokoStableBTree/BTree"; -import BTreeMap "mo:MotokoStableBTree/modules/btreemap"; -import BTreeMapMemory "mo:MotokoStableBTree/modules/memory"; +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"; @@ -22,25 +19,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"); @@ -69,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); @@ -225,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.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..06e1b7f 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 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..1153468 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 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..d85d2c1 100644 --- a/example/MemoryQueue.mo +++ b/example/MemoryQueue.mo @@ -1,11 +1,11 @@ -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 Map "mo:map/Map"; +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@.v9.0.1/Map"; import MemoryQueue "../src/MemoryQueue"; // "mo:memory_collection/MemoryQueue" import TypeUtils "../src/TypeUtils"; // "mo:memory_collection/TypeUtils" 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..ef5eb97 100644 --- a/mops.toml +++ b/mops.toml @@ -7,19 +7,19 @@ 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" +"test@.v2.1.1" = "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" +"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 6c2e2ad..7797018 100644 --- a/src/MemoryBTree/Base.mo +++ b/src/MemoryBTree/Base.mo @@ -1,17 +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 Find "mo:map/Map/modules/find"; +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 MemoryCmp "../TypeUtils/MemoryCmp"; import Blobify "../TypeUtils/Blobify"; @@ -376,7 +375,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 +391,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 +401,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 +422,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); @@ -636,9 +635,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 +653,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); }; @@ -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/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 7fae09b..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"; @@ -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/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 601aad1..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"; @@ -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) {}; }; 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..8aede49 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"; @@ -189,135 +189,207 @@ module Blobify { public let Time : Blobify = Buffer.Buffer; diff --git a/tests/MemoryBTree/MemoryBTree.Load.Test.mo b/tests/MemoryBTree/MemoryBTree.Load.Test.mo new file mode 100644 index 0000000..812774a --- /dev/null +++ b/tests/MemoryBTree/MemoryBTree.Load.Test.mo @@ -0,0 +1,490 @@ +// @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 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; + }; + }; + }; + +}; + +func btree_load_test(node_capacity : Nat) { + let btree = MemoryBTree.new(?node_capacity); + let btree_utils = MemoryBTree.createUtils(TypeUtils.Blob, TypeUtils.Blob); + suite( + "MemoryBTree Blob Memory Load Tests", + func() { + + 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); + }, + ); + }, + ); +}; + +for (node_capacity in [4, 8, 32, 1024, 4028].vals()) { + suite( + "MemoryBTree Blob Memory Load Tests with node capacity " # debug_show (node_capacity), + func() { + btree_load_test(node_capacity); + }, + ); +}; 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..780dbdd 100644 --- a/tests/MemoryBTree/MemoryBTree.Test.mo +++ b/tests/MemoryBTree/MemoryBTree.Test.mo @@ -1,17 +1,20 @@ // @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 Map "mo:map/Map"; -import MemoryRegion "mo:memory-region/MemoryRegion"; +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 Array "mo:base@.v0.14.11/Array"; +import Blob "mo:base@.v0.14.11/Blob"; +import Nat8 "mo:base@.v0.14.11/Nat8"; + +import Fuzz "mo:fuzz@.v1.0.0"; +import Itertools "mo:itertools@.v0.2.2/Iter"; +import Map "mo:map@.v9.0.1/Map"; +import MemoryRegion "mo:memory-region@.v1.3.2/MemoryRegion"; import MemoryBTree "../../src/MemoryBTree/Base"; import TypeUtils "../../src/TypeUtils"; @@ -26,25 +29,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; @@ -67,585 +52,597 @@ let random = Itertools.toBuffer<(Nat, Nat)>( let sorted = Buffer.clone(random); sorted.sort(func(a : (Nat, Nat), b : (Nat, Nat)) : Order = Nat.compare(a.0, b.0)); -let btree = MemoryBTree._new_with_options(?8, ?0, false); let btree_utils = MemoryBTree.createUtils(TypeUtils.Nat, TypeUtils.Nat); -suite( - "MemoryBTree", - func() { - test( - "insert random", - func() { - let map = Map.new(); - // assert btree.order == 4; +func btree_tests(node_capacity : Nat) { + let btree = MemoryBTree.new(?node_capacity); + + suite( + "MemoryBTree", + func() { + test( + "insert random", + func() { + let map = Map.new(); + // assert btree.order == 4; - // Debug.print("random size " # debug_show random.size()); - label for_loop for ((k, i) in random.vals()) { - // Debug.print("inserting " # debug_show k # " at index " # debug_show i); + // Debug.print("random size " # debug_show random.size()); + label for_loop for ((k, i) in random.vals()) { + // Debug.print("inserting " # debug_show k # " at index " # debug_show i); - ignore Map.put(map, nhash, k, i); - ignore MemoryBTree.insert(btree, btree_utils, k, i); - assert MemoryBTree.size(btree) == i + 1; + ignore Map.put(map, nhash, k, i); + ignore MemoryBTree.insert(btree, btree_utils, k, i); + assert MemoryBTree.size(btree) == i + 1; - // Debug.print("keys " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); - // Debug.print("leafs " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); + // Debug.print("keys " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); + // Debug.print("leafs " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); - let subtree_size = if (btree.is_root_a_leaf) Leaf.get_count(btree, btree.root) else Branch.get_subtree_size(btree, btree.root); + let subtree_size = if (btree.is_root_a_leaf) Leaf.get_count(btree, btree.root) else Branch.get_subtree_size(btree, btree.root); - // Debug.print("subtree_size " # debug_show subtree_size); - assert subtree_size == MemoryBTree.size(btree); + // Debug.print("subtree_size " # debug_show subtree_size); + assert subtree_size == MemoryBTree.size(btree); + + // Debug.print("(i, k, v) -> " # debug_show (i, k, MemoryBTree.get(btree, btree_utils, k))); + if (?i != MemoryBTree.get(btree, btree_utils, k)) { + Debug.print("mismatch: " # debug_show (k, (?i, MemoryBTree.get(btree, btree_utils, k))) # " at index " # debug_show i); + assert false; + }; - // Debug.print("(i, k, v) -> " # debug_show (i, k, MemoryBTree.get(btree, btree_utils, k))); - if (?i != MemoryBTree.get(btree, btree_utils, k)) { - Debug.print("mismatch: " # debug_show (k, (?i, MemoryBTree.get(btree, btree_utils, k))) # " at index " # debug_show i); - assert false; }; - }; + assert Methods.validate_memory(btree, btree_utils); - assert Methods.validate_memory(btree, btree_utils); + // Debug.print("entries: " # debug_show Iter.toArray(MemoryBTree.entries(btree, btree_utils))); - // Debug.print("entries: " # debug_show Iter.toArray(MemoryBTree.entries(btree, btree_utils))); + let entries = MemoryBTree.entries(btree, btree_utils); + let entry = Utils.unwrap(entries.next(), "expected key"); + var prev = entry.0; - let entries = MemoryBTree.entries(btree, btree_utils); - let entry = Utils.unwrap(entries.next(), "expected key"); - var prev = entry.0; + for ((i, (key, val)) in Itertools.enumerate(entries)) { + if (prev > key) { + Debug.print("mismatch: " # debug_show (prev, key) # " at index " # debug_show i); + assert false; + }; - for ((i, (key, val)) in Itertools.enumerate(entries)) { - if (prev > key) { - Debug.print("mismatch: " # debug_show (prev, key) # " at index " # debug_show i); - assert false; - }; + let expected = Map.get(map, nhash, key); + if (expected != ?val) { + Debug.print("mismatch: " # debug_show (key, (expected, val)) # " at index " # debug_show (i + 1)); + assert false; + }; - let expected = Map.get(map, nhash, key); - if (expected != ?val) { - Debug.print("mismatch: " # debug_show (key, (expected, val)) # " at index " # debug_show (i + 1)); - assert false; - }; + if (?val != MemoryBTree.get(btree, btree_utils, key)) { + Debug.print("mismatch: " # debug_show (key, (expected, MemoryBTree.get(btree, btree_utils, key))) # " at index " # debug_show (i + 1)); + assert false; + }; - if (?val != MemoryBTree.get(btree, btree_utils, key)) { - Debug.print("mismatch: " # debug_show (key, (expected, MemoryBTree.get(btree, btree_utils, key))) # " at index " # debug_show (i + 1)); - assert false; + prev := key; }; - prev := key; - }; - - assert Methods.validate_memory(btree, btree_utils); - }, - ); - - test( - "get()", - func() { - var i = 0; - for ((key, val) in random.vals()) { - let got = MemoryBTree.get(btree, btree_utils, key); - if (?val != got) { - Debug.print("mismatch: " # debug_show (val, got) # " at index " # debug_show i); - assert false; - }; - i += 1; - }; - }, - ); - - test( - "getIndex", - func() { - - for (i in Itertools.range(0, sorted.size())) { - let (key, _) = sorted.get(i); - - let expected = i; - let rank = MemoryBTree.getIndex(btree, btree_utils, key); - if (not (rank == expected)) { - Debug.print("mismatch for key:" # debug_show key); - Debug.print("expected != rank: " # debug_show (expected, rank)); - assert false; + assert Methods.validate_memory(btree, btree_utils); + }, + ); + + test( + "get()", + func() { + var i = 0; + for ((key, val) in random.vals()) { + let got = MemoryBTree.get(btree, btree_utils, key); + if (?val != got) { + Debug.print("mismatch: " # debug_show (val, got) # " at index " # debug_show i); + assert false; + }; + i += 1; }; - }; - }, - ); + }, + ); - test( - "getExpectedIndex", - func() { + test( + "getIndex", + func() { - for (i in Itertools.range(0, sorted.size())) { - let (key, _) = sorted.get(i); + for (i in Itertools.range(0, sorted.size())) { + let (key, _) = sorted.get(i); - let expected = #Found(i); - let rank = MemoryBTree.getExpectedIndex(btree, btree_utils, key); - - if (not (rank == expected)) { - Debug.print("getIndex -> " # debug_show (MemoryBTree.getIndex(btree, btree_utils, key))); - Debug.print("mismatch for key:" # debug_show key); - Debug.print("expected != rank: " # debug_show (expected, rank)); - assert false; - }; - }; - - let non_consecutive_range = Itertools.add( - Iter.map( - Iter.filter( - Itertools.slidingTuples(Itertools.range(0, sorted.size())), - func((i, j) : (Nat, Nat)) : Bool = (sorted.get(i).0 + 1) != sorted.get(j).0, - ), - func((i, j) : (Nat, Nat)) : Nat = i, - ), - sorted.size() - 1 : Nat, - ); - - for (i in non_consecutive_range) { - let key = sorted.get(i).0 + 1; - - let expected = #NotFound(i + 1); - let rank = MemoryBTree.getExpectedIndex(btree, btree_utils, key); - - if (not (rank == expected)) { - Debug.print("getIndex -> " # debug_show (MemoryBTree.getIndex(btree, btree_utils, key))); - Debug.print("mismatch for key:" # debug_show key); - Debug.print("expected != rank: " # debug_show (expected, rank)); - assert false; - }; - }; - }, - ); - - test( - "getFromIndex", - func() { - for (i in Itertools.range(0, sorted.size())) { - let expected = sorted.get(i); - let received = MemoryBTree.getFromIndex(btree, btree_utils, i); - - if (not ((expected, expected) == received)) { - Debug.print("mismatch at rank:" # debug_show i); - Debug.print("expected != received: " # debug_show ((expected, expected), received)); - assert false; + let expected = i; + let rank = MemoryBTree.getIndex(btree, btree_utils, key); + if (not (rank == expected)) { + Debug.print("mismatch for key:" # debug_show key); + Debug.print("expected != rank: " # debug_show (expected, rank)); + assert false; + }; }; - }; - }, - ); + }, + ); - test( - "getFloor()", - func() { + test( + "getExpectedIndex", + func() { - for (i in Itertools.range(0, sorted.size())) { - let (key, _) = sorted.get(i); + for (i in Itertools.range(0, sorted.size())) { + let (key, _) = sorted.get(i); - let expected = sorted.get(i); - let received = MemoryBTree.getFloor(btree, btree_utils, key); + let expected = #Found(i); + let rank = MemoryBTree.getExpectedIndex(btree, btree_utils, key); - if (not (?expected == received)) { - Debug.print("equality check failed"); - Debug.print("mismatch at key:" # debug_show key); - Debug.print("expected != received: " # debug_show (expected, received)); - assert false; + if (not (rank == expected)) { + Debug.print("getIndex -> " # debug_show (MemoryBTree.getIndex(btree, btree_utils, key))); + Debug.print("mismatch for key:" # debug_show key); + Debug.print("expected != rank: " # debug_show (expected, rank)); + assert false; + }; }; - let prev = key - 1; + let non_consecutive_range = Itertools.add( + Iter.map( + Iter.filter( + Itertools.slidingTuples(Itertools.range(0, sorted.size())), + func((i, j) : (Nat, Nat)) : Bool = (sorted.get(i).0 + 1) != sorted.get(j).0, + ), + func((i, j) : (Nat, Nat)) : Nat = i, + ), + sorted.size() - 1 : Nat, + ); - if (i > 0) { - let expected = sorted.get(i - 1); - let received = MemoryBTree.getFloor(btree, btree_utils, prev); + for (i in non_consecutive_range) { + let key = sorted.get(i).0 + 1; - if (not (?(expected) == received)) { - Debug.print("prev key failed"); - Debug.print("mismatch at key:" # debug_show prev); - Debug.print("expected != received: " # debug_show (expected, received)); + let expected = #NotFound(i + 1); + let rank = MemoryBTree.getExpectedIndex(btree, btree_utils, key); + + if (not (rank == expected)) { + Debug.print("getIndex -> " # debug_show (MemoryBTree.getIndex(btree, btree_utils, key))); + Debug.print("mismatch for key:" # debug_show key); + Debug.print("expected != rank: " # debug_show (expected, rank)); assert false; }; - } else { - assert MemoryBTree.getFloor(btree, btree_utils, prev) == null; }; + }, + ); + + test( + "getFromIndex", + func() { + for (i in Itertools.range(0, sorted.size())) { + let expected = sorted.get(i); + let received = MemoryBTree.getFromIndex(btree, btree_utils, i); + + if (not ((expected, expected) == received)) { + Debug.print("mismatch at rank:" # debug_show i); + Debug.print("expected != received: " # debug_show ((expected, expected), received)); + assert false; + }; + }; + }, + ); + + test( + "getFloor()", + func() { - let next = key + 1; + for (i in Itertools.range(0, sorted.size())) { + let (key, _) = sorted.get(i); - do { - let expected = if (i + 1 < sorted.size() and sorted.get(i + 1).0 == next) sorted.get(i + 1) else sorted.get(i); - let received = MemoryBTree.getFloor(btree, btree_utils, next); + let expected = sorted.get(i); + let received = MemoryBTree.getFloor(btree, btree_utils, key); if (not (?expected == received)) { - Debug.print("next key failed"); - Debug.print("mismatch at key:" # debug_show next); + Debug.print("equality check failed"); + Debug.print("mismatch at key:" # debug_show key); Debug.print("expected != received: " # debug_show (expected, received)); assert false; }; - }; - }; - }, - ); + let prev = key - 1; + + if (i > 0) { + let expected = sorted.get(i - 1); + let received = MemoryBTree.getFloor(btree, btree_utils, prev); + + if (not (?(expected) == received)) { + Debug.print("prev key failed"); + Debug.print("mismatch at key:" # debug_show prev); + Debug.print("expected != received: " # debug_show (expected, received)); + assert false; + }; + } else { + assert MemoryBTree.getFloor(btree, btree_utils, prev) == null; + }; + + let next = key + 1; - test( - "getCeiling()", - func() { - for (i in Itertools.range(0, sorted.size())) { - var key = sorted.get(i).0; + do { + let expected = if (i + 1 < sorted.size() and sorted.get(i + 1).0 == next) sorted.get(i + 1) else sorted.get(i); + let received = MemoryBTree.getFloor(btree, btree_utils, next); - let expected = sorted.get(i); - let received = MemoryBTree.getCeiling(btree, btree_utils, key); + if (not (?expected == received)) { + Debug.print("next key failed"); + Debug.print("mismatch at key:" # debug_show next); + Debug.print("expected != received: " # debug_show (expected, received)); + assert false; + }; + }; - if (not (?expected == received)) { - Debug.print("equality check failed"); - Debug.print("mismatch at key:" # debug_show key); - Debug.print("expected != received: " # debug_show (expected, received)); - assert false; }; + }, + ); - let prev = key - 1; + test( + "getCeiling()", + func() { + for (i in Itertools.range(0, sorted.size())) { + var key = sorted.get(i).0; - do { - let expected = if (i > 0 and sorted.get(i - 1).0 == prev) sorted.get(i - 1) else sorted.get(i); - let received = MemoryBTree.getCeiling(btree, btree_utils, prev); + let expected = sorted.get(i); + let received = MemoryBTree.getCeiling(btree, btree_utils, key); if (not (?expected == received)) { - Debug.print("prev key failed"); - Debug.print("mismatch at key:" # debug_show prev); + Debug.print("equality check failed"); + Debug.print("mismatch at key:" # debug_show key); Debug.print("expected != received: " # debug_show (expected, received)); assert false; }; - }; - let next = key + 1; + let prev = key - 1; - if (i + 1 < sorted.size()) { - let expected = sorted.get(i + 1); - let received = MemoryBTree.getCeiling(btree, btree_utils, next); + do { + let expected = if (i > 0 and sorted.get(i - 1).0 == prev) sorted.get(i - 1) else sorted.get(i); + let received = MemoryBTree.getCeiling(btree, btree_utils, prev); - if (not (?expected == received)) { - Debug.print("next key failed"); - Debug.print("mismatch at key:" # debug_show next); - Debug.print("expected != received: " # debug_show (expected, received)); + if (not (?expected == received)) { + Debug.print("prev key failed"); + Debug.print("mismatch at key:" # debug_show prev); + Debug.print("expected != received: " # debug_show (expected, received)); + assert false; + }; + }; + + let next = key + 1; + + if (i + 1 < sorted.size()) { + let expected = sorted.get(i + 1); + let received = MemoryBTree.getCeiling(btree, btree_utils, next); + + if (not (?expected == received)) { + Debug.print("next key failed"); + Debug.print("mismatch at key:" # debug_show next); + Debug.print("expected != received: " # debug_show (expected, received)); + assert false; + }; + } else { + assert MemoryBTree.getCeiling(btree, btree_utils, next) == null; + }; + + }; + }, + ); + test( + "entries()", + func() { + var i = 0; + for ((a, b) in Itertools.zip(MemoryBTree.entries(btree, btree_utils), sorted.vals())) { + if (a != b) { + Debug.print("mismatch: " # debug_show (a, b) # " at index " # debug_show i); assert false; }; - } else { - assert MemoryBTree.getCeiling(btree, btree_utils, next) == null; + i += 1; }; - }; - }, - ); - test( - "entries()", - func() { - var i = 0; - for ((a, b) in Itertools.zip(MemoryBTree.entries(btree, btree_utils), sorted.vals())) { - if (a != b) { - Debug.print("mismatch: " # debug_show (a, b) # " at index " # debug_show i); - assert false; - }; - i += 1; - }; + assert i == sorted.size(); - assert i == sorted.size(); + assert Methods.validate_memory(btree, btree_utils); - assert Methods.validate_memory(btree, btree_utils); + }, + ); - }, - ); + test( + "scan", + func() { + let sliding_tuples = Itertools.range(0, MemoryBTree.size(btree)) + |> Iter.map(_, func(n : Nat) : Nat = n * 100) + |> Itertools.takeWhile(_, func(n : Nat) : Bool = n < MemoryBTree.size(btree)) + |> Itertools.slidingTuples(_); - test( - "scan", - func() { - let sliding_tuples = Itertools.range(0, MemoryBTree.size(btree)) - |> Iter.map(_, func(n : Nat) : Nat = n * 100) - |> Itertools.takeWhile(_, func(n : Nat) : Bool = n < MemoryBTree.size(btree)) - |> Itertools.slidingTuples(_); + for ((i, j) in sliding_tuples) { + let start_key = sorted.get(i).0; + let end_key = sorted.get(j).0; - for ((i, j) in sliding_tuples) { - let start_key = sorted.get(i).0; - let end_key = sorted.get(j).0; + var index = i; - var index = i; + for ((k, v) in MemoryBTree.scan(btree, btree_utils, ?start_key, ?end_key)) { + let expected = sorted.get(index).0; - for ((k, v) in MemoryBTree.scan(btree, btree_utils, ?start_key, ?end_key)) { - let expected = sorted.get(index).0; + if (not (expected == k)) { + Debug.print("mismatch: " # debug_show (expected, k)); + Debug.print("scan " # debug_show Iter.toArray(MemoryBTree.scan(btree, btree_utils, ?start_key, ?end_key))); - if (not (expected == k)) { - Debug.print("mismatch: " # debug_show (expected, k)); - Debug.print("scan " # debug_show Iter.toArray(MemoryBTree.scan(btree, btree_utils, ?start_key, ?end_key))); + let expected_vals = Iter.range(i, j) + |> Iter.map(_, func(n : Nat) : Nat = sorted.get(n).1); + Debug.print("expected " # debug_show Iter.toArray(expected_vals)); + assert false; + }; - let expected_vals = Iter.range(i, j) - |> Iter.map(_, func(n : Nat) : Nat = sorted.get(n).1); - Debug.print("expected " # debug_show Iter.toArray(expected_vals)); - assert false; + index += 1; }; - - index += 1; }; - }; - }, - ); - - test( - "range", - func() { - let sliding_tuples = Itertools.range(0, MemoryBTree.size(btree)) - |> Iter.map(_, func(n : Nat) : Nat = n * 100) - |> Itertools.takeWhile(_, func(n : Nat) : Bool = n < MemoryBTree.size(btree)) - |> Itertools.slidingTuples(_); - - let sorted_array = Buffer.toArray(sorted); - - for ((i, j) in sliding_tuples) { - - if ( - not Itertools.equal<(Nat, Nat)>( - MemoryBTree.range(btree, btree_utils, i, j), - Itertools.fromArraySlice<(Nat, Nat)>(sorted_array, i, j), - func(a : (Nat, Nat), b : (Nat, Nat)) : Bool = a == b, - ) - ) { - Debug.print("mismatch: " # debug_show (i, j)); - Debug.print("range " # debug_show Iter.toArray(MemoryBTree.range(btree, btree_utils, i, j))); - Debug.print("expected " # debug_show Iter.toArray(Itertools.fromArraySlice(sorted_array, i, j))); - assert false; + }, + ); + + test( + "range", + func() { + let sliding_tuples = Itertools.range(0, MemoryBTree.size(btree)) + |> Iter.map(_, func(n : Nat) : Nat = n * 100) + |> Itertools.takeWhile(_, func(n : Nat) : Bool = n < MemoryBTree.size(btree)) + |> Itertools.slidingTuples(_); + + let sorted_array = Buffer.toArray(sorted); + + for ((i, j) in sliding_tuples) { + + if ( + not Itertools.equal<(Nat, Nat)>( + MemoryBTree.range(btree, btree_utils, i, j), + Itertools.fromArraySlice<(Nat, Nat)>(sorted_array, i, j), + func(a : (Nat, Nat), b : (Nat, Nat)) : Bool = a == b, + ) + ) { + Debug.print("mismatch: " # debug_show (i, j)); + Debug.print("range " # debug_show Iter.toArray(MemoryBTree.range(btree, btree_utils, i, j))); + Debug.print("expected " # debug_show Iter.toArray(Itertools.fromArraySlice(sorted_array, i, j))); + assert false; + }; }; - }; - }, - ); + }, + ); - test( - "replace", - func() { - let size = MemoryBTree.size(btree); - let mem_blocks = Buffer.Buffer<(MemoryBlock, MemoryBlock)>(8); - let blobs = Buffer.Buffer<(Blob, Blob)>(8); - assert Methods.validate_memory(btree, btree_utils); + test( + "replace", + func() { + let size = MemoryBTree.size(btree); + let mem_blocks = Buffer.Buffer<(MemoryBlock, MemoryBlock)>(8); + let blobs = Buffer.Buffer<(Blob, Blob)>(8); + assert Methods.validate_memory(btree, btree_utils); - for ((key, i) in random.vals()) { + for ((key, i) in random.vals()) { - let prev_val = i; - let new_val = 1 + prev_val * 10; + let prev_val = i; + let new_val = 1 + prev_val * 10; - // Debug.print("replacing " # debug_show key # " at index " # debug_show i # " with " # debug_show new_val); - // Debug.print("tree before insert: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); - // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); + // Debug.print("replacing " # debug_show key # " at index " # debug_show i # " with " # debug_show new_val); + // Debug.print("tree before insert: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); + // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); - let ?prev_id = MemoryBTree.getId(btree, btree_utils, key); - assert ?(key, prev_val) == MemoryBTree.lookup(btree, btree_utils, prev_id); - let ?mem_block = MemoryBTree._lookup_mem_block(btree, prev_id); - let prev_key_blob = MemoryRegion.loadBlob(btree.data, mem_block.0.0, mem_block.0.1); - let prev_val_blob = MemoryRegion.loadBlob(btree.data, mem_block.1.0, mem_block.1.1); - // MemoryBTree._lookup_val_blob(btree, prev_id); + let ?prev_id = MemoryBTree.getId(btree, btree_utils, key); + assert ?(key, prev_val) == MemoryBTree.lookup(btree, btree_utils, prev_id); + let ?mem_block = MemoryBTree._lookup_mem_block(btree, prev_id); + let prev_key_blob = MemoryRegion.loadBlob(btree.data, mem_block.0.0, mem_block.0.1); + let prev_val_blob = MemoryRegion.loadBlob(btree.data, mem_block.1.0, mem_block.1.1); + // MemoryBTree._lookup_val_blob(btree, prev_id); - assert ?prev_val == MemoryBTree.insert(btree, btree_utils, key, new_val); + assert ?prev_val == MemoryBTree.insert(btree, btree_utils, key, new_val); - let ?id = MemoryBTree.getId(btree, btree_utils, key); + let ?id = MemoryBTree.getId(btree, btree_utils, key); - assert ?new_val == MemoryBTree.get(btree, btree_utils, key); + assert ?new_val == MemoryBTree.get(btree, btree_utils, key); - let ?new_mem_block = MemoryBTree._lookup_mem_block(btree, id); - // Debug.print("id at test: " # debug_show id); + let ?new_mem_block = MemoryBTree._lookup_mem_block(btree, id); + // Debug.print("id at test: " # debug_show id); - // Debug.print("new entry: " # debug_show (key, new_val)); - assert ?(key, new_val) == MemoryBTree.lookup(btree, btree_utils, id); - assert prev_key_blob == MemoryRegion.loadBlob(btree.data, new_mem_block.0.0, new_mem_block.0.1); - let new_val_blob = btree_utils.value.blobify.to_blob(new_val); + // Debug.print("new entry: " # debug_show (key, new_val)); + assert ?(key, new_val) == MemoryBTree.lookup(btree, btree_utils, id); + assert prev_key_blob == MemoryRegion.loadBlob(btree.data, new_mem_block.0.0, new_mem_block.0.1); + let new_val_blob = btree_utils.value.blobify.to_blob(new_val); - let recieved_val_blob = MemoryRegion.loadBlob(btree.values, new_mem_block.1.0, new_mem_block.1.1); - // Debug.print("new_val_mem_block: " # debug_show new_mem_block.1); - // Debug.print("new_val_blob (recieved, expected) " # debug_show (recieved_val_blob, new_val_blob)); - assert new_val_blob == recieved_val_blob; + let recieved_val_blob = MemoryRegion.loadBlob(btree.values, new_mem_block.1.0, new_mem_block.1.1); + // Debug.print("new_val_mem_block: " # debug_show new_mem_block.1); + // Debug.print("new_val_blob (recieved, expected) " # debug_show (recieved_val_blob, new_val_blob)); + assert new_val_blob == recieved_val_blob; - mem_blocks.add(new_mem_block); - blobs.add((prev_key_blob, new_val_blob)); + mem_blocks.add(new_mem_block); + blobs.add((prev_key_blob, new_val_blob)); - if (i > 0) { - let ?left_id = MemoryBTree.getId(btree, btree_utils, random.get(i - 1).0); - let ?left_key_blob = MemoryBTree._lookup_key_blob(btree, left_id); - let ?left_val_blob = MemoryBTree._lookup_val_blob(btree, left_id); + if (i > 0) { + let ?left_id = MemoryBTree.getId(btree, btree_utils, random.get(i - 1).0); + let ?left_key_blob = MemoryBTree._lookup_key_blob(btree, left_id); + let ?left_val_blob = MemoryBTree._lookup_val_blob(btree, left_id); - let ?left_mem_block = MemoryBTree._lookup_mem_block(btree, left_id); + let ?left_mem_block = MemoryBTree._lookup_mem_block(btree, left_id); - let left_blob_entry = (left_key_blob, left_val_blob); - let expected_blob_entry = blobs.get(i - 1); + let left_blob_entry = (left_key_blob, left_val_blob); + let expected_blob_entry = blobs.get(i - 1); - if (left_blob_entry != expected_blob_entry) { - Debug.print("blob entry mismatch: " # debug_show (left_blob_entry, expected_blob_entry) # " at index " # debug_show (i - 1)); - Debug.print("left_mem_block " # debug_show left_mem_block); - Debug.print(debug_show Buffer.toArray(mem_blocks)); - assert false; + if (left_blob_entry != expected_blob_entry) { + Debug.print("blob entry mismatch: " # debug_show (left_blob_entry, expected_blob_entry) # " at index " # debug_show (i - 1)); + Debug.print("left_mem_block " # debug_show left_mem_block); + Debug.print(debug_show Buffer.toArray(mem_blocks)); + assert false; + }; }; - }; - // Debug.print("tree after insert: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); - // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); + // Debug.print("tree after insert: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); + // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); - assert MemoryBTree.size(btree) == size; - }; + assert MemoryBTree.size(btree) == size; + }; - assert Methods.validate_memory(btree, btree_utils); + assert Methods.validate_memory(btree, btree_utils); - var i = 0; - for ((key, _val) in random.vals()) { - let val = 1 + _val * 10; - let received = MemoryBTree.get(btree, btree_utils, key); - let ?id = MemoryBTree.getId(btree, btree_utils, key); - let ?mem_block = MemoryBTree._lookup_mem_block(btree, id); - let expected_mem_block = mem_blocks.get(i); + var i = 0; + for ((key, _val) in random.vals()) { + let val = 1 + _val * 10; + let received = MemoryBTree.get(btree, btree_utils, key); + let ?id = MemoryBTree.getId(btree, btree_utils, key); + let ?mem_block = MemoryBTree._lookup_mem_block(btree, id); + let expected_mem_block = mem_blocks.get(i); - let ?(received_key_blob) = MemoryBTree._lookup_key_blob(btree, id); - let ?(received_val_blob) = MemoryBTree._lookup_val_blob(btree, id); - let recieved_blob_entry = (received_key_blob, received_val_blob); + let ?(received_key_blob) = MemoryBTree._lookup_key_blob(btree, id); + let ?(received_val_blob) = MemoryBTree._lookup_val_blob(btree, id); + let recieved_blob_entry = (received_key_blob, received_val_blob); - let expected_blob_entry = blobs.get(i); + let expected_blob_entry = blobs.get(i); - if (recieved_blob_entry != expected_blob_entry) { - Debug.print("blob entry mismatch: " # debug_show (recieved_blob_entry, expected_blob_entry) # " at index " # debug_show i); - Debug.print(debug_show Buffer.toArray(mem_blocks)); - assert false; - }; + if (recieved_blob_entry != expected_blob_entry) { + Debug.print("blob entry mismatch: " # debug_show (recieved_blob_entry, expected_blob_entry) # " at index " # debug_show i); + Debug.print(debug_show Buffer.toArray(mem_blocks)); + assert false; + }; - assert mem_block == expected_mem_block; - if (?val != received) { - Debug.print("mismatch (recieved, expected) " # debug_show (received, val) # " at index " # debug_show i); - assert false; + assert mem_block == expected_mem_block; + if (?val != received) { + Debug.print("mismatch (recieved, expected) " # debug_show (received, val) # " at index " # debug_show i); + assert false; + }; + i += 1; }; - i += 1; - }; - }, - ); + }, + ); - test( - "remove() random", - func() { + test( + "remove() random", + func() { - // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); - // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); + // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); + // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); - for ((key, i) in random.vals()) { - // Debug.print("removing " # debug_show key); - let val = MemoryBTree.remove(btree, btree_utils, key); - // Debug.print("(i, val): " # debug_show (i, val)); - assert ?(1 + i * 10) == val; + for ((key, i) in random.vals()) { + // Debug.print("removing " # debug_show key); + let val = MemoryBTree.remove(btree, btree_utils, key); + // Debug.print("(i, val): " # debug_show (i, val)); + assert ?(1 + i * 10) == val; - assert MemoryBTree.size(btree) == random.size() - i - 1; - // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); - // Debug.print("leaf nodes: " # debug_show Iter.toArray(MemoryBTree.leafNodes(btree, btree_utils))); - }; + assert MemoryBTree.size(btree) == random.size() - i - 1; + // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); + // Debug.print("leaf nodes: " # debug_show Iter.toArray(MemoryBTree.leafNodes(btree, btree_utils))); + }; - assert Methods.validate_memory(btree, btree_utils); + assert Methods.validate_memory(btree, btree_utils); - }, + }, - ); + ); - test( - "clear()", - func() { - MemoryBTree.clear(btree); - assert MemoryBTree.size(btree) == 0; + test( + "clear()", + func() { + MemoryBTree.clear(btree); + assert MemoryBTree.size(btree) == 0; - assert Methods.validate_memory(btree, btree_utils); + assert Methods.validate_memory(btree, btree_utils); - MemoryBTree.clear(btree); - assert MemoryBTree.size(btree) == 0; + MemoryBTree.clear(btree); + assert MemoryBTree.size(btree) == 0; - assert Methods.validate_memory(btree, btree_utils); - }, - ); + assert Methods.validate_memory(btree, btree_utils); + }, + ); - test( - "insert random", - func() { - let map = Map.new(); - // assert btree.order == 4; + test( + "insert random", + func() { + let map = Map.new(); + // assert btree.order == 4; - // Debug.print("random size " # debug_show random.size()); - label for_loop for ((k, i) in random.vals()) { + // Debug.print("random size " # debug_show random.size()); + label for_loop for ((k, i) in random.vals()) { - ignore Map.put(map, nhash, k, i); - ignore MemoryBTree.insert(btree, btree_utils, k, i); - assert MemoryBTree.size(btree) == i + 1; + ignore Map.put(map, nhash, k, i); + ignore MemoryBTree.insert(btree, btree_utils, k, i); + assert MemoryBTree.size(btree) == i + 1; - // Debug.print("keys " # debug_show MemoryBTree.toNodeKeys(btree)); - // Debug.print("leafs " # debug_show MemoryBTree.toLeafNodes(btree)); + // Debug.print("keys " # debug_show MemoryBTree.toNodeKeys(btree)); + // Debug.print("leafs " # debug_show MemoryBTree.toLeafNodes(btree)); - let subtree_size = if (btree.is_root_a_leaf) Leaf.get_count(btree, btree.root) else Branch.get_subtree_size(btree, btree.root); + let subtree_size = if (btree.is_root_a_leaf) Leaf.get_count(btree, btree.root) else Branch.get_subtree_size(btree, btree.root); - assert subtree_size == MemoryBTree.size(btree); + assert subtree_size == MemoryBTree.size(btree); - if (?i != MemoryBTree.get(btree, btree_utils, k)) { - Debug.print("mismatch: " # debug_show (k, (i, MemoryBTree.get(btree, btree_utils, k))) # " at index " # debug_show i); - assert false; + if (?i != MemoryBTree.get(btree, btree_utils, k)) { + Debug.print("mismatch: " # debug_show (k, (i, MemoryBTree.get(btree, btree_utils, k))) # " at index " # debug_show i); + assert false; + }; }; - }; - // Debug.print("entries: " # debug_show Iter.toArray(MemoryBTree.entries(btree, btree_utils))); + // Debug.print("entries: " # debug_show Iter.toArray(MemoryBTree.entries(btree, btree_utils))); - let entries = MemoryBTree.entries(btree, btree_utils); - let entry = Utils.unwrap(entries.next(), "expected key"); - var prev = entry.0; + let entries = MemoryBTree.entries(btree, btree_utils); + let entry = Utils.unwrap(entries.next(), "expected key"); + var prev = entry.0; - for ((i, (key, val)) in Itertools.enumerate(entries)) { - if (prev > key) { - Debug.print("mismatch: " # debug_show (prev, key) # " at index " # debug_show i); - assert false; - }; + for ((i, (key, val)) in Itertools.enumerate(entries)) { + if (prev > key) { + Debug.print("mismatch: " # debug_show (prev, key) # " at index " # debug_show i); + assert false; + }; - let expected = Map.get(map, nhash, key); - if (expected != ?val) { - Debug.print("mismatch: " # debug_show (key, (expected, val)) # " at index " # debug_show (i + 1)); - assert false; - }; + let expected = Map.get(map, nhash, key); + if (expected != ?val) { + Debug.print("mismatch: " # debug_show (key, (expected, val)) # " at index " # debug_show (i + 1)); + assert false; + }; + + if (?val != MemoryBTree.get(btree, btree_utils, key)) { + Debug.print("mismatch: " # debug_show (key, (expected, MemoryBTree.get(btree, btree_utils, key))) # " at index " # debug_show (i + 1)); + assert false; + }; - if (?val != MemoryBTree.get(btree, btree_utils, key)) { - Debug.print("mismatch: " # debug_show (key, (expected, MemoryBTree.get(btree, btree_utils, key))) # " at index " # debug_show (i + 1)); - assert false; + prev := key; }; - prev := key; - }; + assert Methods.validate_memory(btree, btree_utils); - assert Methods.validate_memory(btree, btree_utils); + }, + ); - }, - ); + test( + "remove()", + func() { - test( - "remove()", - func() { + // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); + // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); - // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); - // Debug.print("leaf nodes: " # debug_show MemoryBTree.toLeafNodes(btree, btree_utils)); + for ((key, i) in random.vals()) { + // Debug.print("removing " # debug_show key); + let val = MemoryBTree.remove(btree, btree_utils, key); + // Debug.print("(i, val): " # debug_show (i, val)); + assert ?i == val; - for ((key, i) in random.vals()) { - // Debug.print("removing " # debug_show key); - let val = MemoryBTree.remove(btree, btree_utils, key); - // Debug.print("(i, val): " # debug_show (i, val)); - assert ?i == val; + assert MemoryBTree.size(btree) == random.size() - i - 1; + // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); + // Debug.print("leaf nodes: " # debug_show Iter.toArray(MemoryBTree.leafNodes(btree, btree_utils))); + }; - assert MemoryBTree.size(btree) == random.size() - i - 1; - // Debug.print("node keys: " # debug_show MemoryBTree.toNodeKeys(btree, btree_utils)); - // Debug.print("leaf nodes: " # debug_show Iter.toArray(MemoryBTree.leafNodes(btree, btree_utils))); - }; + assert Methods.validate_memory(btree, btree_utils); - assert Methods.validate_memory(btree, btree_utils); + }, - }, + ); - ); + test( + "clear() after the btree has been re-populated", + func() { + MemoryBTree.clear(btree); + assert MemoryBTree.size(btree) == 0; - test( - "clear() after the btree has been re-populated", - func() { - MemoryBTree.clear(btree); - assert MemoryBTree.size(btree) == 0; + assert Methods.validate_memory(btree, btree_utils); - assert Methods.validate_memory(btree, btree_utils); + MemoryBTree.clear(btree); + assert MemoryBTree.size(btree) == 0; - MemoryBTree.clear(btree); - assert MemoryBTree.size(btree) == 0; + assert Methods.validate_memory(btree, btree_utils); + }, - assert Methods.validate_memory(btree, btree_utils); - }, + ); - ); + }, + ); +}; - }, -); +for (node_capacity in [4, 8, 32, 1024, 4028].vals()) { + suite( + "MemoryBTree with node capacity " # debug_show (node_capacity), + func() { + btree_tests(node_capacity); + }, + ); +}; 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/MemoryBTree/TypeUtils/BigEndian.BackwardCompatible.Nat.Test.mo b/tests/MemoryBTree/TypeUtils/BigEndian.BackwardCompatible.Nat.Test.mo new file mode 100644 index 0000000..8f26eda --- /dev/null +++ b/tests/MemoryBTree/TypeUtils/BigEndian.BackwardCompatible.Nat.Test.mo @@ -0,0 +1,67 @@ +// @testmode wasi +import Prim "mo:prim"; + +import Array "mo:base@.v0.14.11/Array"; +import Nat8 "mo:base@.v0.14.11/Nat8"; +import Blob "mo:base@.v0.14.11/Blob"; +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 Iter "mo:base@.v0.14.11/Iter"; +import Buffer "mo:base@.v0.14.11/Buffer"; +import { test; suite } "mo:test@.v2.1.1"; + +import Fuzz "mo:fuzz@.v1.0.0"; +import Itertools "mo:itertools@.v0.2.2/Iter"; + +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"; + +let legacy_btree = MemoryBTree.new(?32); +let legacy_btree_utils = MemoryBTree.createUtils(TypeUtils.Legacy.BigEndian.Nat, TypeUtils.Legacy.Nat); + +let btree = MemoryBTree.new(?32); +let btree_utils = MemoryBTree.createUtils(TypeUtils.Nat, TypeUtils.Nat); + +let fuzz = Fuzz.fromSeed(0x29); + +suite( + "MemoryBTree Big Endian TypeUtils Test", + func() { + let sorted = Buffer.Buffer<(Nat, Nat)>(10_000); + + test( + "Ensure legacy and current serializers are sorted correctly", + func() { + + for (i in Iter.range(0, 10)) { + let key = fuzz.nat.randomRange(0, (2 ** 64) - 1); + let val = fuzz.nat.randomRange(0, (2 ** 64) - 1); + + ignore MemoryBTree.insert(legacy_btree, legacy_btree_utils, key, val); + ignore MemoryBTree.insert(btree, btree_utils, key, val); + sorted.add((key, val)); + }; + + sorted.sort(func(a, b) = Nat.compare(a.0, b.0)); + + assert Itertools.equal( + MemoryBTree.entries(legacy_btree, legacy_btree_utils), + sorted.vals(), + func(a : (Nat, Nat), b : (Nat, Nat)) : Bool = a.0 == b.0 and a.1 == b.1, + ); + + assert Itertools.equal( + MemoryBTree.entries(btree, btree_utils), + sorted.vals(), + func(a : (Nat, Nat), b : (Nat, Nat)) : Bool = a.0 == b.0 and a.1 == b.1, + ); + }, + ); + + }, +); 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; }, );