Skip to content

Commit

Permalink
Eliminate intermediate serialization for dict insert
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Aug 15, 2023
1 parent ddcafea commit 1f4cc00
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 10 deletions.
79 changes: 79 additions & 0 deletions src/cell/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,14 @@ impl CellBuilder {
unsafe { CellSlice::new_unchecked(IntermediateDataCell::wrap(self)) }
}

/// Returns a slice which contains builder data and references.
///
/// NOTE: intermediate cell hash is undefined.
pub fn as_full_slice(&self) -> CellSlice<'_> {
// SAFETY: we interpret cell builder data as ordinary cell
unsafe { CellSlice::new_unchecked(IntermediateFullCell::wrap(self)) }
}

/// Returns an underlying cell data.
#[inline]
pub fn raw_data(&self) -> &[u8; 128] {
Expand Down Expand Up @@ -1059,6 +1067,77 @@ impl CellImpl for IntermediateDataCell {
}
}

#[repr(transparent)]
struct IntermediateFullCell(CellBuilder);

impl IntermediateFullCell {
#[inline(always)]
const fn wrap(value: &CellBuilder) -> &Self {
// SAFETY: IntermediateFullCell is #[repr(transparent)]
unsafe { &*(value as *const CellBuilder as *const Self) }
}
}

impl CellImpl for IntermediateFullCell {
fn descriptor(&self) -> CellDescriptor {
CellDescriptor {
d1: CellDescriptor::compute_d1(LevelMask::EMPTY, false, self.0.references.len() as u8),
d2: CellDescriptor::compute_d2(self.0.bit_len),
}
}

fn data(&self) -> &[u8] {
self.0.raw_data()
}

fn bit_len(&self) -> u16 {
self.0.bit_len
}

fn reference(&self, index: u8) -> Option<&DynCell> {
match self.0.references.get(index) {
Some(cell) => Some(cell.as_ref()),
None => None,
}
}

fn reference_cloned(&self, index: u8) -> Option<Cell> {
self.0.references.get(index).cloned()
}

fn virtualize(&self) -> &DynCell {
self
}

fn hash(&self, _: u8) -> &HashBytes {
panic!("Hash for an intermediate data cell is not defined");
}

fn depth(&self, _: u8) -> u16 {
0
}

fn take_first_child(&mut self) -> Option<Cell> {
None
}

fn replace_first_child(&mut self, parent: Cell) -> Result<Cell, Cell> {
Err(parent)
}

fn take_next_child(&mut self) -> Option<Cell> {
None
}

#[cfg(feature = "stats")]
fn stats(&self) -> CellTreeStats {
CellTreeStats {
bit_count: self.0.bit_len as u64,
cell_count: 1 + self.0.references.len() as u64,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
10 changes: 5 additions & 5 deletions src/dict/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ pub fn dict_insert(
root: &Option<Cell>,
key: &mut CellSlice,
key_bit_len: u16,
value: &CellSlice,
value: &dyn Store,
mode: SetMode,
finalizer: &mut dyn Finalizer,
) -> Result<(Option<Cell>, bool), Error> {
Expand Down Expand Up @@ -293,7 +293,7 @@ pub fn dict_insert_owned(
root: &Option<Cell>,
key: &mut CellSlice,
key_bit_len: u16,
value: &CellSlice,
value: &dyn Store,
mode: SetMode,
finalizer: &mut dyn Finalizer,
) -> Result<(Option<Cell>, bool, Option<CellSliceParts>), Error> {
Expand Down Expand Up @@ -906,12 +906,12 @@ pub fn dict_remove_bound_owned(
fn make_leaf(
key: &CellSlice,
key_bit_len: u16,
value: &CellSlice,
value: &dyn Store,
finalizer: &mut dyn Finalizer,
) -> Result<Cell, Error> {
let mut builder = CellBuilder::new();
ok!(write_label(key, key_bit_len, &mut builder));
ok!(builder.store_slice(value));
ok!(value.store_into(&mut builder, finalizer));
builder.build_ext(finalizer)
}

Expand All @@ -921,7 +921,7 @@ fn split_edge(
prefix: &mut CellSlice,
lcp: &CellSlice,
key: &mut CellSlice,
value: &CellSlice,
value: &dyn Store,
finalizer: &mut dyn Finalizer,
) -> Result<Cell, Error> {
// Advance the key
Expand Down
9 changes: 4 additions & 5 deletions src/dict/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,14 +677,13 @@ where
V: Store,
{
let (new_root, changed) = {
let mut builder = CellBuilder::new();
ok!(key.store_into(&mut builder, &mut Cell::default_finalizer()));
let value = ok!(CellBuilder::build_from_ext(value, finalizer));
let mut key_builder = CellBuilder::new();
ok!(key.store_into(&mut key_builder, &mut Cell::default_finalizer()));
ok!(dict_insert(
&self.root,
&mut builder.as_data_slice(),
&mut key_builder.as_data_slice(),
K::BITS,
&ok!(value.as_ref().as_slice()),
value,
mode,
finalizer
))
Expand Down
11 changes: 11 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ impl<T, const N: usize> ArrayVec<T, N> {
self.len += 1;
}

/// Returns a reference to an element.
pub fn get(&self, n: u8) -> Option<&T> {
if n < self.len {
let references = self.inner.as_ptr() as *const T;
// SAFETY: {len} elements were initialized, n < len
Some(unsafe { &*references.add(n as usize) })
} else {
None
}
}

/// Returns the inner data without dropping its elements.
///
/// # Safety
Expand Down

0 comments on commit 1f4cc00

Please sign in to comment.