mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
perf(trie): optimize in memory cursor (#14600)
This commit is contained in:
@ -1,23 +1,36 @@
|
|||||||
/// The implementation of forward-only in memory cursor over the entries.
|
/// The implementation of forward-only in memory cursor over the entries.
|
||||||
|
///
|
||||||
/// The cursor operates under the assumption that the supplied collection is pre-sorted.
|
/// The cursor operates under the assumption that the supplied collection is pre-sorted.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ForwardInMemoryCursor<'a, K, V> {
|
pub struct ForwardInMemoryCursor<'a, K, V> {
|
||||||
/// The reference to the pre-sorted collection of entries.
|
/// The reference to the pre-sorted collection of entries.
|
||||||
entries: &'a Vec<(K, V)>,
|
entries: std::slice::Iter<'a, (K, V)>,
|
||||||
/// The index where cursor is currently positioned.
|
is_empty: bool,
|
||||||
index: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K, V> ForwardInMemoryCursor<'a, K, V> {
|
impl<'a, K, V> ForwardInMemoryCursor<'a, K, V> {
|
||||||
/// Create new forward cursor positioned at the beginning of the collection.
|
/// Create new forward cursor positioned at the beginning of the collection.
|
||||||
|
///
|
||||||
/// The cursor expects all of the entries have been sorted in advance.
|
/// The cursor expects all of the entries have been sorted in advance.
|
||||||
pub const fn new(entries: &'a Vec<(K, V)>) -> Self {
|
#[inline]
|
||||||
Self { entries, index: 0 }
|
pub fn new(entries: &'a [(K, V)]) -> Self {
|
||||||
|
Self { entries: entries.iter(), is_empty: entries.is_empty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the cursor is empty, regardless of its position.
|
/// Returns `true` if the cursor is empty, regardless of its position.
|
||||||
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.entries.is_empty()
|
self.is_empty
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn peek(&self) -> Option<&(K, V)> {
|
||||||
|
self.entries.clone().next()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<&(K, V)> {
|
||||||
|
self.entries.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,26 +39,58 @@ where
|
|||||||
K: PartialOrd + Clone,
|
K: PartialOrd + Clone,
|
||||||
V: Clone,
|
V: Clone,
|
||||||
{
|
{
|
||||||
/// Advances the cursor forward while `comparator` returns `true` or until the collection is
|
|
||||||
/// exhausted. Returns the first entry for which `comparator` returns `false` or `None`.
|
|
||||||
fn advance_while_false(&mut self, comparator: impl Fn(&K) -> bool) -> Option<(K, V)> {
|
|
||||||
let mut entry = self.entries.get(self.index);
|
|
||||||
while entry.is_some_and(|entry| comparator(&entry.0)) {
|
|
||||||
self.index += 1;
|
|
||||||
entry = self.entries.get(self.index);
|
|
||||||
}
|
|
||||||
entry.cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the first entry from the current cursor position that's greater or equal to the
|
/// Returns the first entry from the current cursor position that's greater or equal to the
|
||||||
/// provided key. This method advances the cursor forward.
|
/// provided key. This method advances the cursor forward.
|
||||||
pub fn seek(&mut self, key: &K) -> Option<(K, V)> {
|
pub fn seek(&mut self, key: &K) -> Option<(K, V)> {
|
||||||
self.advance_while_false(|k| k < key)
|
self.advance_while(|k| k < key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the first entry from the current cursor position that's greater than the provided
|
/// Returns the first entry from the current cursor position that's greater than the provided
|
||||||
/// key. This method advances the cursor forward.
|
/// key. This method advances the cursor forward.
|
||||||
pub fn first_after(&mut self, key: &K) -> Option<(K, V)> {
|
pub fn first_after(&mut self, key: &K) -> Option<(K, V)> {
|
||||||
self.advance_while_false(|k| k <= key)
|
self.advance_while(|k| k <= key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advances the cursor forward while `predicate` returns `true` or until the collection is
|
||||||
|
/// exhausted.
|
||||||
|
///
|
||||||
|
/// Returns the first entry for which `predicate` returns `false` or `None`. The cursor will
|
||||||
|
/// point to the returned entry.
|
||||||
|
fn advance_while(&mut self, predicate: impl Fn(&K) -> bool) -> Option<(K, V)> {
|
||||||
|
let mut entry;
|
||||||
|
loop {
|
||||||
|
entry = self.peek();
|
||||||
|
if entry.is_some_and(|(k, _)| predicate(k)) {
|
||||||
|
self.next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry.cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cursor() {
|
||||||
|
let mut cursor = ForwardInMemoryCursor::new(&[(1, ()), (2, ()), (3, ()), (4, ()), (5, ())]);
|
||||||
|
|
||||||
|
assert_eq!(cursor.seek(&0), Some((1, ())));
|
||||||
|
assert_eq!(cursor.peek(), Some(&(1, ())));
|
||||||
|
|
||||||
|
assert_eq!(cursor.seek(&3), Some((3, ())));
|
||||||
|
assert_eq!(cursor.peek(), Some(&(3, ())));
|
||||||
|
|
||||||
|
assert_eq!(cursor.seek(&3), Some((3, ())));
|
||||||
|
assert_eq!(cursor.peek(), Some(&(3, ())));
|
||||||
|
|
||||||
|
assert_eq!(cursor.seek(&4), Some((4, ())));
|
||||||
|
assert_eq!(cursor.peek(), Some(&(4, ())));
|
||||||
|
|
||||||
|
assert_eq!(cursor.seek(&6), None);
|
||||||
|
assert_eq!(cursor.peek(), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,7 +57,7 @@ where
|
|||||||
C: HashedCursor<Value = Account>,
|
C: HashedCursor<Value = Account>,
|
||||||
{
|
{
|
||||||
/// Create new instance of [`HashedPostStateAccountCursor`].
|
/// Create new instance of [`HashedPostStateAccountCursor`].
|
||||||
pub const fn new(cursor: C, post_state_accounts: &'a HashedAccountsSorted) -> Self {
|
pub fn new(cursor: C, post_state_accounts: &'a HashedAccountsSorted) -> Self {
|
||||||
let post_state_cursor = ForwardInMemoryCursor::new(&post_state_accounts.accounts);
|
let post_state_cursor = ForwardInMemoryCursor::new(&post_state_accounts.accounts);
|
||||||
let destroyed_accounts = &post_state_accounts.destroyed_accounts;
|
let destroyed_accounts = &post_state_accounts.destroyed_accounts;
|
||||||
Self { cursor, post_state_cursor, destroyed_accounts, last_account: None }
|
Self { cursor, post_state_cursor, destroyed_accounts, last_account: None }
|
||||||
|
|||||||
@ -62,7 +62,7 @@ pub struct InMemoryAccountTrieCursor<'a, C> {
|
|||||||
impl<'a, C: TrieCursor> InMemoryAccountTrieCursor<'a, C> {
|
impl<'a, C: TrieCursor> InMemoryAccountTrieCursor<'a, C> {
|
||||||
/// Create new account trie cursor from underlying cursor and reference to
|
/// Create new account trie cursor from underlying cursor and reference to
|
||||||
/// [`TrieUpdatesSorted`].
|
/// [`TrieUpdatesSorted`].
|
||||||
pub const fn new(cursor: C, trie_updates: &'a TrieUpdatesSorted) -> Self {
|
pub fn new(cursor: C, trie_updates: &'a TrieUpdatesSorted) -> Self {
|
||||||
let in_memory_cursor = ForwardInMemoryCursor::new(&trie_updates.account_nodes);
|
let in_memory_cursor = ForwardInMemoryCursor::new(&trie_updates.account_nodes);
|
||||||
Self {
|
Self {
|
||||||
cursor,
|
cursor,
|
||||||
|
|||||||
Reference in New Issue
Block a user