diff --git a/aptos-move/aptos-gas-schedule/src/gas_schedule/move_stdlib.rs b/aptos-move/aptos-gas-schedule/src/gas_schedule/move_stdlib.rs index ef2b19452885ec..486869ffafbf9a 100644 --- a/aptos-move/aptos-gas-schedule/src/gas_schedule/move_stdlib.rs +++ b/aptos-move/aptos-gas-schedule/src/gas_schedule/move_stdlib.rs @@ -7,7 +7,7 @@ use crate::{ gas_feature_versions::{RELEASE_V1_18, RELEASE_V1_22}, gas_schedule::NativeGasParameters, }; -use aptos_gas_algebra::{InternalGas, InternalGasPerArg, InternalGasPerByte}; +use aptos_gas_algebra::{InternalGas, InternalGasPerAbstractValueUnit, InternalGasPerArg, InternalGasPerByte}; crate::gas_schedule::macros::define_gas_parameters!( MoveStdlibGasParameters, 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 9b5e23b32965b1..0ddc969eda9405 100644 --- a/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md +++ b/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md @@ -3,11 +3,22 @@ # Module `0x1::big_ordered_map` -Type of large-scale search trees. +This module provides an implementation for an big ordered map. +Big means that it is stored across multiple resources, and doesn't have an +upper limit on number of elements it can contain. -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). +Keys point to values, and each key in the map must be unique. + +Currently, one implementation is provided - BPlusTreeMap, backed by a B+Tree, +with each node being a separate resource, internally containing OrderedMap. + +BPlusTreeMap is chosen since the biggest (performance and gast) +costs are reading resources, and it: +* reduces number of resource accesses +* reduces number of rebalancing operations, and makes each rebalancing +operation touch only few resources +* it allows for parallelism for keys that are not close to each other, +once it contains enough keys - [Struct `Node`](#0x1_big_ordered_map_Node) @@ -20,21 +31,20 @@ more metadata into one node, which is more disk friendly (and gas friendly). - [Function `destroy_empty`](#0x1_big_ordered_map_destroy_empty) - [Function `add`](#0x1_big_ordered_map_add) - [Function `upsert`](#0x1_big_ordered_map_upsert) -- [Function `add_or_upsert_impl`](#0x1_big_ordered_map_add_or_upsert_impl) - [Function `remove`](#0x1_big_ordered_map_remove) -- [Function `is_begin_iter`](#0x1_big_ordered_map_is_begin_iter) -- [Function `is_end_iter`](#0x1_big_ordered_map_is_end_iter) -- [Function `iter_get_key`](#0x1_big_ordered_map_iter_get_key) - [Function `lower_bound`](#0x1_big_ordered_map_lower_bound) - [Function `find`](#0x1_big_ordered_map_find) - [Function `contains`](#0x1_big_ordered_map_contains) - [Function `borrow`](#0x1_big_ordered_map_borrow) -- [Function `borrow_mut`](#0x1_big_ordered_map_borrow_mut) - [Function `new_begin_iter`](#0x1_big_ordered_map_new_begin_iter) - [Function `new_end_iter`](#0x1_big_ordered_map_new_end_iter) -- [Function `next_iter`](#0x1_big_ordered_map_next_iter) -- [Function `prev_iter`](#0x1_big_ordered_map_prev_iter) -- [Function `init_max_degrees`](#0x1_big_ordered_map_init_max_degrees) +- [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_next`](#0x1_big_ordered_map_iter_next) +- [Function `iter_prev`](#0x1_big_ordered_map_iter_prev) +- [Function `add_or_upsert_impl`](#0x1_big_ordered_map_add_or_upsert_impl) +- [Function `validate_size_and_init_max_degrees`](#0x1_big_ordered_map_validate_size_and_init_max_degrees) - [Function `destroy_inner_child`](#0x1_big_ordered_map_destroy_inner_child) - [Function `destroy_empty_node`](#0x1_big_ordered_map_destroy_empty_node) - [Function `new_node`](#0x1_big_ordered_map_new_node) @@ -54,6 +64,7 @@ more metadata into one node, which is more disk friendly (and gas friendly).
use 0x1::bcs;
 use 0x1::cmp;
+use 0x1::error;
 use 0x1::math64;
 use 0x1::option;
 use 0x1::ordered_map;
@@ -68,6 +79,11 @@ more metadata into one node, which is more disk friendly (and gas friendly).
 
 A node of the BigOrderedMap.
 
+Inner node will have all children be Child::Inner, pointing to the child nodes.
+Leaf node will have all children be Child::Leaf.
+Basically - Leaf node is a single-resource OrderedMap, containing as much keys as can fit.
+So Leaf node contains multiple values, not just one.
+
 
 
struct Node<K: store, V: store> has store
 
@@ -329,11 +345,31 @@ The BigOrderedMap data structure. + + + + +
const EITER_OUT_OF_BOUNDS: u64 = 3;
+
+ + + +Map key already exists -
const EKEY_ALREADY_EXISTS: u64 = 4;
+
const EKEY_ALREADY_EXISTS: u64 = 1;
+
+ + + + + +Map key is not found + + +
const EKEY_NOT_FOUND: u64 = 2;
 
@@ -365,38 +401,38 @@ The BigOrderedMap data structure. - + -
const E_INTERNAL: u64 = 0;
+
const EARGUMENT_BYTES_TOO_LARGE: u64 = 6;
 
- + -
const E_INVALID_PARAMETER: u64 = 3;
+
const EINTERNAL_INVARIANT_BROKEN: u64 = 7;
 
- + -
const E_TREE_NOT_EMPTY: u64 = 1;
+
const EINVALID_CONFIG_PARAMETER: u64 = 4;
 
- + -
const E_TREE_TOO_BIG: u64 = 2;
+
const EMAP_NOT_EMPTY: u64 = 5;
 
@@ -410,6 +446,15 @@ The BigOrderedMap data structure. + + + + +
const MAX_NODE_BYTES: u64 = 204800;
+
+ + + ## Function `new` @@ -453,12 +498,12 @@ If 0 is passed, then it is dynamically computed based on size of first key and v
public fun new_with_config<K: store, V: store>(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool, num_to_preallocate: u64): BigOrderedMap<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);
+    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));
     let nodes = if (reuse_slots) {
         storage_slots_allocator::new_reuse_storage_slots(num_to_preallocate)
     } else {
-        assert!(num_to_preallocate == 0, E_INVALID_PARAMETER);
+        assert!(num_to_preallocate == 0, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
         storage_slots_allocator::new_storage_slots()
     };
     let root_index = nodes.add(new_node(/*is_leaf=*/true, /*parent=*/NULL_INDEX));
@@ -481,7 +526,7 @@ If 0 is passed, then it is dynamically computed based on size of first key and v
 
 ## Function `destroy_empty`
 
-Destroys the tree if it's empty, otherwise aborts.
+Destroys the map if it's empty, otherwise aborts.
 
 
 
public fun destroy_empty<K: store, V: store>(self: big_ordered_map::BigOrderedMap<K, V>)
@@ -495,7 +540,6 @@ Destroys the tree if it's empty, otherwise aborts.
 
 
public fun destroy_empty<K: store, V: store>(self: BigOrderedMap<K, V>) {
     let BigOrderedMap::BPlusTreeMap { nodes, root_index, min_leaf_index: _, max_leaf_index: _, inner_max_degree: _, leaf_max_degree: _ } = self;
-    // aptos_std::debug::print(&nodes);
     nodes.remove(root_index).destroy_empty_node();
     nodes.destroy();
 }
@@ -510,7 +554,7 @@ Destroys the tree if it's empty, otherwise aborts.
 ## Function `add`
 
 Inserts the key/value into the BigOrderedMap.
-Aborts if the key is already in the tree.
+Aborts if the key is already in the map.
 
 
 
public fun add<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V)
@@ -535,7 +579,7 @@ Aborts if the key is already in the tree.
 
 ## Function `upsert`
 
-If the key doesn't exist in the tree, inserts the key/value, and returns none.
+If the key doesn't exist in the map, inserts the key/value, and returns none.
 Otherwise updates the value under the given key, and returns the old value.
 
 
@@ -564,49 +608,6 @@ Otherwise updates the value under the given key, and returns the old value.
 
 
 
