diff --git a/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md b/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md index 94c90af960da1..be91446074592 100644 --- a/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md +++ b/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md @@ -33,10 +33,12 @@ allowing cleaner iterator APIs. - [Constants](#@Constants_0) - [Function `new`](#0x1_big_ordered_map_new) - [Function `new_with_config`](#0x1_big_ordered_map_new_with_config) +- [Function `new_from`](#0x1_big_ordered_map_new_from) - [Function `destroy_empty`](#0x1_big_ordered_map_destroy_empty) - [Function `add`](#0x1_big_ordered_map_add) - [Function `upsert`](#0x1_big_ordered_map_upsert) - [Function `remove`](#0x1_big_ordered_map_remove) +- [Function `add_all`](#0x1_big_ordered_map_add_all) - [Function `lower_bound`](#0x1_big_ordered_map_lower_bound) - [Function `find`](#0x1_big_ordered_map_find) - [Function `contains`](#0x1_big_ordered_map_contains) @@ -46,7 +48,9 @@ allowing cleaner iterator APIs. - [Function `new_end_iter`](#0x1_big_ordered_map_new_end_iter) - [Function `iter_is_begin`](#0x1_big_ordered_map_iter_is_begin) - [Function `iter_is_end`](#0x1_big_ordered_map_iter_is_end) -- [Function `iter_get_key`](#0x1_big_ordered_map_iter_get_key) +- [Function `iter_borrow_key`](#0x1_big_ordered_map_iter_borrow_key) +- [Function `iter_borrow`](#0x1_big_ordered_map_iter_borrow) +- [Function `iter_borrow_mut`](#0x1_big_ordered_map_iter_borrow_mut) - [Function `iter_next`](#0x1_big_ordered_map_iter_next) - [Function `iter_prev`](#0x1_big_ordered_map_iter_prev) - [Function `borrow_node`](#0x1_big_ordered_map_borrow_node) @@ -208,7 +212,7 @@ An iterator to iterate all keys in the BigOrderedMap. TODO: Once fields can be (mutable) references, this class will be deprecated. -
enum IteratorPtr<K> has drop
+
enum IteratorPtr<K> has copy, drop
 
@@ -433,7 +437,7 @@ Map key is not found Trying to insert too large of an object into the mp. -
const EARGUMENT_BYTES_TOO_LARGE: u64 = 6;
+
const EARGUMENT_BYTES_TOO_LARGE: u64 = 13;
 
@@ -444,7 +448,7 @@ borrow_mut requires that key and value types have constant size (otherwise it wouldn't be able to guarantee size requirements are not violated) -
const EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE: u64 = 7;
+
const EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE: u64 = 14;
 
@@ -454,7 +458,7 @@ borrow_mut requires that key and value types have constant size The provided configuration parameter is invalid. -
const EINVALID_CONFIG_PARAMETER: u64 = 4;
+
const EINVALID_CONFIG_PARAMETER: u64 = 11;
 
@@ -464,7 +468,7 @@ The provided configuration parameter is invalid. Map isn't empty -
const EMAP_NOT_EMPTY: u64 = 5;
+
const EMAP_NOT_EMPTY: u64 = 12;
 
@@ -545,8 +549,8 @@ it is important to compute and pass inner_max_degree and leaf_max_degree based o
public fun new_with_config<K: store, V: store>(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool, num_to_preallocate: u32): BigOrderedMap<K, V> {
-    assert!(inner_max_degree == 0 || inner_max_degree >= DEFAULT_INNER_MIN_DEGREE, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
-    assert!(leaf_max_degree == 0 || leaf_max_degree >= DEFAULT_LEAF_MIN_DEGREE, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
+    assert!(inner_max_degree == 0 || (inner_max_degree >= DEFAULT_INNER_MIN_DEGREE && (inner_max_degree as u64) <= MAX_DEGREE), error::invalid_argument(EINVALID_CONFIG_PARAMETER));
+    assert!(leaf_max_degree == 0 || (leaf_max_degree >= DEFAULT_LEAF_MIN_DEGREE && (leaf_max_degree as u64) <= MAX_DEGREE), error::invalid_argument(EINVALID_CONFIG_PARAMETER));
     assert!(reuse_slots || num_to_preallocate == 0, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
 
     // Assert that storage_slots_allocator special indices are aligned:
@@ -571,6 +575,34 @@ it is important to compute and pass inner_max_degree and leaf_max_degree based o
 
 
 
+
+
+
+
+## Function `new_from`
+
+Create a BigOrderedMap from a vector of keys and values, with default configuration.
+Aborts with EKEY_ALREADY_EXISTS if duplicate keys are passed in.
+
+
+
public fun new_from<K: copy, drop, store, V: store>(keys: vector<K>, values: vector<V>): big_ordered_map::BigOrderedMap<K, V>
+
+ + + +
+Implementation + + +
public fun new_from<K: drop + copy + store, V: store>(keys: vector<K>, values: vector<V>): BigOrderedMap<K, V> {
+    let map = new();
+    map.add_all(keys, values);
+    map
+}
+
+ + +
@@ -703,6 +735,36 @@ Aborts if there is no entry for key. + + + + +## Function `add_all` + +Add multiple key/value pairs to the map. The keys must not already exist. +Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are passed in. + + +
public fun add_all<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, keys: vector<K>, values: vector<V>)
+
+ + + +
+Implementation + + +
public fun add_all<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, keys: vector<K>, values: vector<V>) {
+    // TODO: Can be optimized, both in insertion order (largest first, then from smallest),
+    // as well as on initializing inner_max_degree/leaf_max_degree better
+    vector::zip(keys, values, |key, value| {
+        self.add(key, value);
+    });
+}
+
+ + +
@@ -735,7 +797,7 @@ key, or an end iterator if such element doesn't exist. if (child_lower_bound.iter_is_end(&node.children)) { self.new_end_iter() } else { - let iter_key = *child_lower_bound.iter_borrow_key(&node.children); + let iter_key = *child_lower_bound.iter_borrow_key(&node.children); new_iter(leaf, child_lower_bound, iter_key) } } @@ -828,10 +890,8 @@ Returns a reference to the element with its key, aborts if the key is not found.
public fun borrow<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: K): &V {
     let iter = self.find(&key);
-
     assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
-    let children = &self.borrow_node(iter.node_index).children;
-    &iter.child_iter.iter_borrow(children).value
+    iter.iter_borrow(self)
 }
 
@@ -856,12 +916,9 @@ Returns a mutable reference to the element with its key at the given index, abor
public fun borrow_mut<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: K): &mut V {
-    assert!(self.constant_kv_size, error::invalid_argument(EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE));
     let iter = self.find(&key);
-
     assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
-    let children = &mut self.borrow_node_mut(iter.node_index).children;
-    &mut iter.child_iter.iter_borrow_mut(children).value
+    iter.iter_borrow_mut(self)
 }
 
@@ -893,7 +950,7 @@ Returns the begin iterator. let node = self.borrow_node(self.min_leaf_index); assert!(!node.children.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); let begin_child_iter = node.children.new_begin_iter(); - let begin_child_key = *begin_child_iter.iter_borrow_key(&node.children); + let begin_child_key = *begin_child_iter.iter_borrow_key(&node.children); new_iter(self.min_leaf_index, begin_child_iter, begin_child_key) }
@@ -979,14 +1036,16 @@ Returns the end iterator. - + -## Function `iter_get_key` +## Function `iter_borrow_key` -Returns the key of the given iterator. +Borrows the key given iterator points to. +Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end. +Note: Requires that the map is not changed after the input iterator is generated. -
public(friend) fun iter_get_key<K>(self: &big_ordered_map::IteratorPtr<K>): &K
+
public(friend) fun iter_borrow_key<K>(self: &big_ordered_map::IteratorPtr<K>): &K
 
@@ -995,7 +1054,7 @@ Returns the key of the given iterator. Implementation -
public(friend) fun iter_get_key<K>(self: &IteratorPtr<K>): &K {
+
public(friend) fun iter_borrow_key<K>(self: &IteratorPtr<K>): &K {
     assert!(!(self is IteratorPtr::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     &self.key
 }
@@ -1003,6 +1062,67 @@ Returns the key of the given iterator.
 
 
 
+
+
+
+
+## Function `iter_borrow`
+
+Borrows the value given iterator points to.
+Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end.
+Note: Requires that the map is not changed after the input iterator is generated.
+
+
+
public(friend) fun iter_borrow<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): &V
+
+ + + +
+Implementation + + +
public(friend) fun iter_borrow<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &BigOrderedMap<K, V>): &V {
+    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    let children = &map.borrow_node(self.node_index).children;
+    &self.child_iter.iter_borrow(children).value
+}
+
+ + + +
+ + + +## Function `iter_borrow_mut` + +Mutably borrows the value iterator points to. +Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end. +Aborts with EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE if KV size doesn't have constant size, +because if it doesn't - we need to call upsert to be able to check size invariants after modification. +Note: Requires that the map is not changed after the input iterator is generated. + + +
public(friend) fun iter_borrow_mut<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): &mut V
+
+ + + +
+Implementation + + +
public(friend) fun iter_borrow_mut<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &mut BigOrderedMap<K, V>): &mut V {
+    assert!(map.constant_kv_size, error::invalid_argument(EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE));
+    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    let children = &mut map.borrow_node_mut(self.node_index).children;
+    &mut self.child_iter.iter_borrow_mut(children).value
+}
+
+ + +
@@ -1032,7 +1152,7 @@ Requires the map is not changed after the input iterator is generated. let child_iter = self.child_iter.iter_next(&node.children); if (!child_iter.iter_is_end(&node.children)) { // next is in the same leaf node - let iter_key = *child_iter.iter_borrow_key(&node.children); + let iter_key = *child_iter.iter_borrow_key(&node.children); return new_iter(node_index, child_iter, iter_key); }; @@ -1043,7 +1163,7 @@ Requires the map is not changed after the input iterator is generated. let child_iter = next_node.children.new_begin_iter(); assert!(!child_iter.iter_is_end(&next_node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - let iter_key = *child_iter.iter_borrow_key(&next_node.children); + let iter_key = *child_iter.iter_borrow_key(&next_node.children); return new_iter(next_index, child_iter, iter_key); }; @@ -1083,7 +1203,7 @@ Requires the map is not changed after the input iterator is generated. if (!self.child_iter.iter_is_begin(&node.children)) { // next is in the same leaf node let child_iter = self.child_iter.iter_prev(&node.children); - let key = *child_iter.iter_borrow_key(&node.children); + let key = *child_iter.iter_borrow_key(&node.children); return new_iter(node_index, child_iter, key); }; node.prev @@ -1096,7 +1216,7 @@ Requires the map is not changed after the input iterator is generated. let prev_children = &prev_node.children; let child_iter = prev_children.new_end_iter().iter_prev(prev_children); - let iter_key = *child_iter.iter_borrow_key(prev_children); + let iter_key = *child_iter.iter_borrow_key(prev_children); new_iter(prev_index, child_iter, iter_key) }
@@ -1187,9 +1307,9 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an // (optimizes out borrowing and path creation in `find_leaf_path`) if (self.root.is_leaf) { let children = &mut self.root.children; - let current_size = children.length(); + let degree = children.length(); - if (current_size < (self.leaf_max_degree as u64)) { + if (degree < (self.leaf_max_degree as u64)) { let result = children.upsert(key, new_leaf_child(value)); assert!(allow_overwrite || result.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS)); return result; @@ -1540,7 +1660,7 @@ return NULL_INDEX if key is larger than any key currently stored in if (child_iter.iter_is_end(children)) { return NULL_INDEX; } else { - current = child_iter.iter_borrow(children).node_index.stored_to_index(); + current = child_iter.iter_borrow(children).node_index.stored_to_index(); }; } } @@ -1585,7 +1705,7 @@ Returns empty path if key is larger than any key currently stored i if (child_iter.iter_is_end(children)) { return vector::empty(); } else { - current = child_iter.iter_borrow(children).node_index.stored_to_index(); + current = child_iter.iter_borrow(children).node_index.stored_to_index(); }; } } @@ -1647,13 +1767,18 @@ Returns empty path if key is larger than any key currently stored i root.is_leaf = new_root.is_leaf; new_root.is_leaf = tmp_is_leaf; - let tmp_prev = root.prev; - root.prev = new_root.prev; - new_root.prev = tmp_prev; + assert!(root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(new_root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(new_root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - let tmp_next = root.next; - root.next = new_root.next; - new_root.next = tmp_next; + // let tmp_prev = root.prev; + // root.prev = new_root.prev; + // new_root.prev = tmp_prev; + + // let tmp_next = root.next; + // root.next = new_root.next; + // new_root.next = tmp_next; let tmp_children = root.children.trim(0); root.children.append_disjoint(new_root.children.trim(0)); @@ -1676,6 +1801,7 @@ It is required that key pointers to the child node, on the pa That means if we are adding a key larger than any currently existing in the map - we needed to update key pointers on the path_to_node to include it, before calling this method. +Returns Child previously associated with the given key. If allow_overwrite is not set, function will abort if key is already present. @@ -1697,24 +1823,25 @@ If allow_overwrite is not set, function will abort if keylet node = self.borrow_node_mut(node_index); let children = &mut node.children; - let current_size = children.length(); + let degree = children.length(); + // Compute directly, as we cannot use get_max_degree(), as self is already mutably borrowed. let max_degree = if (node.is_leaf) { self.leaf_max_degree as u64 } else { self.inner_max_degree as u64 }; - if (current_size < max_degree) { + if (degree < max_degree) { // Adding a child to a current node doesn't exceed the size, so we can just do that. - let result = children.upsert(key, child); + let old_child = children.upsert(key, child); if (node.is_leaf) { - assert!(allow_overwrite || result.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS)); - return result; + assert!(allow_overwrite || old_child.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS)); + return old_child; } else { - assert!(!allow_overwrite && result.is_none(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - return result; + assert!(!allow_overwrite && old_child.is_none(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + return old_child; }; }; @@ -1745,7 +1872,7 @@ If allow_overwrite is not set, function will abort if keylet max_key = { let root_children = &self.root.children; - let max_key = *root_children.new_end_iter().iter_prev(root_children).iter_borrow_key(root_children); + let max_key = *root_children.new_end_iter().iter_prev(root_children).iter_borrow_key(root_children); // need to check if key is largest, as invariant is that "parent's pointers" have been updated, // but key itself can be larger than all previous ones. if (cmp::compare(&max_key, &key).is_lt()) { @@ -1793,7 +1920,6 @@ If allow_overwrite is not set, function will abort if keylet right_node_reserved_slot = reserved_slot; let left_node = node; - let is_leaf = left_node.is_leaf; let left_children = &mut left_node.children; @@ -1801,12 +1927,13 @@ If allow_overwrite is not set, function will abort if keylet left_next = &mut left_node.next; let left_prev = &mut left_node.prev; - // compute the target size for the left node: + // Compute directly, as we cannot use get_max_degree(), as self is already mutably borrowed. let max_degree = if (is_leaf) { self.leaf_max_degree as u64 } else { self.inner_max_degree as u64 }; + // compute the target size for the left node: let target_size = (max_degree + 1) / 2; // Add child (which will exceed the size), and then trim off to create two sets of children of correct sizes. @@ -1825,20 +1952,21 @@ If allow_overwrite is not set, function will abort if keyto the right node, `prev` pointer of the next node is correct, + // Since the previously used index is going to the right node, `prev` pointer of the next node is correct, // and we need to update next pointer of the previous node (if exists) if (*left_prev != NULL_INDEX) { self.nodes.borrow_mut(*left_prev).next = left_node_index; - }; - // Otherwise, we were the smallest node on the level. if this is the leaf level, update the pointer. - if (right_node_index == self.min_leaf_index) { + assert!(right_node_index != self.min_leaf_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + } else if (right_node_index == self.min_leaf_index) { + // Otherwise, if we were the smallest node on the level. if this is the leaf level, update the pointer. + assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); self.min_leaf_index = left_node_index; }; // Largest left key is the split key. - let max_left_key = *left_children.new_end_iter().iter_prev(left_children).iter_borrow_key(left_children); + let max_left_key = *left_children.new_end_iter().iter_prev(left_children).iter_borrow_key(left_children); self.nodes.fill_reserved_slot(left_node_reserved_slot, left_node); self.nodes.fill_reserved_slot(right_node_reserved_slot, right_node); @@ -1877,7 +2005,7 @@ Given a path to node (excluding the node itself), which is currently stored unde children.replace_key_inplace(old_key, new_key); // If we were not updating the largest child, we don't need to continue. - if (children.new_end_iter().iter_prev(children).iter_borrow_key(children) != &new_key) { + if (children.new_end_iter().iter_prev(children).iter_borrow_key(children) != &new_key) { return }; } @@ -1904,10 +2032,10 @@ Given a path to node (excluding the node itself), which is currently stored unde
fun remove_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<u64>, key: &K): Child<V> {
-    // Last node in the path is one where we need to add the child to.
+    // Last node in the path is one where we need to remove the child from.
     let node_index = path_to_node.pop_back();
     let old_child = {
-        // First check if we can perform this operation, without changing structure of the tree (i.e. without adding any nodes).
+        // First check if we can perform this operation, without changing structure of the tree (i.e. without rebalancing any nodes).
 
         // For that we can just borrow the single node
         let node = self.borrow_node_mut(node_index);
@@ -1942,22 +2070,23 @@ Given a path to node (excluding the node itself), which is currently stored unde
             return old_child;
         };
 
+        // Compute directly, as we cannot use get_max_degree(), as self is already mutably borrowed.
         let max_degree = if (is_leaf) {
             self.leaf_max_degree as u64
         } else {
             self.inner_max_degree as u64
         };
-        let current_size = children.length();
+        let degree = children.length();
 
         // See if the node is big enough, or we need to merge it with another node on this level.
-        let big_enough = current_size * 2 >= max_degree;
+        let big_enough = degree * 2 >= max_degree;
 
-        let new_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+        let new_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
 
         // See if max key was updated for the current node, and if so - update it on the path.
         let max_key_updated = cmp::compare(&new_max_key, key).is_lt();
         if (max_key_updated) {
-            assert!(current_size >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(degree >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
             self.update_key(path_to_node, key, new_max_key);
         };
@@ -1985,8 +2114,10 @@ Given a path to node (excluding the node itself), which is currently stored unde
     let sibling_index = {
         let parent_children = &self.borrow_node(*path_to_node.borrow(path_to_node.length() - 1)).children;
         assert!(parent_children.length() >= 2, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-        // We merge with previous node - if it has the same parent, otherwise with next node (which then needs to have the same parent)
-        if (parent_children.new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_to_index() == node_index) {
+        // If we are the largest node from the parent, we merge with the `prev`
+        // (which is then guaranteed to have the same parent, as any node has >1 children),
+        // otherwise we merge with `next`.
+        if (parent_children.new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_to_index() == node_index) {
             prev
         } else {
             next
@@ -1996,31 +2127,32 @@ Given a path to node (excluding the node itself), which is currently stored unde
     let children = &mut node.children;
 
     let (sibling_slot, sibling_node) = self.nodes.remove_and_reserve(sibling_index);
+    assert!(is_leaf == sibling_node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
     let sibling_children = &mut sibling_node.children;
 
     if ((sibling_children.length() - 1) * 2 >= max_degree) {
         // The sibling node has enough elements, we can just borrow an element from the sibling node.
         if (sibling_index == next) {
-            // if sibling is a larger node, we remove a child from the start
-            let old_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+            // if sibling is the node with larger keys, we remove a child from the start
+            let old_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
             let sibling_begin_iter = sibling_children.new_begin_iter();
-            let borrowed_max_key = *sibling_begin_iter.iter_borrow_key(sibling_children);
+            let borrowed_max_key = *sibling_begin_iter.iter_borrow_key(sibling_children);
             let borrowed_element = sibling_begin_iter.iter_remove(sibling_children);
 
-            children.add(borrowed_max_key, borrowed_element);
+            children.new_end_iter().iter_add(children, borrowed_max_key, borrowed_element);
 
             // max_key of the current node changed, so update
             self.update_key(path_to_node, &old_max_key, borrowed_max_key);
         } else {
-            // if sibling is a smaller node, we remove a child from the end
+            // if sibling is the node with smaller keys, we remove a child from the end
             let sibling_end_iter = sibling_children.new_end_iter().iter_prev(sibling_children);
-            let borrowed_max_key = *sibling_end_iter.iter_borrow_key(sibling_children);
+            let borrowed_max_key = *sibling_end_iter.iter_borrow_key(sibling_children);
             let borrowed_element = sibling_end_iter.iter_remove(sibling_children);
 
             children.add(borrowed_max_key, borrowed_element);
 
             // max_key of the sibling node changed, so update
-            self.update_key(path_to_node, &borrowed_max_key, *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children));
+            self.update_key(path_to_node, &borrowed_max_key, *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children));
         };
 
         self.nodes.fill_reserved_slot(node_slot, node);
@@ -2029,17 +2161,17 @@ Given a path to node (excluding the node itself), which is currently stored unde
     };
 
     // The sibling node doesn't have enough elements to borrow, merge with the sibling node.
-    // Keep the slot of the larger node of the two, to not require updating key on the parent nodes.
-    // But append to the smaller node, as ordered_map::append is more efficient when adding to the end.
+    // Keep the slot of the node with larger keys of the two, to not require updating key on the parent nodes.
+    // But append to the node with smaller keys, as ordered_map::append is more efficient when adding to the end.
     let (key_to_remove, reserved_slot_to_remove) = if (sibling_index == next) {
         // destroying larger sibling node, keeping sibling_slot.
         let Node { children: sibling_children, is_leaf: _, prev: _, next: sibling_next } = sibling_node;
-        let key_to_remove = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+        let key_to_remove = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
         children.append_disjoint(sibling_children);
         node.next = sibling_next;
 
         if (node.next != NULL_INDEX) {
-            assert!(self.nodes.borrow_mut(node.next).prev == sibling_index, 1);
+            assert!(self.nodes.borrow_mut(node.next).prev == sibling_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
 
         // we are removing node_index, which previous's node's next was pointing to,
@@ -2049,6 +2181,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         };
         // Otherwise, we were the smallest node on the level. if this is the leaf level, update the pointer.
         if (self.min_leaf_index == node_index) {
+            assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
             self.min_leaf_index = sibling_index;
         };
 
@@ -2058,12 +2191,12 @@ Given a path to node (excluding the node itself), which is currently stored unde
     } else {
         // destroying larger current node, keeping node_slot
         let Node { children: node_children, is_leaf: _, prev: _, next: node_next } = node;
-        let key_to_remove = *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children);
+        let key_to_remove = *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children);
         sibling_children.append_disjoint(node_children);
         sibling_node.next = node_next;
 
         if (sibling_node.next != NULL_INDEX) {
-            assert!(self.nodes.borrow_mut(sibling_node.next).prev == node_index, 1);
+            assert!(self.nodes.borrow_mut(sibling_node.next).prev == node_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
         // we are removing sibling node_index, which previous's node's next was pointing to,
         // so update the pointer
@@ -2072,6 +2205,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         };
         // Otherwise, sibling was the smallest node on the level. if this is the leaf level, update the pointer.
         if (self.min_leaf_index == sibling_index) {
+            assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
             self.min_leaf_index = node_index;
         };
 
diff --git a/aptos-move/framework/aptos-stdlib/doc/btree_map.md b/aptos-move/framework/aptos-stdlib/doc/btree_map.md
deleted file mode 100644
index 292b9a39ab48b..0000000000000
--- a/aptos-move/framework/aptos-stdlib/doc/btree_map.md
+++ /dev/null
@@ -1,1886 +0,0 @@
-
-
-
-# Module `0x1::btree_map`
-
-Type of large-scale search trees.
-
-It internally uses BTree to organize the search tree data structure for keys. Comparing with
-other common search trees like AVL or Red-black tree, a BTree node has more children, and packs
-more metadata into one node, which is more disk friendly (and gas friendly).
-
-
--  [Struct `Node`](#0x1_btree_map_Node)
--  [Enum `Child`](#0x1_btree_map_Child)
--  [Enum `Iterator`](#0x1_btree_map_Iterator)
--  [Enum `BTreeMap`](#0x1_btree_map_BTreeMap)
--  [Constants](#@Constants_0)
--  [Function `new`](#0x1_btree_map_new)
--  [Function `new_with_config`](#0x1_btree_map_new_with_config)
--  [Function `destroy_empty`](#0x1_btree_map_destroy_empty)
--  [Function `init_max_degrees`](#0x1_btree_map_init_max_degrees)
--  [Function `insert`](#0x1_btree_map_insert)
--  [Function `upsert`](#0x1_btree_map_upsert)
--  [Function `remove`](#0x1_btree_map_remove)
--  [Function `is_null_index`](#0x1_btree_map_is_null_index)
--  [Function `is_begin_iter`](#0x1_btree_map_is_begin_iter)
--  [Function `is_end_iter`](#0x1_btree_map_is_end_iter)
--  [Function `lower_bound`](#0x1_btree_map_lower_bound)
--  [Function `find`](#0x1_btree_map_find)
--  [Function `contains`](#0x1_btree_map_contains)
--  [Function `get_key`](#0x1_btree_map_get_key)
--  [Function `borrow`](#0x1_btree_map_borrow)
--  [Function `borrow_mut`](#0x1_btree_map_borrow_mut)
--  [Function `size`](#0x1_btree_map_size)
--  [Function `size_for_node`](#0x1_btree_map_size_for_node)
--  [Function `empty`](#0x1_btree_map_empty)
--  [Function `new_begin_iter`](#0x1_btree_map_new_begin_iter)
--  [Function `new_end_iter`](#0x1_btree_map_new_end_iter)
--  [Function `next_iter`](#0x1_btree_map_next_iter)
--  [Function `next_iter_or_die`](#0x1_btree_map_next_iter_or_die)
--  [Function `prev_iter`](#0x1_btree_map_prev_iter)
--  [Function `prev_iter_or_die`](#0x1_btree_map_prev_iter_or_die)
--  [Function `destroy_inner_child`](#0x1_btree_map_destroy_inner_child)
--  [Function `destroy_empty_node`](#0x1_btree_map_destroy_empty_node)
--  [Function `new_node`](#0x1_btree_map_new_node)
--  [Function `new_node_with_children`](#0x1_btree_map_new_node_with_children)
--  [Function `new_inner_child`](#0x1_btree_map_new_inner_child)
--  [Function `new_leaf_child`](#0x1_btree_map_new_leaf_child)
--  [Function `new_iter`](#0x1_btree_map_new_iter)
--  [Function `find_leaf`](#0x1_btree_map_find_leaf)
--  [Function `binary_search`](#0x1_btree_map_binary_search)
--  [Function `get_max_degree`](#0x1_btree_map_get_max_degree)
--  [Function `insert_at`](#0x1_btree_map_insert_at)
--  [Function `update_key`](#0x1_btree_map_update_key)
--  [Function `remove_at`](#0x1_btree_map_remove_at)
-
-
-
use 0x1::bcs;
-use 0x1::cmp;
-use 0x1::debug;
-use 0x1::math64;
-use 0x1::option;
-use 0x1::table_with_length;
-use 0x1::vector;
-
- - - - - -## Struct `Node` - -A node of the BTreeMap. - - -
struct Node<K: store, V: store> has store
-
- - - -
-Fields - - -
-
-is_leaf: bool -
-
- -
-
-parent: u64 -
-
- -
-
-children: vector<btree_map::Child<K, V>> -
-
- -
-
-prev: u64 -
-
- -
-
-next: u64 -
-
- -
-
- - -
- - - -## Enum `Child` - -The metadata of a child of a node. - - -
enum Child<K: store, V: store> has store
-
- - - -
-Variants - - -
-Inner - - -
-Fields - - -
-
-max_key: K -
-
- -
-
-node_index: u64 -
-
- -
-
- - -
- -
- -
-Leaf - - -
-Fields - - -
-
-max_key: K -
-
- -
-
-value: V -
-
- -
-
- - -
- -
- -
- - - -## Enum `Iterator` - -An iterator to iterate all keys in the BTreeMap. - - -
enum Iterator<K> has copy, drop
-
- - - -
-Variants - - -
-End - - -
-Fields - - -
-
- - -
- -
- -
-Some - - -
-Fields - - -
-
-node_index: u64 -
-
- -
-
-child_index: u64 -
-
- -
-
-key: K -
-
- -
-
- - -
- -
- -
- - - -## Enum `BTreeMap` - -The BTreeMap data structure. - - -
enum BTreeMap<K: store, V: store> has store
-
- - - -
-Variants - - -
-V1 - - -
-Fields - - -
-
-root_index: u64 -
-
- -
-
-nodes: table_with_length::TableWithLength<u64, btree_map::Node<K, V>> -
-
- -
-
-min_leaf_index: u64 -
-
- -
-
-max_leaf_index: u64 -
-
- -
-
-inner_max_degree: u16 -
-
- -
-
-leaf_max_degree: u16 -
-
- -
-
- - -
- -
- -
- - - -## Constants - - - - - - -
const DEFAULT_INNER_MIN_DEGREE: u16 = 4;
-
- - - - - - - -
const DEFAULT_LEAF_MIN_DEGREE: u16 = 2;
-
- - - - - - - -
const DEFAULT_TARGET_NODE_SIZE: u64 = 2048;
-
- - - - - - - -
const E_INTERNAL: u64 = 0;
-
- - - - - - - -
const E_INVALID_PARAMETER: u64 = 3;
-
- - - - - - - -
const E_TREE_NOT_EMPTY: u64 = 1;
-
- - - - - - - -
const E_TREE_TOO_BIG: u64 = 2;
-
- - - - - - - -
const MAX_DEGREE: u64 = 4096;
-
- - - - - - - -
const NULL_INDEX: u64 = 0;
-
- - - - - -## Function `new` - -Returns a new BTreeMap with the default configuration. - - -
public fun new<K: store, V: store>(): btree_map::BTreeMap<K, V>
-
- - - -
-Implementation - - -
public fun new<K: store, V: store>(): BTreeMap<K, V> {
-    new_with_config(0, 0)
-}
-
- - - -
- - - -## Function `new_with_config` - -Returns a new BTreeMap with the provided max degree consts (the maximum # of children a node can have). -If 0 is passed, then it is dynamically computed based on size of first key and value. - - -
public fun new_with_config<K: store, V: store>(inner_max_degree: u16, leaf_max_degree: u16): btree_map::BTreeMap<K, V>
-
- - - -
-Implementation - - -
public fun new_with_config<K: store, V: store>(inner_max_degree: u16, leaf_max_degree: u16): BTreeMap<K, V> {
-    assert!(inner_max_degree == 0 || inner_max_degree >= DEFAULT_INNER_MIN_DEGREE, E_INVALID_PARAMETER);
-    assert!(leaf_max_degree == 0 || leaf_max_degree >= DEFAULT_LEAF_MIN_DEGREE, E_INVALID_PARAMETER);
-    let root_node = new_node(/*is_leaf=*/true, /*parent=*/NULL_INDEX);
-    let nodes = table_with_length::new();
-    let root_index = 1;
-    nodes.add(root_index, root_node);
-    BTreeMap::V1 {
-        root_index: root_index,
-        nodes: nodes,
-        min_leaf_index: root_index,
-        max_leaf_index: root_index,
-        inner_max_degree: inner_max_degree,
-        leaf_max_degree: leaf_max_degree
-    }
-}
-
- - - -
- - - -## Function `destroy_empty` - -Destroys the tree if it's empty, otherwise aborts. - - -
public fun destroy_empty<K: store, V: store>(self: btree_map::BTreeMap<K, V>)
-
- - - -
-Implementation - - -
public fun destroy_empty<K: store, V: store>(self: BTreeMap<K, V>) {
-    let BTreeMap::V1 { nodes, root_index, min_leaf_index: _, max_leaf_index: _, inner_max_degree: _, leaf_max_degree: _ } = self;
-    aptos_std::debug::print(&nodes);
-    assert!(nodes.length() == 1, E_TREE_NOT_EMPTY);
-    nodes.remove(root_index).destroy_empty_node();
-    nodes.destroy_empty();
-}
-
- - - -
- - - -## Function `init_max_degrees` - - - -
fun init_max_degrees<K: store, V: store>(self: &mut btree_map::BTreeMap<K, V>, key: &K, value: &V)
-
- - - -
-Implementation - - -
fun init_max_degrees<K: store, V: store>(self: &mut BTreeMap<K, V>, key: &K, value: &V) {
-    if (self.inner_max_degree == 0 || self.leaf_max_degree == 0) {
-        let key_size = bcs::serialized_size(key);
-
-        if (self.inner_max_degree == 0) {
-            self.inner_max_degree = max(min(MAX_DEGREE, DEFAULT_TARGET_NODE_SIZE / key_size), DEFAULT_INNER_MIN_DEGREE as u64) as u16;
-        };
-
-        if (self.leaf_max_degree == 0) {
-            let value_size = bcs::serialized_size(value);
-            self.leaf_max_degree = max(min(MAX_DEGREE, DEFAULT_TARGET_NODE_SIZE / (key_size + value_size)), DEFAULT_LEAF_MIN_DEGREE as u64) as u16;
-        };
-    };
-}
-
- - - -
- - - -## Function `insert` - -Inserts the key/value into the BTreeMap. -Aborts if the key is already in the tree. - - -
public fun insert<K: copy, drop, store, V: store>(self: &mut btree_map::BTreeMap<K, V>, key: K, value: V)
-
- - - -
-Implementation - - -
public fun insert<K: drop + copy + store, V: store>(self: &mut BTreeMap<K, V>, key: K, value: V) {
-    if (self.inner_max_degree == 0 || self.leaf_max_degree == 0) {
-        self.init_max_degrees(&key, &value);
-    };
-
-    let leaf = self.find_leaf(key);
-
-    if (leaf == NULL_INDEX) {
-        // In this case, the key is greater than all keys in the tree.
-        leaf = self.max_leaf_index;
-        let current = self.nodes.borrow(leaf).parent;
-        while (current != NULL_INDEX) {
-            let current_node = self.nodes.borrow_mut(current);
-            let last_index = current_node.children.length() - 1;
-            let last_element = current_node.children.borrow_mut(last_index);
-            last_element.max_key = key;
-            current = current_node.parent;
-        }
-    };
-
-    self.insert_at(leaf, new_leaf_child(key, value));
-}
-
- - - -
- - - -## Function `upsert` - -If the key doesn't exist in the tree, inserts the key/value, and returns none. -Otherwise updates the value under the given key, and returns the old value. - - -
public fun upsert<K: copy, drop, store, V: store>(self: &mut btree_map::BTreeMap<K, V>, key: K, value: V): option::Option<V>
-
- - - -
-Implementation - - -
public fun upsert<K: drop + copy + store, V: store>(self: &mut BTreeMap<K, V>, key: K, value: V): Option<V> {
-    if (self.inner_max_degree == 0 || self.leaf_max_degree == 0) {
-        self.init_max_degrees(&key, &value);
-    };
-
-    let iter = self.find(key);
-    if (is_end_iter(self, &iter)) {
-        self.insert(key, value);
-        return option::none()
-    } else {
-        let node = self.nodes.borrow_mut(iter.node_index);
-        let children = &mut node.children;
-
-        // Field swap doesn't compile.
-        // let child = vector::borrow_mut(children, iter.child_index);
-        // assert!(child.max_key == key, E_INTERNAL);
-        // let old = child.value;
-        // child.value = value;
-        // option::some(old)
-
-        let Child::Leaf {
-            max_key: old_max_key,
-            value: old_value,
-        } = children.replace(iter.child_index, Child::Leaf { max_key: key, value: value });
-        assert!(old_max_key == key, E_INTERNAL);
-        option::some(old_value)
-    }
-}
-
- - - -
- - - -## Function `remove` - -Removes the entry from BTreeMap and returns the value which key maps to. -Aborts if there is no entry for key. - - -
public fun remove<K: copy, drop, store, V: store>(self: &mut btree_map::BTreeMap<K, V>, key: K): V
-
- - - -
-Implementation - - -
public fun remove<K: drop + copy + store, V: store>(self: &mut BTreeMap<K, V>, key: K): V {
-    let iter = self.find(key);
-    assert!(!is_end_iter(self, &iter), E_INTERNAL);
-
-    let Child::Leaf {
-        value,
-        max_key: _,
-    } = self.remove_at(iter.node_index, key);
-
-    value
-}
-
- - - -
- - - -## Function `is_null_index` - - - -
public fun is_null_index(node_index: u64): bool
-
- - - -
-Implementation - - -
public fun is_null_index(node_index: u64): bool {
-    node_index == NULL_INDEX
-}
-
- - - -
- - - -## Function `is_begin_iter` - - - -
public fun is_begin_iter<K: store, V: store>(tree: &btree_map::BTreeMap<K, V>, iter: &btree_map::Iterator<K>): bool
-
- - - -
-Implementation - - -
public fun is_begin_iter<K: store, V: store>(tree: &BTreeMap<K, V>, iter: &Iterator<K>): bool {
-    if (iter is Iterator::End<K>) {
-        empty(tree)
-    } else {
-        (iter.node_index == tree.min_leaf_index && iter.child_index == 0)
-    }
-}
-
- - - -
- - - -## Function `is_end_iter` - - - -
public fun is_end_iter<K: store, V: store>(_tree: &btree_map::BTreeMap<K, V>, iter: &btree_map::Iterator<K>): bool
-
- - - -
-Implementation - - -
public fun is_end_iter<K: store, V: store>(_tree: &BTreeMap<K, V>, iter: &Iterator<K>): bool {
-    iter is Iterator::End<K>
-}
-
- - - -
- - - -## Function `lower_bound` - -Returns an iterator pointing to the first element that is greater or equal to the provided -key, or an end iterator if such element doesn't exist. - - -
public fun lower_bound<K: copy, drop, store, V: store>(self: &btree_map::BTreeMap<K, V>, key: K): btree_map::Iterator<K>
-
- - - -
-Implementation - - -
public fun lower_bound<K: drop + copy + store, V: store>(self: &BTreeMap<K, V>, key: K): Iterator<K> {
-    let leaf = self.find_leaf(key);
-    if (leaf == NULL_INDEX) {
-        return self.new_end_iter()
-    };
-
-    let node = self.nodes.borrow(leaf);
-    assert!(node.is_leaf, E_INTERNAL);
-
-    let keys = &node.children;
-
-    let len = keys.length();
-
-    let index = binary_search(key, keys, 0, len);
-    if (index == len) {
-        self.new_end_iter()
-    } else {
-        new_iter(leaf, index, keys.borrow(index).max_key)
-    }
-}
-
- - - -
- - - -## Function `find` - -Returns an iterator pointing to the element that equals to the provided key, or an end -iterator if the key is not found. - - -
public fun find<K: copy, drop, store, V: store>(self: &btree_map::BTreeMap<K, V>, key: K): btree_map::Iterator<K>
-
- - - -
-Implementation - - -
public fun find<K: drop + copy + store, V: store>(self: &BTreeMap<K, V>, key: K): Iterator<K> {
-    let lower_bound = self.lower_bound(key);
-    if (is_end_iter(self, &lower_bound)) {
-        lower_bound
-    } else if (lower_bound.key == key) {
-        lower_bound
-    } else {
-        self.new_end_iter()
-    }
-}
-
- - - -
- - - -## Function `contains` - -Returns true iff the key exists in the tree. - - -
public fun contains<K: copy, drop, store, V: store>(self: &btree_map::BTreeMap<K, V>, key: K): bool
-
- - - -
-Implementation - - -
public fun contains<K: drop + copy + store, V: store>(self: &BTreeMap<K, V>, key: K): bool {
-    let lower_bound = self.lower_bound(key);
-    if (is_end_iter(self, &lower_bound)) {
-        false
-    } else if (lower_bound.key == key) {
-        true
-    } else {
-        false
-    }
-}
-
- - - -
- - - -## Function `get_key` - -Returns the key of the given iterator. - - -
public fun get_key<K: copy>(iter: &btree_map::Iterator<K>): K
-
- - - -
-Implementation - - -
public fun get_key<K: copy>(iter: &Iterator<K>): K {
-    assert!(!(iter is Iterator::End<K>), E_INVALID_PARAMETER);
-    iter.key
-}
-
- - - -
- - - -## Function `borrow` - -Returns a reference to the element with its key, aborts if the key is not found. - - -
public fun borrow<K: copy, drop, store, V: store>(self: &btree_map::BTreeMap<K, V>, key: K): &V
-
- - - -
-Implementation - - -
public fun borrow<K: drop + copy + store, V: store>(self: &BTreeMap<K, V>, key: K): &V {
-    let iter = self.find(key);
-
-    assert!(is_end_iter(self, &iter), E_INVALID_PARAMETER);
-    let children = &self.nodes.borrow(iter.node_index).children;
-    &children.borrow(iter.child_index).value
-}
-
- - - -
- - - -## Function `borrow_mut` - -Returns a mutable reference to the element with its key at the given index, aborts if the key is not found. - - -
public fun borrow_mut<K: copy, drop, store, V: store>(self: &mut btree_map::BTreeMap<K, V>, key: K): &mut V
-
- - - -
-Implementation - - -
public fun borrow_mut<K: drop + copy + store, V: store>(self: &mut BTreeMap<K, V>, key: K): &mut V {
-    let iter = self.find(key);
-
-    assert!(is_end_iter(self, &iter), E_INVALID_PARAMETER);
-    let children = &mut self.nodes.borrow_mut(iter.node_index).children;
-    &mut children.borrow_mut(iter.child_index).value
-}
-
- - - -
- - - -## Function `size` - -Returns the number of elements in the BTreeMap. - - -
public fun size<K: store, V: store>(self: &btree_map::BTreeMap<K, V>): u64
-
- - - -
-Implementation - - -
public fun size<K: store, V: store>(self: &BTreeMap<K, V>): u64 {
-    self.size_for_node(self.root_index)
-}
-
- - - -
- - - -## Function `size_for_node` - - - -
fun size_for_node<K: store, V: store>(self: &btree_map::BTreeMap<K, V>, node_index: u64): u64
-
- - - -
-Implementation - - -
fun size_for_node<K: store, V: store>(self: &BTreeMap<K, V>, node_index: u64): u64 {
-    let node = self.nodes.borrow(node_index);
-    if (node.is_leaf) {
-        node.children.length()
-    } else {
-        let size = 0;
-
-        for (i in 0..node.children.length()) {
-            size = size + self.size_for_node(node.children[i].node_index);
-        };
-        size
-    }
-}
-
- - - -
- - - -## Function `empty` - -Returns true iff the BTreeMap is empty. - - -
fun empty<K: store, V: store>(self: &btree_map::BTreeMap<K, V>): bool
-
- - - -
-Implementation - - -
fun empty<K: store, V: store>(self: &BTreeMap<K, V>): bool {
-    let node = self.nodes.borrow(self.min_leaf_index);
-
-    node.children.is_empty()
-}
-
- - - -
- - - -## Function `new_begin_iter` - -Return the begin iterator. - - -
public fun new_begin_iter<K: copy, store, V: store>(self: &btree_map::BTreeMap<K, V>): btree_map::Iterator<K>
-
- - - -
-Implementation - - -
public fun new_begin_iter<K: copy + store, V: store>(self: &BTreeMap<K, V>): Iterator<K> {
-    if (self.empty()) {
-        return Iterator::End;
-    };
-
-    let node = self.nodes.borrow(self.min_leaf_index);
-    let key = node.children.borrow(0).max_key;
-
-    new_iter(self.min_leaf_index, 0, key)
-}
-
- - - -
- - - -## Function `new_end_iter` - -Return the end iterator. - - -
public fun new_end_iter<K: copy, store, V: store>(self: &btree_map::BTreeMap<K, V>): btree_map::Iterator<K>
-
- - - -
-Implementation - - -
public fun new_end_iter<K: copy + store, V: store>(self: &BTreeMap<K, V>): Iterator<K> {
-    Iterator::End
-}
-
- - - -
- - - -## Function `next_iter` - -Returns the next iterator, or none if already at the end iterator. -Requires the tree is not changed after the input iterator is generated. - - -
public fun next_iter<K: copy, drop, store, V: store>(tree: &btree_map::BTreeMap<K, V>, iter: btree_map::Iterator<K>): option::Option<btree_map::Iterator<K>>
-
- - - -
-Implementation - - -
public fun next_iter<K: drop + copy + store, V: store>(tree: &BTreeMap<K, V>, iter: Iterator<K>): Option<Iterator<K>> {
-    if (iter is Iterator::End<K>) {
-        option::none()
-    } else {
-        option::some(next_iter_or_die(tree, iter))
-    }
-}
-
- - - -
- - - -## Function `next_iter_or_die` - -Returns the next iterator, aborts if already at the end iterator. -Requires the tree is not changed after the input iterator is generated. - - -
public fun next_iter_or_die<K: copy, drop, store, V: store>(tree: &btree_map::BTreeMap<K, V>, iter: btree_map::Iterator<K>): btree_map::Iterator<K>
-
- - - -
-Implementation - - -
public fun next_iter_or_die<K: drop + copy + store, V: store>(tree: &BTreeMap<K, V>, iter: Iterator<K>): Iterator<K> {
-    assert!(!(iter is Iterator::End<K>), E_INVALID_PARAMETER);
-
-    let node_index = iter.node_index;
-
-    let node = table_with_length::borrow(&tree.nodes, node_index);
-    iter.child_index = iter.child_index + 1;
-    if (iter.child_index < vector::length(&node.children)) {
-        iter.key = vector::borrow(&node.children, iter.child_index).max_key;
-        return iter
-    };
-
-    let next_index = node.next;
-    if (next_index != NULL_INDEX) {
-        let next_node = table_with_length::borrow(&tree.nodes, next_index);
-        iter.node_index = next_index;
-        iter.child_index = 0;
-        iter.key = vector::borrow(&next_node.children, 0).max_key;
-        return iter
-    };
-
-    new_end_iter(tree)
-}
-
- - - -
- - - -## Function `prev_iter` - -Returns the previous iterator, or none if already at the begin iterator. -Requires the tree is not changed after the input iterator is generated. - - -
public fun prev_iter<K: copy, drop, store, V: store>(tree: &btree_map::BTreeMap<K, V>, iter: btree_map::Iterator<K>): option::Option<btree_map::Iterator<K>>
-
- - - -
-Implementation - - -
public fun prev_iter<K: drop + copy + store, V: store>(tree: &BTreeMap<K, V>, iter: Iterator<K>): Option<Iterator<K>> {
-    if (iter.node_index == tree.min_leaf_index && iter.child_index == 0) {
-        return option::none()
-    };
-
-    option::some(prev_iter_or_die(tree, iter))
-}
-
- - - -
- - - -## Function `prev_iter_or_die` - -Returns the previous iterator, aborts if already at the begin iterator. -Requires the tree is not changed after the input iterator is generated. - - -
public fun prev_iter_or_die<K: copy, drop, store, V: store>(tree: &btree_map::BTreeMap<K, V>, iter: btree_map::Iterator<K>): btree_map::Iterator<K>
-
- - - -
-Implementation - - -
public fun prev_iter_or_die<K: drop + copy + store, V: store>(tree: &BTreeMap<K, V>, iter: Iterator<K>): Iterator<K> {
-    let prev_index = if (iter is Iterator::End<K>) {
-        tree.max_leaf_index
-    } else {
-        let node_index = iter.node_index;
-        let node = table_with_length::borrow(&tree.nodes, node_index);
-        if (iter.child_index >= 1) {
-            iter.child_index = iter.child_index - 1;
-            iter.key = vector::borrow(&node.children, iter.child_index).max_key;
-            return iter
-        };
-        node.prev
-    };
-
-    assert!(prev_index != NULL_INDEX, E_INTERNAL);
-
-    let prev_node = table_with_length::borrow(&tree.nodes, prev_index);
-    let len = vector::length(&prev_node.children);
-
-    Iterator::Some {
-        node_index: prev_index,
-        child_index: len - 1,
-        key: vector::borrow(&prev_node.children, len - 1).max_key,
-    }
-}
-
- - - -
- - - -## Function `destroy_inner_child` - - - -
fun destroy_inner_child<K: drop, store, V: store>(self: btree_map::Child<K, V>)
-
- - - -
-Implementation - - -
fun destroy_inner_child<K: drop + store, V: store>(self: Child<K, V>) {
-    let Child::Inner {
-        max_key: _,
-        node_index: _,
-    } = self;
-}
-
- - - -
- - - -## Function `destroy_empty_node` - - - -
fun destroy_empty_node<K: store, V: store>(self: btree_map::Node<K, V>)
-
- - - -
-Implementation - - -
fun destroy_empty_node<K: store, V: store>(self: Node<K, V>) {
-    let Node { children, is_leaf: _, parent: _, prev: _, next: _ } = self;
-    assert!(children.is_empty(), E_TREE_NOT_EMPTY);
-    children.destroy_empty();
-}
-
- - - -
- - - -## Function `new_node` - - - -
fun new_node<K: store, V: store>(is_leaf: bool, parent: u64): btree_map::Node<K, V>
-
- - - -
-Implementation - - -
fun new_node<K: store, V: store>(is_leaf: bool, parent: u64): Node<K, V> {
-    Node {
-        is_leaf: is_leaf,
-        parent: parent,
-        children: vector::empty(),
-        prev: NULL_INDEX,
-        next: NULL_INDEX,
-    }
-}
-
- - - -
- - - -## Function `new_node_with_children` - - - -
fun new_node_with_children<K: store, V: store>(is_leaf: bool, parent: u64, children: vector<btree_map::Child<K, V>>): btree_map::Node<K, V>
-
- - - -
-Implementation - - -
fun new_node_with_children<K: store, V: store>(is_leaf: bool, parent: u64, children: vector<Child<K, V>>): Node<K, V> {
-    Node {
-        is_leaf: is_leaf,
-        parent: parent,
-        children: children,
-        prev: NULL_INDEX,
-        next: NULL_INDEX,
-    }
-}
-
- - - -
- - - -## Function `new_inner_child` - - - -
fun new_inner_child<K: store, V: store>(max_key: K, node_index: u64): btree_map::Child<K, V>
-
- - - -
-Implementation - - -
fun new_inner_child<K: store, V: store>(max_key: K, node_index: u64): Child<K, V> {
-    Child::Inner {
-        max_key: max_key,
-        node_index: node_index,
-    }
-}
-
- - - -
- - - -## Function `new_leaf_child` - - - -
fun new_leaf_child<K: store, V: store>(max_key: K, value: V): btree_map::Child<K, V>
-
- - - -
-Implementation - - -
fun new_leaf_child<K: store, V: store>(max_key: K, value: V): Child<K, V> {
-    Child::Leaf {
-        max_key: max_key,
-        value: value,
-    }
-}
-
- - - -
- - - -## Function `new_iter` - - - -
fun new_iter<K: store>(node_index: u64, child_index: u64, key: K): btree_map::Iterator<K>
-
- - - -
-Implementation - - -
fun new_iter<K: store>(node_index: u64, child_index: u64, key: K): Iterator<K> {
-    Iterator::Some {
-        node_index: node_index,
-        child_index: child_index,
-        key: key,
-    }
-}
-
- - - -
- - - -## Function `find_leaf` - - - -
fun find_leaf<K: copy, drop, store, V: store>(self: &btree_map::BTreeMap<K, V>, key: K): u64
-
- - - -
-Implementation - - -
fun find_leaf<K: drop + copy + store, V: store>(self: &BTreeMap<K, V>, key: K): u64 {
-    let current = self.root_index;
-    while (current != NULL_INDEX) {
-        let node = self.nodes.borrow(current);
-        if (node.is_leaf) {
-            return current
-        };
-        let len = node.children.length();
-        if (cmp::compare(&node.children.borrow(len - 1).max_key, &key).is_less_than()) {
-            return NULL_INDEX
-        };
-
-        let index = binary_search(key, &node.children, 0, len);
-
-        current = node.children.borrow(index).node_index;
-    };
-
-    NULL_INDEX
-}
-
- - - -
- - - -## Function `binary_search` - - - -
fun binary_search<K: drop, store, V: store>(key: K, children: &vector<btree_map::Child<K, V>>, start: u64, end: u64): u64
-
- - - -
-Implementation - - -
fun binary_search<K: drop + store, V: store>(key: K, children: &vector<Child<K, V>>, start: u64, end: u64): u64 {
-    let l = start;
-    let r = end;
-    while (l != r) {
-        let mid = l + (r - l) / 2;
-        if (cmp::compare(&vector::borrow(children, mid).max_key, &key).is_less_than()) {
-            l = mid + 1;
-        } else {
-            r = mid;
-        };
-    };
-    l
-}
-
- - - -
- - - -## Function `get_max_degree` - - - -
fun get_max_degree<K: store, V: store>(self: &btree_map::BTreeMap<K, V>, leaf: bool): u64
-
- - - -
-Implementation - - -
fun get_max_degree<K: store, V: store>(self: &BTreeMap<K, V>, leaf: bool): u64 {
-    if (leaf) {
-        self.leaf_max_degree as u64
-    } else {
-        self.inner_max_degree as u64
-    }
-}
-
- - - -
- - - -## Function `insert_at` - - - -
fun insert_at<K: copy, drop, store, V: store>(self: &mut btree_map::BTreeMap<K, V>, node_index: u64, child: btree_map::Child<K, V>)
-
- - - -
-Implementation - - -
fun insert_at<K: drop + copy + store, V: store>(self: &mut BTreeMap<K, V>, node_index: u64, child: Child<K, V>) {
-    let current_size = {
-        let node = table_with_length::borrow_mut(&mut self.nodes, node_index);
-        let children = &mut node.children;
-        let current_size = vector::length(children);
-        let key = child.max_key;
-
-        let max_degree = if (node.is_leaf) {
-            self.leaf_max_degree as u64
-        } else {
-            self.inner_max_degree as u64
-        };
-
-        if (current_size < max_degree) {
-            let index = binary_search(key, children, 0, current_size);
-            assert!(index >= current_size || children[index].max_key != key, E_INTERNAL); // key cannot already be inside.
-            vector::insert(children, index, child);
-            return
-        };
-        current_size
-    };
-
-    // # of children in the current node exceeds the threshold, need to split into two nodes.
-    let node = table_with_length::remove(&mut self.nodes, node_index);
-    let parent_index = node.parent;
-    let is_leaf = &mut node.is_leaf;
-    let next = &mut node.next;
-    let prev = &mut node.prev;
-    let children = &mut node.children;
-    let key = child.max_key;
-
-    let max_degree = if (*is_leaf) {
-        self.leaf_max_degree as u64
-    } else {
-        self.inner_max_degree as u64
-    };
-    let target_size = (max_degree + 1) / 2;
-
-    let l = binary_search(key, children, 0, current_size);
-
-    let left_node_index = table_with_length::length(&self.nodes) + 2;
-
-    if (parent_index == NULL_INDEX) {
-        // Splitting root now, need to create a new root.
-        parent_index = table_with_length::length(&self.nodes) + 3;
-        node.parent = parent_index;
-
-        self.root_index = parent_index;
-        let parent_node = new_node(/*is_leaf=*/false, /*parent=*/NULL_INDEX);
-        let max_element = vector::borrow(children, current_size - 1).max_key;
-        if (cmp::compare(&max_element, &key).is_less_than()) {
-            max_element = key;
-        };
-        vector::push_back(&mut parent_node.children, new_inner_child(max_element, node_index));
-        table_with_length::add(&mut self.nodes, parent_index, parent_node);
-    };
-
-    let new_node_children = if (l < target_size) {
-        let new_node_children = vector::split_off(children, target_size - 1);
-        vector::insert(children, l, child);
-        new_node_children
-    } else {
-        vector::insert(children, l, child);
-        vector::split_off(children, target_size)
-    };
-
-    let right_node = new_node_with_children(*is_leaf, parent_index, new_node_children);
-
-    right_node.next = *next;
-    *next = node_index;
-    right_node.prev = left_node_index;
-    if (*prev != NULL_INDEX) {
-        table_with_length::borrow_mut(&mut self.nodes, *prev).next = left_node_index;
-    };
-
-    if (!*is_leaf) {
-        let i = 0;
-        while (i < target_size) {
-            table_with_length::borrow_mut(&mut self.nodes, vector::borrow(children, i).node_index).parent = left_node_index;
-            i = i + 1;
-        };
-    };
-
-    let split_key = vector::borrow(children, target_size - 1).max_key;
-
-    table_with_length::add(&mut self.nodes, left_node_index, node);
-    table_with_length::add(&mut self.nodes, node_index, right_node);
-    if (node_index == self.min_leaf_index) {
-        self.min_leaf_index = left_node_index;
-    };
-    insert_at(self, parent_index, new_inner_child(split_key, left_node_index));
-}
-
- - - -
- - - -## Function `update_key` - - - -
fun update_key<K: copy, drop, store, V: store>(self: &mut btree_map::BTreeMap<K, V>, node_index: u64, old_key: K, new_key: K)
-
- - - -
-Implementation - - -
fun update_key<K: drop + copy + store, V: store>(self: &mut BTreeMap<K, V>, node_index: u64, old_key: K, new_key: K) {
-    if (node_index == NULL_INDEX) {
-        return
-    };
-
-    let node = table_with_length::borrow_mut(&mut self.nodes, node_index);
-    let keys = &mut node.children;
-    let current_size = vector::length(keys);
-
-    let index = binary_search(old_key, keys, 0, current_size);
-
-    vector::borrow_mut(keys, index).max_key = new_key;
-    move keys;
-
-    if (index == current_size - 1) {
-        update_key(self, node.parent, old_key, new_key);
-    };
-}
-
- - - -
- - - -## Function `remove_at` - - - -
fun remove_at<K: copy, drop, store, V: store>(self: &mut btree_map::BTreeMap<K, V>, node_index: u64, key: K): btree_map::Child<K, V>
-
- - - -
-Implementation - - -
fun remove_at<K: drop + copy + store, V: store>(self: &mut BTreeMap<K, V>, node_index: u64, key: K): Child<K, V> {
-    let (old_child, current_size) = {
-        let node = table_with_length::borrow_mut(&mut self.nodes, node_index);
-
-        let children = &mut node.children;
-        let current_size = vector::length(children);
-
-        if (current_size == 1 && !node.is_leaf) {
-            // Remove the only element at root node.
-            assert!(node_index == self.root_index, E_INTERNAL);
-            assert!(key == vector::borrow(children, 0).max_key, E_INTERNAL);
-            return vector::pop_back(children);
-        };
-
-        let is_leaf = node.is_leaf;
-
-        let index = binary_search(key, children, 0, current_size);
-
-        assert!(index < current_size, E_INTERNAL);
-
-        let max_key_updated = index == (current_size - 1);
-        let old_child = vector::remove(children, index);
-        current_size = current_size - 1;
-
-        // always look at inner degree on reduction
-        let big_enough = current_size * 2 >= (self.inner_max_degree as u64);
-        if (!max_key_updated && big_enough) {
-            return old_child;
-        };
-
-        if (!big_enough && node_index == self.root_index) {
-            // promote only child to root, and drop current root.
-            if (current_size == 1 && !is_leaf) {
-                let Child::Inner {
-                    node_index: inner_child_index,
-                    max_key: _,
-                } = vector::pop_back(children);
-                self.root_index = inner_child_index;
-                table_with_length::borrow_mut(&mut self.nodes, self.root_index).parent = NULL_INDEX;
-                destroy_empty_node(table_with_length::remove(&mut self.nodes, node_index));
-            } else {
-                // nothing to change
-            };
-            return old_child;
-        };
-
-        if (max_key_updated) {
-            let new_max_key = vector::borrow(children, current_size - 1).max_key;
-            let parent = node.parent;
-
-            update_key(self, parent, key, new_max_key);
-
-            if (big_enough) {
-                return old_child;
-            }
-        };
-
-        (old_child, current_size)
-    };
-
-    // We need to update tree beyond the current node
-
-    let node = table_with_length::remove(&mut self.nodes, node_index);
-
-    let prev = node.prev;
-    let next = node.next;
-    let parent = node.parent;
-    let is_leaf = node.is_leaf;
-
-    let children = &mut node.children;
-
-    // Children size is below threshold, we need to rebalance
-
-    let brother_index = next;
-    if (brother_index == NULL_INDEX || table_with_length::borrow(&self.nodes, brother_index).parent != parent) {
-        brother_index = prev;
-    };
-    let brother_node = table_with_length::remove(&mut self.nodes, brother_index);
-    let brother_children = &mut brother_node.children;
-    let brother_size = vector::length(brother_children);
-
-    // always look at inner degree on reduction
-    if ((brother_size - 1) * 2 >= (self.inner_max_degree as u64)) {
-        // The brother node has enough elements, borrow an element from the brother node.
-        brother_size = brother_size - 1;
-        if (brother_index == next) {
-            let borrowed_element = vector::remove(brother_children, 0);
-            if (borrowed_element is Child::Inner<K, V>) {
-                table_with_length::borrow_mut(&mut self.nodes, borrowed_element.node_index).parent = node_index;
-            };
-            let borrowed_max_key = borrowed_element.max_key;
-            vector::push_back(children, borrowed_element);
-            update_key(self, parent, vector::borrow(children, current_size - 2).max_key, borrowed_max_key);
-        } else {
-            let borrowed_element = vector::pop_back(brother_children);
-            if (borrowed_element is Child::Inner<K, V>) {
-                table_with_length::borrow_mut(&mut self.nodes, borrowed_element.node_index).parent = node_index;
-            };
-            vector::insert(children, 0, borrowed_element);
-            update_key(self, parent, vector::borrow(children, 0).max_key, vector::borrow(brother_children, brother_size - 1).max_key);
-        };
-
-        table_with_length::add(&mut self.nodes, node_index, node);
-        table_with_length::add(&mut self.nodes, brother_index, brother_node);
-        return old_child;
-    };
-
-    // The brother node doesn't have enough elements to borrow, merge with the brother node.
-    if (brother_index == next) {
-        if (!is_leaf) {
-            let len = vector::length(children);
-            let i = 0;
-            while (i < len) {
-                table_with_length::borrow_mut(&mut self.nodes, vector::borrow(children, i).node_index).parent = brother_index;
-                i = i + 1;
-            };
-        };
-        let Node { children: brother_children, is_leaf: _, parent: _, prev: _, next: brother_next } = brother_node;
-        vector::append(children, brother_children);
-        node.next = brother_next;
-        let key_to_remove = vector::borrow(children, current_size - 1).max_key;
-
-        move children;
-
-        if (node.next != NULL_INDEX) {
-            table_with_length::borrow_mut(&mut self.nodes, node.next).prev = brother_index;
-        };
-        if (node.prev != NULL_INDEX) {
-            table_with_length::borrow_mut(&mut self.nodes, node.prev).next = brother_index;
-        };
-
-        table_with_length::add(&mut self.nodes, brother_index, node);
-        if (self.min_leaf_index == node_index) {
-            self.min_leaf_index = brother_index;
-        };
-
-        if (parent != NULL_INDEX) {
-            destroy_inner_child(remove_at(self, parent, key_to_remove));
-        };
-    } else {
-        if (!is_leaf) {
-            let len = vector::length(brother_children);
-            let i = 0;
-            while (i < len) {
-                table_with_length::borrow_mut(&mut self.nodes, vector::borrow(brother_children, i).node_index).parent = node_index;
-                i = i + 1;
-            };
-        };
-        let Node { children: node_children, is_leaf: _, parent: _, prev: _, next: node_next } = node;
-        vector::append(brother_children, node_children);
-        brother_node.next = node_next;
-        let key_to_remove = vector::borrow(brother_children, brother_size - 1).max_key;
-
-        move brother_children;
-
-        if (brother_node.next != NULL_INDEX) {
-            table_with_length::borrow_mut(&mut self.nodes, brother_node.next).prev = node_index;
-        };
-        if (brother_node.prev != NULL_INDEX) {
-            table_with_length::borrow_mut(&mut self.nodes, brother_node.prev).next = node_index;
-        };
-
-        table_with_length::add(&mut self.nodes, node_index, brother_node);
-        if (self.min_leaf_index == brother_index) {
-            self.min_leaf_index = node_index;
-        };
-
-        if (parent != NULL_INDEX) {
-            destroy_inner_child(remove_at(self, parent, key_to_remove));
-        };
-    };
-    old_child
-}
-
- - - -
- - -[move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md b/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md index ae5650a96ea4d..cedffb19962e7 100644 --- a/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md +++ b/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md @@ -504,7 +504,11 @@ and can be used only in modules that know by themselves that allocator is empty. reuse_spare_count: _, } => { assert!(reuse_head_index == NULL_INDEX, EINTERNAL_INVARIANT_BROKEN); - slots.destroy_some().destroy_known_empty_unsafe(); + if (slots.is_some()) { + slots.destroy_some().destroy_known_empty_unsafe(); + } else { + slots.destroy_none(); + } }, }; } diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move b/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move index 89a194508b499..ebbec1cf8a359 100644 --- a/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move +++ b/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move @@ -645,13 +645,18 @@ module aptos_std::big_ordered_map { root.is_leaf = new_root.is_leaf; new_root.is_leaf = tmp_is_leaf; - let tmp_prev = root.prev; - root.prev = new_root.prev; - new_root.prev = tmp_prev; + assert!(root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(new_root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(new_root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - let tmp_next = root.next; - root.next = new_root.next; - new_root.next = tmp_next; + // let tmp_prev = root.prev; + // root.prev = new_root.prev; + // new_root.prev = tmp_prev; + + // let tmp_next = root.next; + // root.next = new_root.next; + // new_root.next = tmp_next; let tmp_children = root.children.trim(0); root.children.append_disjoint(new_root.children.trim(0)); @@ -807,13 +812,14 @@ module aptos_std::big_ordered_map { // right node's prev becomes current left node right_node.prev = left_node_index; - // Since the previuosly used index is going to the right node, `prev` pointer of the next node is correct, + // Since the previously used index is going to the right node, `prev` pointer of the next node is correct, // and we need to update next pointer of the previous node (if exists) if (*left_prev != NULL_INDEX) { self.nodes.borrow_mut(*left_prev).next = left_node_index; assert!(right_node_index != self.min_leaf_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); } else if (right_node_index == self.min_leaf_index) { // Otherwise, if we were the smallest node on the level. if this is the leaf level, update the pointer. + assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); self.min_leaf_index = left_node_index; }; @@ -844,10 +850,10 @@ module aptos_std::big_ordered_map { } fun remove_at(self: &mut BigOrderedMap, path_to_node: vector, key: &K): Child { - // Last node in the path is one where we need to add the child to. + // Last node in the path is one where we need to remove the child from. let node_index = path_to_node.pop_back(); let old_child = { - // First check if we can perform this operation, without changing structure of the tree (i.e. without adding any nodes). + // First check if we can perform this operation, without changing structure of the tree (i.e. without rebalancing any nodes). // For that we can just borrow the single node let node = self.borrow_node_mut(node_index); @@ -939,6 +945,7 @@ module aptos_std::big_ordered_map { let children = &mut node.children; let (sibling_slot, sibling_node) = self.nodes.remove_and_reserve(sibling_index); + assert!(is_leaf == sibling_node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); let sibling_children = &mut sibling_node.children; if ((sibling_children.length() - 1) * 2 >= max_degree) { @@ -992,6 +999,7 @@ module aptos_std::big_ordered_map { }; // Otherwise, we were the smallest node on the level. if this is the leaf level, update the pointer. if (self.min_leaf_index == node_index) { + assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); self.min_leaf_index = sibling_index; }; @@ -1015,6 +1023,7 @@ module aptos_std::big_ordered_map { }; // Otherwise, sibling was the smallest node on the level. if this is the leaf level, update the pointer. if (self.min_leaf_index == sibling_index) { + assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); self.min_leaf_index = node_index; }; @@ -1540,6 +1549,94 @@ module aptos_std::big_ordered_map { map.destroy(); } + #[test_only] + inline fun comparison_test(repeats: u64, inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool, next_1: ||u64, next_2: ||u64) { + let big_map = new_with_config(inner_max_degree, leaf_max_degree, reuse_slots, if (reuse_slots) {4} else {0}); + let small_map = ordered_map::new(); + for (i in 0..repeats) { + let is_insert = if (2 * i < repeats) { + i % 3 != 2 + } else { + i % 3 == 0 + }; + if (is_insert) { + let v = next_1(); + assert!(big_map.upsert(v, v) == small_map.upsert(v, v), i); + } else { + let v = next_2(); + assert!(big_map.remove(&v) == small_map.remove(&v), i); + }; + if ((i + 1) % 50 == 0) { + big_map.validate_map(); + + let big_iter = big_map.new_begin_iter(); + let small_iter = small_map.new_begin_iter(); + while (!big_iter.iter_is_end(&big_map) || !small_iter.iter_is_end(&small_map)) { + assert!(big_iter.iter_borrow_key() == small_iter.iter_borrow_key(&small_map), i); + assert!(big_iter.iter_borrow(&big_map) == small_iter.iter_borrow(&small_map), i); + big_iter = big_iter.iter_next(&big_map); + small_iter = small_iter.iter_next(&small_map); + }; + }; + }; + big_map.destroy(); + } + + #[test_only] + const OFFSET: u64 = 270001; + #[test_only] + const MOD: u64 = 1000000; + + #[test] + fun test_comparison_random() { + let x = 1234; + let y = 1234; + comparison_test(500, 5, 5, false, + || { + x = x + OFFSET; + if (x > MOD) { x = x - MOD}; + x + }, + || { + y = y + OFFSET; + if (y > MOD) { y = y - MOD}; + y + }, + ); + } + + #[test] + fun test_comparison_increasing() { + let x = 0; + let y = 0; + comparison_test(500, 5, 5, false, + || { + x = x + 1; + x + }, + || { + y = y + 1; + y + }, + ); + } + + #[test] + fun test_comparison_decreasing() { + let x = 100000; + let y = 100000; + comparison_test(500, 5, 5, false, + || { + x = x - 1; + x + }, + || { + y = y - 1; + y + }, + ); + } + #[test_only] fun test_large_data_set_helper(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool) { use std::vector; @@ -1645,58 +1742,58 @@ module aptos_std::big_ordered_map { test_large_data_set_helper(4, 6, false); } - #[test] - fun test_large_data_set_order_4_6_true() { - test_large_data_set_helper(4, 6, true); - } + // #[test] + // fun test_large_data_set_order_4_6_true() { + // test_large_data_set_helper(4, 6, true); + // } - #[test] - fun test_large_data_set_order_16_false() { - test_large_data_set_helper(16, 16, false); - } + // #[test] + // fun test_large_data_set_order_16_false() { + // test_large_data_set_helper(16, 16, false); + // } - #[test] - fun test_large_data_set_order_16_true() { - test_large_data_set_helper(16, 16, true); - } + // #[test] + // fun test_large_data_set_order_16_true() { + // test_large_data_set_helper(16, 16, true); + // } - #[test] - fun test_large_data_set_order_31_false() { - test_large_data_set_helper(31, 31, false); - } + // #[test] + // fun test_large_data_set_order_31_false() { + // test_large_data_set_helper(31, 31, false); + // } - #[test] - fun test_large_data_set_order_31_true() { - test_large_data_set_helper(31, 31, true); - } + // #[test] + // fun test_large_data_set_order_31_true() { + // test_large_data_set_helper(31, 31, true); + // } - #[test] - fun test_large_data_set_order_31_3_false() { - test_large_data_set_helper(31, 3, false); - } + // #[test] + // fun test_large_data_set_order_31_3_false() { + // test_large_data_set_helper(31, 3, false); + // } - #[test] - fun test_large_data_set_order_31_3_true() { - test_large_data_set_helper(31, 3, true); - } + // #[test] + // fun test_large_data_set_order_31_3_true() { + // test_large_data_set_helper(31, 3, true); + // } - #[test] - fun test_large_data_set_order_31_5_false() { - test_large_data_set_helper(31, 5, false); - } + // #[test] + // fun test_large_data_set_order_31_5_false() { + // test_large_data_set_helper(31, 5, false); + // } - #[test] - fun test_large_data_set_order_31_5_true() { - test_large_data_set_helper(31, 5, true); - } + // #[test] + // fun test_large_data_set_order_31_5_true() { + // test_large_data_set_helper(31, 5, true); + // } - #[test] - fun test_large_data_set_order_32_false() { - test_large_data_set_helper(32, 32, false); - } + // #[test] + // fun test_large_data_set_order_32_false() { + // test_large_data_set_helper(32, 32, false); + // } - #[test] - fun test_large_data_set_order_32_true() { - test_large_data_set_helper(32, 32, true); - } + // #[test] + // fun test_large_data_set_order_32_true() { + // test_large_data_set_helper(32, 32, true); + // } }