From 65c89833707efc46396d9621152d8217f5068a64 Mon Sep 17 00:00:00 2001 From: igor-aptos <110557261+igor-aptos@users.noreply.github.com> Date: Tue, 14 Jan 2025 00:31:37 -0800 Subject: [PATCH] Add destroy() and for_each() to BigOrderedMap, and move to aptos-framework (#15723) * Add destroy() and for_each() to BigOrderedMap * move to aptos-framework --------- Co-authored-by: Igor --- .../doc/big_ordered_map.md | 327 ++++++++++++------ .../doc/ordered_map.md | 146 ++++---- .../framework/aptos-framework/doc/overview.md | 2 + .../datastructures}/big_ordered_map.move | 124 +++++-- .../sources/datastructures}/ordered_map.move | 0 .../aptos-stdlib/doc/fixed_point64.md | 12 +- .../framework/aptos-stdlib/doc/overview.md | 2 - .../framework/aptos-stdlib/doc/simple_map.md | 4 +- .../doc/storage_slots_allocator.md | 20 +- .../storage_slots_allocator.move | 17 +- .../src/raw_module_data.rs | 38 +- 11 files changed, 425 insertions(+), 267 deletions(-) rename aptos-move/framework/{aptos-stdlib => aptos-framework}/doc/big_ordered_map.md (79%) rename aptos-move/framework/{aptos-stdlib => aptos-framework}/doc/ordered_map.md (81%) rename aptos-move/framework/{aptos-stdlib/sources/data_structures => aptos-framework/sources/datastructures}/big_ordered_map.move (95%) rename aptos-move/framework/{aptos-stdlib/sources/data_structures => aptos-framework/sources/datastructures}/ordered_map.move (100%) diff --git a/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md b/aptos-move/framework/aptos-framework/doc/big_ordered_map.md similarity index 79% rename from aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md rename to aptos-move/framework/aptos-framework/doc/big_ordered_map.md index ca0f8f36c4577..dac43b4483ca1 100644 --- a/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md +++ b/aptos-move/framework/aptos-framework/doc/big_ordered_map.md @@ -53,6 +53,9 @@ allowing cleaner iterator APIs. - [Function `iter_borrow_mut`](#0x1_big_ordered_map_iter_borrow_mut) - [Function `iter_next`](#0x1_big_ordered_map_iter_next) - [Function `iter_prev`](#0x1_big_ordered_map_iter_prev) +- [Function `for_each`](#0x1_big_ordered_map_for_each) +- [Function `for_each_ref`](#0x1_big_ordered_map_for_each_ref) +- [Function `destroy`](#0x1_big_ordered_map_destroy) - [Function `borrow_node`](#0x1_big_ordered_map_borrow_node) - [Function `borrow_node_mut`](#0x1_big_ordered_map_borrow_node_mut) - [Function `add_or_upsert_impl`](#0x1_big_ordered_map_add_or_upsert_impl) @@ -82,14 +85,14 @@ allowing cleaner iterator APIs. - [Function `length_for_node`](#@Specification_1_length_for_node) -
use 0x1::bcs;
-use 0x1::cmp;
-use 0x1::error;
-use 0x1::math64;
-use 0x1::option;
+
use 0x1::bcs;
+use 0x1::cmp;
+use 0x1::error;
+use 0x1::math64;
+use 0x1::option;
 use 0x1::ordered_map;
-use 0x1::storage_slots_allocator;
-use 0x1::vector;
+use 0x1::storage_slots_allocator;
+use 0x1::vector;
 
@@ -171,7 +174,7 @@ Contents of a child node.
-node_index: storage_slots_allocator::StoredSlot +node_index: storage_slots_allocator::StoredSlot
@@ -310,7 +313,7 @@ The BigOrderedMap data structure. Root node. It is stored directly in the resource itself, unlike all other nodes.
-nodes: storage_slots_allocator::StorageSlotsAllocator<big_ordered_map::Node<K, V>> +nodes: storage_slots_allocator::StorageSlotsAllocator<big_ordered_map::Node<K, V>>
Storage of all non-root nodes. They are stored in separate storage slots. @@ -360,51 +363,51 @@ The BigOrderedMap data structure. ## Constants - + -Internal errors. +Map key already exists -
const EINTERNAL_INVARIANT_BROKEN: u64 = 20;
+
const EKEY_ALREADY_EXISTS: u64 = 1;
 
- + +Map key is not found -
const NULL_INDEX: u64 = 0;
+
const EKEY_NOT_FOUND: u64 = 2;
 
- + -Trying to do an operation on an IteratorPtr that would go out of bounds +Internal errors. -
const EITER_OUT_OF_BOUNDS: u64 = 3;
+
const EINTERNAL_INVARIANT_BROKEN: u64 = 20;
 
- + -Map key already exists -
const EKEY_ALREADY_EXISTS: u64 = 1;
+
const NULL_INDEX: u64 = 0;
 
- + -Map key is not found +Trying to do an operation on an IteratorPtr that would go out of bounds -
const EKEY_NOT_FOUND: u64 = 2;
+
const EITER_OUT_OF_BOUNDS: u64 = 3;
 
@@ -524,8 +527,8 @@ it is required to use new_with_config, to explicitly select automatic or specifi
public fun new<K: store, V: store>(): BigOrderedMap<K, V> {
     assert!(
-        bcs::constant_serialized_size<K>().is_some() && bcs::constant_serialized_size<V>().is_some(),
-        error::invalid_argument(EINVALID_CONFIG_PARAMETER)
+        bcs::constant_serialized_size<K>().is_some() && bcs::constant_serialized_size<V>().is_some(),
+        error::invalid_argument(EINVALID_CONFIG_PARAMETER)
     );
 
     new_with_config(0, 0, false, 0)
@@ -560,15 +563,15 @@ it is important to compute and pass inner_max_degree and leaf_max_degree based o
 
 
 
public fun new_with_config<K: store, V: store>(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool, num_to_preallocate: u32): BigOrderedMap<K, V> {
-    assert!(inner_max_degree == 0 || (inner_max_degree >= DEFAULT_INNER_MIN_DEGREE && (inner_max_degree as u64) <= MAX_DEGREE), error::invalid_argument(EINVALID_CONFIG_PARAMETER));
-    assert!(leaf_max_degree == 0 || (leaf_max_degree >= DEFAULT_LEAF_MIN_DEGREE && (leaf_max_degree as u64) <= MAX_DEGREE), error::invalid_argument(EINVALID_CONFIG_PARAMETER));
-    assert!(reuse_slots || num_to_preallocate == 0, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
+    assert!(inner_max_degree == 0 || (inner_max_degree >= DEFAULT_INNER_MIN_DEGREE && (inner_max_degree as u64) <= MAX_DEGREE), error::invalid_argument(EINVALID_CONFIG_PARAMETER));
+    assert!(leaf_max_degree == 0 || (leaf_max_degree >= DEFAULT_LEAF_MIN_DEGREE && (leaf_max_degree as u64) <= MAX_DEGREE), error::invalid_argument(EINVALID_CONFIG_PARAMETER));
+    assert!(reuse_slots || num_to_preallocate == 0, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
 
-    // Assert that storage_slots_allocator special indices are aligned:
-    assert!(storage_slots_allocator::is_null_index(NULL_INDEX), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-    assert!(storage_slots_allocator::is_special_unused_index(ROOT_INDEX), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    // Assert that storage_slots_allocator special indices are aligned:
+    assert!(storage_slots_allocator::is_null_index(NULL_INDEX), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(storage_slots_allocator::is_special_unused_index(ROOT_INDEX), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
-    let nodes = storage_slots_allocator::new(storage_slots_allocator::new_config(reuse_slots, num_to_preallocate));
+    let nodes = storage_slots_allocator::new(storage_slots_allocator::new_config(reuse_slots, num_to_preallocate));
 
     let self = BigOrderedMap::BPlusTreeMap {
         root: new_node(/*is_leaf=*/true),
@@ -596,7 +599,7 @@ Create a BigOrderedMap from a vector of keys and values, with default configurat
 Aborts with EKEY_ALREADY_EXISTS if duplicate keys are passed in.
 
 
-
public fun new_from<K: copy, drop, store, V: store>(keys: vector<K>, values: vector<V>): big_ordered_map::BigOrderedMap<K, V>
+
public fun new_from<K: copy, drop, store, V: store>(keys: vector<K>, values: vector<V>): big_ordered_map::BigOrderedMap<K, V>
 
@@ -605,7 +608,7 @@ Aborts with EKEY_ALREADY_EXISTS if duplicate keys are passed in. Implementation -
public fun new_from<K: drop + copy + store, V: store>(keys: vector<K>, values: vector<V>): BigOrderedMap<K, V> {
+
public fun new_from<K: drop + copy + store, V: store>(keys: vector<K>, values: vector<V>): BigOrderedMap<K, V> {
     let map = new();
     map.add_all(keys, values);
     map
@@ -637,7 +640,7 @@ Destroys the map if it's empty, otherwise aborts.
     root.destroy_empty_node();
     // If root node is empty, then we know that no storage slots are used,
     // and so we can safely destroy all nodes.
-    nodes.destroy_known_empty_unsafe();
+    nodes.destroy_empty();
 }
 
@@ -679,7 +682,7 @@ 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<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V): option::Option<V>
+
public fun upsert<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V): option::Option<V>
 
@@ -694,10 +697,10 @@ Otherwise updates the value under the given key, and returns the old value. let Child::Leaf { value: old_value, } = result.destroy_some(); - option::some(old_value) + option::some(old_value) } else { result.destroy_none(); - option::none() + option::none() } }
@@ -735,7 +738,7 @@ Aborts if there is no entry for key. let path_to_leaf = self.find_leaf_path(key); - assert!(!path_to_leaf.is_empty(), error::invalid_argument(EKEY_NOT_FOUND)); + assert!(!path_to_leaf.is_empty(), error::invalid_argument(EKEY_NOT_FOUND)); let Child::Leaf { value, @@ -756,7 +759,7 @@ Add multiple key/value pairs to the map. The keys must not already exist. Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are passed in. -
public fun add_all<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, keys: vector<K>, values: vector<V>)
+
public fun add_all<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, keys: vector<K>, values: vector<V>)
 
@@ -765,10 +768,10 @@ Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are pass Implementation -
public fun add_all<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, keys: vector<K>, values: vector<V>) {
+
public fun add_all<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, keys: vector<K>, values: vector<V>) {
     // TODO: Can be optimized, both in insertion order (largest first, then from smallest),
     // as well as on initializing inner_max_degree/leaf_max_degree better
-    vector::zip(keys, values, |key, value| {
+    vector::zip(keys, values, |key, value| {
         self.add(key, value);
     });
 }
@@ -802,7 +805,7 @@ key, or an end iterator if such element doesn't exist.
     };
 
     let node = self.borrow_node(leaf);
-    assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    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(&node.children)) {
@@ -901,8 +904,14 @@ Returns a reference to the element with its key, aborts if the key is not found.
 
 
public fun borrow<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): &V {
     let iter = self.find(key);
-    assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
-    iter.iter_borrow(self)
+    assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
+
+    // TODO cannot call iter_borrow, because reference checks assume return has reference to iter that is being destroyed
+    // iter.iter_borrow(self)
+
+    assert!(!iter.iter_is_end(self), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    let children = &self.borrow_node(iter.node_index).children;
+    &iter.child_iter.iter_borrow(children).value
 }
 
@@ -928,7 +937,7 @@ Returns a mutable reference to the element with its key at the given index, abor
public fun borrow_mut<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: &K): &mut V {
     let iter = self.find(key);
-    assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
+    assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
     iter.iter_borrow_mut(self)
 }
 
@@ -959,7 +968,7 @@ Returns the begin iterator. }; let node = self.borrow_node(self.min_leaf_index); - assert!(!node.children.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + 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) @@ -1066,7 +1075,7 @@ Note: Requires that the map is not changed after the input iterator is generated
public(friend) fun iter_borrow_key<K>(self: &IteratorPtr<K>): &K {
-    assert!(!(self is IteratorPtr::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!(self is IteratorPtr::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     &self.key
 }
 
@@ -1084,7 +1093,7 @@ Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end. Note: Requires that the map is not changed after the input iterator is generated. -
public(friend) fun iter_borrow<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): &V
+
public(friend) fun iter_borrow<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): &V
 
@@ -1093,8 +1102,8 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &BigOrderedMap<K, V>): &V {
-    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+
public(friend) fun iter_borrow<K: store, V: store>(self: &IteratorPtr<K>, map: &BigOrderedMap<K, V>): &V {
+    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     let children = &map.borrow_node(self.node_index).children;
     &self.child_iter.iter_borrow(children).value
 }
@@ -1115,7 +1124,7 @@ because if it doesn't - we need to call upsert to be able to check
 Note: Requires that the map is not changed after the input iterator is generated.
 
 
-
public(friend) fun iter_borrow_mut<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): &mut V
+
public(friend) fun iter_borrow_mut<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): &mut V
 
@@ -1124,9 +1133,9 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow_mut<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &mut BigOrderedMap<K, V>): &mut V {
-    assert!(map.constant_kv_size, error::invalid_argument(EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE));
-    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+
public(friend) fun iter_borrow_mut<K: store, V: store>(self: &IteratorPtr<K>, map: &mut BigOrderedMap<K, V>): &mut V {
+    assert!(map.constant_kv_size, error::invalid_argument(EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE));
+    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     let children = &mut map.borrow_node_mut(self.node_index).children;
     &mut self.child_iter.iter_borrow_mut(children).value
 }
@@ -1155,7 +1164,7 @@ Requires the map is not changed after the input iterator is generated.
 
 
 
public(friend) fun iter_next<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &BigOrderedMap<K, V>): IteratorPtr<K> {
-    assert!(!(self is IteratorPtr::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!(self is IteratorPtr::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
     let node_index = self.node_index;
     let node = map.borrow_node(node_index);
@@ -1173,7 +1182,7 @@ Requires the map is not changed after the input iterator is generated.
         let next_node = map.borrow_node(next_index);
 
         let child_iter = next_node.children.new_begin_iter();
-        assert!(!child_iter.iter_is_end(&next_node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+        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);
     };
@@ -1220,7 +1229,7 @@ Requires the map is not changed after the input iterator is generated.
         node.prev
     };
 
-    assert!(prev_index != NULL_INDEX, error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(prev_index != NULL_INDEX, error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
     // next is in a different leaf node
     let prev_node = map.borrow_node(prev_index);
@@ -1234,6 +1243,96 @@ Requires the map is not changed after the input iterator is generated.
 
 
 
+
+
+
+
+## Function `for_each`
+
+Apply the function to each element in the vector, consuming it.
+
+
+
public(friend) fun for_each<K: copy, drop, store, V: store>(self: big_ordered_map::BigOrderedMap<K, V>, f: |(K, V)|)
+
+ + + +
+Implementation + + +
public(friend) inline fun for_each<K: drop + copy + store, V: store>(self: BigOrderedMap<K, V>, f: |K, V|) {
+    // TODO - this can be done more efficiently, by destroying the leaves directly
+    // but that requires more complicated code and testing.
+    let it = self.new_begin_iter();
+    while (!it.iter_is_end(&self)) {
+        let k = *it.iter_borrow_key();
+        let v = self.remove(&k);
+        f(k, v);
+        it = self.new_begin_iter();
+    };
+    destroy_empty(self)
+}
+
+ + + +
+ + + +## Function `for_each_ref` + +Apply the function to a reference of each element in the vector. + + +
public(friend) fun for_each_ref<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, f: |(&K, &V)|)
+
+ + + +
+Implementation + + +
public(friend) inline fun for_each_ref<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, f: |&K, &V|) {
+    let it = self.new_begin_iter();
+    while (!it.iter_is_end(self)) {
+        f(it.iter_borrow_key(), it.iter_borrow(self));
+        it = it.iter_next(self);
+    };
+}
+
+ + + +
+ + + +## Function `destroy` + +Destroy a map, by destroying elements individually. + + +
public(friend) fun destroy<K: copy, drop, store, V: store>(self: big_ordered_map::BigOrderedMap<K, V>, dv: |V|)
+
+ + + +
+Implementation + + +
public(friend) inline fun destroy<K: drop + copy + store, V: store>(self: BigOrderedMap<K, V>, dv: |V|) {
+    for_each(self, |_k, v| {
+        dv(v);
+    });
+}
+
+ + +
@@ -1300,7 +1399,7 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an -
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>>
+
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>>
 
@@ -1322,7 +1421,7 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an if (degree < (self.leaf_max_degree as u64)) { let result = children.upsert(key, new_leaf_child(value)); - assert!(allow_overwrite || result.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS)); + assert!(allow_overwrite || result.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS)); return result; }; }; @@ -1373,8 +1472,8 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an
fun validate_dynamic_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 key_size = bcs::serialized_size(key);
+    let value_size = bcs::serialized_size(value);
     self.validate_size_and_init_max_degrees(key_size, value_size)
 }
 
@@ -1399,8 +1498,8 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an
fun validate_static_size_and_init_max_degrees<K: store, V: store>(self: &mut BigOrderedMap<K, V>) {
-    let key_size = bcs::constant_serialized_size<K>();
-    let value_size = bcs::constant_serialized_size<V>();
+    let key_size = bcs::constant_serialized_size<K>();
+    let value_size = bcs::constant_serialized_size<V>();
 
     if (key_size.is_some() && value_size.is_some()) {
         self.validate_size_and_init_max_degrees(key_size.destroy_some(), value_size.destroy_some());
@@ -1440,8 +1539,8 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an
     };
 
     // Make sure that no nodes can exceed the upper size limit.
-    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));
+    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));
 }
 