-
-
-
-
-## Function `add_or_upsert_impl`
-
-
-
-
fun add_or_upsert_impl<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
-
- - - -
-Implementation - - -
fun add_or_upsert_impl<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: K, value: V, allow_overwrite: bool): Option<Child<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_value = current_node.children.new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children);
-            current_node.children.add(key, last_value);
-            current = current_node.parent;
-        }
-    };
-
-    self.add_at(leaf, key, new_leaf_child(value), allow_overwrite)
-}
-
- - -
@@ -628,7 +629,7 @@ Aborts if there is no entry for key.
public fun remove<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: &K): V {
     let iter = self.find(key);
-    assert!(!is_end_iter(self, &iter), E_INTERNAL);
+    assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
 
     let Child::Leaf {
         value,
@@ -640,84 +641,6 @@ Aborts if there is no entry for key.
 
 
 
-
-
-
-
-## Function `is_begin_iter`
-
-
-
-
public fun is_begin_iter<K: store, V: store>(tree: &big_ordered_map::BigOrderedMap<K, V>, iter: &big_ordered_map::Iterator<K>): bool
-
- - - -
-Implementation - - -
public fun is_begin_iter<K: store, V: store>(tree: &BigOrderedMap<K, V>, iter: &Iterator<K>): bool {
-    if (iter is Iterator::End<K>) {
-        tree.is_empty()
-    } else {
-        (iter.node_index == tree.min_leaf_index && iter.child_iter.iter_is_begin_from_non_empty())
-    }
-}
-
- - - -
- - - -## Function `is_end_iter` - - - -
public fun is_end_iter<K: store, V: store>(_tree: &big_ordered_map::BigOrderedMap<K, V>, iter: &big_ordered_map::Iterator<K>): bool
-
- - - -
-Implementation - - -
public fun is_end_iter<K: store, V: store>(_tree: &BigOrderedMap<K, V>, iter: &Iterator<K>): bool {
-    iter is Iterator::End<K>
-}
-
- - - -
- - - -## Function `iter_get_key` - -Returns the key of the given iterator. - - -
public fun iter_get_key<K>(self: &big_ordered_map::Iterator<K>): &K
-
- - - -
-Implementation - - -
public fun iter_get_key<K>(self: &Iterator<K>): &K {
-    assert!(!(self is Iterator::End<K>), E_INVALID_PARAMETER);
-    &self.key
-}
-
- - -
@@ -744,10 +667,10 @@ key, or an end iterator if such element doesn't exist. }; let node = self.nodes.borrow(leaf); - assert!(node.is_leaf, E_INTERNAL); + assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); let child_lower_bound = node.children.lower_bound(key); - if (child_lower_bound.iter_is_end()) { + 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); @@ -779,7 +702,7 @@ iterator if the key is not found.
public fun find<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): Iterator<K> {
     let lower_bound = self.lower_bound(key);
-    if (is_end_iter(self, &lower_bound)) {
+    if (lower_bound.iter_is_end(self)) {
         lower_bound
     } else if (&lower_bound.key == key) {
         lower_bound
@@ -797,7 +720,7 @@ iterator if the key is not found.
 
 ## Function `contains`
 
-Returns true iff the key exists in the tree.
+Returns true iff the key exists in the map.
 
 
 
public fun contains<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): bool
@@ -811,7 +734,7 @@ Returns true iff the key exists in the tree.
 
 
public fun contains<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): bool {
     let lower_bound = self.lower_bound(key);
-    if (is_end_iter(self, &lower_bound)) {
+    if (lower_bound.iter_is_end(self)) {
         false
     } else if (&lower_bound.key == key) {
         true
@@ -844,7 +767,7 @@ 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!(is_end_iter(self, &iter), E_INVALID_PARAMETER);
+    assert!(iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
     let children = &self.nodes.borrow(iter.node_index).children;
     &iter.child_iter.iter_borrow(children).value
 }
@@ -854,14 +777,14 @@ Returns a reference to the element with its key, aborts if the key is not found.
 
 
 
-
+
 
-## Function `borrow_mut`
+## Function `new_begin_iter`
 
-Returns a mutable reference to the element with its key at the given index, aborts if the key is not found.
+Return the begin iterator.
 
 
-
public fun borrow_mut<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K): &mut V
+
public fun new_begin_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::Iterator<K>
 
@@ -870,12 +793,16 @@ Returns a mutable reference to the element with its key at the given index, abor Implementation -
public fun borrow_mut<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: K): &mut V {
-    let iter = self.find(&key);
+
public fun new_begin_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): Iterator<K> {
+    if (self.is_empty()) {
+        return Iterator::End;
+    };
 
-    assert!(is_end_iter(self, &iter), E_INVALID_PARAMETER);
-    let children = &mut self.nodes.borrow_mut(iter.node_index).children;
-    &mut iter.child_iter.iter_borrow_mut(children).value
+    let node = self.nodes.borrow(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);
+    new_iter(self.min_leaf_index, begin_child_iter, begin_child_key)
 }
 
@@ -883,14 +810,14 @@ Returns a mutable reference to the element with its key at the given index, abor - + -## Function `new_begin_iter` +## Function `new_end_iter` -Return the begin iterator. +Return the end iterator. -
public fun new_begin_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::Iterator<K>
+
public fun new_end_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::Iterator<K>
 
@@ -899,16 +826,36 @@ Return the begin iterator. Implementation -
public fun new_begin_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): Iterator<K> {
-    if (self.is_empty()) {
-        return Iterator::End;
-    };
+
public fun new_end_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): Iterator<K> {
+    Iterator::End
+}
+
- let node = self.nodes.borrow(self.min_leaf_index); - assert!(!node.children.is_empty(), E_INTERNAL); - let begin_child_iter = node.children.new_begin_iter(); - let begin_child_key = *begin_child_iter.iter_borrow_key(&node.children); - new_iter(self.min_leaf_index, begin_child_iter, begin_child_key) + + + + + + +## Function `iter_is_begin` + + + +
public fun iter_is_begin<K: store, V: store>(self: &big_ordered_map::Iterator<K>, map: &big_ordered_map::BigOrderedMap<K, V>): bool
+
+ + + +
+Implementation + + +
public fun iter_is_begin<K: store, V: store>(self: &Iterator<K>, map: &BigOrderedMap<K, V>): bool {
+    if (self is Iterator::End<K>) {
+        map.is_empty()
+    } else {
+        (self.node_index == map.min_leaf_index && self.child_iter.iter_is_begin_from_non_empty())
+    }
 }
 
@@ -916,14 +863,13 @@ Return the begin iterator.
- + -## Function `new_end_iter` +## Function `iter_is_end` -Return the end iterator. -
public fun new_end_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::Iterator<K>
+
public fun iter_is_end<K: store, V: store>(self: &big_ordered_map::Iterator<K>, _map: &big_ordered_map::BigOrderedMap<K, V>): bool
 
@@ -932,8 +878,34 @@ Return the end iterator. Implementation -
public fun new_end_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): Iterator<K> {
-    Iterator::End
+
public fun iter_is_end<K: store, V: store>(self: &Iterator<K>, _map: &BigOrderedMap<K, V>): bool {
+    self is Iterator::End<K>
+}
+
+ + + + + + + +## Function `iter_get_key` + +Returns the key of the given iterator. + + +
public fun iter_get_key<K>(self: &big_ordered_map::Iterator<K>): &K
+
+ + + +
+Implementation + + +
public fun iter_get_key<K>(self: &Iterator<K>): &K {
+    assert!(!(self is Iterator::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    &self.key
 }
 
@@ -941,15 +913,15 @@ Return the end iterator.
- + -## Function `next_iter` +## Function `iter_next` Returns the next iterator, or none if already at the end iterator. -Requires the tree is not changed after the input iterator is generated. +Requires the map is not changed after the input iterator is generated. -
public fun next_iter<K: copy, drop, store, V: store>(tree: &big_ordered_map::BigOrderedMap<K, V>, iter: big_ordered_map::Iterator<K>): big_ordered_map::Iterator<K>
+
public fun iter_next<K: copy, drop, store, V: store>(self: big_ordered_map::Iterator<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::Iterator<K>
 
@@ -958,29 +930,29 @@ Requires the tree is not changed after the input iterator is generated. Implementation -
public fun next_iter<K: drop + copy + store, V: store>(tree: &BigOrderedMap<K, V>, iter: Iterator<K>): Iterator<K> {
-    assert!(!(iter is Iterator::End<K>), E_INVALID_PARAMETER);
+
public fun iter_next<K: drop + copy + store, V: store>(self: Iterator<K>, map: &BigOrderedMap<K, V>): Iterator<K> {
+    assert!(!(self is Iterator::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
-    let node_index = iter.node_index;
-    let node = tree.nodes.borrow(node_index);
+    let node_index = self.node_index;
+    let node = map.nodes.borrow(node_index);
 
-    let child_iter = iter.child_iter.iter_next(&node.children);
-    if (!child_iter.iter_is_end()) {
+    let child_iter = self.child_iter.iter_next(&node.children);
+    if (!child_iter.iter_is_end(&node.children)) {
         let iter_key = *child_iter.iter_borrow_key(&node.children);
         return new_iter(node_index, child_iter, iter_key);
     };
 
     let next_index = node.next;
     if (next_index != NULL_INDEX) {
-        let next_node = tree.nodes.borrow(next_index);
+        let next_node = map.nodes.borrow(next_index);
 
         let child_iter = next_node.children.new_begin_iter();
-        assert!(!iter.child_iter.iter_is_end(), E_INTERNAL);
+        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);
         return new_iter(next_index, child_iter, iter_key);
     };
 
-    new_end_iter(tree)
+    new_end_iter(map)
 }
 
@@ -988,15 +960,15 @@ Requires the tree is not changed after the input iterator is generated. - + -## Function `prev_iter` +## Function `iter_prev` Returns the previous iterator, or none if already at the begin iterator. -Requires the tree is not changed after the input iterator is generated. +Requires the map is not changed after the input iterator is generated. -
public fun prev_iter<K: copy, drop, store, V: store>(tree: &big_ordered_map::BigOrderedMap<K, V>, iter: big_ordered_map::Iterator<K>): big_ordered_map::Iterator<K>
+
public fun iter_prev<K: copy, drop, store, V: store>(self: big_ordered_map::Iterator<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::Iterator<K>
 
@@ -1005,27 +977,27 @@ Requires the tree is not changed after the input iterator is generated. Implementation -
public fun prev_iter<K: drop + copy + store, V: store>(tree: &BigOrderedMap<K, V>, iter: Iterator<K>): Iterator<K> {
-    let prev_index = if (iter is Iterator::End<K>) {
-        tree.max_leaf_index
+
public fun iter_prev<K: drop + copy + store, V: store>(self: Iterator<K>, map: &BigOrderedMap<K, V>): Iterator<K> {
+    let prev_index = if (self is Iterator::End<K>) {
+        map.max_leaf_index
     } else {
-        let node_index = iter.node_index;
-        let node = tree.nodes.borrow(node_index);
+        let node_index = self.node_index;
+        let node = map.nodes.borrow(node_index);
 
-        if (!iter.child_iter.iter_is_begin(&node.children)) {
-            let child_iter = iter.child_iter.iter_prev(&node.children);
+        if (!self.child_iter.iter_is_begin(&node.children)) {
+            let child_iter = self.child_iter.iter_prev(&node.children);
             let key = *child_iter.iter_borrow_key(&node.children);
             return new_iter(node_index, child_iter, key);
         };
         node.prev
     };
 
-    assert!(prev_index != NULL_INDEX, E_INTERNAL);
+    assert!(prev_index != NULL_INDEX, error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
-    let prev_node = tree.nodes.borrow(prev_index);
+    let prev_node = map.nodes.borrow(prev_index);
 
     let prev_children = &prev_node.children;
-    let child_iter = prev_children.new_end_iter().iter_prev(prev_children);
+    let child_iter = prev_children.new_end_iter().iter_prev(prev_children);
     let iter_key = *child_iter.iter_borrow_key(prev_children);
     new_iter(prev_index, child_iter, iter_key)
 }
@@ -1035,13 +1007,13 @@ Requires the tree is not changed after the input iterator is generated.
 
 
 
-
+
 
-## Function `init_max_degrees`
+## Function `add_or_upsert_impl`
 
 
 
-
fun init_max_degrees<K: store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: &K, value: &V)
+
fun add_or_upsert_impl<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
 
@@ -1050,19 +1022,65 @@ Requires the tree is not changed after the input iterator is generated. Implementation -
fun init_max_degrees<K: store, V: store>(self: &mut BigOrderedMap<K, V>, key: &K, value: &V) {
-    if (self.inner_max_degree == 0 || self.leaf_max_degree == 0) {
-        let key_size = bcs::serialized_size(key);
+
fun add_or_upsert_impl<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: K, value: V, allow_overwrite: bool): Option<Child<V>> {
+    // TODO cache the check if K and V have constant size
+    // if (self.inner_max_degree == 0 || self.leaf_max_degree == 0) {
+    self.validate_size_and_init_max_degrees(&key, &value);
+    // };
 
-        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;
-        };
+    let leaf = self.find_leaf(&key);
 
-        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;
-        };
+    if (leaf == NULL_INDEX) {
+        // In this case, the key is greater than all keys in the map.
+        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_value = current_node.children.new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children);
+            current_node.children.add(key, last_value);
+            current = current_node.parent;
+        }
+    };
+
+    self.add_at(leaf, key, new_leaf_child(value), allow_overwrite)
+}
+
+ + + + + + + +## Function `validate_size_and_init_max_degrees` + + + +
fun validate_size_and_init_max_degrees<K: store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: &K, value: &V)
+
+ + + +
+Implementation + + +
fun validate_size_and_init_max_degrees<K: store, V: store>(self: &mut BigOrderedMap<K, V>, key: &K, value: &V) {
+    let key_size = bcs::serialized_size(key);
+    let value_size = bcs::serialized_size(value);
+    let entry_size = key_size + value_size;
+
+    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) {
+        self.leaf_max_degree = max(min(MAX_DEGREE, DEFAULT_TARGET_NODE_SIZE / (key_size + value_size)), DEFAULT_LEAF_MIN_DEGREE as u64) as u16;
     };
+
+    assert!(key_size * (self.inner_max_degree as u64) <= MAX_NODE_BYTES, error::invalid_argument(EARGUMENT_BYTES_TOO_LARGE));
+    assert!(entry_size * (self.leaf_max_degree as u64) <= MAX_NODE_BYTES, error::invalid_argument(EARGUMENT_BYTES_TOO_LARGE));
 }
 
@@ -1113,7 +1131,7 @@ Requires the tree is not changed after the input iterator is generated.
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);
+    assert!(children.is_empty(), error::invalid_argument(EMAP_NOT_EMPTY));
     children.destroy_empty();
 }
 
@@ -1286,7 +1304,7 @@ Requires the tree is not changed after the input iterator is generated. }; let children = &node.children; let child_iter = children.lower_bound(key); - if (child_iter.iter_is_end()) { + if (child_iter.iter_is_end(children)) { return NULL_INDEX; } else { current = child_iter.iter_borrow(children).node_index; @@ -1346,7 +1364,7 @@ Requires the tree is not changed after the input iterator is generated.
fun add_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, node_index: u64, key: K, child: Child<V>, allow_overwrite: bool): Option<Child<V>> {
     {
-        let node = self.nodes.borrow_mut(node_index);
+        let node = self.nodes.borrow_mut(node_index);
         let children = &mut node.children;
         let current_size = children.length();
 
@@ -1360,17 +1378,17 @@ Requires the tree is not changed after the input iterator is generated.
             let result = children.upsert(key, child);
 
             if (node.is_leaf) {
-                assert!(allow_overwrite || result.is_none(), EKEY_ALREADY_EXISTS);
+                assert!(allow_overwrite || result.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS));
                 return result;
             } else {
-                assert!(!allow_overwrite && result.is_none(), E_INTERNAL);
+                assert!(!allow_overwrite && result.is_none(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
                 return result;
             };
         };
 
         if (allow_overwrite) {
             let iter = children.find(&key);
-            if (!iter.iter_is_end()) {
+            if (!iter.iter_is_end(children)) {
                 return option::some(iter.iter_replace(children, child));
             }
         }
@@ -1387,7 +1405,7 @@ Requires the tree is not changed after the input iterator is generated.
     if (parent_index == NULL_INDEX) {
         // Splitting root now, need to create a new root.
         let parent_node = new_node(/*is_leaf=*/false, /*parent=*/NULL_INDEX);
-        let max_element = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+        let max_element = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
         if (cmp::compare(&max_element, &key).is_less_than()) {
             max_element = key;
         };
@@ -1407,10 +1425,10 @@ Requires the tree is not changed after the input iterator is generated.
     let target_size = (max_degree + 1) / 2;
 
     children.add(key, child);
-    let new_node_children = children.split_off(target_size);
+    let new_node_children = children.trim(target_size);
 
-    assert!(children.length() <= max_degree, E_INTERNAL);
-    assert!(new_node_children.length() <= max_degree, E_INTERNAL);
+    assert!(children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(new_node_children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
     let right_node = new_node_with_children(*is_leaf, parent_index, new_node_children);
 
@@ -1420,16 +1438,16 @@ Requires the tree is not changed after the input iterator is generated.
     *next = node_index;
     right_node.prev = left_node_index;
     if (*prev != NULL_INDEX) {
-        self.nodes.borrow_mut(*prev).next = left_node_index;
+        self.nodes.borrow_mut(*prev).next = left_node_index;
     };
 
     if (!*is_leaf) {
         children.for_each_ref(|_key, child| {
-            self.nodes.borrow_mut(child.node_index).parent = left_node_index;
+            self.nodes.borrow_mut(child.node_index).parent = left_node_index;
         });
     };
 
-    let split_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+    let split_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
 
     self.nodes.fill_reserved_slot(left_node_slot, node);
     self.nodes.fill_reserved_slot(right_node_slot, right_node);
@@ -1466,11 +1484,11 @@ Requires the tree is not changed after the input iterator is generated.
         return
     };
 
-    let node = self.nodes.borrow_mut(node_index);
+    let node = self.nodes.borrow_mut(node_index);
     let children = &mut node.children;
     children.replace_key_inplace(old_key, new_key);
 
-    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) {
         self.update_key(node.parent, old_key, new_key);
     };
 }
@@ -1496,14 +1514,8 @@ Requires the tree is not changed after the input iterator is generated.
 
 
 
fun remove_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, node_index: u64, key: &K): Child<V> {
-    // aptos_std::debug::print(&std::string::utf8(b"remove_at"));
-    // aptos_std::debug::print(&node_index);
-    // aptos_std::debug::print(key);
-
     let old_child = {
-        let node = self.nodes.borrow_mut(node_index);
-        // aptos_std::debug::print(&std::string::utf8(b"node, borrowed"));
-        // aptos_std::debug::print(node);
+        let node = self.nodes.borrow_mut(node_index);
 
         let children = &mut node.children;
         let current_size = children.length();
@@ -1518,7 +1530,7 @@ Requires the tree is not changed after the input iterator is generated.
         let old_child = children.remove(key);
         current_size = current_size - 1;
 
-        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);
         let max_key_updated = cmp::compare(&new_max_key, key).is_less_than();
 
         let max_degree = if (node.is_leaf) {
@@ -1537,9 +1549,9 @@ Requires the tree is not changed after the input iterator is generated.
             if (current_size == 1 && !is_leaf) {
                 let Child::Inner {
                     node_index: inner_child_index,
-                } = children.new_end_iter().iter_prev(children).iter_remove(children);
+                } = children.new_end_iter().iter_prev(children).iter_remove(children);
                 self.root_index = inner_child_index;
-                self.nodes.borrow_mut(self.root_index).parent = NULL_INDEX;
+                self.nodes.borrow_mut(self.root_index).parent = NULL_INDEX;
                 destroy_empty_node(self.nodes.remove(node_index));
             } else {
                 // nothing to change
@@ -1548,7 +1560,7 @@ Requires the tree is not changed after the input iterator is generated.
         };
 
         if (max_key_updated) {
-            assert!(current_size >= 1, E_INTERNAL);
+            assert!(current_size >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
             let parent = node.parent;
 
@@ -1562,11 +1574,9 @@ Requires the tree is not changed after the input iterator is generated.
         old_child
     };
 
-    // We need to update tree beyond the current node
+    // We need to update map beyond the current node
 
     let (node_slot, node) = self.nodes.remove_and_reserve(node_index);
-    // aptos_std::debug::print(&std::string::utf8(b"node, removed and reserved"));
-    // aptos_std::debug::print(&node);
 
     let prev = node.prev;
     let next = node.next;
@@ -1583,45 +1593,33 @@ Requires the tree is not changed after the input iterator is generated.
         brother_index = prev;
     };
     let (brother_slot, brother_node) = self.nodes.remove_and_reserve(brother_index);
-    // aptos_std::debug::print(&std::string::utf8(b"brother, removed and reserved"));
-    // aptos_std::debug::print(&brother_node);
 
     let brother_children = &mut brother_node.children;
 
     if ((brother_children.length() - 1) * 2 >= max_degree) {
-        // aptos_std::debug::print(&std::string::utf8(b"The brother node has enough elements, borrow an element from the brother node."));
         // The brother node has enough elements, borrow an element from the brother node.
         if (brother_index == next) {
-            // aptos_std::debug::print(&std::string::utf8(b"brother_index == next. Moving from brother."));
-
-            let old_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+            let old_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
             let brother_begin_iter = brother_children.new_begin_iter();
             let borrowed_max_key = *brother_begin_iter.iter_borrow_key(brother_children);
             let borrowed_element = brother_begin_iter.iter_remove(brother_children);
             if (borrowed_element is Child::Inner<V>) {
-                self.nodes.borrow_mut(borrowed_element.node_index).parent = node_index;
+                self.nodes.borrow_mut(borrowed_element.node_index).parent = node_index;
             };
 
-            // aptos_std::debug::print(&borrowed_max_key);
-            // aptos_std::debug::print(&old_max_key);
-
             children.add(borrowed_max_key, borrowed_element);
             self.update_key(parent, &old_max_key, borrowed_max_key);
         } else {
-            // aptos_std::debug::print(&std::string::utf8(b"brother_index != next. Moving from brother"));
-
-            let brother_end_iter = brother_children.new_end_iter().iter_prev(brother_children);
+            let brother_end_iter = brother_children.new_end_iter().iter_prev(brother_children);
             let borrowed_max_key = *brother_end_iter.iter_borrow_key(brother_children);
             let borrowed_element = brother_end_iter.iter_remove(brother_children);
 
             if (borrowed_element is Child::Inner<V>) {
-                self.nodes.borrow_mut(borrowed_element.node_index).parent = node_index;
+                self.nodes.borrow_mut(borrowed_element.node_index).parent = node_index;
             };
 
-            // aptos_std::debug::print(&borrowed_max_key);
-
             children.add(borrowed_max_key, borrowed_element);
-            self.update_key(parent, &borrowed_max_key, *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children));
+            self.update_key(parent, &borrowed_max_key, *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children));
         };
 
         self.nodes.fill_reserved_slot(node_slot, node);
@@ -1629,37 +1627,27 @@ Requires the tree is not changed after the input iterator is generated.
         return old_child;
     };
 
-    // aptos_std::debug::print(&std::string::utf8(b"The brother node doesn't have enough elements to borrow, merge with the brother node."));
-
     // The brother node doesn't have enough elements to borrow, merge with the brother node.
     if (brother_index == next) {
-        // aptos_std::debug::print(&std::string::utf8(b"brother_index == next"));
-
         if (!is_leaf) {
             children.for_each_ref(|_key, child| {
-                self.nodes.borrow_mut(child.node_index).parent = brother_index;
+                self.nodes.borrow_mut(child.node_index).parent = brother_index;
             });
         };
         let Node { children: brother_children, is_leaf: _, parent: _, prev: _, next: brother_next } = brother_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(brother_children);
         node.next = brother_next;
 
         move children;
 
         if (node.next != NULL_INDEX) {
-            self.nodes.borrow_mut(node.next).prev = brother_index;
+            self.nodes.borrow_mut(node.next).prev = brother_index;
         };
         if (node.prev != NULL_INDEX) {
-            self.nodes.borrow_mut(node.prev).next = brother_index;
+            self.nodes.borrow_mut(node.prev).next = brother_index;
         };
 
-        // aptos_std::debug::print(&std::string::utf8(b"keeping node"));
-        // aptos_std::debug::print(&brother_slot);
-        // aptos_std::debug::print(&node);
-        // aptos_std::debug::print(&std::string::utf8(b"freeing node"));
-        // aptos_std::debug::print(&node_slot);
-
         self.nodes.fill_reserved_slot(brother_slot, node);
         self.nodes.free_reserved_slot(node_slot);
         if (self.min_leaf_index == node_index) {
@@ -1670,34 +1658,26 @@ Requires the tree is not changed after the input iterator is generated.
             destroy_inner_child(self.remove_at(parent, &key_to_remove));
         };
     } else {
-        // aptos_std::debug::print(&std::string::utf8(b"brother_index != next"));
-
         if (!is_leaf) {
             brother_children.for_each_ref(|_key, child| {
-                self.nodes.borrow_mut(child.node_index).parent = node_index;
+                self.nodes.borrow_mut(child.node_index).parent = node_index;
             });
         };
 
         let Node { children: node_children, is_leaf: _, parent: _, prev: _, next: node_next } = node;
-        let key_to_remove = *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children);
+        let key_to_remove = *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children);
         brother_children.append(node_children);
         brother_node.next = node_next;
 
         move brother_children;
 
         if (brother_node.next != NULL_INDEX) {
-            self.nodes.borrow_mut(brother_node.next).prev = node_index;
+            self.nodes.borrow_mut(brother_node.next).prev = node_index;
         };
         if (brother_node.prev != NULL_INDEX) {
-            self.nodes.borrow_mut(brother_node.prev).next = node_index;
+            self.nodes.borrow_mut(brother_node.prev).next = node_index;
         };
 
-        // aptos_std::debug::print(&std::string::utf8(b"keeping node"));
-        // aptos_std::debug::print(&node_slot);
-        // aptos_std::debug::print(&brother_node);
-        // aptos_std::debug::print(&std::string::utf8(b"freeing node"));
-        // aptos_std::debug::print(&brother_slot);
-
         self.nodes.fill_reserved_slot(node_slot, brother_node);
         self.nodes.free_reserved_slot(brother_slot);
         if (self.min_leaf_index == brother_index) {
diff --git a/aptos-move/framework/aptos-stdlib/doc/fixed_point64.md b/aptos-move/framework/aptos-stdlib/doc/fixed_point64.md
index d13fba14f020fb..c9d35f6de494ec 100644
--- a/aptos-move/framework/aptos-stdlib/doc/fixed_point64.md
+++ b/aptos-move/framework/aptos-stdlib/doc/fixed_point64.md
@@ -144,22 +144,22 @@ The multiplied value would be too large to be held in a u128
 
 
 
-
+
 
-Abort code on calculation result is negative.
+The computed ratio when converting to a FixedPoint64 would be unrepresentable
 
 
-
const ENEGATIVE_RESULT: u64 = 65542;
+
const ERATIO_OUT_OF_RANGE: u64 = 131077;
 
- + -The computed ratio when converting to a FixedPoint64 would be unrepresentable +Abort code on calculation result is negative. -
const ERATIO_OUT_OF_RANGE: u64 = 131077;
+
const ENEGATIVE_RESULT: u64 = 65542;
 
diff --git a/aptos-move/framework/aptos-stdlib/doc/overview.md b/aptos-move/framework/aptos-stdlib/doc/overview.md index 50dc6a5d6a0f49..fa811e7bef51de 100644 --- a/aptos-move/framework/aptos-stdlib/doc/overview.md +++ b/aptos-move/framework/aptos-stdlib/doc/overview.md @@ -14,6 +14,7 @@ This is the reference documentation of the Aptos standard library. - [`0x1::any`](any.md#0x1_any) - [`0x1::aptos_hash`](hash.md#0x1_aptos_hash) +- [`0x1::big_ordered_map`](big_ordered_map.md#0x1_big_ordered_map) - [`0x1::big_vector`](big_vector.md#0x1_big_vector) - [`0x1::bls12381`](bls12381.md#0x1_bls12381) - [`0x1::bls12381_algebra`](bls12381_algebra.md#0x1_bls12381_algebra) @@ -42,6 +43,7 @@ This is the reference documentation of the Aptos standard library. - [`0x1::simple_map`](simple_map.md#0x1_simple_map) - [`0x1::smart_table`](smart_table.md#0x1_smart_table) - [`0x1::smart_vector`](smart_vector.md#0x1_smart_vector) +- [`0x1::storage_slots_allocator`](storage_slots_allocator.md#0x1_storage_slots_allocator) - [`0x1::string_utils`](string_utils.md#0x1_string_utils) - [`0x1::table`](table.md#0x1_table) - [`0x1::table_with_length`](table_with_length.md#0x1_table_with_length) 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 718f347b51fd30..1c75deb7663ae7 100644 --- a/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md +++ b/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md @@ -38,7 +38,7 @@ for example: - [Function `fill_reserved_slot`](#0x1_storage_slots_allocator_fill_reserved_slot) - [Function `remove_and_reserve`](#0x1_storage_slots_allocator_remove_and_reserve) - [Function `free_reserved_slot`](#0x1_storage_slots_allocator_free_reserved_slot) -- [Function `push_to_reuse_queue`](#0x1_storage_slots_allocator_push_to_reuse_queue) +- [Function `push_to_reuse_queue_if_enabled`](#0x1_storage_slots_allocator_push_to_reuse_queue_if_enabled) - [Function `next_slot_index`](#0x1_storage_slots_allocator_next_slot_index) @@ -288,7 +288,7 @@ for example: for (i in 0..num_to_preallocate) { let slot_index = self.next_slot_index(); - self.push_to_reuse_queue(slot_index); + self.push_to_reuse_queue_if_enabled(slot_index); }; self @@ -353,7 +353,7 @@ for example:
public fun remove<T: store>(self: &mut StorageSlotsAllocator<T>, slot_index: u64): T {
     let Link::Occupied { value } = self.slots.remove(slot_index);
 
-    self.push_to_reuse_queue(slot_index);
+    self.push_to_reuse_queue_if_enabled(slot_index);
 
     value
 }
@@ -581,7 +581,7 @@ Remove storage slot, but reserve it for later.
 
 
public fun free_reserved_slot<T: store>(self: &mut StorageSlotsAllocator<T>, slot: ReservedSlot) {
     let ReservedSlot { slot_index } = slot;
-    self.push_to_reuse_queue(slot_index);
+    self.push_to_reuse_queue_if_enabled(slot_index);
 }
 
@@ -589,13 +589,13 @@ Remove storage slot, but reserve it for later.
- + -## Function `push_to_reuse_queue` +## Function `push_to_reuse_queue_if_enabled` -
fun push_to_reuse_queue<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, slot_index: u64)
+
fun push_to_reuse_queue_if_enabled<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, slot_index: u64)
 
@@ -604,7 +604,7 @@ Remove storage slot, but reserve it for later. Implementation -
fun push_to_reuse_queue<T: store>(self: &mut StorageSlotsAllocator<T>, slot_index: u64) {
+
fun push_to_reuse_queue_if_enabled<T: store>(self: &mut StorageSlotsAllocator<T>, slot_index: u64) {
     if (self is StorageSlotsAllocator::Reuse<T>) {
         self.slots.add(slot_index, Link::Vacant { next: self.reuse_head_index });
         self.reuse_head_index = slot_index;
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 9d876d27bb8fd4..09631e22107e63 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
@@ -1,10 +1,21 @@
-/// Type of large-scale search trees.
+/// This module provides an implementation for an big ordered map.
+/// Big means that it is stored across multiple resources, and doesn't have an
+/// upper limit on number of elements it can contain.
 ///
-/// 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).
-
+/// Keys point to values, and each key in the map must be unique.
+///
+/// Currently, one implementation is provided - BPlusTreeMap, backed by a B+Tree,
+/// with each node being a separate resource, internally containing OrderedMap.
+///
+/// BPlusTreeMap is chosen since the biggest (performance and gast)
+/// costs are reading resources, and it:
+/// * reduces number of resource accesses
+/// * reduces number of rebalancing operations, and makes each rebalancing
+///   operation touch only few resources
+/// * it allows for parallelism for keys that are not close to each other,
+///   once it contains enough keys
 module aptos_std::big_ordered_map {
+    use std::error;
     use std::option::{Self, Option};
     use std::bcs;
     use aptos_std::ordered_map::{Self, OrderedMap};
@@ -12,16 +23,23 @@ module aptos_std::big_ordered_map {
     use aptos_std::storage_slots_allocator::{Self, StorageSlotsAllocator};
     use aptos_std::math64::{max, min};
 
+    /// Map key already exists
+    const EKEY_ALREADY_EXISTS: u64 = 1;
+    /// Map key is not found
+    const EKEY_NOT_FOUND: u64 = 2;
+    // Trying to do an operation on an Iterator that would go out of bounds
+    const EITER_OUT_OF_BOUNDS: u64 = 3;
+    // The provided configuration parameter is invalid.
+    const EINVALID_CONFIG_PARAMETER: u64 = 4;
+    // Map isn't empty
+    const EMAP_NOT_EMPTY: u64 = 5;
+    // Trying to insert too large of an object into the mp.
+    const EARGUMENT_BYTES_TOO_LARGE: u64 = 6;
+
     // Internal errors.
-    const E_INTERNAL: u64 = 0;
-    // The tree is not empty, and cannot be destroyed.
-    const E_TREE_NOT_EMPTY: u64 = 1;
-    // The tree is too big for insertion.
-    const E_TREE_TOO_BIG: u64 = 2;
-    // The provided parameter is invalid.
-    const E_INVALID_PARAMETER: u64 = 3;
+    const EINTERNAL_INVARIANT_BROKEN: u64 = 7;
 
-    const EKEY_ALREADY_EXISTS: u64 = 4;
+    // Internal constants.
 
     const NULL_INDEX: u64 = 0;
     const DEFAULT_TARGET_NODE_SIZE: u64 = 2048;
@@ -31,15 +49,22 @@ module aptos_std::big_ordered_map {
     const DEFAULT_LEAF_MIN_DEGREE: u16 = 3;
     const MAX_DEGREE: u64 = 4096;
 
+    const MAX_NODE_BYTES: u64 = 204800; // 200 KB, well bellow the max resource limit.
+
     /// A node of the BigOrderedMap.
+    ///
+    /// Inner node will have all children be Child::Inner, pointing to the child nodes.
+    /// Leaf node will have all children be Child::Leaf.
+    /// Basically - Leaf node is a single-resource OrderedMap, containing as much keys as can fit.
+    /// So Leaf node contains multiple values, not just one.
     struct Node has store {
         // Whether this node is a leaf node.
         is_leaf: bool,
         // The node index of its parent node, or NULL_INDEX if it doesn't have parent.
         parent: u64,
         // The children of the nodes.
-        // When node is inner node, K represents max_key of the recursive children.
-        // When the node is leaf node, K represents key of the leaf.
+        // When node is inner node, K represents max_key within the child subtree, and values are Child::Inner.
+        // When the node is leaf node, K represents key of the leaf, and values are Child::Leaf.
         children: OrderedMap>,
         // The node index of its previous node at the same level, or NULL_INDEX if it doesn't have a previous node.
         prev: u64,
@@ -50,10 +75,11 @@ module aptos_std::big_ordered_map {
     /// The metadata of a child of a node.
     enum Child has store {
         Inner {
-            // The node index of it's child, or NULL_INDEX if the current node is a leaf node.
+            // The node index of it's child
             node_index: u64,
         },
         Leaf {
+            // Value associated with the leaf node.
             value: V,
         }
     }
@@ -93,9 +119,7 @@ module aptos_std::big_ordered_map {
         }
     }
 
-    /////////////////////////////////
-    // Constructors && Destructors //
-    /////////////////////////////////
+    // ======================= Constructors && Destructors ====================
 
     /// Returns a new BigOrderedMap with the default configuration.
     public fun new(): BigOrderedMap {
@@ -105,12 +129,12 @@ module aptos_std::big_ordered_map {
     /// Returns a new BigOrderedMap 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(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool, num_to_preallocate: u64): BigOrderedMap {
-        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);
+        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));
         let nodes = if (reuse_slots) {
             storage_slots_allocator::new_reuse_storage_slots(num_to_preallocate)
         } else {
-            assert!(num_to_preallocate == 0, E_INVALID_PARAMETER);
+            assert!(num_to_preallocate == 0, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
             storage_slots_allocator::new_storage_slots()
         };
         let root_index = nodes.add(new_node(/*is_leaf=*/true, /*parent=*/NULL_INDEX));
@@ -124,25 +148,22 @@ module aptos_std::big_ordered_map {
         }
     }
 
-    /// Destroys the tree if it's empty, otherwise aborts.
+    /// Destroys the map if it's empty, otherwise aborts.
     public fun destroy_empty(self: BigOrderedMap) {
         let BigOrderedMap::BPlusTreeMap { nodes, root_index, min_leaf_index: _, max_leaf_index: _, inner_max_degree: _, leaf_max_degree: _ } = self;
-        // aptos_std::debug::print(&nodes);
         nodes.remove(root_index).destroy_empty_node();
         nodes.destroy();
     }
 
-    ///////////////
-    // Modifiers //
-    ///////////////
+    // ======================= Section with Modifiers =========================
 
     /// Inserts the key/value into the BigOrderedMap.
-    /// Aborts if the key is already in the tree.
+    /// Aborts if the key is already in the map.
     public fun add(self: &mut BigOrderedMap, key: K, value: V) {
         self.add_or_upsert_impl(key, value, false).destroy_none()
     }
 
-    /// If the key doesn't exist in the tree, inserts the key/value, and returns none.
+    /// If the key doesn't exist in the map, inserts the key/value, and returns none.
     /// Otherwise updates the value under the given key, and returns the old value.
     public fun upsert(self: &mut BigOrderedMap, key: K, value: V): Option {
         let result = self.add_or_upsert_impl(key, value, true);
@@ -157,34 +178,11 @@ module aptos_std::big_ordered_map {
         }
     }
 
-    fun add_or_upsert_impl(self: &mut BigOrderedMap, key: K, value: V, allow_overwrite: bool): Option> {
-        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_value = current_node.children.new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children);
-                current_node.children.add(key, last_value);
-                current = current_node.parent;
-            }
-        };
-
-        self.add_at(leaf, key, new_leaf_child(value), allow_overwrite)
-    }
-
     /// Removes the entry from BigOrderedMap and returns the value which `key` maps to.
     /// Aborts if there is no entry for `key`.
     public fun remove(self: &mut BigOrderedMap, key: &K): V {
         let iter = self.find(key);
-        assert!(!is_end_iter(self, &iter), E_INTERNAL);
+        assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
 
         let Child::Leaf {
             value,
@@ -193,29 +191,7 @@ module aptos_std::big_ordered_map {
         value
     }
 
-    ///////////////
-    // Accessors //
-    ///////////////
-
-    // Returns true iff the iterator is a begin iterator.
-    public fun is_begin_iter(tree: &BigOrderedMap, iter: &Iterator): bool {
-        if (iter is Iterator::End) {
-            tree.is_empty()
-        } else {
-            (iter.node_index == tree.min_leaf_index && iter.child_iter.iter_is_begin_from_non_empty())
-        }
-    }
-
-    // Returns true iff the iterator is an end iterator.
-    public fun is_end_iter(_tree: &BigOrderedMap, iter: &Iterator): bool {
-        iter is Iterator::End
-    }
-
-    /// Returns the key of the given iterator.
-    public fun iter_get_key(self: &Iterator): &K {
-        assert!(!(self is Iterator::End), E_INVALID_PARAMETER);
-        &self.key
-    }
+    // ============================= Accessors ================================
 
     /// 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.
@@ -226,10 +202,10 @@ module aptos_std::big_ordered_map {
         };
 
         let node = self.nodes.borrow(leaf);
-        assert!(node.is_leaf, E_INTERNAL);
+        assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
         let child_lower_bound = node.children.lower_bound(key);
-        if (child_lower_bound.iter_is_end()) {
+        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);
@@ -241,7 +217,7 @@ module aptos_std::big_ordered_map {
     /// iterator if the key is not found.
     public fun find(self: &BigOrderedMap, key: &K): Iterator {
         let lower_bound = self.lower_bound(key);
-        if (is_end_iter(self, &lower_bound)) {
+        if (lower_bound.iter_is_end(self)) {
             lower_bound
         } else if (&lower_bound.key == key) {
             lower_bound
@@ -250,10 +226,10 @@ module aptos_std::big_ordered_map {
         }
     }
 
-    /// Returns true iff the key exists in the tree.
+    /// Returns true iff the key exists in the map.
     public fun contains(self: &BigOrderedMap, key: &K): bool {
         let lower_bound = self.lower_bound(key);
-        if (is_end_iter(self, &lower_bound)) {
+        if (lower_bound.iter_is_end(self)) {
             false
         } else if (&lower_bound.key == key) {
             true
@@ -266,19 +242,22 @@ module aptos_std::big_ordered_map {
     public fun borrow(self: &BigOrderedMap, key: K): &V {
         let iter = self.find(&key);
 
-        assert!(is_end_iter(self, &iter), E_INVALID_PARAMETER);
+        assert!(iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
         let children = &self.nodes.borrow(iter.node_index).children;
         &iter.child_iter.iter_borrow(children).value
     }
 
-    /// 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(self: &mut BigOrderedMap, key: K): &mut V {
-        let iter = self.find(&key);
+    // TODO: Add back for fixed sized structs only.
+    // /// 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(self: &mut BigOrderedMap, key: K): &mut V {
+    //     let iter = self.find(&key);
+    //
+    //     assert!(iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
+    //     let children = &mut self.nodes.borrow_mut(iter.node_index).children;
+    //     &mut iter.child_iter.iter_borrow_mut(children).value
+    // }
 
-        assert!(is_end_iter(self, &iter), E_INVALID_PARAMETER);
-        let children = &mut self.nodes.borrow_mut(iter.node_index).children;
-        &mut iter.child_iter.iter_borrow_mut(children).value
-    }
+    // ========================= Iterator functions ===========================
 
     /// Return the begin iterator.
     public fun new_begin_iter(self: &BigOrderedMap): Iterator {
@@ -287,7 +266,7 @@ module aptos_std::big_ordered_map {
         };
 
         let node = self.nodes.borrow(self.min_leaf_index);
-        assert!(!node.children.is_empty(), E_INTERNAL);
+        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);
         new_iter(self.min_leaf_index, begin_child_iter, begin_child_key)
@@ -298,53 +277,73 @@ module aptos_std::big_ordered_map {
         Iterator::End
     }
 
+    // Returns true iff the iterator is a begin iterator.
+    public fun iter_is_begin(self: &Iterator, map: &BigOrderedMap): bool {
+        if (self is Iterator::End) {
+            map.is_empty()
+        } else {
+            (self.node_index == map.min_leaf_index && self.child_iter.iter_is_begin_from_non_empty())
+        }
+    }
+
+    // Returns true iff the iterator is an end iterator.
+    public fun iter_is_end(self: &Iterator, _map: &BigOrderedMap): bool {
+        self is Iterator::End
+    }
+
+    /// Returns the key of the given iterator.
+    public fun iter_get_key(self: &Iterator): &K {
+        assert!(!(self is Iterator::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+        &self.key
+    }
+
     /// 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(tree: &BigOrderedMap, iter: Iterator): Iterator {
-        assert!(!(iter is Iterator::End), E_INVALID_PARAMETER);
+    /// Requires the map is not changed after the input iterator is generated.
+    public fun iter_next(self: Iterator, map: &BigOrderedMap): Iterator {
+        assert!(!(self is Iterator::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
-        let node_index = iter.node_index;
-        let node = tree.nodes.borrow(node_index);
+        let node_index = self.node_index;
+        let node = map.nodes.borrow(node_index);
 
-        let child_iter = iter.child_iter.iter_next(&node.children);
-        if (!child_iter.iter_is_end()) {
+        let child_iter = self.child_iter.iter_next(&node.children);
+        if (!child_iter.iter_is_end(&node.children)) {
             let iter_key = *child_iter.iter_borrow_key(&node.children);
             return new_iter(node_index, child_iter, iter_key);
         };
 
         let next_index = node.next;
         if (next_index != NULL_INDEX) {
-            let next_node = tree.nodes.borrow(next_index);
+            let next_node = map.nodes.borrow(next_index);
 
             let child_iter = next_node.children.new_begin_iter();
-            assert!(!iter.child_iter.iter_is_end(), E_INTERNAL);
+            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);
             return new_iter(next_index, child_iter, iter_key);
         };
 
-        new_end_iter(tree)
+        new_end_iter(map)
     }
 
     /// 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(tree: &BigOrderedMap, iter: Iterator): Iterator {
-        let prev_index = if (iter is Iterator::End) {
-            tree.max_leaf_index
+    /// Requires the map is not changed after the input iterator is generated.
+    public fun iter_prev(self: Iterator, map: &BigOrderedMap): Iterator {
+        let prev_index = if (self is Iterator::End) {
+            map.max_leaf_index
         } else {
-            let node_index = iter.node_index;
-            let node = tree.nodes.borrow(node_index);
+            let node_index = self.node_index;
+            let node = map.nodes.borrow(node_index);
 
-            if (!iter.child_iter.iter_is_begin(&node.children)) {
-                let child_iter = iter.child_iter.iter_prev(&node.children);
+            if (!self.child_iter.iter_is_begin(&node.children)) {
+                let child_iter = self.child_iter.iter_prev(&node.children);
                 let key = *child_iter.iter_borrow_key(&node.children);
                 return new_iter(node_index, child_iter, key);
             };
             node.prev
         };
 
-        assert!(prev_index != NULL_INDEX, E_INTERNAL);
+        assert!(prev_index != NULL_INDEX, error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
-        let prev_node = tree.nodes.borrow(prev_index);
+        let prev_node = map.nodes.borrow(prev_index);
 
         let prev_children = &prev_node.children;
         let child_iter = prev_children.new_end_iter().iter_prev(prev_children);
@@ -352,23 +351,47 @@ module aptos_std::big_ordered_map {
         new_iter(prev_index, child_iter, iter_key)
     }
 
-    //////////////////////////////
-    // Internal Implementations //
-    //////////////////////////////
+    // ====================== Internal Implementations ========================
 
-    fun init_max_degrees(self: &mut BigOrderedMap, key: &K, value: &V) {
-        if (self.inner_max_degree == 0 || self.leaf_max_degree == 0) {
-            let key_size = bcs::serialized_size(key);
+    fun add_or_upsert_impl(self: &mut BigOrderedMap, key: K, value: V, allow_overwrite: bool): Option> {
+        // TODO cache the check if K and V have constant size
+        // if (self.inner_max_degree == 0 || self.leaf_max_degree == 0) {
+        self.validate_size_and_init_max_degrees(&key, &value);
+        // };
 
-            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;
-            };
+        let leaf = self.find_leaf(&key);
 
-            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;
-            };
+        if (leaf == NULL_INDEX) {
+            // In this case, the key is greater than all keys in the map.
+            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_value = current_node.children.new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children);
+                current_node.children.add(key, last_value);
+                current = current_node.parent;
+            }
         };
+
+        self.add_at(leaf, key, new_leaf_child(value), allow_overwrite)
+    }
+
+    fun validate_size_and_init_max_degrees(self: &mut BigOrderedMap, key: &K, value: &V) {
+        let key_size = bcs::serialized_size(key);
+        let value_size = bcs::serialized_size(value);
+        let entry_size = key_size + value_size;
+
+        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) {
+            self.leaf_max_degree = max(min(MAX_DEGREE, DEFAULT_TARGET_NODE_SIZE / (key_size + value_size)), DEFAULT_LEAF_MIN_DEGREE as u64) as u16;
+        };
+
+        assert!(key_size * (self.inner_max_degree as u64) <= MAX_NODE_BYTES, error::invalid_argument(EARGUMENT_BYTES_TOO_LARGE));
+        assert!(entry_size * (self.leaf_max_degree as u64) <= MAX_NODE_BYTES, error::invalid_argument(EARGUMENT_BYTES_TOO_LARGE));
     }
 
     fun destroy_inner_child(self: Child) {
@@ -379,7 +402,7 @@ module aptos_std::big_ordered_map {
 
     fun destroy_empty_node(self: Node) {
         let Node { children, is_leaf: _, parent: _, prev: _, next: _ } = self;
-        assert!(children.is_empty(), E_TREE_NOT_EMPTY);
+        assert!(children.is_empty(), error::invalid_argument(EMAP_NOT_EMPTY));
         children.destroy_empty();
     }
 
@@ -432,7 +455,7 @@ module aptos_std::big_ordered_map {
             };
             let children = &node.children;
             let child_iter = children.lower_bound(key);
-            if (child_iter.iter_is_end()) {
+            if (child_iter.iter_is_end(children)) {
                 return NULL_INDEX;
             } else {
                 current = child_iter.iter_borrow(children).node_index;
@@ -466,17 +489,17 @@ module aptos_std::big_ordered_map {
                 let result = children.upsert(key, child);
 
                 if (node.is_leaf) {
-                    assert!(allow_overwrite || result.is_none(), EKEY_ALREADY_EXISTS);
+                    assert!(allow_overwrite || result.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS));
                     return result;
                 } else {
-                    assert!(!allow_overwrite && result.is_none(), E_INTERNAL);
+                    assert!(!allow_overwrite && result.is_none(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
                     return result;
                 };
             };
 
             if (allow_overwrite) {
                 let iter = children.find(&key);
-                if (!iter.iter_is_end()) {
+                if (!iter.iter_is_end(children)) {
                     return option::some(iter.iter_replace(children, child));
                 }
             }
@@ -513,10 +536,10 @@ module aptos_std::big_ordered_map {
         let target_size = (max_degree + 1) / 2;
 
         children.add(key, child);
-        let new_node_children = children.split_off(target_size);
+        let new_node_children = children.trim(target_size);
 
-        assert!(children.length() <= max_degree, E_INTERNAL);
-        assert!(new_node_children.length() <= max_degree, E_INTERNAL);
+        assert!(children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+        assert!(new_node_children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
         let right_node = new_node_with_children(*is_leaf, parent_index, new_node_children);
 
@@ -562,14 +585,8 @@ module aptos_std::big_ordered_map {
     }
 
     fun remove_at(self: &mut BigOrderedMap, node_index: u64, key: &K): Child {
-        // aptos_std::debug::print(&std::string::utf8(b"remove_at"));
-        // aptos_std::debug::print(&node_index);
-        // aptos_std::debug::print(key);
-
         let old_child = {
             let node = self.nodes.borrow_mut(node_index);
-            // aptos_std::debug::print(&std::string::utf8(b"node, borrowed"));
-            // aptos_std::debug::print(node);
 
             let children = &mut node.children;
             let current_size = children.length();
@@ -614,7 +631,7 @@ module aptos_std::big_ordered_map {
             };
 
             if (max_key_updated) {
-                assert!(current_size >= 1, E_INTERNAL);
+                assert!(current_size >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
                 let parent = node.parent;
 
@@ -628,11 +645,9 @@ module aptos_std::big_ordered_map {
             old_child
         };
 
-        // We need to update tree beyond the current node
+        // We need to update map beyond the current node
 
         let (node_slot, node) = self.nodes.remove_and_reserve(node_index);
-        // aptos_std::debug::print(&std::string::utf8(b"node, removed and reserved"));
-        // aptos_std::debug::print(&node);
 
         let prev = node.prev;
         let next = node.next;
@@ -649,17 +664,12 @@ module aptos_std::big_ordered_map {
             brother_index = prev;
         };
         let (brother_slot, brother_node) = self.nodes.remove_and_reserve(brother_index);
-        // aptos_std::debug::print(&std::string::utf8(b"brother, removed and reserved"));
-        // aptos_std::debug::print(&brother_node);
 
         let brother_children = &mut brother_node.children;
 
         if ((brother_children.length() - 1) * 2 >= max_degree) {
-            // aptos_std::debug::print(&std::string::utf8(b"The brother node has enough elements, borrow an element from the brother node."));
             // The brother node has enough elements, borrow an element from the brother node.
             if (brother_index == next) {
-                // aptos_std::debug::print(&std::string::utf8(b"brother_index == next. Moving from brother."));
-
                 let old_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
                 let brother_begin_iter = brother_children.new_begin_iter();
                 let borrowed_max_key = *brother_begin_iter.iter_borrow_key(brother_children);
@@ -668,14 +678,9 @@ module aptos_std::big_ordered_map {
                     self.nodes.borrow_mut(borrowed_element.node_index).parent = node_index;
                 };
 
-                // aptos_std::debug::print(&borrowed_max_key);
-                // aptos_std::debug::print(&old_max_key);
-
                 children.add(borrowed_max_key, borrowed_element);
                 self.update_key(parent, &old_max_key, borrowed_max_key);
             } else {
-                // aptos_std::debug::print(&std::string::utf8(b"brother_index != next. Moving from brother"));
-
                 let brother_end_iter = brother_children.new_end_iter().iter_prev(brother_children);
                 let borrowed_max_key = *brother_end_iter.iter_borrow_key(brother_children);
                 let borrowed_element = brother_end_iter.iter_remove(brother_children);
@@ -684,8 +689,6 @@ module aptos_std::big_ordered_map {
                     self.nodes.borrow_mut(borrowed_element.node_index).parent = node_index;
                 };
 
-                // aptos_std::debug::print(&borrowed_max_key);
-
                 children.add(borrowed_max_key, borrowed_element);
                 self.update_key(parent, &borrowed_max_key, *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children));
             };
@@ -695,12 +698,8 @@ module aptos_std::big_ordered_map {
             return old_child;
         };
 
-        // aptos_std::debug::print(&std::string::utf8(b"The brother node doesn't have enough elements to borrow, merge with the brother node."));
-
         // The brother node doesn't have enough elements to borrow, merge with the brother node.
         if (brother_index == next) {
-            // aptos_std::debug::print(&std::string::utf8(b"brother_index == next"));
-
             if (!is_leaf) {
                 children.for_each_ref(|_key, child| {
                     self.nodes.borrow_mut(child.node_index).parent = brother_index;
@@ -720,12 +719,6 @@ module aptos_std::big_ordered_map {
                 self.nodes.borrow_mut(node.prev).next = brother_index;
             };
 
-            // aptos_std::debug::print(&std::string::utf8(b"keeping node"));
-            // aptos_std::debug::print(&brother_slot);
-            // aptos_std::debug::print(&node);
-            // aptos_std::debug::print(&std::string::utf8(b"freeing node"));
-            // aptos_std::debug::print(&node_slot);
-
             self.nodes.fill_reserved_slot(brother_slot, node);
             self.nodes.free_reserved_slot(node_slot);
             if (self.min_leaf_index == node_index) {
@@ -736,8 +729,6 @@ module aptos_std::big_ordered_map {
                 destroy_inner_child(self.remove_at(parent, &key_to_remove));
             };
         } else {
-            // aptos_std::debug::print(&std::string::utf8(b"brother_index != next"));
-
             if (!is_leaf) {
                 brother_children.for_each_ref(|_key, child| {
                     self.nodes.borrow_mut(child.node_index).parent = node_index;
@@ -758,12 +749,6 @@ module aptos_std::big_ordered_map {
                 self.nodes.borrow_mut(brother_node.prev).next = node_index;
             };
 
-            // aptos_std::debug::print(&std::string::utf8(b"keeping node"));
-            // aptos_std::debug::print(&node_slot);
-            // aptos_std::debug::print(&brother_node);
-            // aptos_std::debug::print(&std::string::utf8(b"freeing node"));
-            // aptos_std::debug::print(&brother_slot);
-
             self.nodes.fill_reserved_slot(node_slot, brother_node);
             self.nodes.free_reserved_slot(brother_slot);
             if (self.min_leaf_index == brother_index) {
@@ -796,14 +781,23 @@ module aptos_std::big_ordered_map {
         }
     }
 
+    /// Returns true iff the BigOrderedMap is empty.
+    fun is_empty(self: &BigOrderedMap): bool {
+        let node = self.nodes.borrow(self.min_leaf_index);
+
+        node.children.is_empty()
+    }
+
+    // ============================= Tests ====================================
+
     #[test_only]
-    fun print_tree(self: &BigOrderedMap) {
+    fun print_map(self: &BigOrderedMap) {
         aptos_std::debug::print(self);
-        self.print_tree_for_node(self.root_index, 0);
+        self.print_map_for_node(self.root_index, 0);
     }
 
     #[test_only]
-    fun print_tree_for_node(self: &BigOrderedMap, node_index: u64, level: u64) {
+    fun print_map_for_node(self: &BigOrderedMap, node_index: u64, level: u64) {
         let node = self.nodes.borrow(node_index);
 
         aptos_std::debug::print(&level);
@@ -812,30 +806,19 @@ module aptos_std::big_ordered_map {
 
         if (!node.is_leaf) {
             node.children.for_each_ref(|_key, node| {
-                self.print_tree_for_node(node.node_index, level + 1);
+                self.print_map_for_node(node.node_index, level + 1);
             });
         };
     }
 
-    /// Returns true iff the BigOrderedMap is empty.
-    fun is_empty(self: &BigOrderedMap): bool {
-        let node = self.nodes.borrow(self.min_leaf_index);
-
-        node.children.is_empty()
-    }
-
-    ///////////
-    // Tests //
-    ///////////
-
     #[test_only]
     fun destroy(self: BigOrderedMap) {
         let it = new_begin_iter(&self);
-        while (!is_end_iter(&self, &it)) {
+        while (!it.iter_is_end(&self)) {
             remove(&mut self, it.iter_get_key());
-            assert!(is_end_iter(&self, &find(&self, it.iter_get_key())), E_INTERNAL);
+            assert!(find(&self, it.iter_get_key()).iter_is_end(&self), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
             it = new_begin_iter(&self);
-            self.validate_tree();
+            self.validate_map();
         };
 
         self.destroy_empty();
@@ -846,26 +829,26 @@ module aptos_std::big_ordered_map {
         let expected_num_elements = self.length();
         let num_elements = 0;
         let it = new_begin_iter(self);
-        while (!is_end_iter(self, &it)) {
+        while (!it.iter_is_end(self)) {
             num_elements = num_elements + 1;
-            it = next_iter(self, it);
+            it = it.iter_next(self);
         };
-        assert!(num_elements == expected_num_elements, E_INTERNAL);
+        assert!(num_elements == expected_num_elements, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
         let num_elements = 0;
         let it = new_end_iter(self);
-        while (!is_begin_iter(self, &it)) {
-            it = prev_iter(self, it);
+        while (!it.iter_is_begin(self)) {
+            it = it.iter_prev(self);
             num_elements = num_elements + 1;
         };
-        assert!(num_elements == expected_num_elements, E_INTERNAL);
+        assert!(num_elements == expected_num_elements, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
         let it = new_end_iter(self);
-        if (!is_begin_iter(self, &it)) {
-            it = prev_iter(self, it);
-            assert!(it.node_index == self.max_leaf_index, E_INTERNAL);
+        if (!it.iter_is_begin(self)) {
+            it = it.iter_prev(self);
+            assert!(it.node_index == self.max_leaf_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         } else {
-            assert!(expected_num_elements == 0, E_INTERNAL);
+            assert!(expected_num_elements == 0, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
     }
 
@@ -873,14 +856,14 @@ module aptos_std::big_ordered_map {
     fun validate_subtree(self: &BigOrderedMap, node_index: u64, expected_lower_bound_key: Option, expected_max_key: Option, expected_parent: u64) {
         let node = self.nodes.borrow(node_index);
         let len = node.children.length();
-        assert!(len <= self.get_max_degree(node.is_leaf), E_INTERNAL);
+        assert!(len <= self.get_max_degree(node.is_leaf), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
         if (node_index != self.root_index) {
-            assert!(len >= 1, E_INTERNAL);
-            assert!(len * 2 >= self.get_max_degree(node.is_leaf) || node_index == self.root_index, E_INTERNAL);
+            assert!(len >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(len * 2 >= self.get_max_degree(node.is_leaf) || node_index == self.root_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
 
-        assert!(node.parent == expected_parent, E_INTERNAL);
+        assert!(node.parent == expected_parent, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
         node.children.validate_ordered();
 
@@ -889,48 +872,48 @@ module aptos_std::big_ordered_map {
             if (!node.is_leaf) {
                 self.validate_subtree(child.node_index, previous_max_key, option::some(*key), node_index);
             } else {
-                assert!((child is Child::Leaf), E_INTERNAL);
+                assert!((child is Child::Leaf), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
             };
             previous_max_key = option::some(*key);
         });
 
         if (option::is_some(&expected_max_key)) {
             let expected_max_key = option::extract(&mut expected_max_key);
-            assert!(&expected_max_key == node.children.new_end_iter().iter_prev(&node.children).iter_borrow_key(&node.children), E_INTERNAL);
+            assert!(&expected_max_key == node.children.new_end_iter().iter_prev(&node.children).iter_borrow_key(&node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
 
         if (option::is_some(&expected_lower_bound_key)) {
             let expected_lower_bound_key = option::extract(&mut expected_lower_bound_key);
-            assert!(cmp::compare(&expected_lower_bound_key, node.children.new_begin_iter().iter_borrow_key(&node.children)).is_less_than(), E_INTERNAL);
+            assert!(cmp::compare(&expected_lower_bound_key, node.children.new_begin_iter().iter_borrow_key(&node.children)).is_less_than(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
     }
 
     #[test_only]
-    fun validate_tree(self: &BigOrderedMap) {
+    fun validate_map(self: &BigOrderedMap) {
         self.validate_subtree(self.root_index, option::none(), option::none(), NULL_INDEX);
         self.validate_iteration();
     }
 
     #[test]
-    fun test_smart_tree() {
+    fun test_small_example() {
         let map = new_with_config(5, 3, true, 2);
-        map.print_tree(); map.validate_tree();
-        add(&mut map, 1, 1); map.print_tree(); map.validate_tree();
-        add(&mut map, 2, 2); map.print_tree(); map.validate_tree();
-        let r1 = upsert(&mut map, 3, 3); map.print_tree(); map.validate_tree();
-        assert!(r1 == option::none(), E_INTERNAL);
-        add(&mut map, 4, 4); map.print_tree(); map.validate_tree();
-        let r2 = upsert(&mut map, 4, 8); map.print_tree(); map.validate_tree();
-        assert!(r2 == option::some(4), E_INTERNAL);
-        add(&mut map, 5, 5); map.print_tree(); map.validate_tree();
-        add(&mut map, 6, 6); map.print_tree(); map.validate_tree();
-
-        remove(&mut map, &5); map.print_tree(); map.validate_tree();
-        remove(&mut map, &4); map.print_tree(); map.validate_tree();
-        remove(&mut map, &1); map.print_tree(); map.validate_tree();
-        remove(&mut map, &3); map.print_tree(); map.validate_tree();
-        remove(&mut map, &2); map.print_tree(); map.validate_tree();
-        remove(&mut map, &6); map.print_tree(); map.validate_tree();
+        map.print_map(); map.validate_map();
+        add(&mut map, 1, 1); map.print_map(); map.validate_map();
+        add(&mut map, 2, 2); map.print_map(); map.validate_map();
+        let r1 = upsert(&mut map, 3, 3); map.print_map(); map.validate_map();
+        assert!(r1 == option::none(), 1);
+        add(&mut map, 4, 4); map.print_map(); map.validate_map();
+        let r2 = upsert(&mut map, 4, 8); map.print_map(); map.validate_map();
+        assert!(r2 == option::some(4), 2);
+        add(&mut map, 5, 5); map.print_map(); map.validate_map();
+        add(&mut map, 6, 6); map.print_map(); map.validate_map();
+
+        remove(&mut map, &5); map.print_map(); map.validate_map();
+        remove(&mut map, &4); map.print_map(); map.validate_map();
+        remove(&mut map, &1); map.print_map(); map.validate_map();
+        remove(&mut map, &3); map.print_map(); map.validate_map();
+        remove(&mut map, &2); map.print_map(); map.validate_map();
+        remove(&mut map, &6); map.print_map(); map.validate_map();
 
         destroy_empty(map);
     }
@@ -941,42 +924,42 @@ module aptos_std::big_ordered_map {
 
         for (i in 0..50) {
             map.upsert(i, i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         for (i in 0..40) {
             map.remove(&i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         for (i in 50..100) {
             map.upsert(i, i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         for (i in 50..90) {
             map.remove(&i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         for (i in 100..150) {
             map.upsert(i, i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         for (i in 100..150) {
             map.remove(&i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         for (i in 40..50) {
             map.remove(&i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         for (i in 90..100) {
             map.remove(&i);
-            map.validate_tree();
+            map.validate_map();
         };
 
         destroy_empty(map);
@@ -995,10 +978,10 @@ module aptos_std::big_ordered_map {
         let it = new_begin_iter(&map);
 
         let i = 0;
-        while (!is_end_iter(&map, &it)) {
-            assert!(i == it.key, E_INTERNAL);
+        while (!it.iter_is_end(&map)) {
+            assert!(i == it.key, i);
             i = i + 1;
-            it = next_iter(&map, it);
+            it = it.iter_next(&map);
         };
 
         destroy(map);
@@ -1022,13 +1005,13 @@ module aptos_std::big_ordered_map {
         while (i < len) {
             let element = data.borrow(i);
             let it = find(&map, element);
-            assert!(!is_end_iter(&map, &it), E_INTERNAL);
-            assert!(it.iter_get_key() == element, E_INTERNAL);
+            assert!(!it.iter_is_end(&map), i);
+            assert!(it.iter_get_key() == element, i);
             i = i + 1;
         };
 
-        assert!(is_end_iter(&map, &find(&map, &4)), E_INTERNAL);
-        assert!(is_end_iter(&map, &find(&map, &9)), E_INTERNAL);
+        assert!(find(&map, &4).iter_is_end(&map), 0);
+        assert!(find(&map, &9).iter_is_end(&map), 1);
 
         destroy(map);
     }
@@ -1051,76 +1034,80 @@ module aptos_std::big_ordered_map {
         while (i < len) {
             let element = *data.borrow(i);
             let it = lower_bound(&map, &element);
-            assert!(!is_end_iter(&map, &it), E_INTERNAL);
-            assert!(it.key == element, E_INTERNAL);
+            assert!(!it.iter_is_end(&map), i);
+            assert!(it.key == element, i);
             i = i + 1;
         };
 
-        assert!(lower_bound(&map, &0).key == 1, E_INTERNAL);
-        assert!(lower_bound(&map, &4).key == 5, E_INTERNAL);
-        assert!(lower_bound(&map, &9).key == 10, E_INTERNAL);
-        assert!(is_end_iter(&map, &lower_bound(&map, &13)), E_INTERNAL);
+        assert!(lower_bound(&map, &0).key == 1, 0);
+        assert!(lower_bound(&map, &4).key == 5, 1);
+        assert!(lower_bound(&map, &9).key == 10, 2);
+        assert!(lower_bound(&map, &13).iter_is_end(&map), 3);
 
         remove(&mut map, &3);
-        assert!(lower_bound(&map, &3).key == 5, E_INTERNAL);
+        assert!(lower_bound(&map, &3).key == 5, 4);
         remove(&mut map, &5);
-        assert!(lower_bound(&map, &3).key == 6, E_INTERNAL);
-        assert!(lower_bound(&map, &4).key == 6, E_INTERNAL);
+        assert!(lower_bound(&map, &3).key == 6, 5);
+        assert!(lower_bound(&map, &4).key == 6, 6);
 
         destroy(map);
     }
 
     #[test_only]
     fun test_large_data_set_helper(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool) {
+        use std::vector;
+
         let map = new_with_config(inner_max_degree, leaf_max_degree, reuse_slots, if (reuse_slots) {4} else {0});
         let data = ordered_map::large_dataset();
         let shuffled_data = ordered_map::large_dataset_shuffled();
 
-        let i = 0;
         let len = data.length();
-        while (i < len) {
+        for (i in 0..len) {
             let element = *data.borrow(i);
             map.upsert(element, element);
-            map.validate_tree();
-            i = i + 1;
+            map.validate_map();
         };
 
-        let i = 0;
-        while (i < len) {
+        for (i in 0..len) {
             let element = shuffled_data.borrow(i);
             let it = map.find(element);
-            assert!(!is_end_iter(&map, &it), E_INTERNAL);
-            assert!(it.iter_get_key() == element, E_INTERNAL);
+            assert!(!it.iter_is_end(&map), i);
+            assert!(it.iter_get_key() == element, i);
 
             // aptos_std::debug::print(&it);
 
-            let it_next = next_iter(&map, it);
+            let it_next = it.iter_next(&map);
             let it_after = map.lower_bound(&(*element + 1));
 
             // aptos_std::debug::print(&it_next);
             // aptos_std::debug::print(&it_after);
             // aptos_std::debug::print(&std::string::utf8(b"bla"));
 
-            assert!(it_next == it_after, E_INTERNAL);
-
-            i = i + 1;
+            assert!(it_next == it_after, i);
         };
 
-
-        let i = 0;
-        while (i < len) {
+        let removed = vector::empty();
+        for (i in 0..len) {
             let element = shuffled_data.borrow(i);
-            map.remove(element);
-            map.validate_map();
-            i = i + 1;
+            if (!removed.contains(element)) {
+                removed.push_back(*element);
+                map.remove(element);
+                map.validate_map();
+            } else {
+                assert!(!map.contains(element));
+            };
         };
 
         map.destroy_empty();
     }
 
     #[test]
-    fun test_large_data_set_order_5() {
+    fun test_large_data_set_order_5_false() {
         test_large_data_set_helper(5, 5, false);
+    }
+
+    #[test]
+    fun test_large_data_set_order_5_true() {
         test_large_data_set_helper(5, 5, true);
     }
 
@@ -1135,56 +1122,92 @@ module aptos_std::big_ordered_map {
     }
 
     #[test]
-    fun test_large_data_set_order_4_4() {
+    fun test_large_data_set_order_4_4_false() {
         test_large_data_set_helper(4, 4, false);
+    }
+
+    #[test]
+    fun test_large_data_set_order_4_4_true() {
         test_large_data_set_helper(4, 4, true);
     }
 
     #[test]
-    fun test_large_data_set_order_6() {
+    fun test_large_data_set_order_6_false() {
         test_large_data_set_helper(6, 6, false);
+    }
+
+    #[test]
+    fun test_large_data_set_order_6_true() {
         test_large_data_set_helper(6, 6, true);
     }
 
     #[test]
-    fun test_large_data_set_order_6_3() {
+    fun test_large_data_set_order_6_3_false() {
         test_large_data_set_helper(6, 3, false);
+    }
+
+    #[test]
+    fun test_large_data_set_order_6_3_true() {
         test_large_data_set_helper(6, 3, true);
     }
 
     #[test]
-    fun test_large_data_set_order_4_6() {
+    fun test_large_data_set_order_4_6_false() {
         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_16() {
+    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_31() {
+    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_3() {
+    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_5() {
+    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_32() {
+    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);
     }
 }
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move b/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move
index bdce7fb38235a9..2c08f05d670fe1 100644
--- a/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move
+++ b/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move
@@ -42,6 +42,7 @@ module aptos_std::storage_slots_allocator {
             new_slot_index: u64,
             reuse_head_index: u64,
         },
+        // TODO implement variant that inlines first node?
     }
 
     struct ReservedSlot {
@@ -64,7 +65,7 @@ module aptos_std::storage_slots_allocator {
 
         for (i in 0..num_to_preallocate) {
             let slot_index = self.next_slot_index();
-            self.push_to_reuse_queue(slot_index);
+            self.push_to_reuse_queue_if_enabled(slot_index);
         };
 
         self
@@ -89,7 +90,7 @@ module aptos_std::storage_slots_allocator {
     public fun remove(self: &mut StorageSlotsAllocator, slot_index: u64): T {
         let Link::Occupied { value } = self.slots.remove(slot_index);
 
-        self.push_to_reuse_queue(slot_index);
+        self.push_to_reuse_queue_if_enabled(slot_index);
 
         value
     }
@@ -126,7 +127,11 @@ module aptos_std::storage_slots_allocator {
         self.slot_index
     }
 
-    // splitting add into getting ReservedSlot, and then inserting it later
+    // We also provide here operations where `add()` is split into `reserve_slot`,
+    // and then doing fill_reserved_slot later.
+
+    // Similarly we have `remove_and_reserve`, and then `fill_reserved_slot` later.
+
     public fun reserve_slot(self: &mut StorageSlotsAllocator): ReservedSlot {
         if (self is StorageSlotsAllocator::Reuse) {
             let slot_index = self.reuse_head_index;
@@ -158,10 +163,10 @@ module aptos_std::storage_slots_allocator {
 
     public fun free_reserved_slot(self: &mut StorageSlotsAllocator, slot: ReservedSlot) {
         let ReservedSlot { slot_index } = slot;
-        self.push_to_reuse_queue(slot_index);
+        self.push_to_reuse_queue_if_enabled(slot_index);
     }
 
-    fun push_to_reuse_queue(self: &mut StorageSlotsAllocator, slot_index: u64) {
+    fun push_to_reuse_queue_if_enabled(self: &mut StorageSlotsAllocator, slot_index: u64) {
         if (self is StorageSlotsAllocator::Reuse) {
             self.slots.add(slot_index, Link::Vacant { next: self.reuse_head_index });
             self.reuse_head_index = slot_index;