diff --git a/src/dict/mod.rs b/src/dict/mod.rs index 568a926a..442de180 100644 --- a/src/dict/mod.rs +++ b/src/dict/mod.rs @@ -190,6 +190,8 @@ pub fn dict_remove_owned( /// Inserts the value associated with key in dictionary /// in accordance with the logic of the specified [`SetMode`]. +/// +/// Returns a tuple with a new dict root, and changed flag. pub fn dict_insert( root: &Option, key: &mut CellSlice, @@ -197,73 +199,113 @@ pub fn dict_insert( value: &CellSlice, mode: SetMode, finalizer: &mut dyn Finalizer, -) -> Result, Error> { - // Creates a leaf node - fn make_leaf( - key: &CellSlice, - key_bit_len: u16, - value: &CellSlice, - finalizer: &mut dyn Finalizer, - ) -> Result { - let mut builder = CellBuilder::new(); - ok!(write_label(key, key_bit_len, &mut builder)); - ok!(builder.store_slice(value)); - builder.build_ext(finalizer) +) -> Result<(Option, bool), Error> { + if key.remaining_bits() != key_bit_len { + return Err(Error::CellUnderflow); } - // Splits an edge or leaf - fn split( - data: &CellSlice, - prefix: &mut CellSlice, - lcp: &CellSlice, - key: &mut CellSlice, - value: &CellSlice, - finalizer: &mut dyn Finalizer, - ) -> Result { - // Advance the key - let prev_key_bit_len = key.remaining_bits(); - if !key.try_advance(lcp.remaining_bits() + 1, 0) { - return Err(Error::CellUnderflow); + let mut data = match root.as_ref() { + Some(data) => data.as_ref(), + None if mode.can_add() => { + let data = ok!(make_leaf(key, key_bit_len, value, finalizer)); + return Ok((Some(data), true)); } + None => return Ok((None, false)), + }; + + let mut stack = Vec::::new(); + + let mut leaf = loop { + let mut remaining_data = ok!(data.as_slice()); + + // Read the next part of the key from the current data + let prefix = &mut ok!(read_label(&mut remaining_data, key.remaining_bits())); + + // Match the prefix with the key + let lcp = key.longest_common_data_prefix(prefix); + match lcp.remaining_bits().cmp(&key.remaining_bits()) { + // If all bits match, an existing value was found + std::cmp::Ordering::Equal => { + // Check if we can replace the value + if !mode.can_replace() { + return Ok((root.clone(), false)); + } + // Replace the existing value + break ok!(make_leaf(prefix, key.remaining_bits(), value, finalizer)); + } + // LCP is less than prefix, an edge to slice was found + std::cmp::Ordering::Less if lcp.remaining_bits() < prefix.remaining_bits() => { + // Check if we can add a new value + if !mode.can_add() { + return Ok((root.clone(), false)); + } + break ok!(split(&remaining_data, prefix, &lcp, key, value, finalizer)); + } + // The key contains the entire prefix, but there are still some bits left + std::cmp::Ordering::Less => { + // Fail fast if there are not enough references in the fork + if data.reference_count() != 2 { + return Err(Error::CellUnderflow); + } - // Read the next bit from the data - prefix.try_advance(lcp.remaining_bits(), 0); - let old_to_right = ok!(prefix.load_bit()); + // Remove the LCP from the key + key.try_advance(lcp.remaining_bits(), 0); - // Create a leaf for the old value - let mut left = ok!(make_leaf(prefix, key.remaining_bits(), data, finalizer)); - // Create a leaf for the right value - let mut right = ok!(make_leaf(key, key.remaining_bits(), value, finalizer)); + // Load the next branch + let next_branch = match key.load_bit() { + Ok(bit) => Branch::from(bit), + Err(e) => return Err(e), + }; + + let child = match data.reference(next_branch as u8) { + Some(child) => child, + None => return Err(Error::CellUnderflow), + }; - // The part that starts with 1 goes to the right cell - if old_to_right { - std::mem::swap(&mut left, &mut right); + // Push an intermediate edge to the stack + stack.push(Segment { data, next_branch }); + data = child; + } + std::cmp::Ordering::Greater => { + debug_assert!(false, "LCP of prefix and key can't be greater than key"); + unsafe { std::hint::unreachable_unchecked() }; + } } + }; - // Create fork - let mut builder = CellBuilder::new(); - ok!(write_label(lcp, prev_key_bit_len, &mut builder)); - ok!(builder.store_reference(left)); - ok!(builder.store_reference(right)); - builder.build_ext(finalizer) - } + leaf = ok!(rebuild_dict_from_stack(stack, leaf, finalizer)); + + Ok((Some(leaf), true)) +} +/// Inserts the value associated with key in dictionary +/// in accordance with the logic of the specified [`SetMode`]. +/// +/// Returns a tuple with a new dict root, changed flag and the previous value. +pub fn dict_insert_owned( + root: &Option, + key: &mut CellSlice, + key_bit_len: u16, + value: &CellSlice, + mode: SetMode, + finalizer: &mut dyn Finalizer, +) -> Result<(Option, bool, Option), Error> { if key.remaining_bits() != key_bit_len { return Err(Error::CellUnderflow); } - let mut data = match root.as_ref() { - Some(data) => data.as_ref(), + let root = match root.as_ref() { + Some(data) => data, None if mode.can_add() => { let data = ok!(make_leaf(key, key_bit_len, value, finalizer)); - return Ok(Some(data)); + return Ok((Some(data), true, None)); } - None => return Ok(None), + None => return Ok((None, false, None)), }; - + let mut data = root.as_ref(); let mut stack = Vec::::new(); - let mut leaf = loop { + let (mut leaf, value_range) = loop { let mut remaining_data = ok!(data.as_slice()); // Read the next part of the key from the current data @@ -276,18 +318,24 @@ pub fn dict_insert( std::cmp::Ordering::Equal => { // Check if we can replace the value if !mode.can_replace() { - return Ok(root.clone()); + return Ok((Some(root.clone()), false, None)); } // Replace the existing value - break ok!(make_leaf(prefix, key.remaining_bits(), value, finalizer)); + break ( + ok!(make_leaf(prefix, key.remaining_bits(), value, finalizer)), + Some(remaining_data.range()), + ); } // LCP is less than prefix, an edge to slice was found std::cmp::Ordering::Less if lcp.remaining_bits() < prefix.remaining_bits() => { // Check if we can add a new value if !mode.can_add() { - return Ok(root.clone()); + return Ok((Some(root.clone()), false, None)); } - break ok!(split(&remaining_data, prefix, &lcp, key, value, finalizer)); + break ( + ok!(split(&remaining_data, prefix, &lcp, key, value, finalizer)), + None, + ); } // The key contains the entire prefix, but there are still some bits left std::cmp::Ordering::Less => { @@ -321,9 +369,22 @@ pub fn dict_insert( } }; + let value = match value_range { + Some(range) => match stack.last() { + Some(Segment { data, next_branch }) => { + match data.reference_cloned(*next_branch as u8) { + Some(cell) => Some((cell, range)), + None => return Err(Error::CellUnderflow), + } + } + None => Some((root.clone(), range)), + }, + None => None, + }; + leaf = ok!(rebuild_dict_from_stack(stack, leaf, finalizer)); - Ok(Some(leaf)) + Ok((Some(leaf), true, value)) } /// Returns a `CellSlice` of the value corresponding to the key. @@ -822,6 +883,56 @@ pub fn dict_remove_bound_owned( Ok((Some(leaf), Some((key, removed)))) } +// Creates a leaf node +fn make_leaf( + key: &CellSlice, + key_bit_len: u16, + value: &CellSlice, + finalizer: &mut dyn Finalizer, +) -> Result { + let mut builder = CellBuilder::new(); + ok!(write_label(key, key_bit_len, &mut builder)); + ok!(builder.store_slice(value)); + builder.build_ext(finalizer) +} + +// Splits an edge or leaf +fn split( + data: &CellSlice, + prefix: &mut CellSlice, + lcp: &CellSlice, + key: &mut CellSlice, + value: &CellSlice, + finalizer: &mut dyn Finalizer, +) -> Result { + // Advance the key + let prev_key_bit_len = key.remaining_bits(); + if !key.try_advance(lcp.remaining_bits() + 1, 0) { + return Err(Error::CellUnderflow); + } + + // Read the next bit from the data + prefix.try_advance(lcp.remaining_bits(), 0); + let old_to_right = ok!(prefix.load_bit()); + + // Create a leaf for the old value + let mut left = ok!(make_leaf(prefix, key.remaining_bits(), data, finalizer)); + // Create a leaf for the right value + let mut right = ok!(make_leaf(key, key.remaining_bits(), value, finalizer)); + + // The part that starts with 1 goes to the right cell + if old_to_right { + std::mem::swap(&mut left, &mut right); + } + + // Create fork + let mut builder = CellBuilder::new(); + ok!(write_label(lcp, prev_key_bit_len, &mut builder)); + ok!(builder.store_reference(left)); + ok!(builder.store_reference(right)); + builder.build_ext(finalizer) +} + /// Type alias for a pair of key and value as cell slice parts. pub type DictOwnedEntry = (CellBuilder, CellSliceParts); diff --git a/src/dict/raw.rs b/src/dict/raw.rs index 1dc363e2..e238a12b 100644 --- a/src/dict/raw.rs +++ b/src/dict/raw.rs @@ -233,8 +233,8 @@ impl RawDict { mut key: CellSlice<'_>, value: CellSlice<'_>, finalizer: &mut dyn Finalizer, - ) -> Result<(), Error> { - self.0 = ok!(dict_insert( + ) -> Result { + let (new_root, changed) = ok!(dict_insert( &self.0, &mut key, N, @@ -242,7 +242,8 @@ impl RawDict { SetMode::Set, finalizer )); - Ok(()) + self.0 = new_root; + Ok(changed) } /// Sets the value associated with the key in the dictionary @@ -252,8 +253,8 @@ impl RawDict { mut key: CellSlice<'_>, value: CellSlice<'_>, finalizer: &mut dyn Finalizer, - ) -> Result<(), Error> { - self.0 = ok!(dict_insert( + ) -> Result { + let (new_root, changed) = ok!(dict_insert( &self.0, &mut key, N, @@ -261,7 +262,8 @@ impl RawDict { SetMode::Replace, finalizer )); - Ok(()) + self.0 = new_root; + Ok(changed) } /// Sets the value associated with key in dictionary, @@ -271,8 +273,8 @@ impl RawDict { mut key: CellSlice<'_>, value: CellSlice<'_>, finalizer: &mut dyn Finalizer, - ) -> Result<(), Error> { - self.0 = ok!(dict_insert( + ) -> Result { + let (new_root, changed) = ok!(dict_insert( &self.0, &mut key, N, @@ -280,7 +282,8 @@ impl RawDict { SetMode::Add, finalizer )); - Ok(()) + self.0 = new_root; + Ok(changed) } /// Removes the value associated with key in dictionary. @@ -356,7 +359,7 @@ impl RawDict { /// Use [`set_ext`] if you need to use a custom finalizer. /// /// [`set_ext`]: RawDict::set_ext - pub fn set(&mut self, key: CellSlice<'_>, value: CellSlice<'_>) -> Result<(), Error> { + pub fn set(&mut self, key: CellSlice<'_>, value: CellSlice<'_>) -> Result { self.set_ext(key, value, &mut Cell::default_finalizer()) } @@ -366,7 +369,7 @@ impl RawDict { /// Use [`replace_ext`] if you need to use a custom finalizer. /// /// [`replace_ext`]: RawDict::replace_ext - pub fn replace(&mut self, key: CellSlice<'_>, value: CellSlice<'_>) -> Result<(), Error> { + pub fn replace(&mut self, key: CellSlice<'_>, value: CellSlice<'_>) -> Result { self.replace_ext(key, value, &mut Cell::default_finalizer()) } @@ -376,7 +379,7 @@ impl RawDict { /// Use [`add_ext`] if you need to use a custom finalizer. /// /// [`add_ext`]: RawDict::add_ext - pub fn add(&mut self, key: CellSlice<'_>, value: CellSlice<'_>) -> Result<(), Error> { + pub fn add(&mut self, key: CellSlice<'_>, value: CellSlice<'_>) -> Result { self.add_ext(key, value, &mut Cell::default_finalizer()) } diff --git a/src/dict/typed.rs b/src/dict/typed.rs index d1aa3e8c..4f965f4e 100644 --- a/src/dict/typed.rs +++ b/src/dict/typed.rs @@ -245,7 +245,7 @@ where /// Use [`set_ext`] if you need to use a custom finalizer. /// /// [`set_ext`]: Dict::set_ext - pub fn set(&mut self, key: Q, value: T) -> Result<(), Error> + pub fn set(&mut self, key: Q, value: T) -> Result where Q: Borrow, T: Borrow, @@ -259,7 +259,7 @@ where /// Use [`replace_ext`] if you need to use a custom finalizer. /// /// [`replace_ext`]: Dict::replace_ext - pub fn replace(&mut self, key: Q, value: T) -> Result<(), Error> + pub fn replace(&mut self, key: Q, value: T) -> Result where Q: Borrow, T: Borrow, @@ -273,7 +273,7 @@ where /// Use [`add_ext`] if you need to use a custom finalizer. /// /// [`add_ext`]: Dict::add_ext - pub fn add(&mut self, key: Q, value: T) -> Result<(), Error> + pub fn add(&mut self, key: Q, value: T) -> Result where Q: Borrow, T: Borrow, @@ -741,7 +741,7 @@ where key: Q, value: T, finalizer: &mut dyn Finalizer, - ) -> Result<(), Error> + ) -> Result where Q: Borrow, T: Borrow, @@ -756,7 +756,7 @@ where key: Q, value: T, finalizer: &mut dyn Finalizer, - ) -> Result<(), Error> + ) -> Result where Q: Borrow, T: Borrow, @@ -771,7 +771,7 @@ where key: Q, value: T, finalizer: &mut dyn Finalizer, - ) -> Result<(), Error> + ) -> Result where Q: Borrow, T: Borrow, @@ -785,14 +785,14 @@ where value: &V, mode: SetMode, finalizer: &mut dyn Finalizer, - ) -> Result<(), Error> + ) -> Result where K: Store + DictKey, V: Store, { let key = ok!(serialize_entry(key, finalizer)); let value = ok!(serialize_entry(value, finalizer)); - self.root = ok!(dict_insert( + let (new_root, changed) = ok!(dict_insert( &self.root, &mut ok!(key.as_ref().as_slice()), K::BITS, @@ -800,7 +800,8 @@ where mode, finalizer )); - Ok(()) + self.root = new_root; + Ok(changed) } } @@ -970,10 +971,10 @@ mod tests { #[test] fn dict_set() { let mut dict = Dict::::new(); - dict.set(123, 0xffff).unwrap(); + assert!(dict.set(123, 0xffff).unwrap()); assert_eq!(dict.get(123).unwrap(), Some(0xffff)); - dict.set(123, 0xcafe).unwrap(); + assert!(dict.set(123, 0xcafe).unwrap()); assert_eq!(dict.get(123).unwrap(), Some(0xcafe)); } @@ -982,7 +983,7 @@ mod tests { fn dict_set_complex() { let mut dict = Dict::::new(); for i in 0..520 { - dict.set(i, true).unwrap(); + assert!(dict.set(i, true).unwrap()); } } @@ -990,7 +991,7 @@ mod tests { fn dict_bounds() { let mut dict = Dict::::new(); for i in -10..=10 { - dict.set(i, i < 0).unwrap(); + assert!(dict.set(i, i < 0).unwrap()); } assert_eq!(dict.get_min(false).unwrap(), Some((0, false))); @@ -1072,12 +1073,12 @@ mod tests { #[test] fn dict_replace() { let mut dict = Dict::::new(); - dict.replace(123, false).unwrap(); + assert!(!dict.replace(123, false).unwrap()); assert!(!dict.contains_key(123).unwrap()); - dict.set(123, false).unwrap(); + assert!(dict.set(123, false).unwrap()); assert_eq!(dict.get(123).unwrap(), Some(false)); - dict.replace(123, true).unwrap(); + assert!(dict.replace(123, true).unwrap()); assert_eq!(dict.get(123).unwrap(), Some(true)); } @@ -1085,10 +1086,10 @@ mod tests { fn dict_add() { let mut dict = Dict::::new(); - dict.add(123, false).unwrap(); + assert!(dict.add(123, false).unwrap()); assert_eq!(dict.get(123).unwrap(), Some(false)); - dict.add(123, true).unwrap(); + assert!(!dict.add(123, true).unwrap()); assert_eq!(dict.get(123).unwrap(), Some(false)); } @@ -1097,7 +1098,7 @@ mod tests { let mut dict = Dict::::new(); for i in 0..10 { - dict.set(i, i).unwrap(); + assert!(dict.set(i, i).unwrap()); } let mut check_remove = |n: u32, expected: Option| -> anyhow::Result<()> {