@@ -1455,7 +1554,7 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an -
fun destroy_inner_child<V: store>(self: big_ordered_map::Child<V>): storage_slots_allocator::StoredSlot
+
fun destroy_inner_child<V: store>(self: big_ordered_map::Child<V>): storage_slots_allocator::StoredSlot
 
@@ -1494,7 +1593,7 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an
fun destroy_empty_node<K: store, V: store>(self: Node<K, V>) {
     let Node { children, is_leaf: _, prev: _, next: _ } = self;
-    assert!(children.is_empty(), error::invalid_argument(EMAP_NOT_EMPTY));
+    assert!(children.is_empty(), error::invalid_argument(EMAP_NOT_EMPTY));
     children.destroy_empty();
 }
 
@@ -1567,7 +1666,7 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an -
fun new_inner_child<V: store>(node_index: storage_slots_allocator::StoredSlot): big_ordered_map::Child<V>
+
fun new_inner_child<V: store>(node_index: storage_slots_allocator::StoredSlot): big_ordered_map::Child<V>
 
@@ -1691,7 +1790,7 @@ Returns the path from root to that leaf (including the leaf itself) Returns empty path if key is larger than any key currently stored in the map. -
fun find_leaf_path<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): vector<u64>
+
fun find_leaf_path<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): vector<u64>
 
