diff --git a/aptos-move/framework/aptos-framework/doc/big_ordered_map.md b/aptos-move/framework/aptos-framework/doc/big_ordered_map.md index 5b430acaf6775..1f97dcba8e4c5 100644 --- a/aptos-move/framework/aptos-framework/doc/big_ordered_map.md +++ b/aptos-move/framework/aptos-framework/doc/big_ordered_map.md @@ -26,15 +26,21 @@ If you need larger, use other constructor methods. Based on initial configuration, BigOrderedMap will always accept insertion of keys and values up to the allowed size, and will abort with EKEY_BYTES_TOO_LARGE or EARGUMENT_BYTES_TOO_LARGE. -TODO: all iterator functions are public(friend) for now, so that they can be modified in a -backward incompatible way. Type is also named IteratorPtr, so that Iterator is free to use later. -They are waiting for Move improvement that will allow references to be part of the struct, +Warning: All iterator functions need to be carefully used, because they are just pointers into the +structure, and modification of the map invalidates them (without compiler being able to catch it). +Type is also named IteratorPtr, so that Iterator is free to use later. +Better guarantees would need future Move improvements that will allow references to be part of the struct, allowing cleaner iterator APIs. +That's why all functions returning iterators are prefixed with "internal_", to clarify nuances needed to make +sure usage is correct. +A set of inline utility methods is provided instead, to provide guaranteed valid usage to iterators. + - [Enum `Node`](#0x1_big_ordered_map_Node) - [Enum `Child`](#0x1_big_ordered_map_Child) - [Enum `IteratorPtr`](#0x1_big_ordered_map_IteratorPtr) +- [Struct `IteratorPtrWithPath`](#0x1_big_ordered_map_IteratorPtrWithPath) - [Enum `BigOrderedMap`](#0x1_big_ordered_map_BigOrderedMap) - [Constants](#@Constants_0) - [Function `new`](#0x1_big_ordered_map_new) @@ -49,11 +55,14 @@ allowing cleaner iterator APIs. - [Function `add`](#0x1_big_ordered_map_add) - [Function `upsert`](#0x1_big_ordered_map_upsert) - [Function `remove`](#0x1_big_ordered_map_remove) +- [Function `remove_or_none`](#0x1_big_ordered_map_remove_or_none) - [Function `add_all`](#0x1_big_ordered_map_add_all) - [Function `pop_front`](#0x1_big_ordered_map_pop_front) - [Function `pop_back`](#0x1_big_ordered_map_pop_back) -- [Function `lower_bound`](#0x1_big_ordered_map_lower_bound) -- [Function `find`](#0x1_big_ordered_map_find) +- [Function `internal_lower_bound`](#0x1_big_ordered_map_internal_lower_bound) +- [Function `internal_find`](#0x1_big_ordered_map_internal_find) +- [Function `internal_find_with_path`](#0x1_big_ordered_map_internal_find_with_path) +- [Function `iter_with_path_get_iter`](#0x1_big_ordered_map_iter_with_path_get_iter) - [Function `contains`](#0x1_big_ordered_map_contains) - [Function `borrow`](#0x1_big_ordered_map_borrow) - [Function `get`](#0x1_big_ordered_map_get) @@ -67,16 +76,16 @@ allowing cleaner iterator APIs. - [Function `for_each_and_clear`](#0x1_big_ordered_map_for_each_and_clear) - [Function `for_each`](#0x1_big_ordered_map_for_each) - [Function `for_each_ref`](#0x1_big_ordered_map_for_each_ref) -- [Function `for_each_ref_friend`](#0x1_big_ordered_map_for_each_ref_friend) - [Function `for_each_mut`](#0x1_big_ordered_map_for_each_mut) - [Function `destroy`](#0x1_big_ordered_map_destroy) -- [Function `new_begin_iter`](#0x1_big_ordered_map_new_begin_iter) -- [Function `new_end_iter`](#0x1_big_ordered_map_new_end_iter) +- [Function `internal_new_begin_iter`](#0x1_big_ordered_map_internal_new_begin_iter) +- [Function `internal_new_end_iter`](#0x1_big_ordered_map_internal_new_end_iter) - [Function `iter_is_begin`](#0x1_big_ordered_map_iter_is_begin) - [Function `iter_is_end`](#0x1_big_ordered_map_iter_is_end) - [Function `iter_borrow_key`](#0x1_big_ordered_map_iter_borrow_key) - [Function `iter_borrow`](#0x1_big_ordered_map_iter_borrow) - [Function `iter_borrow_mut`](#0x1_big_ordered_map_iter_borrow_mut) +- [Function `iter_remove`](#0x1_big_ordered_map_iter_remove) - [Function `iter_next`](#0x1_big_ordered_map_iter_next) - [Function `iter_prev`](#0x1_big_ordered_map_iter_prev) - [Function `for_each_leaf_node_ref`](#0x1_big_ordered_map_for_each_leaf_node_ref) @@ -117,8 +126,8 @@ allowing cleaner iterator APIs. - [Function `add_all`](#@Specification_1_add_all) - [Function `pop_front`](#@Specification_1_pop_front) - [Function `pop_back`](#@Specification_1_pop_back) - - [Function `lower_bound`](#@Specification_1_lower_bound) - - [Function `find`](#@Specification_1_find) + - [Function `internal_lower_bound`](#@Specification_1_internal_lower_bound) + - [Function `internal_find`](#@Specification_1_internal_find) - [Function `contains`](#@Specification_1_contains) - [Function `borrow`](#@Specification_1_borrow) - [Function `borrow_mut`](#@Specification_1_borrow_mut) @@ -127,8 +136,8 @@ allowing cleaner iterator APIs. - [Function `prev_key`](#@Specification_1_prev_key) - [Function `next_key`](#@Specification_1_next_key) - [Function `keys`](#@Specification_1_keys) - - [Function `new_begin_iter`](#@Specification_1_new_begin_iter) - - [Function `new_end_iter`](#@Specification_1_new_end_iter) + - [Function `internal_new_begin_iter`](#@Specification_1_internal_new_begin_iter) + - [Function `internal_new_end_iter`](#@Specification_1_internal_new_end_iter) - [Function `iter_is_begin`](#@Specification_1_iter_is_begin) - [Function `iter_is_end`](#@Specification_1_iter_is_end) - [Function `iter_borrow_key`](#@Specification_1_iter_borrow_key) @@ -349,6 +358,39 @@ TODO: Once fields can be (mutable) references, this class will be deprecated. + + + + +## Struct `IteratorPtrWithPath` + + + +
struct IteratorPtrWithPath<K> has copy, drop
+
+ + + +
+Fields + + +
+
+iterator: big_ordered_map::IteratorPtr<K> +
+
+ +
+
+path: vector<u64> +
+
+ +
+
+ +
@@ -1048,6 +1090,56 @@ Aborts if there is no entry for key. + + + + +## Function `remove_or_none` + +Removes the entry from BigOrderedMap and returns the value which key maps to. +Returns none if there is no entry for key. + + +
public fun remove_or_none<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: &K): option::Option<V>
+
+ + + +
+Implementation + + +
public fun remove_or_none<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: &K): Option<V> {
+    // Optimize case where only root node exists
+    // (optimizes out borrowing and path creation in `find_leaf_path`)
+    if (self.root.is_leaf) {
+        let value_option = self.root.children.remove_or_none(key);
+        if (value_option.is_some()) {
+            let Child::Leaf {
+                value,
+            } = value_option.destroy_some();
+            return option::some(value);
+        } else {
+            value_option.destroy_none();
+            return option::none();
+        }
+    };
+
+    let path_to_leaf = self.find_leaf_path(key);
+
+    if (path_to_leaf.is_empty()) {
+        option::none()
+    } else {
+        let Child::Leaf {
+            value,
+        } = self.remove_at(path_to_leaf, key);
+        option::some(value)
+    }
+}
+
+ + +
@@ -1096,7 +1188,7 @@ Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are pass
public fun pop_front<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>): (K, V) {
-    let it = self.new_begin_iter();
+    let it = self.internal_new_begin_iter();
     let k = *it.iter_borrow_key();
     let v = self.remove(&k);
     (k, v)
@@ -1123,7 +1215,7 @@ Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are pass
 
 
 
public fun pop_back<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>): (K, V) {
-    let it = self.new_end_iter().iter_prev(self);
+    let it = self.internal_new_end_iter().iter_prev(self);
     let k = *it.iter_borrow_key();
     let v = self.remove(&k);
     (k, v)
@@ -1134,15 +1226,18 @@ Aborts with EKEY_ALREADY_EXISTS if key already exist, or duplicate keys are pass
 
 
 
-
+
+
+## Function `internal_lower_bound`
 
-## Function `lower_bound`
+Warning: Marked as internal, as it is safer to utilize provided inline functions instead.
+For direct usage of this method, check Warning at the top of the file corresponding to iterators.
 
 Returns an iterator pointing to the first element that is greater or equal to the provided
 key, or an end iterator if such element doesn't exist.
 
 
-
public(friend) fun lower_bound<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
+
public fun internal_lower_bound<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
 
@@ -1151,18 +1246,18 @@ key, or an end iterator if such element doesn't exist. Implementation -
public(friend) fun lower_bound<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): IteratorPtr<K> {
+
public fun internal_lower_bound<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): IteratorPtr<K> {
     let leaf = self.find_leaf(key);
     if (leaf == NULL_INDEX) {
-        return self.new_end_iter()
+        return self.internal_new_end_iter()
     };
 
     let node = self.borrow_node(leaf);
     assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
 
-    let child_lower_bound = node.children.lower_bound(key);
+    let child_lower_bound = node.children.internal_lower_bound(key);
     if (child_lower_bound.iter_is_end(&node.children)) {
-        self.new_end_iter()
+        self.internal_new_end_iter()
     } else {
         let iter_key = *child_lower_bound.iter_borrow_key(&node.children);
         new_iter(leaf, child_lower_bound, iter_key)
@@ -1174,15 +1269,18 @@ key, or an end iterator if such element doesn't exist.
 
 
 
-
+
 
-## Function `find`
+## Function `internal_find`
+
+Warning: Marked as internal, as it is safer to utilize provided inline functions instead.
+For direct usage of this method, check Warning at the top of the file corresponding to iterators.
 
 Returns an iterator pointing to the element that equals to the provided key, or an end
 iterator if the key is not found.
 
 
-
public(friend) fun find<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
+
public fun internal_find<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
 
@@ -1191,20 +1289,90 @@ iterator if the key is not found. Implementation -
public(friend) fun find<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): IteratorPtr<K> {
-    let lower_bound = self.lower_bound(key);
-    if (lower_bound.iter_is_end(self)) {
-        lower_bound
-    } else if (&lower_bound.key == key) {
-        lower_bound
+
public fun internal_find<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): IteratorPtr<K> {
+    let internal_lower_bound = self.internal_lower_bound(key);
+    if (internal_lower_bound.iter_is_end(self)) {
+        internal_lower_bound
+    } else if (&internal_lower_bound.key == key) {
+        internal_lower_bound
     } else {
-        self.new_end_iter()
+        self.internal_new_end_iter()
     }
 }
 
+ + + + +## Function `internal_find_with_path` + +Warning: Marked as internal, as it is safer to utilize provided inline functions instead. +For direct usage of this method, check Warning at the top of the file corresponding to iterators. + + +
public fun internal_find_with_path<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtrWithPath<K>
+
+ + + +
+Implementation + + +
public fun internal_find_with_path<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): IteratorPtrWithPath<K> {
+    let leaf_path = self.find_leaf_path(key);
+    if (leaf_path.is_empty()) {
+        return IteratorPtrWithPath { iterator: self.internal_new_end_iter(), path: vector::empty() };
+    };
+
+    let leaf = leaf_path[leaf_path.length() - 1];
+    let node = self.borrow_node(leaf);
+    assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+
+    let child_lower_bound = node.children.internal_lower_bound(key);
+    if (child_lower_bound.iter_is_end(&node.children)) {
+        IteratorPtrWithPath { iterator: self.internal_new_end_iter(), path: vector::empty() }
+    } else {
+        let iter_key = *child_lower_bound.iter_borrow_key(&node.children);
+
+        if (&iter_key == key) {
+            IteratorPtrWithPath { iterator: new_iter(leaf, child_lower_bound, iter_key), path: leaf_path }
+        } else {
+            IteratorPtrWithPath { iterator: self.internal_new_end_iter(), path: vector::empty() }
+        }
+    }
+}
+
+ + + +
+ + + +## Function `iter_with_path_get_iter` + + + +
public fun iter_with_path_get_iter<K: copy, drop, store>(self: &big_ordered_map::IteratorPtrWithPath<K>): big_ordered_map::IteratorPtr<K>
+
+ + + +
+Implementation + + +
public fun iter_with_path_get_iter<K: drop + copy + store>(self: &IteratorPtrWithPath<K>): IteratorPtr<K> {
+    self.iterator
+}
+
+ + +
@@ -1224,10 +1392,10 @@ Returns true iff the key exists in the map.
public fun contains<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): bool {
-    let lower_bound = self.lower_bound(key);
-    if (lower_bound.iter_is_end(self)) {
+    let internal_lower_bound = self.internal_lower_bound(key);
+    if (internal_lower_bound.iter_is_end(self)) {
         false
-    } else if (&lower_bound.key == key) {
+    } else if (&internal_lower_bound.key == key) {
         true
     } else {
         false
@@ -1256,7 +1424,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);
+    let iter = self.internal_find(key);
     assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
 
     iter.iter_borrow(self)
@@ -1283,7 +1451,7 @@ Returns a reference to the element with its key, aborts if the key is not found.
 
 
 
public fun get<K: drop + copy + store, V: copy + store>(self: &BigOrderedMap<K, V>, key: &K): Option<V> {
-    let iter = self.find(key);
+    let iter = self.internal_find(key);
     if (iter.iter_is_end(self)) {
         option::none()
     } else {
@@ -1316,7 +1484,7 @@ In case of variable size, use either borrow, copypublic fun borrow_mut<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: &K): &mut V {
-    let iter = self.find(key);
+    let iter = self.internal_find(key);
     assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
     iter.iter_borrow_mut(self)
 }
@@ -1342,7 +1510,7 @@ In case of variable size, use either borrow, copypublic fun borrow_front<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>): (K, &V) {
-    let it = self.new_begin_iter();
+    let it = self.internal_new_begin_iter();
     let key = *it.iter_borrow_key();
     (key, it.iter_borrow(self))
 }
@@ -1368,7 +1536,7 @@ In case of variable size, use either borrow, copypublic fun borrow_back<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>): (K, &V) {
-    let it = self.new_end_iter().iter_prev(self);
+    let it = self.internal_new_end_iter().iter_prev(self);
     let key = *it.iter_borrow_key();
     (key, it.iter_borrow(self))
 }
@@ -1394,7 +1562,7 @@ In case of variable size, use either borrow, copypublic fun prev_key<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): Option<K> {
-    let it = self.lower_bound(key);
+    let it = self.internal_lower_bound(key);
     if (it.iter_is_begin(self)) {
         option::none()
     } else {
@@ -1423,7 +1591,7 @@ In case of variable size, use either borrow, copypublic fun next_key<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): Option<K> {
-    let it = self.lower_bound(key);
+    let it = self.internal_lower_bound(key);
     if (it.iter_is_end(self)) {
         option::none()
     } else {
@@ -1466,8 +1634,8 @@ Disclaimer: This function may be costly as the BigOrderedMap may be huge in size
 
 
public fun to_ordered_map<K: drop + copy + store, V: copy + store>(self: &BigOrderedMap<K, V>): OrderedMap<K, V> {
     let result = ordered_map::new();
-    self.for_each_ref_friend(|k, v| {
-        result.new_end_iter().iter_add(&mut result, *k, *v);
+    self.for_each_ref(|k, v| {
+        result.internal_new_end_iter().iter_add(&mut result, *k, *v);
     });
     result
 }
@@ -1498,7 +1666,7 @@ use iterartor or next_key/prev_key to iterate over across portion of the map.
 
 
public fun keys<K: store + copy + drop, V: store + copy>(self: &BigOrderedMap<K, V>): vector<K> {
     let result = vector[];
-    self.for_each_ref_friend(|k, _v| {
+    self.for_each_ref(|k, _v| {
         result.push_back(*k);
     });
     result
@@ -1579,9 +1747,6 @@ to O(n).
 
 Apply the function to a reference of each element in the vector.
 
-Current implementation is O(n * log(n)). After function values will be optimized
-to O(n).
-
 
 
public fun for_each_ref<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, f: |&K, &V|)
 
@@ -1593,58 +1758,15 @@ to O(n).
public inline fun for_each_ref<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, f: |&K, &V|) {
-    // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time,
-    // but is the only one available through the public API.
-    if (!self.is_empty()) {
-        let (k, v) = self.borrow_front();
-        f(&k, v);
-
-        let cur_k = self.next_key(&k);
-        while (cur_k.is_some()) {
-            let k = cur_k.destroy_some();
-            f(&k, self.borrow(&k));
-
-            cur_k = self.next_key(&k);
-        };
-    };
-
-    // TODO use this more efficient implementation when function values are enabled.
-    // self.for_each_leaf_node_ref(|node| {
-    //     node.children.for_each_ref(|k: &K, v: &Child<V>| {
-    //         f(k, &v.value);
-    //     });
-    // })
-}
-
- - - - - - - -## Function `for_each_ref_friend` - - - -
public(friend) fun for_each_ref_friend<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, f: |&K, &V|)
-
- - - -
-Implementation - - -
public(friend) inline fun for_each_ref_friend<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, f: |&K, &V|) {
-    let iter = self.new_begin_iter();
+    let iter = self.internal_new_begin_iter();
     while (!iter.iter_is_end(self)) {
         f(iter.iter_borrow_key(), iter.iter_borrow(self));
         iter = iter.iter_next(self);
     };
 
+    // TODO use this more efficient implementation when function values are enabled.
     // self.for_each_leaf_node_ref(|node| {
-    //     node.children.for_each_ref_friend(|k: &K, v: &Child<V>| {
+    //     node.children.for_each_ref(|k: &K, v: &Child<V>| {
     //         f(k, &v.value);
     //     });
     // })
@@ -1661,9 +1783,6 @@ to O(n).
 
 Apply the function to a mutable reference of each key-value pair in the map.
 
-Current implementation is O(n * log(n)). After function values will be optimized
-to O(n).
-
 
 
public fun for_each_mut<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, f: |&K, &mut V|)
 
@@ -1675,31 +1794,12 @@ to O(n).
public inline fun for_each_mut<K: copy + drop + store, V: store>(self: &mut BigOrderedMap<K, V>, f: |&K, &mut V|) {
-    // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time,
-    // but is the only one available through the public API.
-    if (!self.is_empty()) {
-        let (k, _v) = self.borrow_front();
-
-        let done = false;
-        while (!done) {
-            f(&k, self.borrow_mut(&k));
-
-            let cur_k = self.next_key(&k);
-            if (cur_k.is_some()) {
-                k = cur_k.destroy_some();
-            } else {
-                done = true;
-            }
-        };
-    };
-
-    // TODO: if we make iterator api public update to:
-    // let iter = self.new_begin_iter();
-    // while (!iter.iter_is_end(self)) {
-    //     let key = *iter.iter_borrow_key(self);
-    //     f(key, iter.iter_borrow_mut(self));
-    //     iter = iter.iter_next(self);
-    // }
+    let iter = self.internal_new_begin_iter();
+    while (!iter.iter_is_end(self)) {
+        let key = *iter.iter_borrow_key();
+        f(&key, iter.iter_borrow_mut(self));
+        iter = iter.iter_next(self);
+    }
 }
 
@@ -1737,14 +1837,17 @@ to O(n).
- + -## Function `new_begin_iter` +## Function `internal_new_begin_iter` + +Warning: Marked as internal, as it is safer to utilize provided inline functions instead. +For direct usage of this method, check Warning at the top of the file corresponding to iterators. Returns the begin iterator. -
public(friend) fun new_begin_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun internal_new_begin_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
@@ -1753,14 +1856,14 @@ Returns the begin iterator. Implementation -
public(friend) fun new_begin_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): IteratorPtr<K> {
+
public fun internal_new_begin_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): IteratorPtr<K> {
     if (self.is_empty()) {
         return IteratorPtr::End;
     };
 
     let node = self.borrow_node(self.min_leaf_index);
     assert!(!node.children.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
-    let begin_child_iter = node.children.new_begin_iter();
+    let begin_child_iter = node.children.internal_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)
 }
@@ -1770,14 +1873,17 @@ Returns the begin iterator.
 
 
 
-
+
+
+## Function `internal_new_end_iter`
 
-## Function `new_end_iter`
+Warning: Marked as internal, as it is safer to utilize provided inline functions instead.
+For direct usage of this method, check Warning at the top of the file corresponding to iterators.
 
 Returns the end iterator.
 
 
-
public(friend) fun new_end_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun internal_new_end_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
@@ -1786,7 +1892,7 @@ Returns the end iterator. Implementation -
public(friend) fun new_end_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): IteratorPtr<K> {
+
public fun internal_new_end_iter<K: copy + store, V: store>(self: &BigOrderedMap<K, V>): IteratorPtr<K> {
     IteratorPtr::End
 }
 
@@ -1801,7 +1907,7 @@ Returns the end iterator. -
public(friend) fun iter_is_begin<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): bool
+
public fun iter_is_begin<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): bool
 
@@ -1810,7 +1916,7 @@ Returns the end iterator. Implementation -
public(friend) fun iter_is_begin<K: store, V: store>(self: &IteratorPtr<K>, map: &BigOrderedMap<K, V>): bool {
+
public fun iter_is_begin<K: store, V: store>(self: &IteratorPtr<K>, map: &BigOrderedMap<K, V>): bool {
     if (self is IteratorPtr::End<K>) {
         map.is_empty()
     } else {
@@ -1829,7 +1935,7 @@ Returns the end iterator.
 
 
 
-
public(friend) fun iter_is_end<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, _map: &big_ordered_map::BigOrderedMap<K, V>): bool
+
public fun iter_is_end<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, _map: &big_ordered_map::BigOrderedMap<K, V>): bool
 
@@ -1838,7 +1944,7 @@ Returns the end iterator. Implementation -
public(friend) fun iter_is_end<K: store, V: store>(self: &IteratorPtr<K>, _map: &BigOrderedMap<K, V>): bool {
+
public fun iter_is_end<K: store, V: store>(self: &IteratorPtr<K>, _map: &BigOrderedMap<K, V>): bool {
     self is IteratorPtr::End<K>
 }
 
@@ -1856,7 +1962,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_key<K>(self: &big_ordered_map::IteratorPtr<K>): &K
+
public fun iter_borrow_key<K>(self: &big_ordered_map::IteratorPtr<K>): &K
 
@@ -1865,7 +1971,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow_key<K>(self: &IteratorPtr<K>): &K {
+
public fun iter_borrow_key<K>(self: &IteratorPtr<K>): &K {
     assert!(!(self is IteratorPtr::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     &self.key
 }
@@ -1884,7 +1990,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: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): &V
+
public fun iter_borrow<K: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): &V
 
@@ -1893,7 +1999,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow<K: drop + store, V: store>(self: IteratorPtr<K>, map: &BigOrderedMap<K, V>): &V {
+
public fun iter_borrow<K: drop + 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 IteratorPtr::Some { node_index, child_iter, key: _ } = self;
     let children = &map.borrow_node(node_index).children;
@@ -1918,7 +2024,7 @@ In case of variable size, use either borrow, copypublic(friend) fun iter_borrow_mut<K: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): &mut V
+
public fun iter_borrow_mut<K: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): &mut V
 
@@ -1927,7 +2033,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow_mut<K: drop + store, V: store>(self: IteratorPtr<K>, map: &mut BigOrderedMap<K, V>): &mut V {
+
public fun iter_borrow_mut<K: drop + store, V: store>(self: IteratorPtr<K>, map: &mut BigOrderedMap<K, V>): &mut V {
     assert!(map.constant_kv_size || bcs::constant_serialized_size<V>().is_some(), error::invalid_argument(EBORROW_MUT_REQUIRES_CONSTANT_VALUE_SIZE));
     assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     let IteratorPtr::Some { node_index, child_iter, key: _ } = self;
@@ -1938,6 +2044,50 @@ Note: Requires that the map is not changed after the input iterator is generated
 
 
 
+
+
+
+
+## Function `iter_remove`
+
+Removes the entry from BigOrderedMap and returns the value which key maps to.
+Aborts if there is no entry for key.
+
+
+
public fun iter_remove<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtrWithPath<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): V
+
+ + + +
+Implementation + + +
public fun iter_remove<K: drop + copy + store, V: store>(self: IteratorPtrWithPath<K>, map: &mut BigOrderedMap<K, V>): V {
+    let IteratorPtrWithPath { iterator: iter, path: path_to_leaf } = self;
+    assert!(!iter.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS));
+    let IteratorPtr::Some { node_index: _, child_iter, key } = iter;
+
+    // Optimize case where only root node exists
+    // (optimizes out borrowing and path creation in `find_leaf_path`)
+    if (map.root.is_leaf) {
+        let Child::Leaf {
+            value,
+        } = child_iter.iter_remove(&mut map.root.children);
+        return value;
+    };
+
+    assert!(!path_to_leaf.is_empty(), error::invalid_argument(EKEY_NOT_FOUND));
+
+    let Child::Leaf {
+        value,
+    } = map.remove_at(path_to_leaf, &key);
+    value
+}
+
+ + +
@@ -1949,7 +2099,7 @@ Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end. Requires the map is not changed after the input iterator is generated. -
public(friend) fun iter_next<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun iter_next<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
@@ -1958,7 +2108,7 @@ Requires the map is not changed after the input iterator is generated. Implementation -
public(friend) fun iter_next<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &BigOrderedMap<K, V>): IteratorPtr<K> {
+
public 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));
 
     let node_index = self.node_index;
@@ -1976,13 +2126,13 @@ Requires the map is not changed after the input iterator is generated.
     if (next_index != NULL_INDEX) {
         let next_node = map.borrow_node(next_index);
 
-        let child_iter = next_node.children.new_begin_iter();
+        let child_iter = next_node.children.internal_new_begin_iter();
         assert!(!child_iter.iter_is_end(&next_node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
         let iter_key = *child_iter.iter_borrow_key(&next_node.children);
         return new_iter(next_index, child_iter, iter_key);
     };
 
-    map.new_end_iter()
+    map.internal_new_end_iter()
 }
 
@@ -1999,7 +2149,7 @@ Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the beginning. Requires the map is not changed after the input iterator is generated. -
public(friend) fun iter_prev<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun iter_prev<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
@@ -2008,7 +2158,7 @@ Requires the map is not changed after the input iterator is generated. Implementation -
public(friend) fun iter_prev<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &BigOrderedMap<K, V>): IteratorPtr<K> {
+
public fun iter_prev<K: drop + copy + store, V: store>(self: IteratorPtr<K>, map: &BigOrderedMap<K, V>): IteratorPtr<K> {
     let prev_index = if (self is IteratorPtr::End<K>) {
         map.max_leaf_index
     } else {
@@ -2030,7 +2180,7 @@ Requires the map is not changed after the input iterator is generated.
     let prev_node = map.borrow_node(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.internal_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)
 }
@@ -2177,7 +2327,7 @@ Borrow a node mutably, given an index. Works for both root (i.e. inline) node an
             if (current_node.is_leaf) {
                 break;
             };
-            let last_value = current_node.children.new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children);
+            let last_value = current_node.children.internal_new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children);
             current = last_value.node_index.stored_to_index();
             current_node.children.add(key, last_value);
         };
