diff --git a/canbench_results.yml b/canbench_results.yml index 76f2bee3..62a7066d 100644 --- a/canbench_results.yml +++ b/canbench_results.yml @@ -133,379 +133,379 @@ benches: scopes: {} btreemap_insert_10mib_values: total: - instructions: 145812477 + instructions: 145922325 heap_increase: 0 stable_memory_increase: 32 scopes: {} btreemap_insert_blob_1024_128: total: - instructions: 5161897359 + instructions: 5161914701 heap_increase: 0 stable_memory_increase: 262 scopes: {} btreemap_insert_blob_1024_128_v2: total: - instructions: 5551050739 + instructions: 5551068081 heap_increase: 0 stable_memory_increase: 196 scopes: {} btreemap_insert_blob_1024_16: total: - instructions: 5117351375 + instructions: 5117369042 heap_increase: 0 stable_memory_increase: 241 scopes: {} btreemap_insert_blob_1024_16_v2: total: - instructions: 5508484410 + instructions: 5508502115 heap_increase: 0 stable_memory_increase: 181 scopes: {} btreemap_insert_blob_1024_256: total: - instructions: 5184887283 + instructions: 5184904755 heap_increase: 0 stable_memory_increase: 292 scopes: {} btreemap_insert_blob_1024_256_v2: total: - instructions: 5574297530 + instructions: 5574315002 heap_increase: 0 stable_memory_increase: 219 scopes: {} btreemap_insert_blob_1024_32: total: - instructions: 5124591897 + instructions: 5124609174 heap_increase: 0 stable_memory_increase: 239 scopes: {} btreemap_insert_blob_1024_32_v2: total: - instructions: 5514794407 + instructions: 5514811773 heap_increase: 0 stable_memory_increase: 180 scopes: {} btreemap_insert_blob_1024_4: total: - instructions: 5013226971 + instructions: 5013244404 heap_increase: 0 stable_memory_increase: 235 scopes: {} btreemap_insert_blob_1024_4_v2: total: - instructions: 5408556192 + instructions: 5408573739 heap_increase: 0 stable_memory_increase: 176 scopes: {} btreemap_insert_blob_1024_512: total: - instructions: 5296477642 + instructions: 5296495023 heap_increase: 0 stable_memory_increase: 348 scopes: {} btreemap_insert_blob_1024_512_v2: total: - instructions: 5692592790 + instructions: 5692610171 heap_increase: 0 stable_memory_increase: 261 scopes: {} btreemap_insert_blob_1024_64: total: - instructions: 5160666685 + instructions: 5160684248 heap_increase: 0 stable_memory_increase: 250 scopes: {} btreemap_insert_blob_1024_64_v2: total: - instructions: 5550334403 + instructions: 5550351966 heap_increase: 0 stable_memory_increase: 188 scopes: {} btreemap_insert_blob_1024_8: total: - instructions: 5098581170 + instructions: 5098598668 heap_increase: 0 stable_memory_increase: 237 scopes: {} btreemap_insert_blob_1024_8_v2: total: - instructions: 5491442141 + instructions: 5491459791 heap_increase: 0 stable_memory_increase: 178 scopes: {} btreemap_insert_blob_128_1024: total: - instructions: 1521313518 + instructions: 1521330782 heap_increase: 0 stable_memory_increase: 260 scopes: {} btreemap_insert_blob_128_1024_v2: total: - instructions: 1651648946 + instructions: 1651666210 heap_increase: 0 stable_memory_increase: 195 scopes: {} btreemap_insert_blob_16_1024: total: - instructions: 914649153 + instructions: 914664896 heap_increase: 0 stable_memory_increase: 215 scopes: {} btreemap_insert_blob_16_1024_v2: total: - instructions: 1012886554 + instructions: 1012902411 heap_increase: 0 stable_memory_increase: 161 scopes: {} btreemap_insert_blob_256_1024: total: - instructions: 2072274900 + instructions: 2072292372 heap_increase: 0 stable_memory_increase: 292 scopes: {} btreemap_insert_blob_256_1024_v2: total: - instructions: 2262444663 + instructions: 2262462135 heap_increase: 0 stable_memory_increase: 219 scopes: {} btreemap_insert_blob_32_1024: total: - instructions: 971181545 + instructions: 971198185 heap_increase: 0 stable_memory_increase: 230 scopes: {} btreemap_insert_blob_32_1024_v2: total: - instructions: 1063753591 + instructions: 1063770231 heap_increase: 0 stable_memory_increase: 173 scopes: {} btreemap_insert_blob_4_1024: total: - instructions: 702280030 + instructions: 702289156 heap_increase: 0 stable_memory_increase: 123 scopes: {} btreemap_insert_blob_4_1024_v2: total: - instructions: 787268408 + instructions: 787277534 heap_increase: 0 stable_memory_increase: 92 scopes: {} btreemap_insert_blob_512_1024: total: - instructions: 3204802664 + instructions: 3204820188 heap_increase: 0 stable_memory_increase: 351 scopes: {} btreemap_insert_blob_512_1024_v2: total: - instructions: 3464684781 + instructions: 3464702305 heap_increase: 0 stable_memory_increase: 263 scopes: {} btreemap_insert_blob_64_1024: total: - instructions: 1242001761 + instructions: 1242018908 heap_increase: 0 stable_memory_increase: 245 scopes: {} btreemap_insert_blob_64_1024_v2: total: - instructions: 1345180958 + instructions: 1345198105 heap_increase: 0 stable_memory_increase: 183 scopes: {} btreemap_insert_blob_8_1024: total: - instructions: 828098541 + instructions: 828112100 heap_increase: 0 stable_memory_increase: 183 scopes: {} btreemap_insert_blob_8_1024_v2: total: - instructions: 919884588 + instructions: 919898223 heap_increase: 0 stable_memory_increase: 138 scopes: {} btreemap_insert_blob_8_u64: total: - instructions: 424320990 + instructions: 424334575 heap_increase: 0 stable_memory_increase: 6 scopes: {} btreemap_insert_blob_8_u64_v2: total: - instructions: 524532367 + instructions: 524551164 heap_increase: 0 stable_memory_increase: 4 scopes: {} btreemap_insert_u64_blob_8: total: - instructions: 435841221 + instructions: 435858693 heap_increase: 0 stable_memory_increase: 7 scopes: {} btreemap_insert_u64_blob_8_v2: total: - instructions: 502367747 + instructions: 502390007 heap_increase: 0 stable_memory_increase: 5 scopes: {} btreemap_insert_u64_u64: total: - instructions: 448311336 + instructions: 448328834 heap_increase: 0 stable_memory_increase: 7 scopes: {} btreemap_insert_u64_u64_v2: total: - instructions: 518585831 + instructions: 518609796 heap_increase: 0 stable_memory_increase: 6 scopes: {} btreemap_iter_count_10mib_values: total: - instructions: 521270 + instructions: 525036 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_count_small_values: total: - instructions: 10242765 + instructions: 10458516 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_128_1024: total: - instructions: 1916023862 + instructions: 1916049094 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_128_1024_v2: total: - instructions: 2060123740 + instructions: 2060148972 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_16_1024: total: - instructions: 1174997981 + instructions: 1175020990 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_16_1024_v2: total: - instructions: 1310740941 + instructions: 1310763950 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_256_1024: total: - instructions: 2563712145 + instructions: 2563737681 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_256_1024_v2: total: - instructions: 2714997748 + instructions: 2715023284 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_32_1024: total: - instructions: 1257954087 + instructions: 1257978407 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_32_1024_v2: total: - instructions: 1396007710 + instructions: 1396032068 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_4_1024: total: - instructions: 730539960 + instructions: 730553298 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_4_1024_v2: total: - instructions: 832319712 + instructions: 832333088 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_512_1024: total: - instructions: 3925463425 + instructions: 3925489037 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_512_1024_v2: total: - instructions: 4079794221 + instructions: 4079819871 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_64_1024: total: - instructions: 1579833528 + instructions: 1579858589 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_64_1024_v2: total: - instructions: 1719825276 + instructions: 1719850337 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_1024: total: - instructions: 958306352 + instructions: 958326169 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_1024_v2: total: - instructions: 1076045855 + instructions: 1076065710 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_u64: total: - instructions: 549451611 + instructions: 549471466 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_u64_v2: total: - instructions: 685586627 + instructions: 685613050 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_blob_8: total: - instructions: 609355138 + instructions: 609380674 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_blob_8_v2: total: - instructions: 705661181 + instructions: 705692037 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_u64: total: - instructions: 634545364 + instructions: 634570938 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_u64_v2: total: - instructions: 739907256 + instructions: 739939423 heap_increase: 0 stable_memory_increase: 0 scopes: {} @@ -517,13 +517,13 @@ benches: scopes: {} memory_manager_grow: total: - instructions: 352839872 + instructions: 351687872 heap_increase: 2 stable_memory_increase: 32000 scopes: {} memory_manager_overhead: total: - instructions: 1182161127 + instructions: 1182143127 heap_increase: 0 stable_memory_increase: 8320 scopes: {} diff --git a/src/btreemap.rs b/src/btreemap.rs index 716eaf77..47c6ab58 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1023,96 +1023,7 @@ where key_range.end_bound().cloned(), ); - let mut cursors = vec![]; - - match key_range.start_bound() { - Bound::Unbounded => { - cursors.push(Cursor::Address(self.root_addr)); - Iter::new_in_range(self, range, cursors) - } - Bound::Included(key) | Bound::Excluded(key) => { - let mut node = self.load_node(self.root_addr); - loop { - match node.search(key) { - Ok(idx) => { - if let Bound::Included(_) = key_range.start_bound() { - // We found the key exactly matching the left bound. - // Here is where we'll start the iteration. - cursors.push(Cursor::Node { - node, - next: Index::Entry(idx), - }); - return Iter::new_in_range(self, range, cursors); - } else { - // We found the key that we must - // exclude. We add its right neighbor - // to the stack and start iterating - // from its right child. - let right_child = match node.node_type() { - NodeType::Internal => Some(node.child(idx + 1)), - NodeType::Leaf => None, - }; - - if idx + 1 != node.entries_len() - && key_range.contains(node.key(idx + 1)) - { - cursors.push(Cursor::Node { - node, - next: Index::Entry(idx + 1), - }); - } - if let Some(right_child) = right_child { - cursors.push(Cursor::Address(right_child)); - } - return Iter::new_in_range(self, range, cursors); - } - } - Err(idx) => { - // The `idx` variable points to the first - // key that is greater than the left - // bound. - // - // If the index points to a valid node, we - // will visit its left subtree and then - // return to this key. - // - // If the index points at the end of - // array, we'll continue with the right - // child of the last key. - - // Load the left child of the node to visit if it exists. - // This is done first to avoid cloning the node. - let child = match node.node_type() { - NodeType::Internal => { - // Note that loading a child node cannot fail since - // len(children) = len(entries) + 1 - Some(self.load_node(node.child(idx))) - } - NodeType::Leaf => None, - }; - - if idx < node.entries_len() && key_range.contains(node.key(idx)) { - cursors.push(Cursor::Node { - node, - next: Index::Entry(idx), - }); - } - - match child { - None => { - // Leaf node. Return an iterator with the found cursors. - return Iter::new_in_range(self, range, cursors); - } - Some(child) => { - // Iterate over the child node. - node = child; - } - } - } - } - } - } - } + Iter::new_in_range(self, range) } /// Returns an iterator pointing to the first element below the given bound. @@ -1161,7 +1072,7 @@ where } } // If the cursors are empty, the iterator will be empty. - return Iter::new_in_range(self, dummy_bounds, cursors); + return Iter::new_with_cursors(self, dummy_bounds, cursors); } debug_assert!(node.key(idx - 1) < bound); @@ -1169,7 +1080,7 @@ where node, next: Index::Entry(idx - 1), }); - return Iter::new_in_range(self, dummy_bounds, cursors); + return Iter::new_with_cursors(self, dummy_bounds, cursors); } NodeType::Internal => { let child = self.load_node(node.child(idx)); diff --git a/src/btreemap/iter.rs b/src/btreemap/iter.rs index 3949352f..2492aca7 100644 --- a/src/btreemap/iter.rs +++ b/src/btreemap/iter.rs @@ -29,6 +29,11 @@ where // A reference to the map being iterated on. map: &'a BTreeMap, + // A flag indicating if the cursors have been initialized yet. This is needed to distinguish + // between the case where the iteration hasn't started yet and the case where the iteration has + // finished (in both cases the `cursors` field will be empty). + cursors_initialized: bool, + // A stack of cursors indicating the current position in the tree. cursors: Vec>, @@ -45,8 +50,8 @@ where pub(crate) fn new(map: &'a BTreeMap) -> Self { Self { map, - // Initialize the cursors with the address of the root of the map. - cursors: vec![Cursor::Address(map.root_addr)], + cursors_initialized: false, + cursors: vec![], range: (Bound::Unbounded, Bound::Unbounded), } } @@ -55,26 +60,135 @@ where pub(crate) fn null(map: &'a BTreeMap) -> Self { Self { map, + cursors_initialized: true, cursors: vec![], range: (Bound::Unbounded, Bound::Unbounded), } } - pub(crate) fn new_in_range( + pub(crate) fn new_in_range(map: &'a BTreeMap, range: (Bound, Bound)) -> Self { + Self { + map, + cursors_initialized: false, + cursors: vec![], + range, + } + } + + // This can be used as an optimisation if the cursors have already been calculated + pub(crate) fn new_with_cursors( map: &'a BTreeMap, range: (Bound, Bound), cursors: Vec>, ) -> Self { Self { map, + cursors_initialized: true, cursors, range, } } + fn initialize_cursors(&mut self) { + debug_assert!(!self.cursors_initialized); + + match self.range.start_bound() { + Bound::Unbounded => { + self.cursors.push(Cursor::Address(self.map.root_addr)); + } + Bound::Included(key) | Bound::Excluded(key) => { + let mut node = self.map.load_node(self.map.root_addr); + loop { + match node.search(key) { + Ok(idx) => { + if let Bound::Included(_) = self.range.start_bound() { + // We found the key exactly matching the left bound. + // Here is where we'll start the iteration. + self.cursors.push(Cursor::Node { + node, + next: Index::Entry(idx), + }); + break; + } else { + // We found the key that we must + // exclude. We add its right neighbor + // to the stack and start iterating + // from its right child. + let right_child = match node.node_type() { + NodeType::Internal => Some(node.child(idx + 1)), + NodeType::Leaf => None, + }; + + if idx + 1 != node.entries_len() + && self.range.contains(node.key(idx + 1)) + { + self.cursors.push(Cursor::Node { + node, + next: Index::Entry(idx + 1), + }); + } + if let Some(right_child) = right_child { + self.cursors.push(Cursor::Address(right_child)); + } + break; + } + } + Err(idx) => { + // The `idx` variable points to the first + // key that is greater than the left + // bound. + // + // If the index points to a valid node, we + // will visit its left subtree and then + // return to this key. + // + // If the index points at the end of + // array, we'll continue with the right + // child of the last key. + + // Load the left child of the node to visit if it exists. + // This is done first to avoid cloning the node. + let child = match node.node_type() { + NodeType::Internal => { + // Note that loading a child node cannot fail since + // len(children) = len(entries) + 1 + Some(self.map.load_node(node.child(idx))) + } + NodeType::Leaf => None, + }; + + if idx < node.entries_len() && self.range.contains(node.key(idx)) { + self.cursors.push(Cursor::Node { + node, + next: Index::Entry(idx), + }); + } + + match child { + None => { + // Leaf node. Return an iterator with the found cursors. + break; + } + Some(child) => { + // Iterate over the child node. + node = child; + } + } + } + } + } + } + } + self.cursors_initialized = true; + } + // Iterates to find the next element in the requested range. // If it exists, `map` is applied to that element and the result is returned. fn next_map, usize) -> T>(&mut self, map: F) -> Option { + if !self.cursors_initialized { + self.initialize_cursors(); + } + // If the cursors are empty. Iteration is complete. match self.cursors.pop()? { Cursor::Address(address) => {