@@ -1700,8 +1799,8 @@ Returns empty path if key is larger than any key currently stored i Implementation -
fun find_leaf_path<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): vector<u64> {
-    let vec = vector::empty();
+
fun find_leaf_path<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): vector<u64> {
+    let vec = vector::empty();
 
     let current = ROOT_INDEX;
     loop {
@@ -1714,7 +1813,7 @@ Returns empty path if key is larger than any key currently stored i
         let children = &node.children;
         let child_iter = children.lower_bound(key);
         if (child_iter.iter_is_end(children)) {
-            return vector::empty();
+            return vector::empty();
         } else {
             current = child_iter.iter_borrow(children).node_index.stored_to_index();
         };
@@ -1770,18 +1869,18 @@ Returns empty path if key is larger than any key currently stored i
 
 
 
fun replace_root<K: store, V: store>(self: &mut BigOrderedMap<K, V>, new_root: Node<K, V>): Node<K, V> {
-    // TODO: once mem::replace is made public/released, update to:
-    // mem::replace(&mut self.root, new_root_node)
+    // TODO: once mem::replace is made public/released, update to:
+    // mem::replace(&mut self.root, new_root_node)
 
     let root = &mut self.root;
     let tmp_is_leaf = root.is_leaf;
     root.is_leaf = new_root.is_leaf;
     new_root.is_leaf = tmp_is_leaf;
 
-    assert!(root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-    assert!(root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-    assert!(new_root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-    assert!(new_root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(new_root.prev == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(new_root.next == NULL_INDEX, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
     // let tmp_prev = root.prev;
     // root.prev = new_root.prev;
@@ -1816,7 +1915,7 @@ Returns Child previously associated with the given key.
 If allow_overwrite is not set, function will abort if key is already present.
 
 
-
fun add_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: K, child: big_ordered_map::Child<V>, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
+
fun add_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: K, child: big_ordered_map::Child<V>, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
 
@@ -1825,11 +1924,11 @@ If allow_overwrite is not set, function will abort if keyImplementation -
fun add_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<u64>, key: K, child: Child<V>, allow_overwrite: bool): Option<Child<V>> {
+
fun add_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<u64>, key: K, child: Child<V>, allow_overwrite: bool): Option<Child<V>> {
     // Last node in the path is one where we need to add the child to.
     let node_index = path_to_node.pop_back();
     {
-        // First check if we can perform this operation, without changing structure of the tree (i.e. without adding any nodes).
+        // First check if we can perform this operation, without changing structure of the tree (i.e. without adding any nodes).
 
         // For that we can just borrow the single node
         let node = self.borrow_node_mut(node_index);
@@ -1848,10 +1947,10 @@ If allow_overwrite is not set, function will abort if keylet old_child = children.upsert(key, child);
 
             if (node.is_leaf) {
-                assert!(allow_overwrite || old_child.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS));
+                assert!(allow_overwrite || old_child.is_none(), error::invalid_argument(EKEY_ALREADY_EXISTS));
                 return old_child;
             } else {
-                assert!(!allow_overwrite && old_child.is_none(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+                assert!(!allow_overwrite && old_child.is_none(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
                 return old_child;
             };
         };
@@ -1860,10 +1959,10 @@ If allow_overwrite is not set, function will abort if keywith `key` already exists, we either need to replace or abort.
         let iter = children.find(&key);
         if (!iter.iter_is_end(children)) {
-            assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-            assert!(allow_overwrite, error::invalid_argument(EKEY_ALREADY_EXISTS));
+            assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(allow_overwrite, error::invalid_argument(EKEY_ALREADY_EXISTS));
 
-            return option::some(iter.iter_replace(children, child));
+            return option::some(iter.iter_replace(children, child));
         }
     };
 
@@ -1872,7 +1971,7 @@ If allow_overwrite is not set, function will abort if keyto move root node to become a child and have a new root node,
     // in order to be able to split the node on the level it is.
     let (reserved_slot, node) = if (node_index == ROOT_INDEX) {
-        assert!(path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+        assert!(path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
         // Splitting root now, need to create a new root.
         // Since root is stored direclty in the resource, we will swap-in the new node there.
@@ -1886,7 +1985,7 @@ If allow_overwrite is not set, function will abort if keylet max_key = *root_children.new_end_iter().iter_prev(root_children).iter_borrow_key(root_children);
             // need to check if key is largest, as invariant is that "parent's pointers" have been updated,
             // but key itself can be larger than all previous ones.
-            if (cmp::compare(&max_key, &key).is_lt()) {
+            if (cmp::compare(&max_key, &key).is_lt()) {
                 max_key = key;
             };
             max_key
@@ -1917,7 +2016,7 @@ If allow_overwrite is not set, function will abort if keymove node_index;
 
     // Now we can perform the split at the current level, as we know we are not at the root level.
-    assert!(!path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(!path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
     // Parent has a reference under max key to the current node, so existing index
     // needs to be the right node.
@@ -1951,8 +2050,8 @@ If allow_overwrite is not set, function will abort if keyadd(key, child);
     let right_node_children = left_children.trim(target_size);
 
-    assert!(left_children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-    assert!(right_node_children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(left_children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(right_node_children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
     let right_node = new_node_with_children(is_leaf, right_node_children);
 
@@ -1969,10 +2068,10 @@ If allow_overwrite is not set, function will abort if keyto update next pointer of the previous node (if exists)
     if (*left_prev != NULL_INDEX) {
         self.nodes.borrow_mut(*left_prev).next = left_node_index;
-        assert!(right_node_index != self.min_leaf_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+        assert!(right_node_index != self.min_leaf_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
     } else if (right_node_index == self.min_leaf_index) {
         // Otherwise, if we were the smallest node on the level. if this is the leaf level, update the pointer.
-        assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+        assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         self.min_leaf_index = left_node_index;
     };
 
@@ -1984,7 +2083,7 @@ If allow_overwrite is not set, function will abort if keyChild (i.e. pointer to the left node) in the parent.
     self.add_at(path_to_node, max_left_key, new_inner_child(left_node_slot), false).destroy_none();
-    option::none()
+    option::none()
 }
 
@@ -1999,7 +2098,7 @@ If allow_overwrite is not set, function will abort if keyfun update_key<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, old_key: &K, new_key: K) +
fun update_key<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, old_key: &K, new_key: K)
 
@@ -2008,7 +2107,7 @@ Given a path to node (excluding the node itself), which is currently stored unde Implementation -
fun update_key<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<u64>, old_key: &K, new_key: K) {
+
fun update_key<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<u64>, old_key: &K, new_key: K) {
     while (!path_to_node.is_empty()) {
         let node_index = path_to_node.pop_back();
         let node = self.borrow_node_mut(node_index);
@@ -2033,7 +2132,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
 
 
 
-
fun remove_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: &K): big_ordered_map::Child<V>
+
fun remove_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: &K): big_ordered_map::Child<V>
 
@@ -2042,11 +2141,11 @@ Given a path to node (excluding the node itself), which is currently stored unde Implementation -
fun remove_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<u64>, key: &K): Child<V> {
+
fun remove_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<u64>, key: &K): Child<V> {
     // Last node in the path is one where we need to remove the child from.
     let node_index = path_to_node.pop_back();
     let old_child = {
-        // First check if we can perform this operation, without changing structure of the tree (i.e. without rebalancing any nodes).
+        // First check if we can perform this operation, without changing structure of the tree (i.e. without rebalancing any nodes).
 
         // For that we can just borrow the single node
         let node = self.borrow_node_mut(node_index);
@@ -2059,7 +2158,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
             // If current node is root, lower limit of max_degree/2 nodes doesn't apply.
             // So we can adjust internally
 
-            assert!(path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
             if (!is_leaf && children.length() == 1) {
                 // If root is not leaf, but has a single child, promote only child to root,
@@ -2095,9 +2194,9 @@ Given a path to node (excluding the node itself), which is currently stored unde
         let new_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
 
         // See if max key was updated for the current node, and if so - update it on the path.
-        let max_key_updated = cmp::compare(&new_max_key, key).is_lt();
+        let max_key_updated = cmp::compare(&new_max_key, key).is_lt();
         if (max_key_updated) {
-            assert!(degree >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(degree >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
             self.update_key(path_to_node, key, new_max_key);
         };
@@ -2124,9 +2223,9 @@ Given a path to node (excluding the node itself), which is currently stored unde
     // index of the node we will rebalance with.
     let sibling_index = {
         let parent_children = &self.borrow_node(*path_to_node.borrow(path_to_node.length() - 1)).children;
-        assert!(parent_children.length() >= 2, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+        assert!(parent_children.length() >= 2, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         // If we are the largest node from the parent, we merge with the `prev`
-        // (which is then guaranteed to have the same parent, as any node has >1 children),
+        // (which is then guaranteed to have the same parent, as any node has >1 children),
         // otherwise we merge with `next`.
         if (parent_children.new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_to_index() == node_index) {
             prev
@@ -2138,7 +2237,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
     let children = &mut node.children;
 
     let (sibling_slot, sibling_node) = self.nodes.remove_and_reserve(sibling_index);
-    assert!(is_leaf == sibling_node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(is_leaf == sibling_node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
     let sibling_children = &mut sibling_node.children;
 
     if ((sibling_children.length() - 1) * 2 >= max_degree) {
@@ -2182,7 +2281,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         node.next = sibling_next;
 
         if (node.next != NULL_INDEX) {
-            assert!(self.nodes.borrow_mut(node.next).prev == sibling_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(self.nodes.borrow_mut(node.next).prev == sibling_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
 
         // we are removing node_index, which previous's node's next was pointing to,
@@ -2192,7 +2291,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         };
         // Otherwise, we were the smallest node on the level. if this is the leaf level, update the pointer.
         if (self.min_leaf_index == node_index) {
-            assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
             self.min_leaf_index = sibling_index;
         };
 
@@ -2207,7 +2306,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         sibling_node.next = node_next;
 
         if (sibling_node.next != NULL_INDEX) {
-            assert!(self.nodes.borrow_mut(sibling_node.next).prev == node_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(self.nodes.borrow_mut(sibling_node.next).prev == node_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         };
         // we are removing sibling node_index, which previous's node's next was pointing to,
         // so update the pointer
@@ -2216,7 +2315,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         };
         // Otherwise, sibling was the smallest node on the level. if this is the leaf level, update the pointer.
         if (self.min_leaf_index == sibling_index) {
-            assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+            assert!(is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
             self.min_leaf_index = node_index;
         };
 
@@ -2225,7 +2324,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         (key_to_remove, sibling_slot)
     };
 
-    assert!(!path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+    assert!(!path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
     let slot_to_remove = destroy_inner_child(self.remove_at(path_to_node, &key_to_remove));
     self.nodes.free_reserved_slot(reserved_slot_to_remove, slot_to_remove);
 
@@ -2284,7 +2383,7 @@ Returns the number of elements in the BigOrderedMap.
     } else {
         let size = 0;
 
-        node.children.for_each_ref(|_key, child| {
+        node.children.for_each_ref(|_key, child| {
             size = size + self.length_for_node(child.node_index.stored_to_index());
         });
         size
@@ -2339,7 +2438,7 @@ Returns true iff the BigOrderedMap is empty.
 ### Function `add_at`
 
 
-
fun add_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: K, child: big_ordered_map::Child<V>, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
+
fun add_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: K, child: big_ordered_map::Child<V>, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
 
@@ -2355,7 +2454,7 @@ Returns true iff the BigOrderedMap is empty. ### Function `remove_at` -
fun remove_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: &K): big_ordered_map::Child<V>
+
fun remove_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<u64>, key: &K): big_ordered_map::Child<V>
 
diff --git a/aptos-move/framework/aptos-stdlib/doc/ordered_map.md b/aptos-move/framework/aptos-framework/doc/ordered_map.md similarity index 81% rename from aptos-move/framework/aptos-stdlib/doc/ordered_map.md rename to aptos-move/framework/aptos-framework/doc/ordered_map.md index 4a3a1d56b0733..85c456769972d 100644 --- a/aptos-move/framework/aptos-stdlib/doc/ordered_map.md +++ b/aptos-move/framework/aptos-framework/doc/ordered_map.md @@ -76,10 +76,10 @@ allowing cleaner iterator APIs. - [Specification](#@Specification_1) -
use 0x1::cmp;
-use 0x1::error;
-use 0x1::option;
-use 0x1::vector;
+
use 0x1::cmp;
+use 0x1::error;
+use 0x1::option;
+use 0x1::vector;
 
@@ -144,7 +144,7 @@ The OrderedMap datastructure.
-entries: vector<ordered_map::Entry<K, V>> +entries: vector<ordered_map::Entry<K, V>>
List of entries, sorted by key. @@ -221,31 +221,31 @@ TODO: Once fields can be (mutable) references, this class will be deprecated. ## Constants - + +Map key already exists -
const EITER_OUT_OF_BOUNDS: u64 = 3;
+
const EKEY_ALREADY_EXISTS: u64 = 1;
 
- + -Map key already exists +Map key is not found -
const EKEY_ALREADY_EXISTS: u64 = 1;
+
const EKEY_NOT_FOUND: u64 = 2;
 
- + -Map key is not found -
const EKEY_NOT_FOUND: u64 = 2;
+
const EITER_OUT_OF_BOUNDS: u64 = 3;
 
@@ -278,7 +278,7 @@ Create a new empty OrderedMap, using default (SortedVectorMap) implementation.
public fun new<K, V>(): OrderedMap<K, V> {
     OrderedMap::SortedVectorMap {
-        entries: vector::empty(),
+        entries: vector::empty(),
     }
 }
 
@@ -295,7 +295,7 @@ Create a OrderedMap from a vector of keys and values. Aborts with EKEY_ALREADY_EXISTS if duplicate keys are passed in. -
public fun new_from<K, V>(keys: vector<K>, values: vector<V>): ordered_map::OrderedMap<K, V>
+
public fun new_from<K, V>(keys: vector<K>, values: vector<V>): ordered_map::OrderedMap<K, V>
 
@@ -304,7 +304,7 @@ Aborts with EKEY_ALREADY_EXISTS if duplicate keys are passed in. Implementation -
public fun new_from<K, V>(keys: vector<K>, values: vector<V>): OrderedMap<K, V> {
+
public fun new_from<K, V>(keys: vector<K>, values: vector<V>): OrderedMap<K, V> {
     let map = new();
     add_all(&mut map, keys, values);
     map
@@ -387,7 +387,7 @@ Aborts with EKEY_ALREADY_EXISTS if key already exist.
     let index = binary_search(&key, &self.entries, 0, len);
 
     // key must not already be inside.
-    assert!(index >= len || &self.entries[index].key != &key, error::invalid_argument(EKEY_ALREADY_EXISTS));
+    assert!(index >= len || &self.entries[index].key != &key, error::invalid_argument(EKEY_ALREADY_EXISTS));
     self.entries.insert(index, Entry { key, value });
 }
 
@@ -404,7 +404,7 @@ 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<K: drop, V>(self: &mut ordered_map::OrderedMap<K, V>, key: K, value: V): option::Option<V>
+
public fun upsert<K: drop, V>(self: &mut ordered_map::OrderedMap<K, V>, key: K, value: V): option::Option<V>
 
@@ -422,10 +422,10 @@ Otherwise, updates the value under the given key, and returns the old value. key: _, value: old_value, } = self.entries.replace(index, Entry { key, value }); - option::some(old_value) + option::some(old_value) } else { self.entries.insert(index, Entry { key, value }); - option::none() + option::none() } }
@@ -454,9 +454,9 @@ Aborts with EKEY_NOT_FOUND if key doesn't exist.
public fun remove<K: drop, V>(self: &mut OrderedMap<K, V>, key: &K): V {
     let len = self.entries.length();
     let index = binary_search(key, &self.entries, 0, len);
-    assert!(index < len, error::invalid_argument(EKEY_NOT_FOUND));
+    assert!(index < len, error::invalid_argument(EKEY_NOT_FOUND));
     let Entry { key: old_key, value } = self.entries.remove(index);
-    assert!(key == &old_key, error::invalid_argument(EKEY_NOT_FOUND));
+    assert!(key == &old_key, error::invalid_argument(EKEY_NOT_FOUND));
     value
 }
 
@@ -559,17 +559,17 @@ Aborts with ENEW_KEY_NOT_IN_ORDER if new_key doesn't keep the order
public(friend) fun replace_key_inplace<K: drop, V>(self: &mut OrderedMap<K, V>, old_key: &K, new_key: K) {
     let len = self.entries.length();
     let index = binary_search(old_key, &self.entries, 0, len);
-    assert!(index < len, error::invalid_argument(EKEY_NOT_FOUND));
+    assert!(index < len, error::invalid_argument(EKEY_NOT_FOUND));
 
-    assert!(old_key == &self.entries[index].key, error::invalid_argument(EKEY_NOT_FOUND));
+    assert!(old_key == &self.entries[index].key, error::invalid_argument(EKEY_NOT_FOUND));
 
     // check that after we update the key, order is going to be respected
     if (index > 0) {
-        assert!(cmp::compare(&self.entries[index - 1].key, &new_key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
+        assert!(cmp::compare(&self.entries[index - 1].key, &new_key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
     };
 
     if (index + 1 < len) {
-        assert!(cmp::compare(&new_key, &self.entries[index + 1].key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
+        assert!(cmp::compare(&new_key, &self.entries[index + 1].key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
     };
 
     self.entries[index].key = new_key;
@@ -588,7 +588,7 @@ Add multiple key/value pairs to the map. The keys must not already exist.
 Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are passed in.
 
 
-
public fun add_all<K, V>(self: &mut ordered_map::OrderedMap<K, V>, keys: vector<K>, values: vector<V>)
+
public fun add_all<K, V>(self: &mut ordered_map::OrderedMap<K, V>, keys: vector<K>, values: vector<V>)
 
@@ -597,9 +597,9 @@ Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are pass Implementation -
public fun add_all<K, V>(self: &mut OrderedMap<K, V>, keys: vector<K>, values: vector<V>) {
+
public fun add_all<K, V>(self: &mut OrderedMap<K, V>, keys: vector<K>, values: vector<V>) {
     // TODO: Can be optimized, by sorting keys and values, and then creating map.
-    vector::zip(keys, values, |key, value| {
+    vector::zip(keys, values, |key, value| {
         self.add(key, value);
     });
 }
@@ -617,7 +617,7 @@ Add multiple key/value pairs to the map, overwrites values if they exist already
 or if duplicate keys are passed in.
 
 
-
public fun upsert_all<K: drop, V: drop>(self: &mut ordered_map::OrderedMap<K, V>, keys: vector<K>, values: vector<V>)
+
public fun upsert_all<K: drop, V: drop>(self: &mut ordered_map::OrderedMap<K, V>, keys: vector<K>, values: vector<V>)
 
@@ -626,9 +626,9 @@ or if duplicate keys are passed in. Implementation -
public fun upsert_all<K: drop, V: drop>(self: &mut OrderedMap<K, V>, keys: vector<K>, values: vector<V>) {
+
public fun upsert_all<K: drop, V: drop>(self: &mut OrderedMap<K, V>, keys: vector<K>, values: vector<V>) {
     // TODO: Can be optimized, by sorting keys and values, and then creating map.
-    vector::zip(keys, values, |key, value| {
+    vector::zip(keys, values, |key, value| {
         self.upsert(key, value);
     });
 }
@@ -683,7 +683,7 @@ Aborts with EKEY_ALREADY_EXISTS if other has a key already present
 
 
public fun append_disjoint<K, V>(self: &mut OrderedMap<K, V>, other: OrderedMap<K, V>) {
     let overwritten = self.append_impl(other);
-    assert!(overwritten.length() == 0, error::invalid_argument(EKEY_ALREADY_EXISTS));
+    assert!(overwritten.length() == 0, error::invalid_argument(EKEY_ALREADY_EXISTS));
     overwritten.destroy_empty();
 }
 
@@ -699,7 +699,7 @@ Aborts with EKEY_ALREADY_EXISTS if other has a key already present Takes all elements from other and adds them to self, returning list of entries in self that were overwritten. -
fun append_impl<K, V>(self: &mut ordered_map::OrderedMap<K, V>, other: ordered_map::OrderedMap<K, V>): vector<ordered_map::Entry<K, V>>
+
fun append_impl<K, V>(self: &mut ordered_map::OrderedMap<K, V>, other: ordered_map::OrderedMap<K, V>): vector<ordered_map::Entry<K, V>>
 
@@ -708,11 +708,11 @@ Takes all elements from other and adds them to self, r Implementation -
fun append_impl<K, V>(self: &mut OrderedMap<K, V>, other: OrderedMap<K, V>): vector<Entry<K,V>> {
+
fun append_impl<K, V>(self: &mut OrderedMap<K, V>, other: OrderedMap<K, V>): vector<Entry<K,V>> {
     let OrderedMap::SortedVectorMap {
         entries: other_entries,
     } = other;
-    let overwritten = vector::empty();
+    let overwritten = vector::empty();
 
     if (other_entries.is_empty()) {
         other_entries.destroy_empty();
@@ -725,25 +725,25 @@ Takes all elements from other and adds them to self, r
     };
 
     // Optimization: if all elements in `other` are larger than all elements in `self`, we can just move them over.
-    if (cmp::compare(&self.entries.borrow(self.entries.length() - 1).key, &other_entries.borrow(0).key).is_lt()) {
+    if (cmp::compare(&self.entries.borrow(self.entries.length() - 1).key, &other_entries.borrow(0).key).is_lt()) {
         self.entries.append(other_entries);
         return overwritten;
     };
 
     // In O(n), traversing from the back, build reverse sorted result, and then reverse it back
-    let reverse_result = vector::empty();
+    let reverse_result = vector::empty();
     let cur_i = self.entries.length() - 1;
     let other_i = other_entries.length() - 1;
 
-    // after the end of the loop, other_entries is empty, and any leftover is in entries
+    // after the end of the loop, other_entries is empty, and any leftover is in entries
     loop {
-        let ord = cmp::compare(&self.entries[cur_i].key, &other_entries[other_i].key);
+        let ord = cmp::compare(&self.entries[cur_i].key, &other_entries[other_i].key);
         if (ord.is_gt()) {
             reverse_result.push_back(self.entries.pop_back());
             if (cur_i == 0) {
                 // make other_entries empty, and rest in entries.
-                // TODO cannot use mem::swap until it is public/released
-                // mem::swap(&mut self.entries, &mut other_entries);
+                // TODO cannot use mem::swap until it is public/released
+                // mem::swap(&mut self.entries, &mut other_entries);
                 self.entries.append(other_entries);
                 break;
             } else {
@@ -946,7 +946,7 @@ Note: Requires that the map is not changed after the input iterator is generated
 
 
 
public(friend) fun iter_next<K, V>(self: IteratorPtr, map: &OrderedMap<K, V>): IteratorPtr {
-    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
     let index = self.index + 1;
     if (index < map.entries.length()) {
@@ -979,7 +979,7 @@ Note: Requires that the map is not changed after the input iterator is generated
 
 
 
public(friend) fun iter_prev<K, V>(self: IteratorPtr, map: &OrderedMap<K, V>): IteratorPtr {
-    assert!(!self.iter_is_begin(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!self.iter_is_begin(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
     let index = if (self is IteratorPtr::End) {
         map.entries.length() - 1
@@ -1099,7 +1099,7 @@ Note: Requires that the map is not changed after the input iterator is generated
 
 
 
public(friend) fun iter_borrow_key<K, V>(self: &IteratorPtr, map: &OrderedMap<K, V>): &K {
-    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
     &map.entries.borrow(self.index).key
 }
@@ -1128,7 +1128,7 @@ Note: Requires that the map is not changed after the input iterator is generated
 
 
 
public(friend) fun iter_borrow<K, V>(self: IteratorPtr, map: &OrderedMap<K, V>): &V {
-    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     &map.entries.borrow(self.index).value
 }
 
@@ -1156,7 +1156,7 @@ Note: Requires that the map is not changed after the input iterator is generated
public(friend) fun iter_borrow_mut<K, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>): &mut V {
-    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     &mut map.entries.borrow_mut(self.index).value
 }
 
@@ -1184,7 +1184,7 @@ Note: Requires that the map is not changed after the input iterator is generated
public(friend) fun iter_remove<K: drop, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>): V {
-    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
     let Entry { key: _, value } = map.entries.remove(self.index);
     value
@@ -1214,11 +1214,11 @@ Note: Requires that the map is not changed after the input iterator is generated
 
 
 
public(friend) fun iter_replace<K: copy + drop, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>, value: V): V {
-    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
 
-    // TODO once mem::replace is public/released, update to:
+    // TODO once mem::replace is public/released, update to:
     // let entry = map.entries.borrow_mut(self.index);
-    // mem::replace(&mut entry.value, value)
+    // mem::replace(&mut entry.value, value)
     let key = map.entries[self.index].key;
     let Entry {
         key: _,
@@ -1259,11 +1259,11 @@ or smaller than the key at the iterator position.
     };
 
     if (insert_index > 0) {
-        assert!(cmp::compare(&map.entries[insert_index - 1].key, &key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
+        assert!(cmp::compare(&map.entries[insert_index - 1].key, &key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
     };
 
     if (insert_index < len) {
-        assert!(cmp::compare(&key, &map.entries[insert_index].key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
+        assert!(cmp::compare(&key, &map.entries[insert_index].key).is_lt(), error::invalid_argument(ENEW_KEY_NOT_IN_ORDER))
     };
 
     map.entries.insert(insert_index, Entry { key, value });
@@ -1309,7 +1309,7 @@ Aborts if self is not empty.
 Return all keys in the map. This requires keys to be copyable.
 
 
-
public fun keys<K: copy, V>(self: &ordered_map::OrderedMap<K, V>): vector<K>
+
public fun keys<K: copy, V>(self: &ordered_map::OrderedMap<K, V>): vector<K>
 
@@ -1318,8 +1318,8 @@ Return all keys in the map. This requires keys to be copyable. Implementation -
public fun keys<K: copy, V>(self: &OrderedMap<K, V>): vector<K> {
-    vector::map_ref(&self.entries, |e| {
+
public fun keys<K: copy, V>(self: &OrderedMap<K, V>): vector<K> {
+    vector::map_ref(&self.entries, |e| {
         let e: &Entry<K, V> = e;
         e.key
     })
@@ -1337,7 +1337,7 @@ Return all keys in the map. This requires keys to be copyable.
 Return all values in the map. This requires values to be copyable.
 
 
-
public fun values<K, V: copy>(self: &ordered_map::OrderedMap<K, V>): vector<V>
+
public fun values<K, V: copy>(self: &ordered_map::OrderedMap<K, V>): vector<V>
 
@@ -1346,8 +1346,8 @@ Return all values in the map. This requires values to be copyable. Implementation -
public fun values<K, V: copy>(self: &OrderedMap<K, V>): vector<V> {
-    vector::map_ref(&self.entries, |e| {
+
public fun values<K, V: copy>(self: &OrderedMap<K, V>): vector<V> {
+    vector::map_ref(&self.entries, |e| {
         let e: &Entry<K, V> = e;
         e.value
     })
@@ -1366,7 +1366,7 @@ Transform the map into two vectors with the keys and values respectively
 Primarily used to destroy a map
 
 
-
public fun to_vec_pair<K, V>(self: ordered_map::OrderedMap<K, V>): (vector<K>, vector<V>)
+
public fun to_vec_pair<K, V>(self: ordered_map::OrderedMap<K, V>): (vector<K>, vector<V>)
 
@@ -1375,14 +1375,14 @@ Primarily used to destroy a map Implementation -
public fun to_vec_pair<K, V>(self: OrderedMap<K, V>): (vector<K>, vector<V>) {
-    let keys: vector<K> = vector::empty();
-    let values: vector<V> = vector::empty();
+
public fun to_vec_pair<K, V>(self: OrderedMap<K, V>): (vector<K>, vector<V>) {
+    let keys: vector<K> = vector::empty();
+    let values: vector<V> = vector::empty();
     let OrderedMap::SortedVectorMap { entries } = self;
-    vector::for_each(entries, |e| {
+    vector::for_each(entries, |e| {
         let Entry { key, value } = e;
-        vector::push_back(&mut keys, key);
-        vector::push_back(&mut values, value);
+        vector::push_back(&mut keys, key);
+        vector::push_back(&mut values, value);
     });
     (keys, values)
 }
@@ -1415,8 +1415,8 @@ using lambdas to destroy the individual keys and values.
     dv: |V|
 ) {
     let (keys, values) = to_vec_pair(self);
-    vector::destroy(keys, |_k| dk(_k));
-    vector::destroy(values, |_v| dv(_v));
+    vector::destroy(keys, |_k| dk(_k));
+    vector::destroy(values, |_v| dv(_v));
 }
 
@@ -1447,7 +1447,7 @@ Apply the function to a reference of each key-value pair in the table. iter = iter.iter_next(self); } // TODO: once move supports private functions udpate to: - // vector::for_each_ref( + // vector::for_each_ref( // &self.entries, // |entry| { // f(&entry.key, &entry.value) @@ -1484,7 +1484,7 @@ Apply the function to a mutable reference of each key-value pair in the table. iter = iter.iter_next(self); } // TODO: once move supports private functions udpate to: - // vector::for_each_mut( + // vector::for_each_mut( // &mut self.entries, // |entry| { // f(&mut entry.key, &mut entry.value) @@ -1529,7 +1529,7 @@ Apply the function to a mutable reference of each key-value pair in the table. -
fun binary_search<K, V>(key: &K, entries: &vector<ordered_map::Entry<K, V>>, start: u64, end: u64): u64
+
fun binary_search<K, V>(key: &K, entries: &vector<ordered_map::Entry<K, V>>, start: u64, end: u64): u64
 
@@ -1538,12 +1538,12 @@ Apply the function to a mutable reference of each key-value pair in the table. Implementation -
fun binary_search<K, V>(key: &K, entries: &vector<Entry<K, V>>, start: u64, end: u64): u64 {
+
fun binary_search<K, V>(key: &K, entries: &vector<Entry<K, V>>, start: u64, end: u64): u64 {
     let l = start;
     let r = end;
     while (l != r) {
         let mid = l + ((r - l) >> 1);
-        let comparison = cmp::compare(&entries.borrow(mid).key, key);
+        let comparison = cmp::compare(&entries.borrow(mid).key, key);
         if (comparison.is_lt()) {
             l = mid + 1;
         } else {
diff --git a/aptos-move/framework/aptos-framework/doc/overview.md b/aptos-move/framework/aptos-framework/doc/overview.md
index 314baa3612ba9..5c29bce73724d 100644
--- a/aptos-move/framework/aptos-framework/doc/overview.md
+++ b/aptos-move/framework/aptos-framework/doc/overview.md
@@ -19,6 +19,7 @@ This is the reference documentation of the Aptos framework.
 -  [`0x1::aptos_account`](aptos_account.md#0x1_aptos_account)
 -  [`0x1::aptos_coin`](aptos_coin.md#0x1_aptos_coin)
 -  [`0x1::aptos_governance`](aptos_governance.md#0x1_aptos_governance)
+-  [`0x1::big_ordered_map`](big_ordered_map.md#0x1_big_ordered_map)
 -  [`0x1::block`](block.md#0x1_block)
 -  [`0x1::chain_id`](chain_id.md#0x1_chain_id)
 -  [`0x1::chain_status`](chain_status.md#0x1_chain_status)
@@ -46,6 +47,7 @@ This is the reference documentation of the Aptos framework.
 -  [`0x1::object`](object.md#0x1_object)
 -  [`0x1::object_code_deployment`](object_code_deployment.md#0x1_object_code_deployment)
 -  [`0x1::optional_aggregator`](optional_aggregator.md#0x1_optional_aggregator)
+-  [`0x1::ordered_map`](ordered_map.md#0x1_ordered_map)
 -  [`0x1::primary_fungible_store`](primary_fungible_store.md#0x1_primary_fungible_store)
 -  [`0x1::randomness`](randomness.md#0x1_randomness)
 -  [`0x1::randomness_api_v0_config`](randomness_api_v0_config.md#0x1_randomness_api_v0_config)
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move b/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.move
similarity index 95%
rename from aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move
rename to aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.move
index 13db9c30033fd..f2b51c191dc42 100644
--- a/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move
+++ b/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.move
@@ -201,7 +201,7 @@ module aptos_std::big_ordered_map {
         root.destroy_empty_node();
         // If root node is empty, then we know that no storage slots are used,
         // and so we can safely destroy all nodes.
-        nodes.destroy_known_empty_unsafe();
+        nodes.destroy_empty();
     }
 
     // ======================= Section with Modifiers =========================
@@ -310,7 +310,13 @@ module aptos_std::big_ordered_map {
     public fun borrow(self: &BigOrderedMap, key: &K): &V {
         let iter = self.find(key);
         assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
-        iter.iter_borrow(self)
+
+        // TODO cannot call iter_borrow, because reference checks assume return has reference to iter that is being destroyed
+        // iter.iter_borrow(self)
+
+        assert!(!iter.iter_is_end(self), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+        let children = &self.borrow_node(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.
@@ -365,7 +371,7 @@ module aptos_std::big_ordered_map {
     /// Borrows the value given iterator points to.
     /// Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end.
     /// Note: Requires that the map is not changed after the input iterator is generated.
-    public(friend) fun iter_borrow(self: IteratorPtr, map: &BigOrderedMap): &V {
+    public(friend) fun iter_borrow(self: &IteratorPtr, map: &BigOrderedMap): &V {
         assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
         let children = &map.borrow_node(self.node_index).children;
         &self.child_iter.iter_borrow(children).value
@@ -376,7 +382,7 @@ module aptos_std::big_ordered_map {
     /// Aborts with EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE if KV size doesn't have constant size,
     /// because if it doesn't - we need to call `upsert` to be able to check size invariants after modification.
     /// Note: Requires that the map is not changed after the input iterator is generated.
-    public(friend) fun iter_borrow_mut(self: IteratorPtr, map: &mut BigOrderedMap): &mut V {
+    public(friend) fun iter_borrow_mut(self: &IteratorPtr, map: &mut BigOrderedMap): &mut V {
         assert!(map.constant_kv_size, error::invalid_argument(EBORROW_MUT_REQUIRES_CONSTANT_KV_SIZE));
         assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
         let children = &mut map.borrow_node_mut(self.node_index).children;
@@ -443,6 +449,36 @@ module aptos_std::big_ordered_map {
         new_iter(prev_index, child_iter, iter_key)
     }
 
+    /// Apply the function to each element in the vector, consuming it.
+    public(friend) inline fun for_each(self: BigOrderedMap, f: |K, V|) {
+        // TODO - this can be done more efficiently, by destroying the leaves directly
+        // but that requires more complicated code and testing.
+        let it = self.new_begin_iter();
+        while (!it.iter_is_end(&self)) {
+            let k = *it.iter_borrow_key();
+            let v = self.remove(&k);
+            f(k, v);
+            it = self.new_begin_iter();
+        };
+        destroy_empty(self)
+    }
+
+    /// Apply the function to a reference of each element in the vector.
+    public(friend) inline fun for_each_ref(self: &BigOrderedMap, f: |&K, &V|) {
+        let it = self.new_begin_iter();
+        while (!it.iter_is_end(self)) {
+            f(it.iter_borrow_key(), it.iter_borrow(self));
+            it = it.iter_next(self);
+        };
+    }
+
+    /// Destroy a map, by destroying elements individually.
+    public(friend) inline fun destroy(self: BigOrderedMap, dv: |V|) {
+        for_each(self, |_k, v| {
+            dv(v);
+        });
+    }
+
     // ====================== Internal Implementations ========================
 
     /// Borrow a node, given an index. Works for both root (i.e. inline) node and separately stored nodes
@@ -1118,7 +1154,7 @@ module aptos_std::big_ordered_map {
     }
 
     #[test_only]
-    fun destroy(self: BigOrderedMap) {
+    fun destroy_and_validate(self: BigOrderedMap) {
         let it = new_begin_iter(&self);
         while (!it.iter_is_end(&self)) {
             remove(&mut self, it.iter_borrow_key());
@@ -1213,9 +1249,19 @@ module aptos_std::big_ordered_map {
         add(&mut map, 5, 5); map.print_map(); map.validate_map();
         add(&mut map, 6, 6); map.print_map(); map.validate_map();
 
-        vector::zip(vector[1, 2, 3, 4, 5, 6], vector[1, 2, 3, 8, 5, 6], |key, value| {
-            assert!(map.borrow(&key) == &value, key + 100);
-            assert!(map.borrow_mut(&key) == &value, key + 200);
+        let expected_keys = vector[1, 2, 3, 4, 5, 6];
+        let expected_values = vector[1, 2, 3, 8, 5, 6];
+
+        let index = 0;
+        map.for_each_ref(|k, v| {
+            assert!(k == expected_keys.borrow(index), *k + 100);
+            assert!(v == expected_values.borrow(index), *k + 200);
+            index += 1;
+        });
+
+        vector::zip(expected_keys, expected_values, |key, value| {
+            assert!(map.borrow(&key) == &value, key + 300);
+            assert!(map.borrow_mut(&key) == &value, key + 400);
         });
 
         remove(&mut map, &5); map.print_map(); map.validate_map();
@@ -1228,6 +1274,20 @@ module aptos_std::big_ordered_map {
         destroy_empty(map);
     }
 
+    #[test]
+    fun test_for_each() {
+        let map = new_with_config(4, 3, false, 0);
+        map.add_all(vector[1, 3, 6, 2, 9, 5, 7, 4, 8], vector[1, 3, 6, 2, 9, 5, 7, 4, 8]);
+
+        let expected = vector[1, 2, 3, 4, 5, 6, 7, 8, 9];
+        let index = 0;
+        map.for_each(|k, v| {
+            assert!(k == expected[index], k + 100);
+            assert!(v == expected[index], k + 200);
+            index += 1;
+        });
+    }
+
     #[test]
     fun test_variable_size() {
         let map = new_with_config, vector>(0, 0, false, 0);
@@ -1323,7 +1383,7 @@ module aptos_std::big_ordered_map {
             it = it.iter_next(&map);
         };
 
-        destroy(map);
+        map.destroy(|_v| {});
     }
 
     #[test]
@@ -1345,7 +1405,7 @@ module aptos_std::big_ordered_map {
         assert!(find(&map, &4).iter_is_end(&map), 0);
         assert!(find(&map, &9).iter_is_end(&map), 1);
 
-        destroy(map);
+        map.destroy(|_v| {});
     }
 
     #[test]
@@ -1375,7 +1435,7 @@ module aptos_std::big_ordered_map {
         assert!(lower_bound(&map, &3).key == 6, 5);
         assert!(lower_bound(&map, &4).key == 6, 6);
 
-        map.destroy();
+        map.destroy(|_v| {});
     }
 
     #[test]
@@ -1389,28 +1449,28 @@ module aptos_std::big_ordered_map {
         let missing = vector[0, 2, 4, 6, 8, 10];
         missing.for_each_ref(|i| assert!(!map.contains(i), *i));
 
-        map.destroy();
+        map.destroy(|_v| {});
     }
 
     #[test]
     #[expected_failure(abort_code = 0x1000B, location = Self)] /// EINVALID_CONFIG_PARAMETER
     fun test_inner_max_degree_too_large() {
         let map = new_with_config(4097, 0, false, 0);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
     #[expected_failure(abort_code = 0x1000B, location = Self)] /// EINVALID_CONFIG_PARAMETER
     fun test_inner_max_degree_too_small() {
         let map = new_with_config(3, 0, false, 0);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
     #[expected_failure(abort_code = 0x1000B, location = Self)] /// EINVALID_CONFIG_PARAMETER
     fun test_leaf_max_degree_too_small() {
         let map = new_with_config(0, 2, false, 0);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1418,7 +1478,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_add_existing_value() {
         let map = new_from(vector[1], vector[1]);
         map.add(1, 2);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test_only]
@@ -1436,7 +1496,7 @@ module aptos_std::big_ordered_map {
         let map = new_with_config(4, 4, false, 0);
         map.add_all(vector_range(1, 10), vector_range(1, 10));
         map.add(3, 3);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1444,7 +1504,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_remove_missing_value() {
         let map = new_from(vector[1], vector[1]);
         map.remove(&2);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1454,7 +1514,7 @@ module aptos_std::big_ordered_map {
         map.add_all(vector_range(1, 10), vector_range(1, 10));
         map.remove(&4);
         map.remove(&4);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1463,7 +1523,7 @@ module aptos_std::big_ordered_map {
         let map = new_with_config(4, 4, false, 0);
         map.add_all(vector_range(1, 10), vector_range(1, 10));
         map.remove(&11);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1471,7 +1531,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_borrow_missing() {
         let map = new_from(vector[1], vector[1]);
         map.borrow(&2);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1479,7 +1539,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_borrow_mut_missing() {
         let map = new_from(vector[1], vector[1]);
         map.borrow_mut(&2);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1488,7 +1548,7 @@ module aptos_std::big_ordered_map {
         let map = new_with_config(0, 0, false, 0);
         map.add(1, vector[1]);
         map.borrow_mut(&1);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1496,7 +1556,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_iter_borrow_key_missing() {
         let map = new_from(vector[1], vector[1]);
         map.new_end_iter().iter_borrow_key();
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1504,7 +1564,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_iter_borrow_missing() {
         let map = new_from(vector[1], vector[1]);
         map.new_end_iter().iter_borrow(&map);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1512,7 +1572,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_iter_borrow_mut_missing() {
         let map = new_from(vector[1], vector[1]);
         map.new_end_iter().iter_borrow_mut(&mut map);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1521,7 +1581,7 @@ module aptos_std::big_ordered_map {
         let map = new_with_config(0, 0, false, 0);
         map.add(1, vector[1]);
         map.new_begin_iter().iter_borrow_mut(&mut map);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1529,7 +1589,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_end_iter_next() {
         let map = new_from(vector[1, 2, 3], vector[1, 2, 3]);
         map.new_end_iter().iter_next(&map);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1537,7 +1597,7 @@ module aptos_std::big_ordered_map {
     fun test_abort_begin_iter_prev() {
         let map = new_from(vector[1, 2, 3], vector[1, 2, 3]);
         map.new_begin_iter().iter_prev(&map);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1553,7 +1613,7 @@ module aptos_std::big_ordered_map {
         let map = new_with_config(0, 0, false, 0);
         map.add(vector[1], 1);
         map.add(vector_range(0, 57), 1);
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test]
@@ -1562,7 +1622,7 @@ module aptos_std::big_ordered_map {
         let map = new_with_config(0, 0, false, 0);
         map.add(1, vector[1]);
         map.add(2, vector_range(0, 107));
-        map.destroy();
+        map.destroy_and_validate();
     }
 
     #[test_only]
@@ -1595,7 +1655,7 @@ module aptos_std::big_ordered_map {
                 };
             };
         };
-        big_map.destroy();
+        big_map.destroy_and_validate();
     }
 
     #[test_only]
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/ordered_map.move b/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.move
similarity index 100%
rename from aptos-move/framework/aptos-stdlib/sources/data_structures/ordered_map.move
rename to aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.move
diff --git a/aptos-move/framework/aptos-stdlib/doc/fixed_point64.md b/aptos-move/framework/aptos-stdlib/doc/fixed_point64.md
index c9d35f6de494e..d13fba14f020f 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
 
 
 
-
+
 
-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;
 
- + -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;
 
diff --git a/aptos-move/framework/aptos-stdlib/doc/overview.md b/aptos-move/framework/aptos-stdlib/doc/overview.md index fa811e7bef51d..d65ef15f6a8c8 100644 --- a/aptos-move/framework/aptos-stdlib/doc/overview.md +++ b/aptos-move/framework/aptos-stdlib/doc/overview.md @@ -14,7 +14,6 @@ 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) @@ -32,7 +31,6 @@ This is the reference documentation of the Aptos standard library. - [`0x1::math_fixed`](math_fixed.md#0x1_math_fixed) - [`0x1::math_fixed64`](math_fixed64.md#0x1_math_fixed64) - [`0x1::multi_ed25519`](multi_ed25519.md#0x1_multi_ed25519) -- [`0x1::ordered_map`](ordered_map.md#0x1_ordered_map) - [`0x1::pool_u64`](pool_u64.md#0x1_pool_u64) - [`0x1::pool_u64_unbound`](pool_u64_unbound.md#0x1_pool_u64_unbound) - [`0x1::ristretto255`](ristretto255.md#0x1_ristretto255) diff --git a/aptos-move/framework/aptos-stdlib/doc/simple_map.md b/aptos-move/framework/aptos-stdlib/doc/simple_map.md index a79e7e4cec288..62eabb8dffa60 100644 --- a/aptos-move/framework/aptos-stdlib/doc/simple_map.md +++ b/aptos-move/framework/aptos-stdlib/doc/simple_map.md @@ -11,7 +11,7 @@ This module provides a solution for unsorted maps, that is it has the properties 5) Adds and removals take O(N) time DEPRECATED: since it's implementation is inneficient, it -has been deprecated in favor of ordered_map.move. +has been deprecated in favor of ordered_map.move. - [Struct `SimpleMap`](#0x1_simple_map_SimpleMap) @@ -66,7 +66,7 @@ has been deprecated in favor of o ## Struct `SimpleMap` DEPRECATED: since it's implementation is inneficient, it -has been deprecated in favor of ordered_map.move. +has been deprecated in favor of ordered_map.move.
struct SimpleMap<Key, Value> has copy, drop, store
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 dc8def915b4d1..c421dfe6cf7d7 100644
--- a/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md
+++ b/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md
@@ -33,7 +33,7 @@ for example:
 -  [Function `new_config`](#0x1_storage_slots_allocator_new_config)
 -  [Function `add`](#0x1_storage_slots_allocator_add)
 -  [Function `remove`](#0x1_storage_slots_allocator_remove)
--  [Function `destroy_known_empty_unsafe`](#0x1_storage_slots_allocator_destroy_known_empty_unsafe)
+-  [Function `destroy_empty`](#0x1_storage_slots_allocator_destroy_empty)
 -  [Function `borrow`](#0x1_storage_slots_allocator_borrow)
 -  [Function `borrow_mut`](#0x1_storage_slots_allocator_borrow_mut)
 -  [Function `reserve_slot`](#0x1_storage_slots_allocator_reserve_slot)
@@ -53,7 +53,7 @@ for example:
 
 
 
use 0x1::option;
-use 0x1::table;
+use 0x1::table_with_length;
 
@@ -190,7 +190,7 @@ Data stored in an individual slot
-slots: option::Option<table::Table<u64, storage_slots_allocator::Link<T>>> +slots: option::Option<table_with_length::TableWithLength<u64, storage_slots_allocator::Link<T>>>
@@ -472,15 +472,13 @@ and there is unique owner for each slot. - + -## Function `destroy_known_empty_unsafe` +## Function `destroy_empty` -We cannot know if allocator is empty or not, so this method is not public, -and can be used only in modules that know by themselves that allocator is empty. -
public(friend) fun destroy_known_empty_unsafe<T: store>(self: storage_slots_allocator::StorageSlotsAllocator<T>)
+
public fun destroy_empty<T: store>(self: storage_slots_allocator::StorageSlotsAllocator<T>)
 
@@ -489,7 +487,7 @@ and can be used only in modules that know by themselves that allocator is empty. Implementation -
public(friend) fun destroy_known_empty_unsafe<T: store>(self: StorageSlotsAllocator<T>) {
+
public fun destroy_empty<T: store>(self: StorageSlotsAllocator<T>) {
     loop {
         let reuse_index = self.maybe_pop_from_reuse_queue();
         if (reuse_index == NULL_INDEX) {
@@ -506,7 +504,7 @@ and can be used only in modules that know by themselves that allocator is empty.
         } => {
             assert!(reuse_head_index == NULL_INDEX, EINTERNAL_INVARIANT_BROKEN);
             if (slots.is_some()) {
-                slots.destroy_some().destroy_known_empty_unsafe();
+                slots.destroy_some().destroy_empty();
             } else {
                 slots.destroy_none();
             }
@@ -851,7 +849,7 @@ Remove storage slot, but reserve it for later.
     let slot_index = self.new_slot_index;
     self.new_slot_index = self.new_slot_index + 1;
     if (self.slots.is_none()) {
-        self.slots.fill(table::new<u64, Link<T>>());
+        self.slots.fill(table_with_length::new<u64, Link<T>>());
     };
     slot_index
 }
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 a58c59bdb78c9..c608052582fa6 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
@@ -16,9 +16,7 @@
 /// * inlining some nodes
 /// * having a fee-payer for any storage creation operations
 module aptos_std::storage_slots_allocator {
-    friend aptos_std::big_ordered_map;
-
-    use aptos_std::table::{Self, Table};
+    use aptos_std::table_with_length::{Self, TableWithLength};
     use std::option::{Self, Option};
 
     const EINVALID_ARGUMENT: u64 = 1;
@@ -48,8 +46,11 @@ module aptos_std::storage_slots_allocator {
     }
 
     enum StorageSlotsAllocator has store {
+        // V1 is sequential - any two operations on the StorageSlotsAllocator will conflict.
+        // In general, StorageSlotsAllocator is invoked on less frequent operations, so
+        // that shouldn't be a big issue.
         V1 {
-            slots: Option>>, // Lazily create slots table only when needed
+            slots: Option>>, // Lazily create slots table only when needed
             new_slot_index: u64,
             should_reuse: bool,
             reuse_head_index: u64,
@@ -114,9 +115,7 @@ module aptos_std::storage_slots_allocator {
         value
     }
 
-    /// We cannot know if allocator is empty or not, so this method is not public,
-    /// and can be used only in modules that know by themselves that allocator is empty.
-    public(friend) fun destroy_known_empty_unsafe(self: StorageSlotsAllocator) {
+    public fun destroy_empty(self: StorageSlotsAllocator) {
         loop {
             let reuse_index = self.maybe_pop_from_reuse_queue();
             if (reuse_index == NULL_INDEX) {
@@ -133,7 +132,7 @@ module aptos_std::storage_slots_allocator {
             } => {
                 assert!(reuse_head_index == NULL_INDEX, EINTERNAL_INVARIANT_BROKEN);
                 if (slots.is_some()) {
-                    slots.destroy_some().destroy_known_empty_unsafe();
+                    slots.destroy_some().destroy_empty();
                 } else {
                     slots.destroy_none();
                 }
@@ -227,7 +226,7 @@ module aptos_std::storage_slots_allocator {
         let slot_index = self.new_slot_index;
         self.new_slot_index = self.new_slot_index + 1;
         if (self.slots.is_none()) {
-            self.slots.fill(table::new>());
+            self.slots.fill(table_with_length::new>());
         };
         slot_index
     }
diff --git a/crates/transaction-workloads-lib/src/raw_module_data.rs b/crates/transaction-workloads-lib/src/raw_module_data.rs
index a8d7050aac7ac..74ff166b26866 100644
--- a/crates/transaction-workloads-lib/src/raw_module_data.rs
+++ b/crates/transaction-workloads-lib/src/raw_module_data.rs
@@ -1744,24 +1744,26 @@ pub static MODULES_COMPLEX: Lazy>> = Lazy::new(|| { vec![
 pub static PACKAGE_AMBASSADOR_TOKEN_METADATA: Lazy> = Lazy::new(|| {
 	vec![
 		10, 97, 109, 98, 97, 115, 115, 97, 100, 111, 114, 1, 0, 0, 0, 0, 0, 0,
-		0, 0, 64, 68, 70, 50, 57, 50, 70, 53, 53, 56, 50, 66, 48, 57, 50, 65,
-		51, 54, 55, 65, 53, 69, 55, 69, 57, 65, 48, 48, 69, 66, 51, 68, 57, 52,
-		48, 55, 56, 67, 49, 54, 69, 65, 66, 65, 48, 50, 52, 69, 65, 65, 50, 52,
-		57, 52, 49, 55, 70, 54, 50, 51, 52, 53, 67, 50, 48, 253, 1, 31, 139, 8,
-		0, 0, 0, 0, 0, 2, 255, 173, 142, 63, 79, 195, 64, 12, 197, 247, 251, 20,
-		86, 24, 186, 144, 63, 172, 72, 12, 21, 162, 43, 11, 91, 84, 161, 203, 157, 155,
-		28, 73, 236, 232, 236, 20, 36, 196, 119, 231, 142, 22, 144, 16, 99, 55, 219, 239,
-		249, 253, 94, 187, 88, 55, 218, 30, 247, 134, 236, 140, 112, 7, 27, 59, 119, 86,
-		196, 122, 142, 27, 115, 196, 40, 129, 41, 159, 111, 170, 166, 106, 54, 198, 92, 129,
-		103, 32, 86, 112, 131, 165, 30, 65, 25, 138, 231, 226, 26, 28, 147, 139, 168, 8,
-		214, 251, 136, 34, 64, 136, 30, 61, 28, 56, 194, 204, 126, 157, 176, 92, 214, 110,
-		10, 50, 128, 162, 104, 160, 30, 14, 49, 33, 95, 57, 142, 166, 61, 63, 161, 236,
-		205, 47, 63, 97, 139, 230, 237, 126, 187, 123, 40, 140, 105, 61, 46, 72, 30, 201,
-		133, 236, 218, 46, 202, 178, 251, 14, 72, 206, 119, 232, 131, 230, 143, 65, 117, 145,
-		219, 186, 78, 235, 176, 118, 149, 227, 185, 182, 217, 92, 78, 182, 147, 243, 248, 67,
-		174, 146, 43, 149, 151, 181, 243, 225, 139, 247, 71, 79, 90, 196, 99, 22, 102, 27,
-		136, 80, 11, 248, 56, 177, 159, 120, 68, 122, 236, 94, 208, 169, 92, 26, 175, 57,
-		187, 228, 83, 248, 191, 21, 62, 1, 7, 30, 19, 174, 183, 1, 0, 0, 1, 10,
+		0, 0, 64, 70, 52, 52, 65, 66, 48, 70, 68, 68, 52, 52, 65, 48, 49, 48,
+		68, 68, 57, 67, 48, 54, 53, 52, 49, 66, 68, 53, 69, 70, 51, 49, 56, 70,
+		70, 68, 70, 70, 69, 69, 56, 70, 53, 57, 52, 68, 68, 52, 51, 53, 48, 68,
+		57, 69, 56, 67, 57, 67, 57, 48, 66, 56, 70, 66, 70, 161, 2, 31, 139, 8,
+		0, 0, 0, 0, 0, 2, 255, 173, 144, 63, 79, 195, 48, 16, 197, 119, 127, 138,
+		83, 58, 116, 33, 127, 88, 145, 24, 42, 68, 87, 22, 182, 168, 66, 142, 125, 77,
+		76, 98, 95, 228, 115, 2, 18, 226, 187, 99, 211, 54, 136, 210, 5, 169, 146, 7,
+		219, 239, 221, 251, 61, 187, 30, 165, 234, 101, 139, 59, 225, 164, 69, 184, 135, 181,
+		180, 141, 100, 150, 154, 252, 90, 204, 232, 217, 144, 75, 215, 183, 69, 85, 84, 107,
+		33, 86, 160, 9, 28, 5, 80, 157, 116, 45, 66, 32, 200, 94, 178, 27, 80, 228,
+		148, 199, 128, 32, 181, 246, 200, 12, 14, 81, 163, 134, 61, 121, 176, 164, 167, 1,
+		243, 113, 106, 6, 195, 29, 4, 228, 96, 92, 11, 123, 31, 145, 111, 228, 123, 81,
+		31, 135, 144, 119, 226, 135, 31, 177, 89, 245, 254, 176, 217, 62, 102, 66, 212, 26,
+		71, 116, 26, 157, 50, 201, 181, 130, 205, 24, 136, 183, 167, 136, 232, 253, 128, 214,
+		132, 52, 211, 133, 48, 242, 93, 89, 198, 99, 55, 53, 133, 34, 91, 202, 100, 206,
+		7, 217, 240, 113, 187, 176, 139, 232, 138, 245, 121, 106, 180, 249, 38, 158, 233, 81,
+		243, 56, 39, 193, 74, 227, 28, 134, 12, 62, 79, 244, 103, 234, 209, 61, 53, 175,
+		168, 2, 95, 187, 64, 72, 217, 57, 29, 194, 47, 150, 184, 240, 1, 3, 41, 57,
+		36, 91, 81, 148, 203, 58, 228, 89, 154, 177, 92, 160, 231, 37, 150, 188, 63, 79,
+		250, 111, 228, 239, 222, 49, 246, 11, 123, 181, 222, 205, 98, 2, 0, 0, 1, 10,
 		97, 109, 98, 97, 115, 115, 97, 100, 111, 114, 0, 0, 0, 4, 0, 0, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 14, 65, 112, 116, 111, 115, 70, 114,