@@ -2518,7 +2668,7 @@ return NULL_INDEX if key is larger than any key currently stored in
             return current;
         };
         let children = &node.children;
-        let child_iter = children.lower_bound(key);
+        let child_iter = children.internal_lower_bound(key);
         if (child_iter.iter_is_end(children)) {
             return NULL_INDEX;
         } else {
@@ -2563,7 +2713,7 @@ Returns empty path if key is larger than any key currently stored i
             return vec;
         };
         let children = &node.children;
-        let child_iter = children.lower_bound(key);
+        let child_iter = children.internal_lower_bound(key);
         if (child_iter.iter_is_end(children)) {
             return vector::empty();
         } else {
@@ -2709,7 +2859,7 @@ 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);
+        let iter = children.internal_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));
@@ -2734,7 +2884,7 @@ If allow_overwrite is not set, function will abort if keylet max_key = {
             let root_children = &self.root.children;
-            let max_key = *root_children.new_end_iter().iter_prev(root_children).iter_borrow_key(root_children);
+            let max_key = *root_children.internal_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()) {
@@ -2828,7 +2978,7 @@ If allow_overwrite is not set, function will abort if keylet max_left_key = *left_children.new_end_iter().iter_prev(left_children).iter_borrow_key(left_children);
+    let max_left_key = *left_children.internal_new_end_iter().iter_prev(left_children).iter_borrow_key(left_children);
 
     self.nodes.fill_reserved_slot(left_node_reserved_slot, left_node);
     self.nodes.fill_reserved_slot(right_node_reserved_slot, right_node);
@@ -2867,7 +3017,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         children.replace_key_inplace(old_key, new_key);
 
         // If we were not updating the largest child, we don't need to continue.
-        if (children.new_end_iter().iter_prev(children).iter_borrow_key(children) != &new_key) {
+        if (children.internal_new_end_iter().iter_prev(children).iter_borrow_key(children) != &new_key) {
             return
         };
     }
@@ -2919,7 +3069,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
 
                 let Child::Inner {
                     node_index: inner_child_index,
-                } = children.new_end_iter().iter_prev(children).iter_remove(children);
+                } = children.internal_new_end_iter().iter_prev(children).iter_remove(children);
 
                 let inner_child = self.nodes.remove(inner_child_index);
                 if (inner_child.is_leaf) {
@@ -2943,7 +3093,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         // See if the node is big enough, or we need to merge it with another node on this level.
         let big_enough = degree * 2 >= max_degree;
 
-        let new_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+        let new_max_key = *children.internal_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();
@@ -2979,7 +3129,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
         // If we are the largest node from the parent, we merge with the `prev`
         // (which is then guaranteed to have the same parent, as any node has >1 children),
         // otherwise we merge with `next`.
-        if (parent_children.new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_to_index() == node_index) {
+        if (parent_children.internal_new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_to_index() == node_index) {
             prev
         } else {
             next
@@ -2996,25 +3146,25 @@ Given a path to node (excluding the node itself), which is currently stored unde
         // The sibling node has enough elements, we can just borrow an element from the sibling node.
         if (sibling_index == next) {
             // if sibling is the node with larger keys, we remove a child from the start
-            let old_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
-            let sibling_begin_iter = sibling_children.new_begin_iter();
+            let old_max_key = *children.internal_new_end_iter().iter_prev(children).iter_borrow_key(children);
+            let sibling_begin_iter = sibling_children.internal_new_begin_iter();
             let borrowed_max_key = *sibling_begin_iter.iter_borrow_key(sibling_children);
-            let borrowed_element = sibling_begin_iter.iter_remove(sibling_children);
+            let borrowed_element = sibling_begin_iter.iter_remove(sibling_children);
 
-            children.new_end_iter().iter_add(children, borrowed_max_key, borrowed_element);
+            children.internal_new_end_iter().iter_add(children, borrowed_max_key, borrowed_element);
 
             // max_key of the current node changed, so update
             self.update_key(path_to_node, &old_max_key, borrowed_max_key);
         } else {
             // if sibling is the node with smaller keys, we remove a child from the end
-            let sibling_end_iter = sibling_children.new_end_iter().iter_prev(sibling_children);
+            let sibling_end_iter = sibling_children.internal_new_end_iter().iter_prev(sibling_children);
             let borrowed_max_key = *sibling_end_iter.iter_borrow_key(sibling_children);
-            let borrowed_element = sibling_end_iter.iter_remove(sibling_children);
+            let borrowed_element = sibling_end_iter.iter_remove(sibling_children);
 
             children.add(borrowed_max_key, borrowed_element);
 
             // max_key of the sibling node changed, so update
-            self.update_key(path_to_node, &borrowed_max_key, *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children));
+            self.update_key(path_to_node, &borrowed_max_key, *sibling_children.internal_new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children));
         };
 
         self.nodes.fill_reserved_slot(node_slot, node);
@@ -3028,7 +3178,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
     let (key_to_remove, reserved_slot_to_remove) = if (sibling_index == next) {
         // destroying larger sibling node, keeping sibling_slot.
         let Node::V1 { children: sibling_children, is_leaf: _, prev: _, next: sibling_next } = sibling_node;
-        let key_to_remove = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+        let key_to_remove = *children.internal_new_end_iter().iter_prev(children).iter_borrow_key(children);
         children.append_disjoint(sibling_children);
         node.next = sibling_next;
 
@@ -3053,7 +3203,7 @@ Given a path to node (excluding the node itself), which is currently stored unde
     } else {
         // destroying larger current node, keeping node_slot
         let Node::V1 { children: node_children, is_leaf: _, prev: _, next: node_next } = node;
-        let key_to_remove = *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children);
+        let key_to_remove = *sibling_children.internal_new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children);
         sibling_children.append_disjoint(node_children);
         sibling_node.next = node_next;
 
