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