Skip to content

Commit

Permalink
Allocate custom matchers collection only when it is needed
Browse files Browse the repository at this point in the history
VecOnDemand collection allocates real vector only on write operations.
  • Loading branch information
vsbogd committed Jan 29, 2025
1 parent 7e9bd81 commit 7d6b416
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod reformove;
pub mod multitrie;
pub mod holeyvec;
pub mod owned_or_borrowed;
pub mod vecondemand;

mod flex_ref;
pub use flex_ref::FlexRef;
Expand Down
96 changes: 96 additions & 0 deletions lib/src/common/vecondemand.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VecOnDemand<T> {
vec: Option<Box<Vec<T>>>,
}

impl<T> Default for VecOnDemand<T> {
fn default() -> Self {
Self{ vec: None }
}
}

impl<T> VecOnDemand<T> {
#[inline]
fn op<'a, R: 'a, S: Fn(&'a Vec<T>) -> R, N: Fn() -> R>(&'a self, on_some: S, on_none: N) -> R {
match &self.vec {
Some(vec) => on_some(vec),
None => on_none(),
}
}

#[inline]
fn op_mut<'a, R: 'a, S: Fn(&'a mut Vec<T>) -> R, N: Fn() -> R>(&'a mut self, on_some: S, on_none: N) -> R {
match &mut self.vec {
Some(vec) => on_some(vec),
None => on_none(),
}
}

pub fn push(&mut self, item: T) {
match &mut self.vec {
Some(vec) => vec.push(item),
None => {
let vec = Box::new(vec![item]);
self.vec = Some(vec);
},
}
}

pub fn remove(&mut self, index: usize) -> T {
match &mut self.vec {
Some(vec) => vec.remove(index),
None => panic!("removal index (is {index}) should be < len (is 0)"),
}
}

pub fn iter(&self) -> std::slice::Iter<'_, T> {
self.op(|v| v.iter(), || [].iter())
}

pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
self.op_mut(|v| v.iter_mut(), || [].iter_mut())
}

pub fn is_empty(&self) -> bool {
self.op(Vec::is_empty, || true)
}

pub fn len(&self) -> usize {
self.op(Vec::len, || 0)
}
}

impl<T> std::ops::Deref for VecOnDemand<T> {
type Target = [T];

#[inline]
fn deref(&self) -> &[T] {
self.op(Vec::as_slice, || &[])
}
}

impl<T> std::ops::DerefMut for VecOnDemand<T> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
self.op_mut(Vec::as_mut_slice, || &mut [])
}
}

impl<'a, T> IntoIterator for &'a VecOnDemand<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;

fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}

impl<'a, T> IntoIterator for &'a mut VecOnDemand<T> {
type Item = &'a mut T;
type IntoIter = std::slice::IterMut<'a, T>;

fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}

3 changes: 2 additions & 1 deletion lib/src/space/grounding/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::serial::NullSerializer;
use crate::matcher::*;
use crate::common::CachingMapper;
use crate::common::collections::write_mapping;
use crate::common::vecondemand::VecOnDemand;

use bimap::BiMap;
use std::hash::Hash;
Expand Down Expand Up @@ -391,7 +392,7 @@ enum AtomTrieNode {
#[derive(Default, Debug, Clone, PartialEq, Eq)]
struct AtomTrieNodeContent {
exact: HashMap<ExactKey, AtomTrieNode>,
custom: Vec<(Atom, AtomTrieNode)>,
custom: VecOnDemand<(Atom, AtomTrieNode)>,
}

type QueryResult = Box<dyn Iterator<Item=Bindings>>;
Expand Down

0 comments on commit 7d6b416

Please sign in to comment.