@@ -3508,12 +3658,12 @@ Given a path to node (excluding the node itself), which is currently stored unde
 
 
 
-
+
 
-### Function `lower_bound`
+### Function `internal_lower_bound`
 
 
-
public(friend) fun lower_bound<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
+
public fun internal_lower_bound<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
 
@@ -3525,12 +3675,12 @@ Given a path to node (excluding the node itself), which is currently stored unde - + -### Function `find` +### Function `internal_find` -
public(friend) fun find<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
+
public fun internal_find<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): big_ordered_map::IteratorPtr<K>
 
@@ -3702,12 +3852,12 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); - + -### Function `new_begin_iter` +### Function `internal_new_begin_iter` -
public(friend) fun new_begin_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun internal_new_begin_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
@@ -3719,12 +3869,12 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); - + -### Function `new_end_iter` +### Function `internal_new_end_iter` -
public(friend) fun new_end_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun internal_new_end_iter<K: copy, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
@@ -3741,7 +3891,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_is_begin` -
public(friend) fun iter_is_begin<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): bool
+
public fun iter_is_begin<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): bool
 
@@ -3758,7 +3908,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_is_end` -
public(friend) fun iter_is_end<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, _map: &big_ordered_map::BigOrderedMap<K, V>): bool
+
public fun iter_is_end<K: store, V: store>(self: &big_ordered_map::IteratorPtr<K>, _map: &big_ordered_map::BigOrderedMap<K, V>): bool
 
@@ -3775,7 +3925,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_borrow_key` -
public(friend) fun iter_borrow_key<K>(self: &big_ordered_map::IteratorPtr<K>): &K
+
public fun iter_borrow_key<K>(self: &big_ordered_map::IteratorPtr<K>): &K
 
@@ -3792,7 +3942,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_borrow` -
public(friend) fun iter_borrow<K: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): &V
+
public fun iter_borrow<K: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): &V
 
