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 c98fea9b16989..54146fc8acca3 100644 --- a/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md +++ b/aptos-move/framework/aptos-stdlib/doc/big_ordered_map.md @@ -43,6 +43,8 @@ once it contains enough keys - [Function `iter_get_key`](#0x1_big_ordered_map_iter_get_key) - [Function `iter_next`](#0x1_big_ordered_map_iter_next) - [Function `iter_prev`](#0x1_big_ordered_map_iter_prev) +- [Function `borrow_node`](#0x1_big_ordered_map_borrow_node) +- [Function `borrow_node_mut`](#0x1_big_ordered_map_borrow_node_mut) - [Function `add_or_upsert_impl`](#0x1_big_ordered_map_add_or_upsert_impl) - [Function `validate_dynamic_size_and_init_max_degrees`](#0x1_big_ordered_map_validate_dynamic_size_and_init_max_degrees) - [Function `validate_static_size_and_init_max_degrees`](#0x1_big_ordered_map_validate_static_size_and_init_max_degrees) @@ -55,6 +57,7 @@ once it contains enough keys - [Function `new_leaf_child`](#0x1_big_ordered_map_new_leaf_child) - [Function `new_iter`](#0x1_big_ordered_map_new_iter) - [Function `find_leaf`](#0x1_big_ordered_map_find_leaf) +- [Function `find_leaf_with_path`](#0x1_big_ordered_map_find_leaf_with_path) - [Function `get_max_degree`](#0x1_big_ordered_map_get_max_degree) - [Function `add_at`](#0x1_big_ordered_map_add_at) - [Function `update_key`](#0x1_big_ordered_map_update_key) @@ -66,12 +69,13 @@ once it contains enough keys
use 0x1::bcs;
use 0x1::cmp;
-use 0x1::enum_option;
use 0x1::error;
use 0x1::math64;
+use 0x1::mem;
use 0x1::option;
use 0x1::ordered_map;
use 0x1::storage_slots_allocator;
+use 0x1::vector;
@@ -103,12 +107,6 @@ So Leaf node contains multiple values, not just one.
parent: storage_slots_allocator::RefToSlot
-children: ordered_map::OrderedMap<K, big_ordered_map::Child<V>>
@@ -290,7 +288,13 @@ The BigOrderedMap data structure.
root_index: storage_slots_allocator::StoredSlot
+root: big_ordered_map::Node<K, V>
+root_index: storage_slots_allocator::RefToSlot
public fun new<K: store, V: store>(): BigOrderedMap<K, V> {
- new_with_config(0, 0, true, false, 0)
+ new_with_config(0, 0, false, 0)
}
@@ -489,7 +493,7 @@ Returns a new BigOrderedMap with the provided max degree consts (the maximum # o
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, root_inline: bool, reuse_slots: bool, num_to_preallocate: u32): big_ordered_map::BigOrderedMap<K, V>
+public fun new_with_config<K: store, V: store>(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool, num_to_preallocate: u32): big_ordered_map::BigOrderedMap<K, V>
@@ -498,17 +502,17 @@ If 0 is passed, then it is dynamically computed based on size of first key and v
Implementation
-public fun new_with_config<K: store, V: store>(inner_max_degree: u16, leaf_max_degree: u16, root_inline: bool, reuse_slots: bool, num_to_preallocate: u32): BigOrderedMap<K, V> {
+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!(reuse_slots || num_to_preallocate == 0, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
- let nodes = storage_slots_allocator::new(storage_slots_allocator::new_config(root_inline, reuse_slots, num_to_preallocate));
+ let nodes = storage_slots_allocator::new(storage_slots_allocator::new_config(reuse_slots, num_to_preallocate));
- let root_slot = nodes.add(new_node(/*is_leaf=*/true, /*parent=*/storage_slots_allocator::null_ref()));
- let root_ref = root_slot.stored_as_ref();
+ let root_ref = storage_slots_allocator::special_ref();
let self = BigOrderedMap::BPlusTreeMap {
- root_index: root_slot,
+ root: new_node(/*is_leaf=*/true),
+ root_index: root_ref,
nodes: nodes,
min_leaf_index: root_ref,
max_leaf_index: root_ref,
@@ -542,8 +546,8 @@ Destroys the map if it's empty, otherwise aborts.
public fun destroy_empty<K: store, V: store>(self: BigOrderedMap<K, V>) {
- let BigOrderedMap::BPlusTreeMap { nodes, root_index, min_leaf_index: _, max_leaf_index: _, constant_kv_size: _, inner_max_degree: _, leaf_max_degree: _ } = self;
- nodes.remove(root_index).destroy_empty_node();
+ let BigOrderedMap::BPlusTreeMap { root, nodes, root_index: _, min_leaf_index: _, max_leaf_index: _, constant_kv_size: _, inner_max_degree: _, leaf_max_degree: _ } = self;
+ root.destroy_empty_node();
nodes.destroy();
}
@@ -586,7 +590,7 @@ If the key doesn't exist in the map, inserts the key/value, and returns none.
Otherwise updates the value under the given key, and returns the old value.
-public fun upsert<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V): enum_option::Option<V>
+public fun upsert<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V): option::Option<V>
@@ -631,12 +635,13 @@ Aborts if there is no entry for key
.
public fun remove<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, key: &K): V {
- let leaf = self.find_leaf(key);
- assert!(!leaf.ref_is_null(), error::invalid_argument(EKEY_NOT_FOUND));
+ let path_to_leaf = self.find_leaf_with_path(key);
+
+ assert!(!path_to_leaf.is_empty(), error::invalid_argument(EKEY_NOT_FOUND));
let Child::Leaf {
value,
- } = self.remove_at(leaf, key);
+ } = self.remove_at(path_to_leaf, key);
value
}
@@ -669,7 +674,7 @@ key, or an end iterator if such element doesn't exist.
return self.new_end_iter()
};
- let node = self.nodes.borrow(leaf);
+ 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);
@@ -771,7 +776,7 @@ Returns a reference to the element with its key, aborts if the key is not found.
let iter = self.find(&key);
assert!(iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
- let children = &self.nodes.borrow(iter.node_index).children;
+ let children = &self.borrow_node(iter.node_index).children;
&iter.child_iter.iter_borrow(children).value
}
@@ -801,7 +806,7 @@ Return the begin iterator.
return Iterator::End;
};
- let node = self.nodes.borrow(self.min_leaf_index);
+ 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);
@@ -937,7 +942,7 @@ Requires the map is not changed after the input iterator is generated.
assert!(!(self is Iterator::End<K>), error::invalid_argument(EITER_OUT_OF_BOUNDS));
let node_index = self.node_index;
- let node = map.nodes.borrow(node_index);
+ let node = map.borrow_node(node_index);
let child_iter = self.child_iter.iter_next(&node.children);
if (!child_iter.iter_is_end(&node.children)) {
@@ -947,7 +952,7 @@ Requires the map is not changed after the input iterator is generated.
let next_index = node.next;
if (!next_index.ref_is_null()) {
- let next_node = map.nodes.borrow(next_index);
+ let next_node = map.borrow_node(next_index);
let child_iter = next_node.children.new_begin_iter();
assert!(!child_iter.iter_is_end(&next_node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
@@ -985,7 +990,7 @@ Requires the map is not changed after the input iterator is generated.
map.max_leaf_index
} else {
let node_index = self.node_index;
- let node = map.nodes.borrow(node_index);
+ let node = map.borrow_node(node_index);
if (!self.child_iter.iter_is_begin(&node.children)) {
let child_iter = self.child_iter.iter_prev(&node.children);
@@ -997,7 +1002,7 @@ Requires the map is not changed after the input iterator is generated.
assert!(!prev_index.ref_is_null(), error::invalid_argument(EITER_OUT_OF_BOUNDS));
- let prev_node = map.nodes.borrow(prev_index);
+ 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);
@@ -1008,6 +1013,62 @@ Requires the map is not changed after the input iterator is generated.
+
+
+
+
+## Function `borrow_node`
+
+
+
+fun borrow_node<K: store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, node: storage_slots_allocator::RefToSlot): &big_ordered_map::Node<K, V>
+
+
+
+
+
+Implementation
+
+
+inline fun borrow_node<K: store, V: store>(self: &BigOrderedMap<K, V>, node: RefToSlot): &Node<K, V> {
+ if (self.root_index == node) {
+ &self.root
+ } else {
+ self.nodes.borrow(node)
+ }
+}
+
+
+
+
+
+
+
+
+## Function `borrow_node_mut`
+
+
+
+fun borrow_node_mut<K: store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, node: storage_slots_allocator::RefToSlot): &mut big_ordered_map::Node<K, V>
+
+
+
+
+
+Implementation
+
+
+inline fun borrow_node_mut<K: store, V: store>(self: &mut BigOrderedMap<K, V>, node: RefToSlot): &mut Node<K, V> {
+ if (self.root_index == node) {
+ &mut self.root
+ } else {
+ self.nodes.borrow_mut(node)
+ }
+}
+
+
+
+
@@ -1016,7 +1077,7 @@ Requires the map is not changed after the input iterator is generated.
-fun add_or_upsert_impl<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V, allow_overwrite: bool): enum_option::Option<big_ordered_map::Child<V>>
+fun add_or_upsert_impl<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, key: K, value: V, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
@@ -1030,22 +1091,29 @@ Requires the map is not changed after the input iterator is generated.
self.validate_dynamic_size_and_init_max_degrees(&key, &value);
};
- let leaf = self.find_leaf(&key);
+ let path_to_leaf = self.find_leaf_with_path(&key);
- if (leaf.ref_is_null()) {
+ if (path_to_leaf.is_empty()) {
// In this case, the key is greater than all keys in the map.
- leaf = self.max_leaf_index;
- let current = self.nodes.borrow(leaf).parent;
- while (!current.ref_is_null()) {
- let current_node = self.nodes.borrow_mut(current);
+ let current = self.root_index;
+
+ loop {
+ path_to_leaf.push_back(current);
+
+ let current_node = self.borrow_node_mut(current);
+ 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);
+ current = last_value.node_index.stored_as_ref();
current_node.children.add(key, last_value);
- current = current_node.parent;
- }
+ };
};
- self.add_at(leaf, key, new_leaf_child(value), allow_overwrite)
+ // aptos_std::debug::print(&std::string::utf8(b"add_or_upsert_impl::path_to_leaf"));
+ // aptos_std::debug::print(&path_to_leaf);
+ self.add_at(path_to_leaf, key, new_leaf_child(value), allow_overwrite)
}
@@ -1188,7 +1256,7 @@ Requires the map is not changed after the input iterator is generated.
fun destroy_empty_node<K: store, V: store>(self: Node<K, V>) {
- let Node { children, is_leaf: _, parent: _, prev: _, next: _ } = self;
+ let Node { children, is_leaf: _, prev: _, next: _ } = self;
assert!(children.is_empty(), error::invalid_argument(EMAP_NOT_EMPTY));
children.destroy_empty();
}
@@ -1204,7 +1272,7 @@ Requires the map is not changed after the input iterator is generated.
-fun new_node<K: store, V: store>(is_leaf: bool, parent: storage_slots_allocator::RefToSlot): big_ordered_map::Node<K, V>
+fun new_node<K: store, V: store>(is_leaf: bool): big_ordered_map::Node<K, V>
@@ -1213,10 +1281,9 @@ Requires the map is not changed after the input iterator is generated.
Implementation
-fun new_node<K: store, V: store>(is_leaf: bool, parent: RefToSlot): Node<K, V> {
+fun new_node<K: store, V: store>(is_leaf: bool): Node<K, V> {
Node {
is_leaf: is_leaf,
- parent: parent,
children: ordered_map::new(),
prev: storage_slots_allocator::null_ref(),
next: storage_slots_allocator::null_ref(),
@@ -1234,7 +1301,7 @@ Requires the map is not changed after the input iterator is generated.
-fun new_node_with_children<K: store, V: store>(is_leaf: bool, parent: storage_slots_allocator::RefToSlot, children: ordered_map::OrderedMap<K, big_ordered_map::Child<V>>): big_ordered_map::Node<K, V>
+fun new_node_with_children<K: store, V: store>(is_leaf: bool, children: ordered_map::OrderedMap<K, big_ordered_map::Child<V>>): big_ordered_map::Node<K, V>
@@ -1243,10 +1310,9 @@ Requires the map is not changed after the input iterator is generated.
Implementation
-fun new_node_with_children<K: store, V: store>(is_leaf: bool, parent: RefToSlot, children: OrderedMap<K, Child<V>>): Node<K, V> {
+fun new_node_with_children<K: store, V: store>(is_leaf: bool, children: OrderedMap<K, Child<V>>): Node<K, V> {
Node {
is_leaf: is_leaf,
- parent: parent,
children: children,
prev: storage_slots_allocator::null_ref(),
next: storage_slots_allocator::null_ref(),
@@ -1354,9 +1420,9 @@ Requires the map is not changed after the input iterator is generated.
fun find_leaf<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): RefToSlot {
- let current = self.root_index.stored_as_ref();
+ let current = self.root_index;
while (!current.ref_is_null()) {
- let node = self.nodes.borrow(current);
+ let node = self.borrow_node(current);
if (node.is_leaf) {
return current;
};
@@ -1375,6 +1441,49 @@ Requires the map is not changed after the input iterator is generated.
+
+
+
+
+## Function `find_leaf_with_path`
+
+
+
+fun find_leaf_with_path<K: copy, drop, store, V: store>(self: &big_ordered_map::BigOrderedMap<K, V>, key: &K): vector<storage_slots_allocator::RefToSlot>
+
+
+
+
+
+Implementation
+
+
+fun find_leaf_with_path<K: drop + copy + store, V: store>(self: &BigOrderedMap<K, V>, key: &K): vector<RefToSlot> {
+ let vec = vector::empty();
+
+ let current = self.root_index;
+ while (!current.ref_is_null()) {
+ vec.push_back(current);
+
+ let node = self.borrow_node(current);
+ if (node.is_leaf) {
+ return vec;
+ };
+ let children = &node.children;
+ let child_iter = children.lower_bound(key);
+ if (child_iter.iter_is_end(children)) {
+ return vector::empty();
+ } else {
+ current = child_iter.iter_borrow(children).node_index.stored_as_ref();
+ }
+ };
+
+ abort error::invalid_state(EINTERNAL_INVARIANT_BROKEN)
+}
+
+
+
+
@@ -1411,7 +1520,7 @@ Requires the map is not changed after the input iterator is generated.
-fun add_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, node_index: storage_slots_allocator::RefToSlot, key: K, child: big_ordered_map::Child<V>, allow_overwrite: bool): enum_option::Option<big_ordered_map::Child<V>>
+fun add_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<storage_slots_allocator::RefToSlot>, key: K, child: big_ordered_map::Child<V>, allow_overwrite: bool): option::Option<big_ordered_map::Child<V>>
@@ -1420,9 +1529,10 @@ Requires the map is not changed after the input iterator is generated.
Implementation
-fun add_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, node_index: RefToSlot, key: K, child: Child<V>, allow_overwrite: bool): Option<Child<V>> {
+fun add_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<RefToSlot>, key: K, child: Child<V>, allow_overwrite: bool): Option<Child<V>> {
+ let node_index = path_to_node.pop_back();
{
- let node = self.nodes.borrow_mut(node_index);
+ let node = self.borrow_node_mut(node_index);
let children = &mut node.children;
let current_size = children.length();
@@ -1453,52 +1563,51 @@ Requires the map is not changed after the input iterator is generated.
};
// # of children in the current node exceeds the threshold, need to split into two nodes.
- let (cur_node_slot, node) = self.nodes.remove_and_reserve(node_index);
- // aptos_std::debug::print(&std::string::utf8(b"node that needs to be split"));
- // aptos_std::debug::print(&node);
- move node_index;
- let is_leaf = node.is_leaf;
- let children = &mut node.children;
- let parent_index = &mut node.parent;
+ let (right_node_slot, node) = if (path_to_node.is_empty()) {
+ // If we are at the root, we need to move root node to become a child and have a new root node.
- let right_node_slot = if (parent_index.ref_is_null()) {
+ assert!(node_index == self.root_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
// aptos_std::debug::print(&std::string::utf8(b"changing root"));
// Splitting root now, need to create a new root.
// We keep root_index always the same
- let new_root_node = new_node(/*is_leaf=*/false, /*parent=*/storage_slots_allocator::null_ref());
+ let new_root_node = new_node<K, V>(/*is_leaf=*/false);
let (replacement_node_stored_slot, replacement_node_slot) = self.nodes.reserve_slot();
// aptos_std::debug::print(&replacement_node_slot);
- let max_element = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+ let root_children = &self.root.children;
+ let max_element = *root_children.new_end_iter().iter_prev(root_children).iter_borrow_key(root_children);
if (cmp::compare(&max_element, &key).is_less_than()) {
max_element = key;
};
new_root_node.children.add(max_element, new_inner_child(replacement_node_stored_slot));
// aptos_std::debug::print(&cur_node_slot);
- *parent_index = cur_node_slot.reserved_as_ref();
- self.nodes.fill_reserved_slot(cur_node_slot, new_root_node);
+ path_to_node.push_back(self.root_index);
+
+ let node = mem::replace(&mut self.root, new_root_node);
let replacement_ref = replacement_node_slot.reserved_as_ref();
- if (!is_leaf) {
- self.nodes.borrow_mut(child.node_index.stored_as_ref()).parent = replacement_ref;
- children.for_each_ref(|_key, child| {
- self.nodes.borrow_mut(child.node_index.stored_as_ref()).parent = replacement_ref;
- });
- } else {
+ if (node.is_leaf) {
self.min_leaf_index = replacement_ref;
self.max_leaf_index = replacement_ref;
};
- replacement_node_slot
+ (replacement_node_slot, node)
} else {
- cur_node_slot
+ let (cur_node_slot, node) = self.nodes.remove_and_reserve(node_index);
+ (cur_node_slot, node)
};
+ // aptos_std::debug::print(&std::string::utf8(b"node that needs to be split"));
+ // aptos_std::debug::print(&node);
+
+ move node_index;
+ let is_leaf = node.is_leaf;
+ let children = &mut node.children;
+
let right_node_ref = right_node_slot.reserved_as_ref();
- let parent_index = *parent_index;
let next = &mut node.next;
let prev = &mut node.prev;
@@ -1515,7 +1624,7 @@ Requires the map is not changed after the input iterator is generated.
assert!(children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
assert!(new_node_children.length() <= max_degree, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
- let right_node = new_node_with_children(is_leaf, parent_index, new_node_children);
+ let right_node = new_node_with_children(is_leaf, new_node_children);
let (left_node_stored_slot, left_node_slot) = self.nodes.reserve_slot();
let left_node_ref = left_node_stored_slot.stored_as_ref();
@@ -1526,12 +1635,6 @@ Requires the map is not changed after the input iterator is generated.
self.nodes.borrow_mut(*prev).next = left_node_ref;
};
- if (!is_leaf) {
- children.for_each_ref(|_key, child| {
- self.nodes.borrow_mut(child.node_index.stored_as_ref()).parent = left_node_ref;
- });
- };
-
let split_key = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
// aptos_std::debug::print(&std::string::utf8(b"creating right node"));
@@ -1548,7 +1651,7 @@ Requires the map is not changed after the input iterator is generated.
if (right_node_ref == self.min_leaf_index) {
self.min_leaf_index = left_node_ref;
};
- self.add_at(parent_index, split_key, new_inner_child(left_node_stored_slot), false).destroy_none();
+ self.add_at(path_to_node, split_key, new_inner_child(left_node_stored_slot), false).destroy_none();
option::none()
}
@@ -1563,7 +1666,7 @@ Requires the map is not changed after the input iterator is generated.
-fun update_key<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, node_index: storage_slots_allocator::RefToSlot, old_key: &K, new_key: K)
+fun update_key<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<storage_slots_allocator::RefToSlot>, old_key: &K, new_key: K)
@@ -1572,17 +1675,18 @@ Requires the map is not changed after the input iterator is generated.
Implementation
-fun update_key<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, node_index: RefToSlot, old_key: &K, new_key: K) {
- if (node_index.ref_is_null()) {
+fun update_key<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<RefToSlot>, old_key: &K, new_key: K) {
+ if (path_to_node.is_empty()) {
return
};
- let node = self.nodes.borrow_mut(node_index);
+ let node_index = path_to_node.pop_back();
+ let node = self.borrow_node_mut(node_index);
let children = &mut node.children;
children.replace_key_inplace(old_key, new_key);
if (children.new_end_iter().iter_prev(children).iter_borrow_key(children) == &new_key) {
- self.update_key(node.parent, old_key, new_key);
+ self.update_key(path_to_node, old_key, new_key);
};
}
@@ -1597,7 +1701,7 @@ Requires the map is not changed after the input iterator is generated.
-fun remove_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, node_index: storage_slots_allocator::RefToSlot, key: &K): big_ordered_map::Child<V>
+fun remove_at<K: copy, drop, store, V: store>(self: &mut big_ordered_map::BigOrderedMap<K, V>, path_to_node: vector<storage_slots_allocator::RefToSlot>, key: &K): big_ordered_map::Child<V>
@@ -1606,19 +1710,22 @@ Requires the map is not changed after the input iterator is generated.
Implementation
-fun remove_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, node_index: RefToSlot, key: &K): Child<V> {
+fun remove_at<K: drop + copy + store, V: store>(self: &mut BigOrderedMap<K, V>, path_to_node: vector<RefToSlot>, key: &K): Child<V> {
+ let node_index = path_to_node.pop_back();
let old_child = {
- let node = self.nodes.borrow_mut(node_index);
+ let node = self.borrow_node_mut(node_index);
let children = &mut node.children;
let is_leaf = node.is_leaf;
let old_child = children.remove(key);
- if (node_index == self.root_index.stored_as_ref()) {
- // promote only child to root, and drop current root.
- // keep the root index the same.
+ if (path_to_node.is_empty()) {
+ assert!(node_index == self.root_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+
if (!is_leaf && children.length() == 1) {
+ // promote only child to root, and drop current root.
+ // keep the root index the same.
let Child::Inner {
node_index: inner_child_index,
} = children.new_end_iter().iter_prev(children).iter_remove(children);
@@ -1626,21 +1733,13 @@ Requires the map is not changed after the input iterator is generated.
move node;
let inner_child = self.nodes.remove(inner_child_index);
- let root_ref = self.root_index.stored_as_ref();
if (inner_child.is_leaf) {
+ let root_ref = self.root_index;
self.min_leaf_index = root_ref;
self.max_leaf_index = root_ref;
- } else {
- inner_child.children.for_each_ref(|_key, child| {
- self.nodes.borrow_mut(child.node_index.stored_as_ref()).parent = root_ref;
- });
};
- inner_child.parent = storage_slots_allocator::null_ref();
-
- let (root_slot, root_value) = self.nodes.remove_and_reserve(node_index);
- destroy_empty_node(root_value);
- self.nodes.fill_reserved_slot(root_slot, inner_child);
+ mem::replace(&mut self.root, inner_child).destroy_empty_node();
}; // else: nothing to change
return old_child;
};
@@ -1663,9 +1762,7 @@ Requires the map is not changed after the input iterator is generated.
if (max_key_updated) {
assert!(current_size >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
- let parent = node.parent;
-
- self.update_key(parent, key, new_max_key);
+ self.update_key(path_to_node, key, new_max_key);
if (big_enough) {
return old_child;
@@ -1675,24 +1772,25 @@ Requires the map is not changed after the input iterator is generated.
old_child
};
- // We need to update map beyond the current node
+ // Children size is below threshold, we need to rebalance
let (node_slot, node) = self.nodes.remove_and_reserve(node_index);
- let prev = node.prev;
- let next = node.next;
- let parent = node.parent;
let is_leaf = node.is_leaf;
let max_degree = self.get_max_degree(is_leaf);
+ let prev = node.prev;
+ let next = node.next;
- let children = &mut node.children;
-
- // Children size is below threshold, we need to rebalance
-
- let brother_index = next;
- if (brother_index.ref_is_null() || self.nodes.borrow(brother_index).parent != parent) {
- brother_index = prev;
+ let brother_index = {
+ let parent_children = &self.nodes.borrow(*path_to_node.borrow(path_to_node.length() - 1)).children;
+ if (parent_children.new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_as_ref() == node_index) {
+ prev
+ } else {
+ next
+ }
};
+
+ let children = &mut node.children;
let (brother_slot, brother_node) = self.nodes.remove_and_reserve(brother_index);
let brother_children = &mut brother_node.children;
@@ -1704,23 +1802,16 @@ Requires the map is not changed after the input iterator is generated.
let brother_begin_iter = brother_children.new_begin_iter();
let borrowed_max_key = *brother_begin_iter.iter_borrow_key(brother_children);
let borrowed_element = brother_begin_iter.iter_remove(brother_children);
- if (borrowed_element is Child::Inner<V>) {
- self.nodes.borrow_mut(borrowed_element.node_index.stored_as_ref()).parent = node_index;
- };
children.add(borrowed_max_key, borrowed_element);
- self.update_key(parent, &old_max_key, borrowed_max_key);
+ self.update_key(path_to_node, &old_max_key, borrowed_max_key);
} else {
let brother_end_iter = brother_children.new_end_iter().iter_prev(brother_children);
let borrowed_max_key = *brother_end_iter.iter_borrow_key(brother_children);
let borrowed_element = brother_end_iter.iter_remove(brother_children);
- if (borrowed_element is Child::Inner<V>) {
- self.nodes.borrow_mut(borrowed_element.node_index.stored_as_ref()).parent = node_index;
- };
-
children.add(borrowed_max_key, borrowed_element);
- self.update_key(parent, &borrowed_max_key, *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children));
+ self.update_key(path_to_node, &borrowed_max_key, *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children));
};
self.nodes.fill_reserved_slot(node_slot, node);
@@ -1730,12 +1821,7 @@ Requires the map is not changed after the input iterator is generated.
// The brother node doesn't have enough elements to borrow, merge with the brother node.
if (brother_index == next) {
- if (!is_leaf) {
- children.for_each_ref(|_key, child| {
- self.nodes.borrow_mut(child.node_index.stored_as_ref()).parent = brother_index;
- });
- };
- let Node { children: brother_children, is_leaf: _, parent: _, prev: _, next: brother_next } = brother_node;
+ let Node { children: brother_children, is_leaf: _, prev: _, next: brother_next } = brother_node;
let key_to_remove = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
children.append(brother_children);
node.next = brother_next;
@@ -1755,17 +1841,11 @@ Requires the map is not changed after the input iterator is generated.
self.min_leaf_index = brother_index;
};
- assert!(!parent.ref_is_null(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
- let node_stored_slot = destroy_inner_child(self.remove_at(parent, &key_to_remove));
+ assert!(!path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+ let node_stored_slot = destroy_inner_child(self.remove_at(path_to_node, &key_to_remove));
self.nodes.free_reserved_slot(node_slot, node_stored_slot);
} else {
- if (!is_leaf) {
- brother_children.for_each_ref(|_key, child| {
- self.nodes.borrow_mut(child.node_index.stored_as_ref()).parent = node_index;
- });
- };
-
- let Node { children: node_children, is_leaf: _, parent: _, prev: _, next: node_next } = node;
+ let Node { children: node_children, is_leaf: _, prev: _, next: node_next } = node;
let key_to_remove = *brother_children.new_end_iter().iter_prev(brother_children).iter_borrow_key(brother_children);
brother_children.append(node_children);
brother_node.next = node_next;
@@ -1785,8 +1865,8 @@ Requires the map is not changed after the input iterator is generated.
self.min_leaf_index = node_index;
};
- assert!(!parent.ref_is_null(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
- let node_stored_slot = destroy_inner_child(self.remove_at(parent, &key_to_remove));
+ assert!(!path_to_node.is_empty(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+ let node_stored_slot = destroy_inner_child(self.remove_at(path_to_node, &key_to_remove));
self.nodes.free_reserved_slot(brother_slot, node_stored_slot);
};
old_child
@@ -1814,7 +1894,7 @@ Returns the number of elements in the BigOrderedMap.
fun length<K: store, V: store>(self: &BigOrderedMap<K, V>): u64 {
- self.length_for_node(self.root_index.stored_as_ref())
+ self.length_for_node(self.root_index)
}
@@ -1838,7 +1918,7 @@ Returns the number of elements in the BigOrderedMap.
fun length_for_node<K: store, V: store>(self: &BigOrderedMap<K, V>, node_index: RefToSlot): u64 {
- let node = self.nodes.borrow(node_index);
+ let node = self.borrow_node(node_index);
if (node.is_leaf) {
node.children.length()
} else {
@@ -1873,7 +1953,7 @@ Returns true iff the BigOrderedMap is empty.
fun is_empty<K: store, V: store>(self: &BigOrderedMap<K, V>): bool {
- let node = self.nodes.borrow(self.min_leaf_index);
+ let node = self.borrow_node(self.min_leaf_index);
node.children.is_empty()
}
diff --git a/aptos-move/framework/aptos-stdlib/doc/ordered_map.md b/aptos-move/framework/aptos-stdlib/doc/ordered_map.md
index 2ffe03c58f818..1693211539641 100644
--- a/aptos-move/framework/aptos-stdlib/doc/ordered_map.md
+++ b/aptos-move/framework/aptos-stdlib/doc/ordered_map.md
@@ -67,9 +67,9 @@ lexicographical sorting for complex types.
use 0x1::cmp;
-use 0x1::enum_option;
use 0x1::error;
use 0x1::mem;
+use 0x1::option;
use 0x1::vector;
@@ -393,7 +393,7 @@ If the key doesn't exist in the map, inserts the key/value, and returns none.
Otherwise, updates the value under the given key, and returns the old value.
-public fun upsert<K: drop, V>(self: &mut ordered_map::OrderedMap<K, V>, key: K, value: V): enum_option::Option<V>
+public fun upsert<K: drop, V>(self: &mut ordered_map::OrderedMap<K, V>, key: K, value: V): option::Option<V>
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 9c05859611ae7..d14846eac6b27 100644
--- a/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md
+++ b/aptos-move/framework/aptos-stdlib/doc/storage_slots_allocator.md
@@ -11,14 +11,13 @@ Allows optionally to initialize slots (and pay for them upfront), and then reuse
providing predictable storage costs.
If we need to mutate multiple slots at the same time, we can workaround borrow_mut preventing us from that,
-via provided pair of transiently_remove
and add_transient_slot
methods, to do so in non-conflicting manner.
+via provided pair of remove_and_reserve
and fill_reserved_slot
methods, to do so in non-conflicting manner.
-Similarly allows getting an address upfront via create_transient_slot
, for a slot created
+Similarly allows getting an address upfront via reserve_slot
, for a slot created
later (i.e. if we need address to initialize the value itself).
In the future, more sophisticated strategies can be added, without breaking/modifying callers,
for example:
-* having one slot embeded into the struct itself
* having a fee-payer for any storage creation operations
@@ -29,8 +28,6 @@ for example:
- [Struct `StoredSlot`](#0x1_storage_slots_allocator_StoredSlot)
- [Struct `RefToSlot`](#0x1_storage_slots_allocator_RefToSlot)
- [Constants](#@Constants_0)
-- [Function `null_ref`](#0x1_storage_slots_allocator_null_ref)
-- [Function `ref_is_null`](#0x1_storage_slots_allocator_ref_is_null)
- [Function `new`](#0x1_storage_slots_allocator_new)
- [Function `new_default_config`](#0x1_storage_slots_allocator_new_default_config)
- [Function `new_config`](#0x1_storage_slots_allocator_new_config)
@@ -39,12 +36,15 @@ for example:
- [Function `destroy`](#0x1_storage_slots_allocator_destroy)
- [Function `borrow`](#0x1_storage_slots_allocator_borrow)
- [Function `borrow_mut`](#0x1_storage_slots_allocator_borrow_mut)
-- [Function `reserved_as_ref`](#0x1_storage_slots_allocator_reserved_as_ref)
-- [Function `stored_as_ref`](#0x1_storage_slots_allocator_stored_as_ref)
- [Function `reserve_slot`](#0x1_storage_slots_allocator_reserve_slot)
- [Function `fill_reserved_slot`](#0x1_storage_slots_allocator_fill_reserved_slot)
- [Function `remove_and_reserve`](#0x1_storage_slots_allocator_remove_and_reserve)
- [Function `free_reserved_slot`](#0x1_storage_slots_allocator_free_reserved_slot)
+- [Function `reserved_as_ref`](#0x1_storage_slots_allocator_reserved_as_ref)
+- [Function `stored_as_ref`](#0x1_storage_slots_allocator_stored_as_ref)
+- [Function `null_ref`](#0x1_storage_slots_allocator_null_ref)
+- [Function `special_ref`](#0x1_storage_slots_allocator_special_ref)
+- [Function `ref_is_null`](#0x1_storage_slots_allocator_ref_is_null)
- [Function `maybe_pop_from_reuse_queue`](#0x1_storage_slots_allocator_maybe_pop_from_reuse_queue)
- [Function `maybe_push_to_reuse_queue`](#0x1_storage_slots_allocator_maybe_push_to_reuse_queue)
- [Function `next_slot_index`](#0x1_storage_slots_allocator_next_slot_index)
@@ -52,7 +52,7 @@ for example:
- [Function `remove_link`](#0x1_storage_slots_allocator_remove_link)
-use 0x1::enum_option;
+use 0x1::option;
use 0x1::table;
@@ -62,6 +62,7 @@ for example:
## Enum `Link`
+Data stored in an individual slot
enum Link<T: store> has store
@@ -144,12 +145,6 @@ for example:
-
-
should_inline: bool
-
--
-
-
--
should_reuse: bool
-
@@ -195,7 +190,7 @@ for example:
-
-
slots: enum_option::Option<table::Table<u64, storage_slots_allocator::Link<T>>>
+slots: option::Option<table::Table<u64, storage_slots_allocator::Link<T>>>
-
@@ -223,12 +218,6 @@ for example:
-
-
- -
-
inline_slot: enum_option::Option<storage_slots_allocator::Link<T>>
-
--
-
@@ -243,6 +232,9 @@ for example:
## Struct `ReservedSlot`
+Handle to a reserved slot within a transaction.
+Not copy/drop/store-able, to guarantee reservation
+is used or released within the transaction.
struct ReservedSlot
@@ -270,6 +262,9 @@ for example:
## Struct `StoredSlot`
+Ownership handle to a slot.
+Not copy/drop-able to make sure slots are released when not needed,
+and there is unique owner for each slot.
struct StoredSlot has store
@@ -297,6 +292,9 @@ for example:
## Struct `RefToSlot`
+(Weak) Reference to a slot.
+We can have variety of RefToSlot
, but only a single StoredSlot
.
+It is on the caller to make sure references are not used after slot is freed.
struct RefToSlot has copy, drop, store
@@ -352,15 +350,6 @@ for example:
-
-
-
-
-const INLINE_SLOT_INDEX: u64 = 1;
-
-
-
-
@@ -370,54 +359,15 @@ for example:
-
-
-## Function `null_ref`
-
-
-
-public fun null_ref(): storage_slots_allocator::RefToSlot
-
-
-
-
-
-Implementation
-
-
-public fun null_ref(): RefToSlot {
- RefToSlot { slot_index: NULL_INDEX }
-}
-
-
-
-
-
-
-
-
-## Function `ref_is_null`
-
-
-
-public fun ref_is_null(self: &storage_slots_allocator::RefToSlot): bool
-
-
-
+
-
-Implementation
-public fun ref_is_null(self: &RefToSlot): bool {
- self.slot_index == NULL_INDEX
-}
+const SPECIAL_SLOT_INDEX: u64 = 1;
-
-
## Function `new`
@@ -440,7 +390,6 @@ for example:
should_reuse: config.should_reuse,
reuse_head_index: NULL_INDEX,
reuse_spare_count: 0,
- inline_slot: option::none(),
};
for (i in 0..config.num_to_preallocate) {
@@ -448,10 +397,6 @@ for example:
result.maybe_push_to_reuse_queue(slot_index);
};
- if (config.should_inline) {
- result.maybe_push_to_reuse_queue(INLINE_SLOT_INDEX);
- };
-
result
}
@@ -477,7 +422,6 @@ for example:
public fun new_default_config(): StorageSlotsAllocatorConfig {
StorageSlotsAllocatorConfig::V1 {
- should_inline: true,
should_reuse: false,
num_to_preallocate: 0,
}
@@ -494,7 +438,7 @@ for example:
-public fun new_config(should_inline: bool, should_reuse: bool, num_to_preallocate: u32): storage_slots_allocator::StorageSlotsAllocatorConfig
+public fun new_config(should_reuse: bool, num_to_preallocate: u32): storage_slots_allocator::StorageSlotsAllocatorConfig
@@ -503,9 +447,8 @@ for example:
Implementation
-public fun new_config(should_inline: bool, should_reuse: bool, num_to_preallocate: u32): StorageSlotsAllocatorConfig {
+public fun new_config(should_reuse: bool, num_to_preallocate: u32): StorageSlotsAllocatorConfig {
StorageSlotsAllocatorConfig::V1 {
- should_inline,
should_reuse,
num_to_preallocate,
}
@@ -535,23 +478,6 @@ for example:
let (stored_slot, reserved_slot) = self.reserve_slot();
self.fill_reserved_slot(reserved_slot, val);
stored_slot
-
- // if (self.should_inline && self.inline_slot.is_none()) {
- // self.inline_slot.fill(val);
- // return INLINE_SLOT_INDEX;
- // }
-
- // if (self.should_reuse) {
- // let slot_index = self.maybe_pop_from_reuse_queue();
- // if (slot_index != NULL_INDEX) {
- // self.slots.borrow_mut().add(slot_index, Link::Occupied { value: val });
- // return StoredSlot { slot_index };
- // };
- // };
-
- // let slot_index = self.next_slot_index();
- // self.slots.borrow_mut().add(slot_index, Link::Occupied { value: val });
- // StoredSlot { slot_index }
}
@@ -578,15 +504,6 @@ for example:
let (reserved_slot, value) = self.remove_and_reserve(slot.stored_as_ref());
self.free_reserved_slot(reserved_slot, slot);
value
-
- // let StoredSlot { slot_index } = slot;
- // if (slot_index == INLINE_SLOT_INDEX) {
- // return self.inline_slot.extract();
- // };
-
- // let Link::Occupied { value } = self.slots.borrow_mut().remove(slot_index);
- // self.maybe_push_to_reuse_queue(slot_index);
- // value
}
@@ -623,9 +540,7 @@ for example:
should_reuse: _,
reuse_head_index,
reuse_spare_count: _,
- inline_slot,
} => {
- inline_slot.destroy_none();
assert!(reuse_head_index == NULL_INDEX, EINTERNAL_INVARIANT_BROKEN);
slots.destroy_some().destroy();
},
@@ -653,13 +568,7 @@ for example:
public fun borrow<T: store>(self: &StorageSlotsAllocator<T>, slot: RefToSlot): &T {
- let slot_index = slot.slot_index;
-
- if (slot_index == INLINE_SLOT_INDEX) {
- return &self.inline_slot.borrow().value;
- };
-
- &self.slots.borrow().borrow(slot_index).value
+ &self.slots.borrow().borrow(slot.slot_index).value
}
@@ -683,12 +592,39 @@ for example:
public fun borrow_mut<T: store>(self: &mut StorageSlotsAllocator<T>, slot: RefToSlot): &mut T {
- let slot_index = slot.slot_index;
- if (slot_index == INLINE_SLOT_INDEX) {
- return &mut self.inline_slot.borrow_mut().value;
+ &mut self.slots.borrow_mut().borrow_mut(slot.slot_index).value
+}
+
+
+
+
+
+
+
+
+## Function `reserve_slot`
+
+
+
+public fun reserve_slot<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>): (storage_slots_allocator::StoredSlot, storage_slots_allocator::ReservedSlot)
+
+
+
+
+
+Implementation
+
+
+public fun reserve_slot<T: store>(self: &mut StorageSlotsAllocator<T>): (StoredSlot, ReservedSlot) {
+ let slot_index = self.maybe_pop_from_reuse_queue();
+ if (slot_index == NULL_INDEX) {
+ slot_index = self.next_slot_index();
};
- &mut self.slots.borrow_mut().borrow_mut(slot_index).value
+ (
+ StoredSlot { slot_index },
+ ReservedSlot { slot_index },
+ )
}
@@ -696,13 +632,13 @@ for example:
-
+
-## Function `reserved_as_ref`
+## Function `fill_reserved_slot`
-public fun reserved_as_ref(self: &storage_slots_allocator::ReservedSlot): storage_slots_allocator::RefToSlot
+public fun fill_reserved_slot<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, slot: storage_slots_allocator::ReservedSlot, val: T)
@@ -711,8 +647,9 @@ for example:
Implementation
-public fun reserved_as_ref(self: &ReservedSlot): RefToSlot {
- RefToSlot { slot_index: self.slot_index }
+public fun fill_reserved_slot<T: store>(self: &mut StorageSlotsAllocator<T>, slot: ReservedSlot, val: T) {
+ let ReservedSlot { slot_index } = slot;
+ self.add_link(slot_index, Link::Occupied { value: val });
}
@@ -720,13 +657,14 @@ for example:
-
+
-## Function `stored_as_ref`
+## Function `remove_and_reserve`
+Remove storage slot, but reserve it for later.
-public fun stored_as_ref(self: &storage_slots_allocator::StoredSlot): storage_slots_allocator::RefToSlot
+public fun remove_and_reserve<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, slot: storage_slots_allocator::RefToSlot): (storage_slots_allocator::ReservedSlot, T)
@@ -735,8 +673,10 @@ for example:
Implementation
-public fun stored_as_ref(self: &StoredSlot): RefToSlot {
- RefToSlot { slot_index: self.slot_index }
+public fun remove_and_reserve<T: store>(self: &mut StorageSlotsAllocator<T>, slot: RefToSlot): (ReservedSlot, T) {
+ let slot_index = slot.slot_index;
+ let Link::Occupied { value } = self.remove_link(slot_index);
+ (ReservedSlot { slot_index }, value)
}
@@ -744,13 +684,13 @@ for example:
-
+
-## Function `reserve_slot`
+## Function `free_reserved_slot`
-public fun reserve_slot<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>): (storage_slots_allocator::StoredSlot, storage_slots_allocator::ReservedSlot)
+public fun free_reserved_slot<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, reserved_slot: storage_slots_allocator::ReservedSlot, stored_slot: storage_slots_allocator::StoredSlot)
@@ -759,16 +699,35 @@ for example:
Implementation
-public fun reserve_slot<T: store>(self: &mut StorageSlotsAllocator<T>): (StoredSlot, ReservedSlot) {
- let slot_index = self.maybe_pop_from_reuse_queue();
- if (slot_index == NULL_INDEX) {
- slot_index = self.next_slot_index();
- };
+public fun free_reserved_slot<T: store>(self: &mut StorageSlotsAllocator<T>, reserved_slot: ReservedSlot, stored_slot: StoredSlot) {
+ let ReservedSlot { slot_index } = reserved_slot;
+ assert!(slot_index == stored_slot.slot_index, EINVALID_ARGUMENT);
+ let StoredSlot { slot_index: _ } = stored_slot;
+ self.maybe_push_to_reuse_queue(slot_index);
+}
+
- (
- StoredSlot { slot_index },
- ReservedSlot { slot_index },
- )
+
+
+
+
+
+
+## Function `reserved_as_ref`
+
+
+
+public fun reserved_as_ref(self: &storage_slots_allocator::ReservedSlot): storage_slots_allocator::RefToSlot
+
+
+
+
+
+Implementation
+
+
+public fun reserved_as_ref(self: &ReservedSlot): RefToSlot {
+ RefToSlot { slot_index: self.slot_index }
}
@@ -776,13 +735,13 @@ for example:
-
+
-## Function `fill_reserved_slot`
+## Function `stored_as_ref`
-public fun fill_reserved_slot<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, slot: storage_slots_allocator::ReservedSlot, val: T)
+public fun stored_as_ref(self: &storage_slots_allocator::StoredSlot): storage_slots_allocator::RefToSlot
@@ -791,9 +750,8 @@ for example:
Implementation
-public fun fill_reserved_slot<T: store>(self: &mut StorageSlotsAllocator<T>, slot: ReservedSlot, val: T) {
- let ReservedSlot { slot_index } = slot;
- self.add_link(slot_index, Link::Occupied { value: val });
+public fun stored_as_ref(self: &StoredSlot): RefToSlot {
+ RefToSlot { slot_index: self.slot_index }
}
@@ -801,14 +759,13 @@ for example:
-
+
-## Function `remove_and_reserve`
+## Function `null_ref`
-Remove storage slot, but reserve it for later.
-public fun remove_and_reserve<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, slot: storage_slots_allocator::RefToSlot): (storage_slots_allocator::ReservedSlot, T)
+public fun null_ref(): storage_slots_allocator::RefToSlot
@@ -817,10 +774,8 @@ Remove storage slot, but reserve it for later.
Implementation
-public fun remove_and_reserve<T: store>(self: &mut StorageSlotsAllocator<T>, slot: RefToSlot): (ReservedSlot, T) {
- let slot_index = slot.slot_index;
- let Link::Occupied { value } = self.remove_link(slot_index);
- (ReservedSlot { slot_index }, value)
+public fun null_ref(): RefToSlot {
+ RefToSlot { slot_index: NULL_INDEX }
}
@@ -828,13 +783,13 @@ Remove storage slot, but reserve it for later.
-
+
-## Function `free_reserved_slot`
+## Function `special_ref`
-public fun free_reserved_slot<T: store>(self: &mut storage_slots_allocator::StorageSlotsAllocator<T>, reserved_slot: storage_slots_allocator::ReservedSlot, stored_slot: storage_slots_allocator::StoredSlot)
+public fun special_ref(): storage_slots_allocator::RefToSlot
@@ -843,11 +798,32 @@ Remove storage slot, but reserve it for later.
Implementation
-public fun free_reserved_slot<T: store>(self: &mut StorageSlotsAllocator<T>, reserved_slot: ReservedSlot, stored_slot: StoredSlot) {
- let ReservedSlot { slot_index } = reserved_slot;
- assert!(slot_index == stored_slot.slot_index, EINVALID_ARGUMENT);
- let StoredSlot { slot_index: _ } = stored_slot;
- self.maybe_push_to_reuse_queue(slot_index);
+public fun special_ref(): RefToSlot {
+ RefToSlot { slot_index: SPECIAL_SLOT_INDEX }
+}
+
+
+
+
+
+
+
+
+## Function `ref_is_null`
+
+
+
+public fun ref_is_null(self: &storage_slots_allocator::RefToSlot): bool
+
+
+
+
+
+Implementation
+
+
+public fun ref_is_null(self: &RefToSlot): bool {
+ self.slot_index == NULL_INDEX
}
@@ -901,7 +877,7 @@ Remove storage slot, but reserve it for later.
fun maybe_push_to_reuse_queue<T: store>(self: &mut StorageSlotsAllocator<T>, slot_index: u64) {
- if (self.should_reuse || slot_index == INLINE_SLOT_INDEX) {
+ if (self.should_reuse) {
self.add_link(slot_index, Link::Vacant { next: self.reuse_head_index });
self.reuse_head_index = slot_index;
self.reuse_spare_count = self.reuse_spare_count + 1;
@@ -958,11 +934,7 @@ Remove storage slot, but reserve it for later.
fun add_link<T: store>(self: &mut StorageSlotsAllocator<T>, slot_index: u64, link: Link<T>) {
- if (slot_index == INLINE_SLOT_INDEX) {
- self.inline_slot.fill(link)
- } else {
- self.slots.borrow_mut().add(slot_index, link);
- }
+ self.slots.borrow_mut().add(slot_index, link);
}
@@ -986,11 +958,7 @@ Remove storage slot, but reserve it for later.
fun remove_link<T: store>(self: &mut StorageSlotsAllocator<T>, slot_index: u64): Link<T> {
- if (slot_index == INLINE_SLOT_INDEX) {
- self.inline_slot.extract()
- } else {
- self.slots.borrow_mut().remove(slot_index)
- }
+ self.slots.borrow_mut().remove(slot_index)
}
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move b/aptos-move/framework/aptos-stdlib/sources/data_structures/big_ordered_map.move
index 052db187276b1..1680ac5fcc03e 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
@@ -17,8 +17,9 @@
module aptos_std::big_ordered_map {
use std::error;
use std::vector;
- use std::enum_option::{Self as option, Option};
+ use std::option::{Self as option, Option};
use std::bcs;
+ use std::mem;
use aptos_std::ordered_map::{Self, OrderedMap};
use aptos_std::cmp;
use aptos_std::storage_slots_allocator::{Self, StorageSlotsAllocator, StoredSlot, RefToSlot};
@@ -101,8 +102,9 @@ module aptos_std::big_ordered_map {
/// The BigOrderedMap data structure.
enum BigOrderedMap has store {
BPlusTreeMap {
+ root: Node,
/// The node index of the root node.
- root_index: StoredSlot,
+ root_index: RefToSlot,
/// Mapping of node_index -> node.
nodes: StorageSlotsAllocator>,
/// The node index of the leftmost node.
@@ -124,22 +126,22 @@ module aptos_std::big_ordered_map {
/// Returns a new BigOrderedMap with the default configuration.
public fun new(): BigOrderedMap {
- new_with_config(0, 0, true, false, 0)
+ new_with_config(0, 0, false, 0)
}
/// Returns a new BigOrderedMap with the provided max degree consts (the maximum # of children a node can have).
/// If 0 is passed, then it is dynamically computed based on size of first key and value.
- public fun new_with_config(inner_max_degree: u16, leaf_max_degree: u16, root_inline: bool, reuse_slots: bool, num_to_preallocate: u32): BigOrderedMap {
+ public fun new_with_config(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool, num_to_preallocate: u32): BigOrderedMap {
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!(reuse_slots || num_to_preallocate == 0, error::invalid_argument(EINVALID_CONFIG_PARAMETER));
- let nodes = storage_slots_allocator::new(storage_slots_allocator::new_config(root_inline, reuse_slots, num_to_preallocate));
+ let nodes = storage_slots_allocator::new(storage_slots_allocator::new_config(reuse_slots, num_to_preallocate));
- let root_slot = nodes.add(new_node(/*is_leaf=*/true));
- let root_ref = root_slot.stored_as_ref();
+ let root_ref = storage_slots_allocator::special_ref();
let self = BigOrderedMap::BPlusTreeMap {
- root_index: root_slot,
+ root: new_node(/*is_leaf=*/true),
+ root_index: root_ref,
nodes: nodes,
min_leaf_index: root_ref,
max_leaf_index: root_ref,
@@ -153,8 +155,8 @@ module aptos_std::big_ordered_map {
/// Destroys the map if it's empty, otherwise aborts.
public fun destroy_empty(self: BigOrderedMap) {
- let BigOrderedMap::BPlusTreeMap { nodes, root_index, min_leaf_index: _, max_leaf_index: _, constant_kv_size: _, inner_max_degree: _, leaf_max_degree: _ } = self;
- nodes.remove(root_index).destroy_empty_node();
+ let BigOrderedMap::BPlusTreeMap { root, nodes, root_index: _, min_leaf_index: _, max_leaf_index: _, constant_kv_size: _, inner_max_degree: _, leaf_max_degree: _ } = self;
+ root.destroy_empty_node();
nodes.destroy();
}
@@ -205,7 +207,7 @@ module aptos_std::big_ordered_map {
return self.new_end_iter()
};
- let node = self.nodes.borrow(leaf);
+ 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);
@@ -247,7 +249,7 @@ module aptos_std::big_ordered_map {
let iter = self.find(&key);
assert!(iter.iter_is_end(self), error::invalid_argument(EKEY_NOT_FOUND));
- let children = &self.nodes.borrow(iter.node_index).children;
+ let children = &self.borrow_node(iter.node_index).children;
&iter.child_iter.iter_borrow(children).value
}
@@ -269,7 +271,7 @@ module aptos_std::big_ordered_map {
return Iterator::End;
};
- let node = self.nodes.borrow(self.min_leaf_index);
+ 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);
@@ -307,7 +309,7 @@ module aptos_std::big_ordered_map {
assert!(!(self is Iterator::End), error::invalid_argument(EITER_OUT_OF_BOUNDS));
let node_index = self.node_index;
- let node = map.nodes.borrow(node_index);
+ let node = map.borrow_node(node_index);
let child_iter = self.child_iter.iter_next(&node.children);
if (!child_iter.iter_is_end(&node.children)) {
@@ -317,7 +319,7 @@ module aptos_std::big_ordered_map {
let next_index = node.next;
if (!next_index.ref_is_null()) {
- let next_node = map.nodes.borrow(next_index);
+ let next_node = map.borrow_node(next_index);
let child_iter = next_node.children.new_begin_iter();
assert!(!child_iter.iter_is_end(&next_node.children), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
@@ -335,7 +337,7 @@ module aptos_std::big_ordered_map {
map.max_leaf_index
} else {
let node_index = self.node_index;
- let node = map.nodes.borrow(node_index);
+ let node = map.borrow_node(node_index);
if (!self.child_iter.iter_is_begin(&node.children)) {
let child_iter = self.child_iter.iter_prev(&node.children);
@@ -347,7 +349,7 @@ module aptos_std::big_ordered_map {
assert!(!prev_index.ref_is_null(), error::invalid_argument(EITER_OUT_OF_BOUNDS));
- let prev_node = map.nodes.borrow(prev_index);
+ 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);
@@ -357,6 +359,22 @@ module aptos_std::big_ordered_map {
// ====================== Internal Implementations ========================
+ inline fun borrow_node(self: &BigOrderedMap, node: RefToSlot): &Node {
+ if (self.root_index == node) {
+ &self.root
+ } else {
+ self.nodes.borrow(node)
+ }
+ }
+
+ inline fun borrow_node_mut(self: &mut BigOrderedMap, node: RefToSlot): &mut Node {
+ if (self.root_index == node) {
+ &mut self.root
+ } else {
+ self.nodes.borrow_mut(node)
+ }
+ }
+
fun add_or_upsert_impl(self: &mut BigOrderedMap, key: K, value: V, allow_overwrite: bool): Option> {
if (!self.constant_kv_size) {
self.validate_dynamic_size_and_init_max_degrees(&key, &value);
@@ -367,12 +385,12 @@ module aptos_std::big_ordered_map {
if (path_to_leaf.is_empty()) {
// In this case, the key is greater than all keys in the map.
- let current = self.root_index.stored_as_ref();
+ let current = self.root_index;
loop {
path_to_leaf.push_back(current);
- let current_node = self.nodes.borrow_mut(current);
+ let current_node = self.borrow_node_mut(current);
if (current_node.is_leaf) {
break;
};
@@ -471,9 +489,9 @@ module aptos_std::big_ordered_map {
}
fun find_leaf(self: &BigOrderedMap, key: &K): RefToSlot {
- let current = self.root_index.stored_as_ref();
+ let current = self.root_index;
while (!current.ref_is_null()) {
- let node = self.nodes.borrow(current);
+ let node = self.borrow_node(current);
if (node.is_leaf) {
return current;
};
@@ -492,11 +510,11 @@ module aptos_std::big_ordered_map {
fun find_leaf_with_path(self: &BigOrderedMap, key: &K): vector {
let vec = vector::empty();
- let current = self.root_index.stored_as_ref();
+ let current = self.root_index;
while (!current.ref_is_null()) {
vec.push_back(current);
- let node = self.nodes.borrow(current);
+ let node = self.borrow_node(current);
if (node.is_leaf) {
return vec;
};
@@ -523,7 +541,7 @@ module aptos_std::big_ordered_map {
fun add_at(self: &mut BigOrderedMap, path_to_node: vector, key: K, child: Child, allow_overwrite: bool): Option> {
let node_index = path_to_node.pop_back();
{
- let node = self.nodes.borrow_mut(node_index);
+ let node = self.borrow_node_mut(node_index);
let children = &mut node.children;
let current_size = children.length();
@@ -554,44 +572,50 @@ module aptos_std::big_ordered_map {
};
// # of children in the current node exceeds the threshold, need to split into two nodes.
- let (cur_node_slot, node) = self.nodes.remove_and_reserve(node_index);
- // aptos_std::debug::print(&std::string::utf8(b"node that needs to be split"));
- // aptos_std::debug::print(&node);
- move node_index;
- let is_leaf = node.is_leaf;
- let children = &mut node.children;
+ let (right_node_slot, node) = if (path_to_node.is_empty()) {
+ // If we are at the root, we need to move root node to become a child and have a new root node.
- let right_node_slot = if (path_to_node.is_empty()) {
+ assert!(node_index == self.root_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
// aptos_std::debug::print(&std::string::utf8(b"changing root"));
// Splitting root now, need to create a new root.
// We keep root_index always the same
- let new_root_node = new_node(/*is_leaf=*/false);
+ let new_root_node = new_node(/*is_leaf=*/false);
let (replacement_node_stored_slot, replacement_node_slot) = self.nodes.reserve_slot();
// aptos_std::debug::print(&replacement_node_slot);
- let max_element = *children.new_end_iter().iter_prev(children).iter_borrow_key(children);
+ let root_children = &self.root.children;
+ let max_element = *root_children.new_end_iter().iter_prev(root_children).iter_borrow_key(root_children);
if (cmp::compare(&max_element, &key).is_less_than()) {
max_element = key;
};
new_root_node.children.add(max_element, new_inner_child(replacement_node_stored_slot));
// aptos_std::debug::print(&cur_node_slot);
- path_to_node.push_back(cur_node_slot.reserved_as_ref());
- self.nodes.fill_reserved_slot(cur_node_slot, new_root_node);
+ path_to_node.push_back(self.root_index);
+
+ let node = mem::replace(&mut self.root, new_root_node);
let replacement_ref = replacement_node_slot.reserved_as_ref();
- if (is_leaf) {
+ if (node.is_leaf) {
self.min_leaf_index = replacement_ref;
self.max_leaf_index = replacement_ref;
};
- replacement_node_slot
+ (replacement_node_slot, node)
} else {
- cur_node_slot
+ let (cur_node_slot, node) = self.nodes.remove_and_reserve(node_index);
+ (cur_node_slot, node)
};
+ // aptos_std::debug::print(&std::string::utf8(b"node that needs to be split"));
+ // aptos_std::debug::print(&node);
+
+ move node_index;
+ let is_leaf = node.is_leaf;
+ let children = &mut node.children;
+
let right_node_ref = right_node_slot.reserved_as_ref();
let next = &mut node.next;
let prev = &mut node.prev;
@@ -646,7 +670,7 @@ module aptos_std::big_ordered_map {
};
let node_index = path_to_node.pop_back();
- let node = self.nodes.borrow_mut(node_index);
+ let node = self.borrow_node_mut(node_index);
let children = &mut node.children;
children.replace_key_inplace(old_key, new_key);
@@ -658,17 +682,19 @@ module aptos_std::big_ordered_map {
fun remove_at(self: &mut BigOrderedMap, path_to_node: vector, key: &K): Child {
let node_index = path_to_node.pop_back();
let old_child = {
- let node = self.nodes.borrow_mut(node_index);
+ let node = self.borrow_node_mut(node_index);
let children = &mut node.children;
let is_leaf = node.is_leaf;
let old_child = children.remove(key);
- if (node_index == self.root_index.stored_as_ref()) {
- // promote only child to root, and drop current root.
- // keep the root index the same.
+ if (path_to_node.is_empty()) {
+ assert!(node_index == self.root_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+
if (!is_leaf && children.length() == 1) {
+ // promote only child to root, and drop current root.
+ // keep the root index the same.
let Child::Inner {
node_index: inner_child_index,
} = children.new_end_iter().iter_prev(children).iter_remove(children);
@@ -676,16 +702,13 @@ module aptos_std::big_ordered_map {
move node;
let inner_child = self.nodes.remove(inner_child_index);
- let root_ref = self.root_index.stored_as_ref();
if (inner_child.is_leaf) {
+ let root_ref = self.root_index;
self.min_leaf_index = root_ref;
self.max_leaf_index = root_ref;
};
- let (root_slot, root_value) = self.nodes.remove_and_reserve(node_index);
- destroy_empty_node(root_value);
-
- self.nodes.fill_reserved_slot(root_slot, inner_child);
+ mem::replace(&mut self.root, inner_child).destroy_empty_node();
}; // else: nothing to change
return old_child;
};
@@ -728,7 +751,7 @@ module aptos_std::big_ordered_map {
let next = node.next;
let brother_index = {
- let parent_children = &self.nodes.borrow(*path_to_node.borrow(path_to_node.length() - 1)).children;
+ let parent_children = &self.borrow_node(*path_to_node.borrow(path_to_node.length() - 1)).children;
if (parent_children.new_end_iter().iter_prev(parent_children).iter_borrow(parent_children).node_index.stored_as_ref() == node_index) {
prev
} else {
@@ -820,11 +843,11 @@ module aptos_std::big_ordered_map {
/// Returns the number of elements in the BigOrderedMap.
fun length(self: &BigOrderedMap): u64 {
- self.length_for_node(self.root_index.stored_as_ref())
+ self.length_for_node(self.root_index)
}
fun length_for_node(self: &BigOrderedMap, node_index: RefToSlot): u64 {
- let node = self.nodes.borrow(node_index);
+ let node = self.borrow_node(node_index);
if (node.is_leaf) {
node.children.length()
} else {
@@ -839,7 +862,7 @@ module aptos_std::big_ordered_map {
/// Returns true iff the BigOrderedMap is empty.
fun is_empty(self: &BigOrderedMap): bool {
- let node = self.nodes.borrow(self.min_leaf_index);
+ let node = self.borrow_node(self.min_leaf_index);
node.children.is_empty()
}
@@ -850,12 +873,12 @@ module aptos_std::big_ordered_map {
fun print_map(self: &BigOrderedMap) {
aptos_std::debug::print(&std::string::utf8(b"print map"));
aptos_std::debug::print(self);
- self.print_map_for_node(self.root_index.stored_as_ref(), 0);
+ self.print_map_for_node(self.root_index, 0);
}
#[test_only]
fun print_map_for_node(self: &BigOrderedMap, node_index: RefToSlot, level: u64) {
- let node = self.nodes.borrow(node_index);
+ let node = self.borrow_node(node_index);
aptos_std::debug::print(&level);
aptos_std::debug::print(&node_index);
@@ -912,13 +935,13 @@ module aptos_std::big_ordered_map {
#[test_only]
fun validate_subtree(self: &BigOrderedMap, node_index: RefToSlot, expected_lower_bound_key: Option, expected_max_key: Option) {
- let node = self.nodes.borrow(node_index);
+ let node = self.borrow_node(node_index);
let len = node.children.length();
assert!(len <= self.get_max_degree(node.is_leaf), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
- if (node_index != self.root_index.stored_as_ref()) {
+ if (node_index != self.root_index) {
assert!(len >= 1, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
- assert!(len * 2 >= self.get_max_degree(node.is_leaf) || node_index == self.root_index.stored_as_ref(), error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
+ assert!(len * 2 >= self.get_max_degree(node.is_leaf) || node_index == self.root_index, error::invalid_state(EINTERNAL_INVARIANT_BROKEN));
};
node.children.validate_ordered();
@@ -946,13 +969,13 @@ module aptos_std::big_ordered_map {
#[test_only]
fun validate_map(self: &BigOrderedMap) {
- self.validate_subtree(self.root_index.stored_as_ref(), option::none(), option::none());
+ self.validate_subtree(self.root_index, option::none(), option::none());
self.validate_iteration();
}
#[test]
fun test_small_example() {
- let map = new_with_config(5, 3, true, true, 2);
+ let map = new_with_config(5, 3, true, 2);
map.print_map(); map.validate_map();
add(&mut map, 1, 1); map.print_map(); map.validate_map();
add(&mut map, 2, 2); map.print_map(); map.validate_map();
@@ -976,7 +999,7 @@ module aptos_std::big_ordered_map {
#[test]
fun test_deleting_and_creating_nodes() {
- let map = new_with_config(4, 3, true, true, 2);
+ let map = new_with_config(4, 3, true, 2);
for (i in 0..50) {
map.upsert(i, i);
@@ -1023,7 +1046,7 @@ module aptos_std::big_ordered_map {
#[test]
fun test_iterator() {
- let map = new_with_config(5, 5, true, true, 2);
+ let map = new_with_config(5, 5, true, 2);
let data = vector[1, 7, 5, 8, 4, 2, 6, 3, 9, 0];
while (data.length() != 0) {
@@ -1045,7 +1068,7 @@ module aptos_std::big_ordered_map {
#[test]
fun test_find() {
- let map = new_with_config(5, 5, true, true, 2);
+ let map = new_with_config(5, 5, true, 2);
let data = vector[11, 1, 7, 5, 8, 2, 6, 3, 0, 10];
@@ -1074,7 +1097,7 @@ module aptos_std::big_ordered_map {
#[test]
fun test_lower_bound() {
- let map = new_with_config(5, 5, true, true, 2);
+ let map = new_with_config(5, 5, true, 2);
let data = vector[11, 1, 7, 5, 8, 2, 6, 3, 12, 10];
@@ -1113,7 +1136,7 @@ module aptos_std::big_ordered_map {
fun test_large_data_set_helper(inner_max_degree: u16, leaf_max_degree: u16, reuse_slots: bool) {
use std::vector;
- let map = new_with_config(inner_max_degree, leaf_max_degree, true, reuse_slots, if (reuse_slots) {4} else {0});
+ let map = new_with_config(inner_max_degree, leaf_max_degree, reuse_slots, if (reuse_slots) {4} else {0});
let data = ordered_map::large_dataset();
let shuffled_data = ordered_map::large_dataset_shuffled();
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/ordered_map.move b/aptos-move/framework/aptos-stdlib/sources/data_structures/ordered_map.move
index ad76bb1acef20..1829398cabb15 100644
--- a/aptos-move/framework/aptos-stdlib/sources/data_structures/ordered_map.move
+++ b/aptos-move/framework/aptos-stdlib/sources/data_structures/ordered_map.move
@@ -21,7 +21,7 @@ module aptos_std::ordered_map {
use std::vector;
- use std::enum_option::{Self as option, Option};
+ use std::option::{Self, Option};
use std::cmp;
use std::error;
use std::mem;
diff --git a/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move b/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move
index bf2b199f8602d..a4e480721267f 100644
--- a/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move
+++ b/aptos-move/framework/aptos-stdlib/sources/data_structures/storage_slots_allocator.move
@@ -18,13 +18,13 @@ module aptos_std::storage_slots_allocator {
friend aptos_std::big_ordered_map;
use aptos_std::table::{Self, Table};
- use std::enum_option::{Self as option, Option};
+ use std::option::{Self, Option};
const EINVALID_ARGUMENT: u64 = 1;
const EINTERNAL_INVARIANT_BROKEN: u64 = 7;
const NULL_INDEX: u64 = 0;
- const INLINE_SLOT_INDEX: u64 = 1;
+ const SPECIAL_SLOT_INDEX: u64 = 1;
const FIRST_INDEX: u64 = 10; // keeping space for new special values
/// Data stored in an individual slot
@@ -42,7 +42,6 @@ module aptos_std::storage_slots_allocator {
enum StorageSlotsAllocatorConfig has copy, drop {
V1 {
- should_inline: bool,
should_reuse: bool,
num_to_preallocate: u32,
}
@@ -55,7 +54,6 @@ module aptos_std::storage_slots_allocator {
should_reuse: bool,
reuse_head_index: u64,
reuse_spare_count: u32,
- inline_slot: Option>, // Optionally put one slot directly inline
},
}
@@ -87,7 +85,6 @@ module aptos_std::storage_slots_allocator {
should_reuse: config.should_reuse,
reuse_head_index: NULL_INDEX,
reuse_spare_count: 0,
- inline_slot: option::none(),
};
for (i in 0..config.num_to_preallocate) {
@@ -95,24 +92,18 @@ module aptos_std::storage_slots_allocator {
result.maybe_push_to_reuse_queue(slot_index);
};
- if (config.should_inline) {
- result.maybe_push_to_reuse_queue(INLINE_SLOT_INDEX);
- };
-
result
}
public fun new_default_config(): StorageSlotsAllocatorConfig {
StorageSlotsAllocatorConfig::V1 {
- should_inline: true,
should_reuse: false,
num_to_preallocate: 0,
}
}
- public fun new_config(should_inline: bool, should_reuse: bool, num_to_preallocate: u32): StorageSlotsAllocatorConfig {
+ public fun new_config(should_reuse: bool, num_to_preallocate: u32): StorageSlotsAllocatorConfig {
StorageSlotsAllocatorConfig::V1 {
- should_inline,
should_reuse,
num_to_preallocate,
}
@@ -144,9 +135,7 @@ module aptos_std::storage_slots_allocator {
should_reuse: _,
reuse_head_index,
reuse_spare_count: _,
- inline_slot,
} => {
- inline_slot.destroy_none();
assert!(reuse_head_index == NULL_INDEX, EINTERNAL_INVARIANT_BROKEN);
slots.destroy_some().destroy();
},
@@ -154,22 +143,11 @@ module aptos_std::storage_slots_allocator {
}
public fun borrow(self: &StorageSlotsAllocator, slot: RefToSlot): &T {
- let slot_index = slot.slot_index;
-
- if (slot_index == INLINE_SLOT_INDEX) {
- return &self.inline_slot.borrow().value;
- };
-
- &self.slots.borrow().borrow(slot_index).value
+ &self.slots.borrow().borrow(slot.slot_index).value
}
public fun borrow_mut(self: &mut StorageSlotsAllocator, slot: RefToSlot): &mut T {
- let slot_index = slot.slot_index;
- if (slot_index == INLINE_SLOT_INDEX) {
- return &mut self.inline_slot.borrow_mut().value;
- };
-
- &mut self.slots.borrow_mut().borrow_mut(slot_index).value
+ &mut self.slots.borrow_mut().borrow_mut(slot.slot_index).value
}
// We also provide here operations where `add()` is split into `reserve_slot`,
@@ -222,6 +200,10 @@ module aptos_std::storage_slots_allocator {
RefToSlot { slot_index: NULL_INDEX }
}
+ public fun special_ref(): RefToSlot {
+ RefToSlot { slot_index: SPECIAL_SLOT_INDEX }
+ }
+
public fun ref_is_null(self: &RefToSlot): bool {
self.slot_index == NULL_INDEX
}
@@ -239,7 +221,7 @@ module aptos_std::storage_slots_allocator {
}
fun maybe_push_to_reuse_queue(self: &mut StorageSlotsAllocator, slot_index: u64) {
- if (self.should_reuse || slot_index == INLINE_SLOT_INDEX) {
+ if (self.should_reuse) {
self.add_link(slot_index, Link::Vacant { next: self.reuse_head_index });
self.reuse_head_index = slot_index;
self.reuse_spare_count = self.reuse_spare_count + 1;
@@ -256,18 +238,10 @@ module aptos_std::storage_slots_allocator {
}
fun add_link(self: &mut StorageSlotsAllocator, slot_index: u64, link: Link) {
- if (slot_index == INLINE_SLOT_INDEX) {
- self.inline_slot.fill(link)
- } else {
- self.slots.borrow_mut().add(slot_index, link);
- }
+ self.slots.borrow_mut().add(slot_index, link);
}
fun remove_link(self: &mut StorageSlotsAllocator, slot_index: u64): Link {
- if (slot_index == INLINE_SLOT_INDEX) {
- self.inline_slot.extract()
- } else {
- self.slots.borrow_mut().remove(slot_index)
- }
+ self.slots.borrow_mut().remove(slot_index)
}
}