Skip to content

Commit

Permalink
Merge master into next-moc
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] authored Nov 24, 2022
2 parents 3d71981 + 384ac49 commit 75547ec
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 46 deletions.
67 changes: 22 additions & 45 deletions src/Trie.mo
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
// list.
//

import Debug "mo:base/Debug";

import Prim "mo:⛔";
import P "Prelude";
import Option "Option";
Expand Down Expand Up @@ -129,44 +131,25 @@ module {
}
};

/// Checks the invariants of the trie structure, including the placement of keys at trie paths
public func isValid<K, V>(t : Trie<K, V>, enforceNormal : Bool) : Bool {
/// @deprecated `isValid` is an internal predicate and will be removed in future.
public func isValid<K, V>(t : Trie<K, V>, _enforceNormal : Bool) : Bool {
func rec(t : Trie<K, V>, bitpos : ?Hash.Hash, bits : Hash.Hash, mask : Hash.Hash) : Bool {
switch t {
case (#empty) {
switch bitpos {
case null { true };
case (?_) { not enforceNormal };
}
true;
};
case (#leaf(l)) {
let len = List.size(l.keyvals);
((len <= MAX_LEAF_SIZE) or (not enforceNormal))
len <= MAX_LEAF_SIZE + 1
and
len == l.size
len == l.size
and
( List.all(
List.all(
l.keyvals,
func ((k : Key<K>, v : V)) : Bool {
// { Prim.debugPrint "testing hash..."; true }
// and
((k.hash & mask) == bits)
// or
// (do {
// Prim.debugPrint("\nmalformed hash!:\n");
// Prim.debugPrintInt(Prim.nat32ToNat(k.hash));
// Prim.debugPrint("\n (key hash) != (path bits): \n");
// Prim.debugPrintInt(Prim.nat32ToNat(bits));
// Prim.debugPrint("\nmask : ");
// Prim.debugPrintInt(Prim.nat32ToNat(mask));
// Prim.debugPrint("\n");
// false
// })
}
)
// or
// (do { Prim.debugPrint("one or more hashes are malformed"); false })
)
}
)
};
case (#branch(b)) {
let bitpos1 =
Expand All @@ -177,12 +160,8 @@ module {
let mask1 = mask | (Prim.natToNat32(1) << bitpos1);
let bits1 = bits | (Prim.natToNat32(1) << bitpos1);
let sum = size(b.left) + size(b.right);
(b.size == sum
// or (do { Prim.debugPrint("malformed size"); false })
)
and
rec(b.left, ?bitpos1, bits, mask1)
and
(b.size == sum) and
rec(b.left, ?bitpos1, bits, mask1) and
rec(b.right, ?bitpos1, bits1, mask1)
};
}
Expand Down Expand Up @@ -981,12 +960,11 @@ module {
case (#branch(b)) {
let fl = rec(b.left, bitpos + 1);
let fr = rec(b.right, bitpos + 1);
switch (isEmpty(fl), isEmpty(fr)) {
case (true, true) { #empty };
case (false, true) { fl };
case (true, false) { fr };
case (false, false) { branch(fl, fr) };
};
if (isEmpty(fl) and isEmpty(fr)) {
#empty
} else {
branch(fl, fr)
}
}
}
};
Expand Down Expand Up @@ -1016,12 +994,11 @@ module {
case (#branch(b)) {
let fl = rec(b.left, bitpos + 1);
let fr = rec(b.right, bitpos + 1);
switch (isEmpty(fl), isEmpty(fr)) {
case (true, true) { #empty };
case (false, true) { fl };
case (true, false) { fr };
case (false, false) { branch(fl, fr) };
};
if (isEmpty(fl) and isEmpty(fr)) {
#empty
} else {
branch(fl, fr)
}
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion test/TrieExampleTest.mo
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ debug {
func equalKV(a : (Text, Nat), b : (Text, Nat)) : Bool { a == b };
assert (isSubSet(actual, expected, equalKV));
assert (isSubSet(expected, actual, equalKV));
assert (Trie.isValid(t2, true));
assert Trie.isValid(t2, false);
};
66 changes: 66 additions & 0 deletions test/trieTest.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import Trie "mo:base/Trie";
import Nat "mo:base/Nat";
import Option "mo:base/Option";
import Iter "mo:base/Iter";
import Text "mo:base/Text";
import Debug "mo:base/Debug";

debug {
type Trie<K, V> = Trie.Trie<K, V>;
type Key<K> = Trie.Key<K>;

func key(i: Nat) : Key<Text> {
let t = Nat.toText i;
{ key = t ; hash = Text.hash t }
};

let max = 100;

// put k-v elements, one by one (but hashes are expected random).
Debug.print "Trie.put";
var t : Trie<Text, Nat> = Trie.empty();
for (i in Iter.range(0, max - 1)) {
let (t1_, x) = Trie.put<Text, Nat>(t, key i, Text.equal, i);
assert (Option.isNull(x));
assert Trie.isValid(t1_, false);
t := t1_;
};
assert Trie.size(t) == max;

// remove all elements, one by one (but hashes are expected random).
do {
Debug.print "Trie.remove";
var t1 = t;
for (i in Iter.range(0, max - 1)) {
let (t1_, x) = Trie.remove<Text, Nat>(t1, key i, Text.equal);
assert Trie.isValid(t1_, false);
assert (Option.isSome(x));
t1 := t1_;
}
};

// filter all elements away, one by one (but hashes are expected random).
do {
Debug.print "Trie.filter";
var t1 = t;
for (i in Iter.range(0, max - 1)) {
t1 := Trie.filter (t1, func (t : Text, n : Nat) : Bool { n != i } );
assert Trie.isValid(t1, false);
assert Trie.size(t1) == (max - (i + 1) : Nat);
}
};

// filter-map all elements away, one by one (but hashes are expected random).
do {
Debug.print "Trie.mapFilter";
var t1 = t;
for (i in Iter.range(0, max - 1)) {
t1 := Trie.mapFilter (t1,
func (t : Text, n : Nat) : ?Nat {
if (n != i) ?n else null }
);
assert Trie.isValid(t1, false);
assert Trie.size(t1) == (max - (i + 1) : Nat);
}
}
};

0 comments on commit 75547ec

Please sign in to comment.