@@ -3809,7 +3959,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_borrow_mut` -
public(friend) fun iter_borrow_mut<K: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): &mut V
+
public fun iter_borrow_mut<K: drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &mut big_ordered_map::BigOrderedMap<K, V>): &mut V
 
@@ -3826,7 +3976,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_next` -
public(friend) fun iter_next<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun iter_next<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
@@ -3843,7 +3993,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_prev` -
public(friend) fun iter_prev<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
+
public fun iter_prev<K: copy, drop, store, V: store>(self: big_ordered_map::IteratorPtr<K>, map: &big_ordered_map::BigOrderedMap<K, V>): big_ordered_map::IteratorPtr<K>
 
diff --git a/aptos-move/framework/aptos-framework/doc/ordered_map.md b/aptos-move/framework/aptos-framework/doc/ordered_map.md index f8845f1dd9c0d..842cddd962aa1 100644 --- a/aptos-move/framework/aptos-framework/doc/ordered_map.md +++ b/aptos-move/framework/aptos-framework/doc/ordered_map.md @@ -22,11 +22,16 @@ All methods that start with iter_*, operate with IteratorPtr being selfkey doesn't exist. + + + + +## Function `remove_or_none` + +Remove a key/value pair from the map. +Returns none if key doesn't exist. + + +
public fun remove_or_none<K: drop, V>(self: &mut ordered_map::OrderedMap<K, V>, key: &K): option::Option<V>
+
+ + + +
+Implementation + + +
public fun remove_or_none<K: drop, V>(self: &mut OrderedMap<K, V>, key: &K): Option<V> {
+    let len = self.entries.length();
+    let index = binary_search(key, &self.entries, 0, len);
+    if (index < len && key == &self.entries[index].key) {
+        let Entry { key: _, value } = self.entries.remove(index);
+        option::some(value)
+    } else {
+        option::none()
+    }
+}
+
+ + +
@@ -534,7 +573,7 @@ Returns whether map contains a given key.
public fun contains<K, V>(self: &OrderedMap<K, V>, key: &K): bool {
-    !self.find(key).iter_is_end(self)
+    !self.internal_find(key).iter_is_end(self)
 }
 
@@ -558,7 +597,7 @@ Returns whether map contains a given key.
public fun borrow<K, V>(self: &OrderedMap<K, V>, key: &K): &V {
-    self.find(key).iter_borrow(self)
+    self.internal_find(key).iter_borrow(self)
 }
 
@@ -582,7 +621,7 @@ Returns whether map contains a given key.
public fun borrow_mut<K, V>(self: &mut OrderedMap<K, V>, key: &K): &mut V {
-    self.find(key).iter_borrow_mut(self)
+    self.internal_find(key).iter_borrow_mut(self)
 }
 
@@ -985,7 +1024,7 @@ After the call, the original map will be left containing the elements [0, at).
public fun prev_key<K: copy, V>(self: &OrderedMap<K, V>, key: &K): Option<K> {
-    let it = self.lower_bound(key);
+    let it = self.internal_lower_bound(key);
     if (it.iter_is_begin(self)) {
         option::none()
     } else {
@@ -1014,7 +1053,7 @@ After the call, the original map will be left containing the elements [0, at).
 
 
 
public fun next_key<K: copy, V>(self: &OrderedMap<K, V>, key: &K): Option<K> {
-    let it = self.lower_bound(key);
+    let it = self.internal_lower_bound(key);
     if (it.iter_is_end(self)) {
         option::none()
     } else {
@@ -1037,15 +1076,18 @@ After the call, the original map will be left containing the elements [0, at).
 
 
 
-
+
+
+## Function `internal_lower_bound`
 
-## Function `lower_bound`
+Warning: Marked as internal, as it is safer to utilize provided inline functions instead.
+For direct usage of this method, check Warning at the top of the file corresponding to iterators.
 
 Returns an iterator pointing to the first element that is greater or equal to the provided
 key, or an end iterator if such element doesn't exist.
 
 
-
public(friend) fun lower_bound<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
+
public fun internal_lower_bound<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
 
@@ -1054,13 +1096,13 @@ key, or an end iterator if such element doesn't exist. Implementation -
public(friend) fun lower_bound<K, V>(self: &OrderedMap<K, V>, key: &K): IteratorPtr {
+
public fun internal_lower_bound<K, V>(self: &OrderedMap<K, V>, key: &K): IteratorPtr {
     let entries = &self.entries;
     let len = entries.length();
 
     let index = binary_search(key, entries, 0, len);
     if (index == len) {
-        self.new_end_iter()
+        self.internal_new_end_iter()
     } else {
         new_iter(index)
     }
@@ -1071,15 +1113,18 @@ key, or an end iterator if such element doesn't exist.
 
 
 
-
+
+
+## Function `internal_find`
 
-## Function `find`
+Warning: Marked as internal, as it is safer to utilize provided inline functions instead.
+For direct usage of this method, check Warning at the top of the file corresponding to iterators.
 
 Returns an iterator pointing to the element that equals to the provided key, or an end
 iterator if the key is not found.
 
 
-
public(friend) fun find<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
+
public fun internal_find<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
 
@@ -1088,14 +1133,14 @@ iterator if the key is not found. Implementation -
public(friend) fun find<K, V>(self: &OrderedMap<K, V>, key: &K): IteratorPtr {
-    let lower_bound = self.lower_bound(key);
-    if (lower_bound.iter_is_end(self)) {
-        lower_bound
-    } else if (lower_bound.iter_borrow_key(self) == key) {
-        lower_bound
+
public fun internal_find<K, V>(self: &OrderedMap<K, V>, key: &K): IteratorPtr {
+    let internal_lower_bound = self.internal_lower_bound(key);
+    if (internal_lower_bound.iter_is_end(self)) {
+        internal_lower_bound
+    } else if (internal_lower_bound.iter_borrow_key(self) == key) {
+        internal_lower_bound
     } else {
-        self.new_end_iter()
+        self.internal_new_end_iter()
     }
 }
 
@@ -1104,14 +1149,17 @@ iterator if the key is not found. - + -## Function `new_begin_iter` +## Function `internal_new_begin_iter` + +Warning: Marked as internal, as it is safer to utilize provided inline functions instead. +For direct usage of this method, check Warning at the top of the file corresponding to iterators. Returns the begin iterator. -
public(friend) fun new_begin_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun internal_new_begin_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -1120,7 +1168,7 @@ Returns the begin iterator. Implementation -
public(friend) fun new_begin_iter<K, V>(self: &OrderedMap<K, V>): IteratorPtr {
+
public fun internal_new_begin_iter<K, V>(self: &OrderedMap<K, V>): IteratorPtr {
     if (self.is_empty()) {
         return IteratorPtr::End;
     };
@@ -1133,14 +1181,17 @@ Returns the begin iterator.
 
 
 
-
+
+
+## Function `internal_new_end_iter`
 
-## Function `new_end_iter`
+Warning: Marked as internal, as it is safer to utilize provided inline functions instead.
+For direct usage of this method, check Warning at the top of the file corresponding to iterators.
 
 Returns the end iterator.
 
 
-
public(friend) fun new_end_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun internal_new_end_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -1149,7 +1200,7 @@ Returns the end iterator. Implementation -
public(friend) fun new_end_iter<K, V>(self: &OrderedMap<K, V>): IteratorPtr {
+
public fun internal_new_end_iter<K, V>(self: &OrderedMap<K, V>): IteratorPtr {
     IteratorPtr::End
 }
 
@@ -1166,7 +1217,7 @@ Returns the next iterator, or none if already at the end iterator. Note: Requires that the map is not changed after the input iterator is generated. -
public(friend) fun iter_next<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun iter_next<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -1175,14 +1226,14 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_next<K, V>(self: IteratorPtr, map: &OrderedMap<K, V>): IteratorPtr {
+
public 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));
 
     let index = self.index + 1;
     if (index < map.entries.length()) {
         new_iter(index)
     } else {
-        map.new_end_iter()
+        map.internal_new_end_iter()
     }
 }
 
@@ -1199,7 +1250,7 @@ Returns the previous iterator, or none if already at the begin iterator. Note: Requires that the map is not changed after the input iterator is generated. -
public(friend) fun iter_prev<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun iter_prev<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -1208,7 +1259,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_prev<K, V>(self: IteratorPtr, map: &OrderedMap<K, V>): IteratorPtr {
+
public 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));
 
     let index = if (self is IteratorPtr::End) {
@@ -1232,7 +1283,7 @@ Note: Requires that the map is not changed after the input iterator is generated
 Returns whether the iterator is a begin iterator.
 
 
-
public(friend) fun iter_is_begin<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): bool
+
public fun iter_is_begin<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): bool
 
@@ -1241,7 +1292,7 @@ Returns whether the iterator is a begin iterator. Implementation -
public(friend) fun iter_is_begin<K, V>(self: &IteratorPtr, map: &OrderedMap<K, V>): bool {
+
public fun iter_is_begin<K, V>(self: &IteratorPtr, map: &OrderedMap<K, V>): bool {
     if (self is IteratorPtr::End) {
         map.is_empty()
     } else {
@@ -1263,7 +1314,7 @@ Returns true iff the iterator is a begin iterator from a non-empty collection.
 This method doesn't require having access to map, unlike iter_is_begin.
 
 
-
public(friend) fun iter_is_begin_from_non_empty(self: &ordered_map::IteratorPtr): bool
+
public fun iter_is_begin_from_non_empty(self: &ordered_map::IteratorPtr): bool
 
@@ -1272,7 +1323,7 @@ This method doesn't require having access to map, unlike iter_is_begin. Implementation -
public(friend) fun iter_is_begin_from_non_empty(self: &IteratorPtr): bool {
+
public fun iter_is_begin_from_non_empty(self: &IteratorPtr): bool {
     if (self is IteratorPtr::End) {
         false
     } else {
@@ -1292,7 +1343,7 @@ This method doesn't require having access to map, unlike iter_is_begin.
 Returns whether the iterator is an end iterator.
 
 
-
public(friend) fun iter_is_end<K, V>(self: &ordered_map::IteratorPtr, _map: &ordered_map::OrderedMap<K, V>): bool
+
public fun iter_is_end<K, V>(self: &ordered_map::IteratorPtr, _map: &ordered_map::OrderedMap<K, V>): bool
 
@@ -1301,7 +1352,7 @@ Returns whether the iterator is an end iterator. Implementation -
public(friend) fun iter_is_end<K, V>(self: &IteratorPtr, _map: &OrderedMap<K, V>): bool {
+
public fun iter_is_end<K, V>(self: &IteratorPtr, _map: &OrderedMap<K, V>): bool {
     self is IteratorPtr::End
 }
 
@@ -1319,7 +1370,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_key<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &K
+
public fun iter_borrow_key<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &K
 
@@ -1328,7 +1379,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow_key<K, V>(self: &IteratorPtr, map: &OrderedMap<K, V>): &K {
+
public 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));
 
     &map.entries.borrow(self.index).key
@@ -1348,7 +1399,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, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &V
+
public fun iter_borrow<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &V
 
@@ -1357,7 +1408,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow<K, V>(self: IteratorPtr, map: &OrderedMap<K, V>): &V {
+
public fun iter_borrow<K, V>(self: IteratorPtr, map: &OrderedMap<K, V>): &V {
     assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
     &map.entries.borrow(self.index).value
 }
@@ -1376,7 +1427,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_mut<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): &mut V
+
public fun iter_borrow_mut<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): &mut V
 
@@ -1385,7 +1436,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_borrow_mut<K, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>): &mut V {
+
public 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));
     &mut map.entries.borrow_mut(self.index).value
 }
@@ -1404,7 +1455,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_remove<K: drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): V
+
public fun iter_remove<K: drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): V
 
@@ -1413,7 +1464,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_remove<K: drop, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>): V {
+
public 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));
 
     let Entry { key: _, value } = map.entries.remove(self.index);
@@ -1434,7 +1485,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_replace<K: copy, drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, value: V): V
+
public fun iter_replace<K: copy, drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, value: V): V
 
@@ -1443,7 +1494,7 @@ Note: Requires that the map is not changed after the input iterator is generated Implementation -
public(friend) fun iter_replace<K: copy + drop, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>, value: V): V {
+
public 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));
 
     // TODO once mem::replace is public/released, update to:
@@ -1471,7 +1522,7 @@ Aborts with ENEW_KEY_NOT_IN_ORDER is key is not larger than the key before the i
 or smaller than the key at the iterator position.
 
 
-
public(friend) fun iter_add<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, key: K, value: V)
+
public fun iter_add<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, key: K, value: V)
 
@@ -1480,7 +1531,7 @@ or smaller than the key at the iterator position. Implementation -
public(friend) fun iter_add<K, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>, key: K, value: V) {
+
public fun iter_add<K, V>(self: IteratorPtr, map: &mut OrderedMap<K, V>, key: K, value: V) {
     let len = map.entries.length();
     let insert_index = if (self is IteratorPtr::End) {
         len
@@ -1689,9 +1740,6 @@ Apply the function to each key-value pair in the map, consuming it.
 
 Apply the function to a reference of each key-value pair in the map.
 
-Current implementation is O(n * log(n)). After function values will be optimized
-to O(n).
-
 
 
public fun for_each_ref<K: copy, drop, V>(self: &ordered_map::OrderedMap<K, V>, f: |&K, &V|)
 
@@ -1703,29 +1751,13 @@ to O(n).
public inline fun for_each_ref<K: copy + drop, V>(self: &OrderedMap<K, V>, f: |&K, &V|) {
-    // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time,
-    // but is the only one available through the public API.
-    if (!self.is_empty()) {
-        let (k, v) = self.borrow_front();
-        f(k, v);
-
-        let cur_k = self.next_key(k);
-        while (cur_k.is_some()) {
-            let k = cur_k.destroy_some();
-            f(&k, self.borrow(&k));
-
-            cur_k = self.next_key(&k);
-        };
-    };
-
-    // TODO: if we make iterator api public update to:
-    // let iter = self.new_begin_iter();
-    // while (!iter.iter_is_end(self)) {
-    //     f(iter.iter_borrow_key(self), iter.iter_borrow(self));
-    //     iter = iter.iter_next(self);
-    // }
+    let iter = self.internal_new_begin_iter();
+    while (!iter.iter_is_end(self)) {
+        f(iter.iter_borrow_key(self), iter.iter_borrow(self));
+        iter = iter.iter_next(self);
+    }
 
-    // TODO: once move supports private functions udpate to:
+    // TODO: once move supports private functions update to:
     // vector::for_each_ref(
     //     &self.entries,
     //     |entry| {
@@ -1737,34 +1769,6 @@ to O(n).
 
 
 
-
-
-
-
-## Function `for_each_ref_friend`
-
-
-
-
public(friend) fun for_each_ref_friend<K: copy, drop, V>(self: &ordered_map::OrderedMap<K, V>, f: |&K, &V|)
-
- - - -
-Implementation - - -
public(friend) inline fun for_each_ref_friend<K: copy + drop, V>(self: &OrderedMap<K, V>, f: |&K, &V|) {
-    let iter = self.new_begin_iter();
-    while (!iter.iter_is_end(self)) {
-        f(iter.iter_borrow_key(self), iter.iter_borrow(self));
-        iter = iter.iter_next(self);
-    }
-}
-
- - -
@@ -1773,9 +1777,6 @@ to O(n). Apply the function to a mutable reference of each key-value pair in the map. -Current implementation is O(n * log(n)). After function values will be optimized -to O(n). -
public fun for_each_mut<K: copy, drop, V>(self: &mut ordered_map::OrderedMap<K, V>, f: |&K, &mut V|)
 
@@ -1787,32 +1788,12 @@ to O(n).
public inline fun for_each_mut<K: copy + drop, V>(self: &mut OrderedMap<K, V>, f: |&K, &mut V|) {
-    // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time,
-    // but is the only one available through the public API.
-    if (!self.is_empty()) {
-        let (k, _v) = self.borrow_front();
-
-        let k = *k;
-        let done = false;
-        while (!done) {
-            f(&k, self.borrow_mut(&k));
-
-            let cur_k = self.next_key(&k);
-            if (cur_k.is_some()) {
-                k = cur_k.destroy_some();
-            } else {
-                done = true;
-            }
-        };
-    };
-
-    // TODO: if we make iterator api public update to:
-    // let iter = self.new_begin_iter();
-    // while (!iter.iter_is_end(self)) {
-    //     let key = *iter.iter_borrow_key(self);
-    //     f(key, iter.iter_borrow_mut(self));
-    //     iter = iter.iter_next(self);
-    // }
+    let iter = self.internal_new_begin_iter();
+    while (!iter.iter_is_end(self)) {
+        let key = *iter.iter_borrow_key(self);
+        f(&key, iter.iter_borrow_mut(self));
+        iter = iter.iter_next(self);
+    }
 
     // TODO: once move supports private functions udpate to:
     // vector::for_each_mut(
@@ -2135,6 +2116,23 @@ to O(n).
 
 
 
+
+
+### Function `remove_or_none`
+
+
+
public fun remove_or_none<K: drop, V>(self: &mut ordered_map::OrderedMap<K, V>, key: &K): option::Option<V>
+
+ + + + +
pragma opaque;
+pragma verify = false;
+
+ + + ### Function `contains` @@ -2430,12 +2428,12 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); - + -### Function `lower_bound` +### Function `internal_lower_bound` -
public(friend) fun lower_bound<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
+
public fun internal_lower_bound<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
 
@@ -2447,12 +2445,12 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); - + -### Function `find` +### Function `internal_find` -
public(friend) fun find<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
+
public fun internal_find<K, V>(self: &ordered_map::OrderedMap<K, V>, key: &K): ordered_map::IteratorPtr
 
@@ -2464,12 +2462,12 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); - + -### Function `new_begin_iter` +### Function `internal_new_begin_iter` -
public(friend) fun new_begin_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun internal_new_begin_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -2481,12 +2479,12 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); - + -### Function `new_end_iter` +### Function `internal_new_end_iter` -
public(friend) fun new_end_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun internal_new_end_iter<K, V>(self: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -2503,7 +2501,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_next` -
public(friend) fun iter_next<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun iter_next<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -2520,7 +2518,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_prev` -
public(friend) fun iter_prev<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
+
public fun iter_prev<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): ordered_map::IteratorPtr
 
@@ -2537,7 +2535,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_is_begin` -
public(friend) fun iter_is_begin<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): bool
+
public fun iter_is_begin<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): bool
 
@@ -2554,7 +2552,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_is_begin_from_non_empty` -
public(friend) fun iter_is_begin_from_non_empty(self: &ordered_map::IteratorPtr): bool
+
public fun iter_is_begin_from_non_empty(self: &ordered_map::IteratorPtr): bool
 
@@ -2571,7 +2569,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_is_end` -
public(friend) fun iter_is_end<K, V>(self: &ordered_map::IteratorPtr, _map: &ordered_map::OrderedMap<K, V>): bool
+
public fun iter_is_end<K, V>(self: &ordered_map::IteratorPtr, _map: &ordered_map::OrderedMap<K, V>): bool
 
@@ -2588,7 +2586,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_borrow_key` -
public(friend) fun iter_borrow_key<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &K
+
public fun iter_borrow_key<K, V>(self: &ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &K
 
@@ -2605,7 +2603,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_borrow` -
public(friend) fun iter_borrow<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &V
+
public fun iter_borrow<K, V>(self: ordered_map::IteratorPtr, map: &ordered_map::OrderedMap<K, V>): &V
 
@@ -2622,7 +2620,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_borrow_mut` -
public(friend) fun iter_borrow_mut<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): &mut V
+
public fun iter_borrow_mut<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): &mut V
 
@@ -2639,7 +2637,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_remove` -
public(friend) fun iter_remove<K: drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): V
+
public fun iter_remove<K: drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>): V
 
@@ -2656,7 +2654,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_replace` -
public(friend) fun iter_replace<K: copy, drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, value: V): V
+
public fun iter_replace<K: copy, drop, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, value: V): V
 
@@ -2673,7 +2671,7 @@ std::cmp::compare(key, k) == std::cmp::Ordering::Greater); ### Function `iter_add` -
public(friend) fun iter_add<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, key: K, value: V)
+
public fun iter_add<K, V>(self: ordered_map::IteratorPtr, map: &mut ordered_map::OrderedMap<K, V>, key: K, value: V)
 
diff --git a/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.move b/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.move index 789b928f6253a..ae79022d5b200 100644 --- a/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.move +++ b/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.move @@ -21,10 +21,15 @@ /// Based on initial configuration, BigOrderedMap will always accept insertion of keys and values /// up to the allowed size, and will abort with EKEY_BYTES_TOO_LARGE or EARGUMENT_BYTES_TOO_LARGE. /// -/// TODO: all iterator functions are public(friend) for now, so that they can be modified in a -/// backward incompatible way. Type is also named IteratorPtr, so that Iterator is free to use later. -/// They are waiting for Move improvement that will allow references to be part of the struct, +/// Warning: All iterator functions need to be carefully used, because they are just pointers into the +/// structure, and modification of the map invalidates them (without compiler being able to catch it). +/// Type is also named IteratorPtr, so that Iterator is free to use later. +/// Better guarantees would need future Move improvements that will allow references to be part of the struct, /// allowing cleaner iterator APIs. +/// +/// That's why all functions returning iterators are prefixed with "internal_", to clarify nuances needed to make +/// sure usage is correct. +/// A set of inline utility methods is provided instead, to provide guaranteed valid usage to iterators. module aptos_std::big_ordered_map { use std::error; use std::vector; @@ -157,6 +162,11 @@ module aptos_std::big_ordered_map { }, } + struct IteratorPtrWithPath has copy, drop { + iterator: IteratorPtr, + path: vector, + } + /// The BigOrderedMap data structure. enum BigOrderedMap has store { BPlusTreeMap { @@ -359,6 +369,36 @@ module aptos_std::big_ordered_map { value } + /// Removes the entry from BigOrderedMap and returns the value which `key` maps to. + /// Returns none if there is no entry for `key`. + public fun remove_or_none(self: &mut BigOrderedMap, key: &K): Option { + // Optimize case where only root node exists + // (optimizes out borrowing and path creation in `find_leaf_path`) + if (self.root.is_leaf) { + let value_option = self.root.children.remove_or_none(key); + if (value_option.is_some()) { + let Child::Leaf { + value, + } = value_option.destroy_some(); + return option::some(value); + } else { + value_option.destroy_none(); + return option::none(); + } + }; + + let path_to_leaf = self.find_leaf_path(key); + + if (path_to_leaf.is_empty()) { + option::none() + } else { + let Child::Leaf { + value, + } = self.remove_at(path_to_leaf, key); + option::some(value) + } + } + /// 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(self: &mut BigOrderedMap, keys: vector, values: vector) { @@ -370,14 +410,14 @@ module aptos_std::big_ordered_map { } public fun pop_front(self: &mut BigOrderedMap): (K, V) { - let it = self.new_begin_iter(); + let it = self.internal_new_begin_iter(); let k = *it.iter_borrow_key(); let v = self.remove(&k); (k, v) } public fun pop_back(self: &mut BigOrderedMap): (K, V) { - let it = self.new_end_iter().iter_prev(self); + let it = self.internal_new_end_iter().iter_prev(self); let k = *it.iter_borrow_key(); let v = self.remove(&k); (k, v) @@ -385,45 +425,82 @@ module aptos_std::big_ordered_map { // ============================= Accessors ================================ + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns an iterator pointing to the first element that is greater or equal to the provided /// key, or an end iterator if such element doesn't exist. - public(friend) fun lower_bound(self: &BigOrderedMap, key: &K): IteratorPtr { + public fun internal_lower_bound(self: &BigOrderedMap, key: &K): IteratorPtr { let leaf = self.find_leaf(key); if (leaf == NULL_INDEX) { - return self.new_end_iter() + return self.internal_new_end_iter() }; let node = self.borrow_node(leaf); assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - let child_lower_bound = node.children.lower_bound(key); + let child_lower_bound = node.children.internal_lower_bound(key); if (child_lower_bound.iter_is_end(&node.children)) { - self.new_end_iter() + self.internal_new_end_iter() } else { let iter_key = *child_lower_bound.iter_borrow_key(&node.children); new_iter(leaf, child_lower_bound, iter_key) } } + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns an iterator pointing to the element that equals to the provided key, or an end /// iterator if the key is not found. - public(friend) fun find(self: &BigOrderedMap, key: &K): IteratorPtr { - let lower_bound = self.lower_bound(key); - if (lower_bound.iter_is_end(self)) { - lower_bound - } else if (&lower_bound.key == key) { - lower_bound + public fun internal_find(self: &BigOrderedMap, key: &K): IteratorPtr { + let internal_lower_bound = self.internal_lower_bound(key); + if (internal_lower_bound.iter_is_end(self)) { + internal_lower_bound + } else if (&internal_lower_bound.key == key) { + internal_lower_bound + } else { + self.internal_new_end_iter() + } + } + + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// + public fun internal_find_with_path(self: &BigOrderedMap, key: &K): IteratorPtrWithPath { + let leaf_path = self.find_leaf_path(key); + if (leaf_path.is_empty()) { + return IteratorPtrWithPath { iterator: self.internal_new_end_iter(), path: vector::empty() }; + }; + + let leaf = leaf_path[leaf_path.length() - 1]; + let node = self.borrow_node(leaf); + assert!(node.is_leaf, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + + let child_lower_bound = node.children.internal_lower_bound(key); + if (child_lower_bound.iter_is_end(&node.children)) { + IteratorPtrWithPath { iterator: self.internal_new_end_iter(), path: vector::empty() } } else { - self.new_end_iter() + let iter_key = *child_lower_bound.iter_borrow_key(&node.children); + + if (&iter_key == key) { + IteratorPtrWithPath { iterator: new_iter(leaf, child_lower_bound, iter_key), path: leaf_path } + } else { + IteratorPtrWithPath { iterator: self.internal_new_end_iter(), path: vector::empty() } + } } } + public fun iter_with_path_get_iter(self: &IteratorPtrWithPath): IteratorPtr { + self.iterator + } + /// 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 (lower_bound.iter_is_end(self)) { + let internal_lower_bound = self.internal_lower_bound(key); + if (internal_lower_bound.iter_is_end(self)) { false - } else if (&lower_bound.key == key) { + } else if (&internal_lower_bound.key == key) { true } else { false @@ -432,14 +509,14 @@ module aptos_std::big_ordered_map { /// Returns a reference to the element with its key, aborts if the key is not found. public fun borrow(self: &BigOrderedMap, key: &K): &V { - let iter = self.find(key); + let iter = self.internal_find(key); assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND)); iter.iter_borrow(self) } public fun get(self: &BigOrderedMap, key: &K): Option { - let iter = self.find(key); + let iter = self.internal_find(key); if (iter.iter_is_end(self)) { option::none() } else { @@ -452,24 +529,24 @@ module aptos_std::big_ordered_map { /// because if it doesn't we cannot assert invariants on the size. /// In case of variable size, use either `borrow`, `copy` then `upsert`, or `remove` and `add` instead of mutable borrow. public fun borrow_mut(self: &mut BigOrderedMap, key: &K): &mut V { - let iter = self.find(key); + let iter = self.internal_find(key); assert!(!iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND)); iter.iter_borrow_mut(self) } public fun borrow_front(self: &BigOrderedMap): (K, &V) { - let it = self.new_begin_iter(); + let it = self.internal_new_begin_iter(); let key = *it.iter_borrow_key(); (key, it.iter_borrow(self)) } public fun borrow_back(self: &BigOrderedMap): (K, &V) { - let it = self.new_end_iter().iter_prev(self); + let it = self.internal_new_end_iter().iter_prev(self); let key = *it.iter_borrow_key(); (key, it.iter_borrow(self)) } public fun prev_key(self: &BigOrderedMap, key: &K): Option { - let it = self.lower_bound(key); + let it = self.internal_lower_bound(key); if (it.iter_is_begin(self)) { option::none() } else { @@ -478,7 +555,7 @@ module aptos_std::big_ordered_map { } public fun next_key(self: &BigOrderedMap, key: &K): Option { - let it = self.lower_bound(key); + let it = self.internal_lower_bound(key); if (it.iter_is_end(self)) { option::none() } else { @@ -503,8 +580,8 @@ module aptos_std::big_ordered_map { /// Disclaimer: This function may be costly as the BigOrderedMap may be huge in size. Use it at your own discretion. public fun to_ordered_map(self: &BigOrderedMap): OrderedMap { let result = ordered_map::new(); - self.for_each_ref_friend(|k, v| { - result.new_end_iter().iter_add(&mut result, *k, *v); + self.for_each_ref(|k, v| { + result.internal_new_end_iter().iter_add(&mut result, *k, *v); }); result } @@ -515,7 +592,7 @@ module aptos_std::big_ordered_map { /// use iterartor or next_key/prev_key to iterate over across portion of the map. public fun keys(self: &BigOrderedMap): vector { let result = vector[]; - self.for_each_ref_friend(|k, _v| { + self.for_each_ref(|k, _v| { result.push_back(*k); }); result @@ -546,78 +623,29 @@ module aptos_std::big_ordered_map { } /// Apply the function to a reference of each element in the vector. - /// - /// Current implementation is O(n * log(n)). After function values will be optimized - /// to O(n). public inline fun for_each_ref(self: &BigOrderedMap, f: |&K, &V|) { - // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time, - // but is the only one available through the public API. - if (!self.is_empty()) { - let (k, v) = self.borrow_front(); - f(&k, v); - - let cur_k = self.next_key(&k); - while (cur_k.is_some()) { - let k = cur_k.destroy_some(); - f(&k, self.borrow(&k)); - - cur_k = self.next_key(&k); - }; - }; - - // TODO use this more efficient implementation when function values are enabled. - // self.for_each_leaf_node_ref(|node| { - // node.children.for_each_ref(|k: &K, v: &Child| { - // f(k, &v.value); - // }); - // }) - } - - // TODO: Temporary friend implementaiton, until for_each_ref can be made efficient. - public(friend) inline fun for_each_ref_friend(self: &BigOrderedMap, f: |&K, &V|) { - let iter = self.new_begin_iter(); + let iter = self.internal_new_begin_iter(); while (!iter.iter_is_end(self)) { f(iter.iter_borrow_key(), iter.iter_borrow(self)); iter = iter.iter_next(self); }; + // TODO use this more efficient implementation when function values are enabled. // self.for_each_leaf_node_ref(|node| { - // node.children.for_each_ref_friend(|k: &K, v: &Child| { + // node.children.for_each_ref(|k: &K, v: &Child| { // f(k, &v.value); // }); // }) } /// Apply the function to a mutable reference of each key-value pair in the map. - /// - /// Current implementation is O(n * log(n)). After function values will be optimized - /// to O(n). public inline fun for_each_mut(self: &mut BigOrderedMap, f: |&K, &mut V|) { - // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time, - // but is the only one available through the public API. - if (!self.is_empty()) { - let (k, _v) = self.borrow_front(); - - let done = false; - while (!done) { - f(&k, self.borrow_mut(&k)); - - let cur_k = self.next_key(&k); - if (cur_k.is_some()) { - k = cur_k.destroy_some(); - } else { - done = true; - } - }; - }; - - // TODO: if we make iterator api public update to: - // let iter = self.new_begin_iter(); - // while (!iter.iter_is_end(self)) { - // let key = *iter.iter_borrow_key(self); - // f(key, iter.iter_borrow_mut(self)); - // iter = iter.iter_next(self); - // } + let iter = self.internal_new_begin_iter(); + while (!iter.iter_is_end(self)) { + let key = *iter.iter_borrow_key(); + f(&key, iter.iter_borrow_mut(self)); + iter = iter.iter_next(self); + } } /// Destroy a map, by destroying elements individually. @@ -632,26 +660,32 @@ module aptos_std::big_ordered_map { // ========================= IteratorPtr functions =========================== + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns the begin iterator. - public(friend) fun new_begin_iter(self: &BigOrderedMap): IteratorPtr { + public fun internal_new_begin_iter(self: &BigOrderedMap): IteratorPtr { if (self.is_empty()) { return IteratorPtr::End; }; let node = self.borrow_node(self.min_leaf_index); assert!(!node.children.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - let begin_child_iter = node.children.new_begin_iter(); + let begin_child_iter = node.children.internal_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) } + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns the end iterator. - public(friend) fun new_end_iter(self: &BigOrderedMap): IteratorPtr { + public fun internal_new_end_iter(self: &BigOrderedMap): IteratorPtr { IteratorPtr::End } // Returns true iff the iterator is a begin iterator. - public(friend) fun iter_is_begin(self: &IteratorPtr, map: &BigOrderedMap): bool { + public fun iter_is_begin(self: &IteratorPtr, map: &BigOrderedMap): bool { if (self is IteratorPtr::End) { map.is_empty() } else { @@ -660,14 +694,14 @@ module aptos_std::big_ordered_map { } // Returns true iff the iterator is an end iterator. - public(friend) fun iter_is_end(self: &IteratorPtr, _map: &BigOrderedMap): bool { + public fun iter_is_end(self: &IteratorPtr, _map: &BigOrderedMap): bool { self is IteratorPtr::End } /// Borrows the key given iterator points to. /// Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end. /// Note: Requires that the map is not changed after the input iterator is generated. - public(friend) fun iter_borrow_key(self: &IteratorPtr): &K { + public fun iter_borrow_key(self: &IteratorPtr): &K { assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS)); &self.key } @@ -675,7 +709,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 fun iter_borrow(self: IteratorPtr, map: &BigOrderedMap): &V { assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS)); let IteratorPtr::Some { node_index, child_iter, key: _ } = self; let children = &map.borrow_node(node_index).children; @@ -689,7 +723,7 @@ module aptos_std::big_ordered_map { /// In case of variable size, use either `borrow`, `copy` then `upsert`, or `remove` and `add` instead of mutable borrow. /// /// 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 fun iter_borrow_mut(self: IteratorPtr, map: &mut BigOrderedMap): &mut V { assert!(map.constant_kv_size || bcs::constant_serialized_size().is_some(), error::invalid_argument(EBORROW_MUT_REQUIRES_CONSTANT_VALUE_SIZE)); assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS)); let IteratorPtr::Some { node_index, child_iter, key: _ } = self; @@ -697,10 +731,34 @@ module aptos_std::big_ordered_map { &mut child_iter.iter_borrow_mut(children).value } + /// Removes the entry from BigOrderedMap and returns the value which `key` maps to. + /// Aborts if there is no entry for `key`. + public fun iter_remove(self: IteratorPtrWithPath, map: &mut BigOrderedMap): V { + let IteratorPtrWithPath { iterator: iter, path: path_to_leaf } = self; + assert!(!iter.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS)); + let IteratorPtr::Some { node_index: _, child_iter, key } = iter; + + // Optimize case where only root node exists + // (optimizes out borrowing and path creation in `find_leaf_path`) + if (map.root.is_leaf) { + let Child::Leaf { + value, + } = child_iter.iter_remove(&mut map.root.children); + return value; + }; + + assert!(!path_to_leaf.is_empty(), error::invalid_argument(EKEY_NOT_FOUND)); + + let Child::Leaf { + value, + } = map.remove_at(path_to_leaf, &key); + value + } + /// Returns the next iterator. /// Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end. /// Requires the map is not changed after the input iterator is generated. - public(friend) fun iter_next(self: IteratorPtr, map: &BigOrderedMap): IteratorPtr { + public fun iter_next(self: IteratorPtr, map: &BigOrderedMap): IteratorPtr { assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS)); let node_index = self.node_index; @@ -718,19 +776,19 @@ module aptos_std::big_ordered_map { if (next_index != NULL_INDEX) { let next_node = map.borrow_node(next_index); - let child_iter = next_node.children.new_begin_iter(); + let child_iter = next_node.children.internal_new_begin_iter(); assert!(!child_iter.iter_is_end(&next_node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); let iter_key = *child_iter.iter_borrow_key(&next_node.children); return new_iter(next_index, child_iter, iter_key); }; - map.new_end_iter() + map.internal_new_end_iter() } /// Returns the previous iterator. /// Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the beginning. /// Requires the map is not changed after the input iterator is generated. - public(friend) fun iter_prev(self: IteratorPtr, map: &BigOrderedMap): IteratorPtr { + public fun iter_prev(self: IteratorPtr, map: &BigOrderedMap): IteratorPtr { let prev_index = if (self is IteratorPtr::End) { map.max_leaf_index } else { @@ -752,7 +810,7 @@ module aptos_std::big_ordered_map { let prev_node = map.borrow_node(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.internal_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) } @@ -821,7 +879,7 @@ module aptos_std::big_ordered_map { if (current_node.is_leaf) { break; }; - let last_value = current_node.children.new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children); + let last_value = current_node.children.internal_new_end_iter().iter_prev(¤t_node.children).iter_remove(&mut current_node.children); current = last_value.node_index.stored_to_index(); current_node.children.add(key, last_value); }; @@ -942,7 +1000,7 @@ module aptos_std::big_ordered_map { return current; }; let children = &node.children; - let child_iter = children.lower_bound(key); + let child_iter = children.internal_lower_bound(key); if (child_iter.iter_is_end(children)) { return NULL_INDEX; } else { @@ -967,7 +1025,7 @@ module aptos_std::big_ordered_map { return vec; }; let children = &node.children; - let child_iter = children.lower_bound(key); + let child_iter = children.internal_lower_bound(key); if (child_iter.iter_is_end(children)) { return vector::empty(); } else { @@ -1053,7 +1111,7 @@ module aptos_std::big_ordered_map { // If we cannot add more nodes without exceeding the size, // but node with `key` already exists, we either need to replace or abort. - let iter = children.find(&key); + let iter = children.internal_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)); @@ -1078,7 +1136,7 @@ module aptos_std::big_ordered_map { let max_key = { let root_children = &self.root.children; - let max_key = *root_children.new_end_iter().iter_prev(root_children).iter_borrow_key(root_children); + let max_key = *root_children.internal_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()) { @@ -1172,7 +1230,7 @@ module aptos_std::big_ordered_map { }; // Largest left key is the split key. - let max_left_key = *left_children.new_end_iter().iter_prev(left_children).iter_borrow_key(left_children); + let max_left_key = *left_children.internal_new_end_iter().iter_prev(left_children).iter_borrow_key(left_children); self.nodes.fill_reserved_slot(left_node_reserved_slot, left_node); self.nodes.fill_reserved_slot(right_node_reserved_slot, right_node); @@ -1191,7 +1249,7 @@ module aptos_std::big_ordered_map { children.replace_key_inplace(old_key, new_key); // If we were not updating the largest child, we don't need to continue. - if (children.new_end_iter().iter_prev(children).iter_borrow_key(children) != &new_key) { + if (children.internal_new_end_iter().iter_prev(children).iter_borrow_key(children) != &new_key) { return }; } @@ -1223,7 +1281,7 @@ module aptos_std::big_ordered_map { let Child::Inner { node_index: inner_child_index, - } = children.new_end_iter().iter_prev(children).iter_remove(children); + } = children.internal_new_end_iter().iter_prev(children).iter_remove(children); let inner_child = self.nodes.remove(inner_child_index); if (inner_child.is_leaf) { @@ -1247,7 +1305,7 @@ module aptos_std::big_ordered_map { // See if the node is big enough, or we need to merge it with another node on this level. let big_enough = degree * 2 >= max_degree; - let new_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children); + let new_max_key = *children.internal_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(); @@ -1283,7 +1341,7 @@ module aptos_std::big_ordered_map { // If we are the largest node from the parent, we merge with the `prev` // (which is then guaranteed to have the same parent, as any node has >1 children), // otherwise we merge with `next`. - if (parent_children.new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_to_index() == node_index) { + if (parent_children.internal_new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_to_index() == node_index) { prev } else { next @@ -1300,25 +1358,25 @@ module aptos_std::big_ordered_map { // The sibling node has enough elements, we can just borrow an element from the sibling node. if (sibling_index == next) { // if sibling is the node with larger keys, we remove a child from the start - let old_max_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children); - let sibling_begin_iter = sibling_children.new_begin_iter(); + let old_max_key = *children.internal_new_end_iter().iter_prev(children).iter_borrow_key(children); + let sibling_begin_iter = sibling_children.internal_new_begin_iter(); let borrowed_max_key = *sibling_begin_iter.iter_borrow_key(sibling_children); let borrowed_element = sibling_begin_iter.iter_remove(sibling_children); - children.new_end_iter().iter_add(children, borrowed_max_key, borrowed_element); + children.internal_new_end_iter().iter_add(children, borrowed_max_key, borrowed_element); // max_key of the current node changed, so update self.update_key(path_to_node, &old_max_key, borrowed_max_key); } else { // if sibling is the node with smaller keys, we remove a child from the end - let sibling_end_iter = sibling_children.new_end_iter().iter_prev(sibling_children); + let sibling_end_iter = sibling_children.internal_new_end_iter().iter_prev(sibling_children); let borrowed_max_key = *sibling_end_iter.iter_borrow_key(sibling_children); let borrowed_element = sibling_end_iter.iter_remove(sibling_children); children.add(borrowed_max_key, borrowed_element); // max_key of the sibling node changed, so update - self.update_key(path_to_node, &borrowed_max_key, *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children)); + self.update_key(path_to_node, &borrowed_max_key, *sibling_children.internal_new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children)); }; self.nodes.fill_reserved_slot(node_slot, node); @@ -1332,7 +1390,7 @@ module aptos_std::big_ordered_map { let (key_to_remove, reserved_slot_to_remove) = if (sibling_index == next) { // destroying larger sibling node, keeping sibling_slot. let Node::V1 { children: sibling_children, is_leaf: _, prev: _, next: sibling_next } = sibling_node; - let key_to_remove = *children.new_end_iter().iter_prev(children).iter_borrow_key(children); + let key_to_remove = *children.internal_new_end_iter().iter_prev(children).iter_borrow_key(children); children.append_disjoint(sibling_children); node.next = sibling_next; @@ -1357,7 +1415,7 @@ module aptos_std::big_ordered_map { } else { // destroying larger current node, keeping node_slot let Node::V1 { children: node_children, is_leaf: _, prev: _, next: node_next } = node; - let key_to_remove = *sibling_children.new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children); + let key_to_remove = *sibling_children.internal_new_end_iter().iter_prev(sibling_children).iter_borrow_key(sibling_children); sibling_children.append_disjoint(node_children); sibling_node.next = node_next; @@ -1422,7 +1480,7 @@ module aptos_std::big_ordered_map { aptos_std::debug::print(node); if (!node.is_leaf) { - node.children.for_each_ref_friend(|_key, node| { + node.children.for_each_ref(|_key, node| { self.print_map_for_node(node.node_index.stored_to_index(), level + 1); }); }; @@ -1430,11 +1488,11 @@ module aptos_std::big_ordered_map { #[test_only] fun destroy_and_validate(self: BigOrderedMap) { - let it = self.new_begin_iter(); + let it = self.internal_new_begin_iter(); while (!it.iter_is_end(&self)) { self.remove(it.iter_borrow_key()); - assert!(self.find(it.iter_borrow_key()).iter_is_end(&self), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - it = self.new_begin_iter(); + assert!(self.internal_find(it.iter_borrow_key()).iter_is_end(&self), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + it = self.internal_new_begin_iter(); self.validate_map(); }; @@ -1446,7 +1504,7 @@ module aptos_std::big_ordered_map { let expected_num_elements = self.compute_length(); assert!((expected_num_elements == 0) == self.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); let num_elements = 0; - let it = self.new_begin_iter(); + let it = self.internal_new_begin_iter(); while (!it.iter_is_end(self)) { num_elements += 1; it = it.iter_next(self); @@ -1455,14 +1513,14 @@ module aptos_std::big_ordered_map { assert!(num_elements == expected_num_elements, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); let num_elements = 0; - let it = self.new_end_iter(); + let it = self.internal_new_end_iter(); while (!it.iter_is_begin(self)) { it = it.iter_prev(self); num_elements += 1; }; assert!(num_elements == expected_num_elements, error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); - let it = self.new_end_iter(); + let it = self.internal_new_end_iter(); 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)); @@ -1485,7 +1543,7 @@ module aptos_std::big_ordered_map { node.children.validate_ordered(); let previous_max_key = expected_lower_bound_key; - node.children.for_each_ref_friend(|key: &K, child: &Child| { + node.children.for_each_ref(|key: &K, child: &Child| { if (!node.is_leaf) { self.validate_subtree(child.node_index.stored_to_index(), previous_max_key, option::some(*key)); } else { @@ -1496,12 +1554,12 @@ module aptos_std::big_ordered_map { if (expected_max_key.is_some()) { let expected_max_key = expected_max_key.extract(); - assert!(&expected_max_key == node.children.new_end_iter().iter_prev(&node.children).iter_borrow_key(&node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(&expected_max_key == node.children.internal_new_end_iter().iter_prev(&node.children).iter_borrow_key(&node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); }; if (expected_lower_bound_key.is_some()) { let expected_lower_bound_key = expected_lower_bound_key.extract(); - assert!(cmp::compare(&expected_lower_bound_key, node.children.new_begin_iter().iter_borrow_key(&node.children)).is_lt(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); + assert!(cmp::compare(&expected_lower_bound_key, node.children.internal_new_begin_iter().iter_borrow_key(&node.children)).is_lt(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN)); }; } @@ -1537,7 +1595,7 @@ module aptos_std::big_ordered_map { }); let index = 0; - map.for_each_ref_friend(|k, v| { + map.for_each_ref(|k, v| { assert!(k == expected_keys.borrow(index), *k + 100); assert!(v == expected_values.borrow(index), *k + 200); index += 1; @@ -1703,7 +1761,7 @@ module aptos_std::big_ordered_map { map.add(element, element); }; - let it = map.new_begin_iter(); + let it = map.internal_new_begin_iter(); let i = 0; while (!it.iter_is_end(&map)) { @@ -1728,14 +1786,14 @@ module aptos_std::big_ordered_map { let i = 0; while (i < data.length()) { let element = data.borrow(i); - let it = map.find(element); + let it = map.internal_find(element); assert!(!it.iter_is_end(&map), i); assert!(it.iter_borrow_key() == element, i); i += 1; }; - assert!(map.find(&4).iter_is_end(&map), 0); - assert!(map.find(&9).iter_is_end(&map), 1); + assert!(map.internal_find(&4).iter_is_end(&map), 0); + assert!(map.internal_find(&9).iter_is_end(&map), 1); map.destroy(|_v| {}); } @@ -1751,22 +1809,22 @@ module aptos_std::big_ordered_map { let i = 0; while (i < data.length()) { let element = *data.borrow(i); - let it = map.lower_bound(&element); + let it = map.internal_lower_bound(&element); assert!(!it.iter_is_end(&map), i); assert!(it.key == element, i); i += 1; }; - assert!(map.lower_bound(&0).key == 1, 0); - assert!(map.lower_bound(&4).key == 5, 1); - assert!(map.lower_bound(&9).key == 10, 2); - assert!(map.lower_bound(&13).iter_is_end(&map), 3); + assert!(map.internal_lower_bound(&0).key == 1, 0); + assert!(map.internal_lower_bound(&4).key == 5, 1); + assert!(map.internal_lower_bound(&9).key == 10, 2); + assert!(map.internal_lower_bound(&13).iter_is_end(&map), 3); map.remove(&3); - assert!(map.lower_bound(&3).key == 5, 4); + assert!(map.internal_lower_bound(&3).key == 5, 4); map.remove(&5); - assert!(map.lower_bound(&3).key == 6, 5); - assert!(map.lower_bound(&4).key == 6, 6); + assert!(map.internal_lower_bound(&3).key == 6, 5); + assert!(map.internal_lower_bound(&4).key == 6, 6); map.destroy(|_v| {}); } @@ -1936,7 +1994,7 @@ module aptos_std::big_ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS fun test_abort_iter_borrow_key_missing() { let map = new_from(vector[1], vector[1]); - map.new_end_iter().iter_borrow_key(); + map.internal_new_end_iter().iter_borrow_key(); map.destroy_and_validate(); } @@ -1944,7 +2002,7 @@ module aptos_std::big_ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS fun test_abort_iter_borrow_missing() { let map = new_from(vector[1], vector[1]); - map.new_end_iter().iter_borrow(&map); + map.internal_new_end_iter().iter_borrow(&map); map.destroy_and_validate(); } @@ -1952,7 +2010,7 @@ module aptos_std::big_ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS 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.internal_new_end_iter().iter_borrow_mut(&mut map); map.destroy_and_validate(); } @@ -1961,7 +2019,7 @@ module aptos_std::big_ordered_map { fun test_abort_iter_borrow_mut_requires_constant_kv_size() { let map = new_with_config(0, 0, false); map.add(1, vector[1]); - map.new_begin_iter().iter_borrow_mut(&mut map); + map.internal_new_begin_iter().iter_borrow_mut(&mut map); map.destroy_and_validate(); } @@ -1969,7 +2027,7 @@ module aptos_std::big_ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS 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.internal_new_end_iter().iter_next(&map); map.destroy_and_validate(); } @@ -1977,7 +2035,7 @@ module aptos_std::big_ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS 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.internal_new_begin_iter().iter_prev(&map); map.destroy_and_validate(); } @@ -2046,8 +2104,8 @@ module aptos_std::big_ordered_map { if ((i + 1) % 50 == 0) { big_map.validate_map(); - let big_iter = big_map.new_begin_iter(); - let small_iter = small_map.new_begin_iter(); + let big_iter = big_map.internal_new_begin_iter(); + let small_iter = small_map.internal_new_begin_iter(); while (!big_iter.iter_is_end(&big_map) || !small_iter.iter_is_end(&small_map)) { assert!(big_iter.iter_borrow_key() == small_iter.iter_borrow_key(&small_map), i); assert!(big_iter.iter_borrow(&big_map) == small_iter.iter_borrow(&small_map), i); @@ -2136,14 +2194,14 @@ module aptos_std::big_ordered_map { for (i in 0..len) { let element = shuffled_data.borrow(i); - let it = map.find(element); + let it = map.internal_find(element); assert!(!it.iter_is_end(&map), i); assert!(it.iter_borrow_key() == element, i); // aptos_std::debug::print(&it); let it_next = it.iter_next(&map); - let it_after = map.lower_bound(&(*element + 1)); + let it_after = map.internal_lower_bound(&(*element + 1)); // aptos_std::debug::print(&it_next); // aptos_std::debug::print(&it_after); diff --git a/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.spec.move b/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.spec.move index efd8d1fb15c59..86e4aa195ff1d 100644 --- a/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.spec.move +++ b/aptos-move/framework/aptos-framework/sources/datastructures/big_ordered_map.spec.move @@ -97,7 +97,7 @@ spec aptos_std::big_ordered_map { pragma verify = false; } - spec lower_bound { + spec internal_lower_bound { pragma opaque; pragma verify = false; } @@ -221,17 +221,17 @@ spec aptos_std::big_ordered_map { } - spec find { + spec internal_find { pragma opaque; pragma verify = false; } - spec new_begin_iter { + spec internal_new_begin_iter { pragma opaque; pragma verify = false; } - spec new_end_iter { + spec internal_new_end_iter { pragma opaque; pragma verify = false; } diff --git a/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.move b/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.move index c007818c05dda..f5c27551f0c4a 100644 --- a/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.move +++ b/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.move @@ -17,11 +17,15 @@ /// Uses cmp::compare for ordering, which compares primitive types natively, and uses common /// lexicographical sorting for complex types. /// -/// TODO: all iterator functions are public(friend) for now, so that they can be modified in a -/// backward incompatible way. Type is also named IteratorPtr, so that Iterator is free to use later. -/// They are waiting for Move improvement that will allow references to be part of the struct, +/// Warning: All iterator functions need to be carefully used, because they are just pointers into the +/// structure, and modification of the map invalidates them (without compiler being able to catch it). +/// Type is also named IteratorPtr, so that Iterator is free to use later. +/// Better guarantees would need future Move improvements that will allow references to be part of the struct, /// allowing cleaner iterator APIs. /// +/// That's why all functions returning iterators are prefixed with "internal_", to clarify nuances needed to make +/// sure usage is correct. +/// A set of inline utility methods is provided instead, to provide guaranteed valid usage to iterators. module aptos_std::ordered_map { friend aptos_std::big_ordered_map; @@ -131,17 +135,30 @@ module aptos_std::ordered_map { value } + /// Remove a key/value pair from the map. + /// Returns none if `key` doesn't exist. + public fun remove_or_none(self: &mut OrderedMap, key: &K): Option { + let len = self.entries.length(); + let index = binary_search(key, &self.entries, 0, len); + if (index < len && key == &self.entries[index].key) { + let Entry { key: _, value } = self.entries.remove(index); + option::some(value) + } else { + option::none() + } + } + /// Returns whether map contains a given key. public fun contains(self: &OrderedMap, key: &K): bool { - !self.find(key).iter_is_end(self) + !self.internal_find(key).iter_is_end(self) } public fun borrow(self: &OrderedMap, key: &K): &V { - self.find(key).iter_borrow(self) + self.internal_find(key).iter_borrow(self) } public fun borrow_mut(self: &mut OrderedMap, key: &K): &mut V { - self.find(key).iter_borrow_mut(self) + self.internal_find(key).iter_borrow_mut(self) } /// Changes the key, while keeping the same value attached to it @@ -304,7 +321,7 @@ module aptos_std::ordered_map { } public fun prev_key(self: &OrderedMap, key: &K): Option { - let it = self.lower_bound(key); + let it = self.internal_lower_bound(key); if (it.iter_is_begin(self)) { option::none() } else { @@ -313,7 +330,7 @@ module aptos_std::ordered_map { } public fun next_key(self: &OrderedMap, key: &K): Option { - let it = self.lower_bound(key); + let it = self.internal_lower_bound(key); if (it.iter_is_end(self)) { option::none() } else { @@ -333,36 +350,46 @@ module aptos_std::ordered_map { // TODO: see if it is more understandable if iterator points between elements, // and there is iter_borrow_next and iter_borrow_prev, and provide iter_insert. + // This is called "cursor" in rust instead. + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns an iterator pointing to the first element that is greater or equal to the provided /// key, or an end iterator if such element doesn't exist. - public(friend) fun lower_bound(self: &OrderedMap, key: &K): IteratorPtr { + public fun internal_lower_bound(self: &OrderedMap, key: &K): IteratorPtr { let entries = &self.entries; let len = entries.length(); let index = binary_search(key, entries, 0, len); if (index == len) { - self.new_end_iter() + self.internal_new_end_iter() } else { new_iter(index) } } + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns an iterator pointing to the element that equals to the provided key, or an end /// iterator if the key is not found. - public(friend) fun find(self: &OrderedMap, key: &K): IteratorPtr { - let lower_bound = self.lower_bound(key); - if (lower_bound.iter_is_end(self)) { - lower_bound - } else if (lower_bound.iter_borrow_key(self) == key) { - lower_bound + public fun internal_find(self: &OrderedMap, key: &K): IteratorPtr { + let internal_lower_bound = self.internal_lower_bound(key); + if (internal_lower_bound.iter_is_end(self)) { + internal_lower_bound + } else if (internal_lower_bound.iter_borrow_key(self) == key) { + internal_lower_bound } else { - self.new_end_iter() + self.internal_new_end_iter() } } + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns the begin iterator. - public(friend) fun new_begin_iter(self: &OrderedMap): IteratorPtr { + public fun internal_new_begin_iter(self: &OrderedMap): IteratorPtr { if (self.is_empty()) { return IteratorPtr::End; }; @@ -370,8 +397,11 @@ module aptos_std::ordered_map { new_iter(0) } + /// Warning: Marked as internal, as it is safer to utilize provided inline functions instead. + /// For direct usage of this method, check Warning at the top of the file corresponding to iterators. + /// /// Returns the end iterator. - public(friend) fun new_end_iter(self: &OrderedMap): IteratorPtr { + public fun internal_new_end_iter(self: &OrderedMap): IteratorPtr { IteratorPtr::End } @@ -381,20 +411,20 @@ module aptos_std::ordered_map { /// Returns the next iterator, or none if already at the end iterator. /// Note: Requires that the map is not changed after the input iterator is generated. - public(friend) fun iter_next(self: IteratorPtr, map: &OrderedMap): IteratorPtr { + public fun iter_next(self: IteratorPtr, map: &OrderedMap): IteratorPtr { assert!(!self.iter_is_end(map), error::invalid_argument(EITER_OUT_OF_BOUNDS)); let index = self.index + 1; if (index < map.entries.length()) { new_iter(index) } else { - map.new_end_iter() + map.internal_new_end_iter() } } /// Returns the previous iterator, or none if already at the begin iterator. /// Note: Requires that the map is not changed after the input iterator is generated. - public(friend) fun iter_prev(self: IteratorPtr, map: &OrderedMap): IteratorPtr { + public fun iter_prev(self: IteratorPtr, map: &OrderedMap): IteratorPtr { assert!(!self.iter_is_begin(map), error::invalid_argument(EITER_OUT_OF_BOUNDS)); let index = if (self is IteratorPtr::End) { @@ -407,7 +437,7 @@ module aptos_std::ordered_map { } /// Returns whether the iterator is a begin iterator. - public(friend) fun iter_is_begin(self: &IteratorPtr, map: &OrderedMap): bool { + public fun iter_is_begin(self: &IteratorPtr, map: &OrderedMap): bool { if (self is IteratorPtr::End) { map.is_empty() } else { @@ -418,7 +448,7 @@ module aptos_std::ordered_map { /// Returns true iff the iterator is a begin iterator from a non-empty collection. /// (I.e. if iterator points to a valid element) /// This method doesn't require having access to map, unlike iter_is_begin. - public(friend) fun iter_is_begin_from_non_empty(self: &IteratorPtr): bool { + public fun iter_is_begin_from_non_empty(self: &IteratorPtr): bool { if (self is IteratorPtr::End) { false } else { @@ -427,14 +457,14 @@ module aptos_std::ordered_map { } /// Returns whether the iterator is an end iterator. - public(friend) fun iter_is_end(self: &IteratorPtr, _map: &OrderedMap): bool { + public fun iter_is_end(self: &IteratorPtr, _map: &OrderedMap): bool { self is IteratorPtr::End } /// Borrows the key given iterator points to. /// Aborts with EITER_OUT_OF_BOUNDS if iterator is pointing to the end. /// Note: Requires that the map is not changed after the input iterator is generated. - public(friend) fun iter_borrow_key(self: &IteratorPtr, map: &OrderedMap): &K { + public fun iter_borrow_key(self: &IteratorPtr, map: &OrderedMap): &K { assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS)); &map.entries.borrow(self.index).key @@ -443,7 +473,7 @@ module aptos_std::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: &OrderedMap): &V { + public fun iter_borrow(self: IteratorPtr, map: &OrderedMap): &V { assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS)); &map.entries.borrow(self.index).value } @@ -451,7 +481,7 @@ module aptos_std::ordered_map { /// Mutably borrows the value 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_mut(self: IteratorPtr, map: &mut OrderedMap): &mut V { + public fun iter_borrow_mut(self: IteratorPtr, map: &mut OrderedMap): &mut V { assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS)); &mut map.entries.borrow_mut(self.index).value } @@ -459,7 +489,7 @@ module aptos_std::ordered_map { /// Removes (key, value) pair iterator points to, returning the previous value. /// 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_remove(self: IteratorPtr, map: &mut OrderedMap): V { + public fun iter_remove(self: IteratorPtr, map: &mut OrderedMap): V { assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS)); let Entry { key: _, value } = map.entries.remove(self.index); @@ -469,7 +499,7 @@ module aptos_std::ordered_map { /// Replaces the value iterator is pointing to, returning the previous value. /// 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_replace(self: IteratorPtr, map: &mut OrderedMap, value: V): V { + public fun iter_replace(self: IteratorPtr, map: &mut OrderedMap, value: V): V { assert!(!(self is IteratorPtr::End), error::invalid_argument(EITER_OUT_OF_BOUNDS)); // TODO once mem::replace is public/released, update to: @@ -486,7 +516,7 @@ module aptos_std::ordered_map { /// Add key/value pair to the map, at the iterator position (before the element at the iterator position). /// Aborts with ENEW_KEY_NOT_IN_ORDER is key is not larger than the key before the iterator, /// or smaller than the key at the iterator position. - public(friend) fun iter_add(self: IteratorPtr, map: &mut OrderedMap, key: K, value: V) { + public fun iter_add(self: IteratorPtr, map: &mut OrderedMap, key: K, value: V) { let len = map.entries.length(); let insert_index = if (self is IteratorPtr::End) { len @@ -567,33 +597,14 @@ module aptos_std::ordered_map { } /// Apply the function to a reference of each key-value pair in the map. - /// - /// Current implementation is O(n * log(n)). After function values will be optimized - /// to O(n). public inline fun for_each_ref(self: &OrderedMap, f: |&K, &V|) { - // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time, - // but is the only one available through the public API. - if (!self.is_empty()) { - let (k, v) = self.borrow_front(); - f(k, v); - - let cur_k = self.next_key(k); - while (cur_k.is_some()) { - let k = cur_k.destroy_some(); - f(&k, self.borrow(&k)); - - cur_k = self.next_key(&k); - }; - }; - - // TODO: if we make iterator api public update to: - // let iter = self.new_begin_iter(); - // while (!iter.iter_is_end(self)) { - // f(iter.iter_borrow_key(self), iter.iter_borrow(self)); - // iter = iter.iter_next(self); - // } + let iter = self.internal_new_begin_iter(); + while (!iter.iter_is_end(self)) { + f(iter.iter_borrow_key(self), iter.iter_borrow(self)); + iter = iter.iter_next(self); + } - // TODO: once move supports private functions udpate to: + // TODO: once move supports private functions update to: // vector::for_each_ref( // &self.entries, // |entry| { @@ -602,46 +613,14 @@ module aptos_std::ordered_map { // ); } - // TODO: Temporary friend implementaiton, until for_each_ref can be made efficient. - public(friend) inline fun for_each_ref_friend(self: &OrderedMap, f: |&K, &V|) { - let iter = self.new_begin_iter(); + /// Apply the function to a mutable reference of each key-value pair in the map. + public inline fun for_each_mut(self: &mut OrderedMap, f: |&K, &mut V|) { + let iter = self.internal_new_begin_iter(); while (!iter.iter_is_end(self)) { - f(iter.iter_borrow_key(self), iter.iter_borrow(self)); + let key = *iter.iter_borrow_key(self); + f(&key, iter.iter_borrow_mut(self)); iter = iter.iter_next(self); } - } - - /// Apply the function to a mutable reference of each key-value pair in the map. - /// - /// Current implementation is O(n * log(n)). After function values will be optimized - /// to O(n). - public inline fun for_each_mut(self: &mut OrderedMap, f: |&K, &mut V|) { - // This implementation is innefficient: O(log(n)) for next_key / borrow lookups every time, - // but is the only one available through the public API. - if (!self.is_empty()) { - let (k, _v) = self.borrow_front(); - - let k = *k; - let done = false; - while (!done) { - f(&k, self.borrow_mut(&k)); - - let cur_k = self.next_key(&k); - if (cur_k.is_some()) { - k = cur_k.destroy_some(); - } else { - done = true; - } - }; - }; - - // TODO: if we make iterator api public update to: - // let iter = self.new_begin_iter(); - // while (!iter.iter_is_end(self)) { - // let key = *iter.iter_borrow_key(self); - // f(key, iter.iter_borrow_mut(self)); - // iter = iter.iter_next(self); - // } // TODO: once move supports private functions udpate to: // vector::for_each_mut( @@ -712,7 +691,7 @@ module aptos_std::ordered_map { fun validate_iteration(self: &OrderedMap) { let expected_num_elements = self.length(); let num_elements = 0; - let it = self.new_begin_iter(); + let it = self.internal_new_begin_iter(); while (!it.iter_is_end(self)) { num_elements += 1; it = it.iter_next(self); @@ -720,7 +699,7 @@ module aptos_std::ordered_map { assert!(num_elements == expected_num_elements, 2); let num_elements = 0; - let it = self.new_end_iter(); + let it = self.internal_new_end_iter(); while (!it.iter_is_begin(self)) { it = it.iter_prev(self); num_elements += 1; @@ -1109,41 +1088,41 @@ module aptos_std::ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS public fun test_iter_end_next_abort() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_next(&map); + map.internal_new_end_iter().iter_next(&map); } #[test] #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS public fun test_iter_end_borrow_key_abort() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_borrow_key(&map); + map.internal_new_end_iter().iter_borrow_key(&map); } #[test] #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS public fun test_iter_end_borrow_abort() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_borrow(&map); + map.internal_new_end_iter().iter_borrow(&map); } #[test] #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS public fun test_iter_end_borrow_mut_abort() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_borrow_mut(&mut map); + map.internal_new_end_iter().iter_borrow_mut(&mut map); } #[test] #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS public fun test_iter_begin_prev_abort() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_prev(&map); + map.internal_new_begin_iter().iter_prev(&map); } #[test] public fun test_iter_is_begin_from_non_empty() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - let iter = map.new_begin_iter(); + let iter = map.internal_new_begin_iter(); assert!(iter.iter_is_begin(&map), 1); assert!(iter.iter_is_begin_from_non_empty(), 1); @@ -1152,7 +1131,7 @@ module aptos_std::ordered_map { assert!(!iter.iter_is_begin_from_non_empty(), 1); let map = new(); - let iter = map.new_begin_iter(); + let iter = map.internal_new_begin_iter(); assert!(iter.iter_is_begin(&map), 1); assert!(!iter.iter_is_begin_from_non_empty(), 1); } @@ -1160,7 +1139,7 @@ module aptos_std::ordered_map { #[test] public fun test_iter_remove() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_next(&map).iter_remove(&mut map); + map.internal_new_begin_iter().iter_next(&map).iter_remove(&mut map); assert!(map == new_from(vector[1, 5], vector[10, 50]), 1); } @@ -1168,13 +1147,13 @@ module aptos_std::ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS public fun test_iter_remove_abort() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_remove(&mut map); + map.internal_new_end_iter().iter_remove(&mut map); } #[test] public fun test_iter_replace() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_next(&map).iter_replace(&mut map, 35); + map.internal_new_begin_iter().iter_next(&map).iter_replace(&mut map, 35); assert!(map == new_from(vector[1, 3, 5], vector[10, 35, 50]), 1); } @@ -1182,29 +1161,29 @@ module aptos_std::ordered_map { #[expected_failure(abort_code = 0x10003, location = Self)] /// EITER_OUT_OF_BOUNDS public fun test_iter_replace_abort() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_replace(&mut map, 35); + map.internal_new_end_iter().iter_replace(&mut map, 35); } #[test] public fun test_iter_add() { { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_add(&mut map, 0, 5); + map.internal_new_begin_iter().iter_add(&mut map, 0, 5); assert!(map == new_from(vector[0, 1, 3, 5], vector[5, 10, 30, 50]), 1); }; { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_next(&map).iter_add(&mut map, 2, 20); + map.internal_new_begin_iter().iter_next(&map).iter_add(&mut map, 2, 20); assert!(map == new_from(vector[1, 2, 3, 5], vector[10, 20, 30, 50]), 2); }; { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_add(&mut map, 6, 60); + map.internal_new_end_iter().iter_add(&mut map, 6, 60); assert!(map == new_from(vector[1, 3, 5, 6], vector[10, 30, 50, 60]), 3); }; { let map = new(); - map.new_end_iter().iter_add(&mut map, 1, 10); + map.internal_new_end_iter().iter_add(&mut map, 1, 10); assert!(map == new_from(vector[1], vector[10]), 4); }; } @@ -1213,28 +1192,28 @@ module aptos_std::ordered_map { #[expected_failure(abort_code = 0x10004, location = Self)] /// ENEW_KEY_NOT_IN_ORDER public fun test_iter_add_abort_1() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_add(&mut map, 1, 5); + map.internal_new_begin_iter().iter_add(&mut map, 1, 5); } #[test] #[expected_failure(abort_code = 0x10004, location = Self)] /// ENEW_KEY_NOT_IN_ORDER public fun test_iter_add_abort_2() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_end_iter().iter_add(&mut map, 5, 55); + map.internal_new_end_iter().iter_add(&mut map, 5, 55); } #[test] #[expected_failure(abort_code = 0x10004, location = Self)] /// ENEW_KEY_NOT_IN_ORDER public fun test_iter_add_abort_3() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_next(&map).iter_add(&mut map, 1, 15); + map.internal_new_begin_iter().iter_next(&map).iter_add(&mut map, 1, 15); } #[test] #[expected_failure(abort_code = 0x10004, location = Self)] /// ENEW_KEY_NOT_IN_ORDER public fun test_iter_add_abort_4() { let map = new_from(vector[1, 3, 5], vector[10, 30, 50]); - map.new_begin_iter().iter_next(&map).iter_add(&mut map, 3, 25); + map.internal_new_begin_iter().iter_next(&map).iter_add(&mut map, 3, 25); } #[test] @@ -1295,12 +1274,12 @@ module aptos_std::ordered_map { for (i in 0..len) { let element = shuffled_data.borrow(i); - let it = map.find(element); + let it = map.internal_find(element); assert!(!it.iter_is_end(&map), 6); assert!(it.iter_borrow_key(&map) == element, 7); let it_next = it.iter_next(&map); - let it_after = map.lower_bound(&(*element + 1)); + let it_after = map.internal_lower_bound(&(*element + 1)); assert!(it_next == it_after, 8); }; diff --git a/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.spec.move b/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.spec.move index 2d3f6b321d308..8e7d64ab75f92 100644 --- a/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.spec.move +++ b/aptos-move/framework/aptos-framework/sources/datastructures/ordered_map.spec.move @@ -119,7 +119,7 @@ spec aptos_std::ordered_map { } - spec lower_bound { + spec internal_lower_bound { pragma opaque; pragma verify = false; } @@ -257,17 +257,17 @@ spec aptos_std::ordered_map { } - spec find { + spec internal_find { pragma opaque; pragma verify = false; } - spec new_begin_iter { + spec internal_new_begin_iter { pragma opaque; pragma verify = false; } - spec new_end_iter { + spec internal_new_end_iter { pragma opaque; pragma verify = false; } @@ -282,5 +282,9 @@ spec aptos_std::ordered_map { pragma verify = false; } + spec remove_or_none { + pragma opaque; + pragma verify = false; + } } diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.exp b/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.exp index aad7cbc7821fd..865bd7393e635 100644 --- a/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.exp +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.exp @@ -6,11 +6,11 @@ error: undeclared receiver function `borrow` for type `vector>` 25 │ &map.entries.borrow(self.index).key │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: undeclared receiver function `lower_bound` for type `OrderedMap` - ┌─ tests/checking/receiver/bad_receiver.move:29:27 +error: undeclared receiver function `internal_lower_bound` for type `OrderedMap` + ┌─ tests/checking/receiver/bad_receiver.move:29:36 │ -29 │ let lower_bound = self.lower_bound(key); - │ ^^^^^^^^^^^^^^^^^^^^^ +29 │ let internal_lower_bound = self.internal_lower_bound(key); + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type cannot have type arguments ┌─ tests/checking/receiver/bad_receiver.move:39:36 diff --git a/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.move b/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.move index da72fd481f0de..64175cba77d43 100644 --- a/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.move +++ b/third_party/move/move-compiler-v2/tests/checking/receiver/bad_receiver.move @@ -25,14 +25,14 @@ module aptos_std::ordered_map { &map.entries.borrow(self.index).key } - public fun find(self: &OrderedMap, key: &K): Iterator { - let lower_bound = self.lower_bound(key); - if (lower_bound.iter_is_end(self)) { - lower_bound - } else if (lower_bound.iter_borrow_key(self) == key) { - lower_bound + public fun internal_find(self: &OrderedMap, key: &K): Iterator { + let internal_lower_bound = self.internal_lower_bound(key); + if (internal_lower_bound.iter_is_end(self)) { + internal_lower_bound + } else if (internal_lower_bound.iter_borrow_key(self) == key) { + internal_lower_bound } else { - self.new_end_iter() + self.internal_new_end_iter() } } @@ -40,7 +40,7 @@ module aptos_std::ordered_map { self.find(key).iter_borrow(self) } - public fun new_end_iter(self: &OrderedMap): Iterator { + public fun internal_new_end_iter(self: &OrderedMap): Iterator { Iterator::End }