diff --git a/Cargo.toml b/Cargo.toml index 3e07ce3..8bbbb4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baa" -version = "0.10.0" +version = "0.11.0" edition = "2021" authors = ["Kevin Laeufer "] description = "BitVector and Array Arithmetic" diff --git a/src/array/borrowed.rs b/src/array/borrowed.rs deleted file mode 100644 index 05a2100..0000000 --- a/src/array/borrowed.rs +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2023-2024 The Regents of the University of California -// Copyright 2024 Cornell University -// released under BSD 3-Clause License -// author: Kevin Laeufer - -use crate::array::ops::{ArrayMutOps, ArrayOps}; -use crate::array::owned::ArrayValue; -use crate::{WidthInt, Word}; - -/// Bit-vector array value that does not own its storage. -#[derive(Clone)] -pub struct ArrayValueRef<'a> { - pub(crate) index_width: WidthInt, - pub(crate) data_width: WidthInt, - pub(crate) words: &'a [Word], -} - -impl<'a> ArrayValueRef<'a> { - pub(crate) fn new(index_width: WidthInt, data_width: WidthInt, words: &'a [Word]) -> Self { - Self { - index_width, - data_width, - words, - } - } -} - -impl<'a> From<&'a ArrayValue> for ArrayValueRef<'a> { - fn from(value: &'a ArrayValue) -> Self { - Self::new(value.index_width, value.index_width, value.words.as_ref()) - } -} - -impl<'a> std::fmt::Debug for ArrayValueRef<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "ArrayValueRef(bv<{}> -> bv<{}>)", - self.index_width, self.data_width - ) - } -} - -impl<'a> ArrayOps for ArrayValueRef<'a> { - fn index_width(&self) -> WidthInt { - self.index_width - } - - fn data_width(&self) -> WidthInt { - self.data_width - } - - fn words(&self) -> &[Word] { - self.words - } -} - -/// Mutable bit-vector array value that does not own its storage. -pub struct ArrayValueMutRef<'a> { - pub(crate) index_width: WidthInt, - pub(crate) data_width: WidthInt, - pub(crate) words: &'a mut [Word], -} - -impl<'a> ArrayValueMutRef<'a> { - pub(crate) fn new(index_width: WidthInt, data_width: WidthInt, words: &'a mut [Word]) -> Self { - Self { - index_width, - data_width, - words, - } - } -} - -impl<'a> From<&'a mut ArrayValue> for ArrayValueMutRef<'a> { - fn from(value: &'a mut ArrayValue) -> Self { - Self::new( - value.index_width, - value.index_width, - value.words.as_mut_slice(), - ) - } -} - -impl<'a> std::fmt::Debug for ArrayValueMutRef<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "ArrayValueMutRef(bv<{}> -> bv<{}>)", - self.index_width, self.data_width - ) - } -} - -impl<'a> ArrayOps for ArrayValueMutRef<'a> { - fn index_width(&self) -> WidthInt { - self.index_width - } - - fn data_width(&self) -> WidthInt { - self.data_width - } - - fn words(&self) -> &[Word] { - self.words - } -} - -impl<'a> ArrayMutOps for ArrayValueMutRef<'a> { - fn words_mut(&mut self) -> &mut [Word] { - self.words - } -} diff --git a/src/array/indexed.rs b/src/array/indexed.rs deleted file mode 100644 index 2111595..0000000 --- a/src/array/indexed.rs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2023-2024 The Regents of the University of California -// Copyright 2024 Cornell University -// released under BSD 3-Clause License -// author: Kevin Laeufer - -use crate::array::borrowed::{ArrayValueMutRef, ArrayValueRef}; -use crate::{BitVecValueIndex, IndexToMutRef, IndexToRef, WidthInt, Word}; -use std::borrow::Borrow; - -/// Index of an array value in a shared value store. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct ArrayValueIndex { - pub(super) first: BitVecValueIndex, - pub(super) index_width: WidthInt, -} - -impl ArrayValueIndex { - pub fn new(first: BitVecValueIndex, index_width: WidthInt) -> Self { - Self { first, index_width } - } -} - -impl ArrayValueIndex { - #[inline] - pub fn num_elements(&self) -> usize { - 1usize << self.index_width - } - - #[inline] - pub fn words(&self) -> usize { - self.first.words() * self.num_elements() - } - - #[inline] - pub fn to_range(&self) -> std::ops::Range { - let start = self.first.index as usize; - let end = start + self.words(); - start..end - } - - #[inline] - pub fn first_element_index(&self) -> BitVecValueIndex { - self.first - } -} - -impl<'a, I> IndexToRef> for &'a [Word] -where - I: Borrow, -{ - fn get_ref(self, index: I) -> ArrayValueRef<'a> { - ArrayValueRef { - index_width: index.borrow().index_width, - data_width: index.borrow().first.width(), - words: &self[index.borrow().to_range()], - } - } -} - -impl<'a, I> IndexToMutRef> for &'a mut [Word] -where - I: Borrow, -{ - fn get_mut_ref(self, index: I) -> ArrayValueMutRef<'a> { - ArrayValueMutRef { - index_width: index.borrow().index_width, - data_width: index.borrow().first.width(), - words: &mut self[index.borrow().to_range()], - } - } -} - -impl<'a, I1, I2> IndexToMutRef<(I1, I2), (ArrayValueMutRef<'a>, ArrayValueRef<'a>)> - for &'a mut [Word] -where - I1: Borrow, - I2: Borrow, -{ - fn get_mut_ref(self, (a, b): (I1, I2)) -> (ArrayValueMutRef<'a>, ArrayValueRef<'a>) { - let (a_words, b_words) = - crate::bv::split_borrow_1(self, a.borrow().to_range(), b.borrow().to_range()); - - ( - ArrayValueMutRef { - index_width: a.borrow().index_width, - data_width: a.borrow().first.width(), - words: a_words, - }, - ArrayValueRef { - index_width: b.borrow().index_width, - data_width: b.borrow().first.width(), - words: b_words, - }, - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ArrayMutOps, BitVecValue}; - - #[test] - fn type_size() { - assert_eq!(std::mem::size_of::(), 4); - assert_eq!(std::mem::size_of::(), 12); - } - - #[test] - fn test_array_index() { - let mut backend = [0; 32]; - - // a four element array with 2-word entries - let a0 = BitVecValueIndex::new(1, 65); - let a = a0.to_array_index(2); - assert_eq!(a.num_elements(), 4); - assert_eq!(a.words(), 8); - assert_eq!(a.to_range(), 1..9); - - // another array of the same size - let b = BitVecValueIndex::new(9, 65).to_array_index(2); - - // set some elements - { - let mut a = backend.get_mut_ref(a); - a.store( - &BitVecValue::from_u64(1, 2), - &BitVecValue::from_u64(1234, 65), - ); - a.store( - &BitVecValue::from_u64(3, 2), - &BitVecValue::from_u64(555555, 65), - ); - } - assert_eq!(backend[2 + 1], 1234); - assert_eq!(backend[3 + 1], 0); - assert_eq!(backend[6 + 1], 555555); - assert_eq!(backend[7 + 1], 0); - - // check b array storage and initialize to magic value - for ii in 9..(9 + 2 * 4) { - assert_eq!(backend[ii], 0); - backend[ii] = 99999; - } - - // assign b := a - { - let (mut b, a) = backend.get_mut_ref((b, a)); - b.assign(a); - } - - // check new b values - assert_eq!(backend[2 + 9], 1234); - assert_eq!(backend[3 + 9], 0); - assert_eq!(backend[6 + 9], 555555); - assert_eq!(backend[7 + 9], 0); - } -} diff --git a/src/array/mod.rs b/src/array/mod.rs index 7bec7e5..6903bb1 100644 --- a/src/array/mod.rs +++ b/src/array/mod.rs @@ -2,12 +2,8 @@ // released under BSD 3-Clause License // author: Kevin Laeufer -mod borrowed; -mod indexed; mod ops; mod owned; -pub use borrowed::{ArrayValueMutRef, ArrayValueRef}; -pub use indexed::ArrayValueIndex; pub use ops::{ArrayMutOps, ArrayOps}; pub use owned::ArrayValue; diff --git a/src/array/ops.rs b/src/array/ops.rs index adb6f90..713085d 100644 --- a/src/array/ops.rs +++ b/src/array/ops.rs @@ -5,9 +5,7 @@ // // Traits for operations on arrays. -use crate::{ - ArrayValueRef, BitVecMutOps, BitVecOps, BitVecValueMutRef, BitVecValueRef, WidthInt, Word, -}; +use crate::{BitVecValueRef, WidthInt, Word}; pub const DENSE_ARRAY_MAX_INDEX_WIDTH: WidthInt = 48; @@ -15,7 +13,6 @@ pub const DENSE_ARRAY_MAX_INDEX_WIDTH: WidthInt = 48; pub trait ArrayOps { fn index_width(&self) -> WidthInt; fn data_width(&self) -> WidthInt; - fn words(&self) -> &[Word]; #[inline] fn words_per_element(&self) -> usize { self.data_width().div_ceil(Word::BITS) as usize @@ -24,59 +21,69 @@ pub trait ArrayOps { fn num_elements(&self) -> usize { 1usize << self.index_width() } - fn select<'a>(&self, index: impl Into>) -> BitVecValueRef { - let index = index.into(); - debug_assert!(self.index_width() <= DENSE_ARRAY_MAX_INDEX_WIDTH); - debug_assert_eq!(self.index_width(), index.width()); - debug_assert_eq!(index.words().len(), 1); - let start = self.words_per_element() * index.words()[0] as usize; - let end = start + self.words_per_element(); - BitVecValueRef::new(self.data_width(), &self.words()[start..end]) - } - fn is_equal(&self, rhs: &R) -> bool { - debug_assert_eq!(self.index_width(), rhs.index_width()); - debug_assert_eq!(self.data_width(), rhs.data_width()); - self.words() == rhs.words() - } + fn select<'a>(&self, index: impl Into>) -> BitVecValueRef; + // { + // let index = index.into(); + // debug_assert!(self.index_width() <= DENSE_ARRAY_MAX_INDEX_WIDTH); + // debug_assert_eq!(self.index_width(), index.width()); + // debug_assert_eq!(index.words().len(), 1); + // let start = self.words_per_element() * index.words()[0] as usize; + // let end = start + self.words_per_element(); + // BitVecValueRef::new(self.data_width(), &self.words()[start..end]) + // } + fn is_equal(&self, rhs: &R) -> bool; + + // { + // debug_assert_eq!(self.index_width(), rhs.index_width()); + // debug_assert_eq!(self.data_width(), rhs.data_width()); + // self.words() == rhs.words() + // } } /// Operations implemented by mutable array values with a dense representation. pub trait ArrayMutOps: ArrayOps { - fn words_mut(&mut self) -> &mut [Word]; fn store<'a, 'b>( &mut self, index: impl Into>, data: impl Into>, - ) { - let index = index.into(); - debug_assert!(self.index_width() <= DENSE_ARRAY_MAX_INDEX_WIDTH); - debug_assert_eq!(self.index_width(), index.width()); - debug_assert_eq!(index.words().len(), 1); - let start = self.words_per_element() * index.words()[0] as usize; - let end = start + self.words_per_element(); - let mut element = - BitVecValueMutRef::new(self.data_width(), &mut self.words_mut()[start..end]); - element.assign(data); - } - fn select_mut(&mut self, index: I) -> BitVecValueMutRef { - debug_assert!(self.index_width() <= DENSE_ARRAY_MAX_INDEX_WIDTH); - debug_assert_eq!(self.index_width(), index.width()); - debug_assert_eq!(index.words().len(), 1); - let start = self.words_per_element() * index.words()[0] as usize; - let end = start + self.words_per_element(); - BitVecValueMutRef::new(self.data_width(), &mut self.words_mut()[start..end]) - } - fn assign<'a>(&mut self, value: impl Into>) { - let value = value.into(); - debug_assert_eq!(self.index_width(), value.index_width()); - debug_assert_eq!(self.data_width(), value.data_width()); - debug_assert_eq!(self.words_mut().len(), value.words().len()); - self.words_mut().copy_from_slice(value.words()); - } + ); + + // { + // let index = index.into(); + // debug_assert!(self.index_width() <= DENSE_ARRAY_MAX_INDEX_WIDTH); + // debug_assert_eq!(self.index_width(), index.width()); + // debug_assert_eq!(index.words().len(), 1); + // let start = self.words_per_element() * index.words()[0] as usize; + // let end = start + self.words_per_element(); + // let mut element = + // BitVecValueMutRef::new(self.data_width(), &mut self.words_mut()[start..end]); + // element.assign(data); + // } + + // only works for dense arrays + // fn select_mut(&mut self, index: I) -> BitVecValueMutRef { + // debug_assert!(self.index_width() <= DENSE_ARRAY_MAX_INDEX_WIDTH); + // debug_assert_eq!(self.index_width(), index.width()); + // debug_assert_eq!(index.words().len(), 1); + // let start = self.words_per_element() * index.words()[0] as usize; + // let end = start + self.words_per_element(); + // BitVecValueMutRef::new(self.data_width(), &mut self.words_mut()[start..end]) + // } + + // only performs well for dense arrays + // fn assign<'a>(&mut self, value: impl Into>) { + // let value = value.into(); + // debug_assert_eq!(self.index_width(), value.index_width()); + // debug_assert_eq!(self.data_width(), value.data_width()); + // debug_assert_eq!(self.words_mut().len(), value.words().len()); + // self.words_mut().copy_from_slice(value.words()); + // } /// sets all bits to zero - fn clear(&mut self) { - self.words_mut().iter_mut().for_each(|w| { - *w = 0; - }); - } + fn clear(&mut self); + + // { + // self.words_mut().iter_mut().for_each(|w| { + // *w = 0; + // }); + // } } diff --git a/src/array/owned.rs b/src/array/owned.rs index de7528c..285d694 100644 --- a/src/array/owned.rs +++ b/src/array/owned.rs @@ -4,7 +4,8 @@ // author: Kevin Laeufer use crate::array::ops::{ArrayMutOps, ArrayOps}; -use crate::{WidthInt, Word}; +use crate::{BitVecValue, WidthInt, Word}; +use std::collections::HashMap; /// Owned dense bit-vector array. #[derive(Clone)] @@ -23,14 +24,64 @@ impl ArrayOps for ArrayValue { fn data_width(&self) -> WidthInt { self.data_width } +} - fn words(&self) -> &[Word] { - &self.words - } +impl ArrayMutOps for ArrayValue {} + +#[derive(Clone)] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +pub struct DenseArrayValue { + index_width: WidthInt, + data_width: WidthInt, + data: DenseArrayImpl, } -impl ArrayMutOps for ArrayValue { - fn words_mut(&mut self) -> &mut [Word] { - &mut self.words +#[derive(Clone)] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +enum DenseArrayImpl { + Bit(BitVecValue), + U8(Vec), + U64(Vec), + Big(Vec), +} + +#[derive(Clone)] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +pub struct SparseArrayValue { + index_width: WidthInt, + data_width: WidthInt, + data: SparseArrayImpl, +} + +#[derive(Clone)] +#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +enum SparseArrayImpl { + U64U64(u64, HashMap), + U64Big(BitVecValue, HashMap), + BigBig(BitVecValue, HashMap), +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn type_size() { + // Dense Array Size + assert_eq!(std::mem::size_of::>(), 24); + assert_eq!(std::mem::size_of::(), 32); + assert_eq!(std::mem::size_of::(), 40); // BitVecValue size + tag + padding + assert_eq!(std::mem::size_of::(), 48); // Impl + size + padding + + // Sparse Array Size + + // the hash table size is independent of the key/value types + assert_eq!(std::mem::size_of::>(), 48); + assert_eq!(std::mem::size_of::>(), 48); + assert_eq!(std::mem::size_of::>(), 48); + + // HashMap + BitVecValue + tag + padding + assert_eq!(std::mem::size_of::(), 48 + 32 + 8); + assert_eq!(std::mem::size_of::(), 88 + 8); // Impl + size + padding } } diff --git a/src/bv/indexed.rs b/src/bv/indexed.rs index d456fea..3286e56 100644 --- a/src/bv/indexed.rs +++ b/src/bv/indexed.rs @@ -5,7 +5,7 @@ // Access a slice of `Word` as a bit-vector. use crate::bv::borrowed::{BitVecValueMutRef, BitVecValueRef}; -use crate::{ArrayValueIndex, BitVecOps, WidthInt, Word}; +use crate::{BitVecOps, WidthInt, Word}; use std::borrow::Borrow; use std::collections::HashMap; use std::fmt::{Debug, Formatter}; @@ -37,11 +37,6 @@ impl BitVecValueIndex { start..end } - #[inline] - pub fn to_array_index(&self, index_width: WidthInt) -> ArrayValueIndex { - ArrayValueIndex::new(self.clone(), index_width) - } - #[inline] pub fn width(&self) -> WidthInt { self.width diff --git a/src/bv/mod.rs b/src/bv/mod.rs index aca60f7..f8c97d5 100644 --- a/src/bv/mod.rs +++ b/src/bv/mod.rs @@ -12,7 +12,6 @@ mod owned; pub use arithmetic::mask; pub use borrowed::{BitVecValueMutRef, BitVecValueRef}; -pub(crate) use indexed::split_borrow_1; pub use indexed::{BitVecValueIndex, IndexToMutRef, IndexToRef, ValueInterner}; pub use ops::{BitVecMutOps, BitVecOps}; pub use owned::BitVecValue; diff --git a/src/container.rs b/src/container.rs deleted file mode 100644 index 04521c1..0000000 --- a/src/container.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 Cornell University -// released under BSD 3-Clause License -// author: Kevin Laeufer - -use crate::{ArrayValueRef, BitVecValueRef}; - -/// Array or BitVec value reference. -pub enum ValueRef<'a> { - BitVec(BitVecValueRef<'a>), - Array(ArrayValueRef<'a>), -} - -impl<'a> TryFrom> for BitVecValueRef<'a> { - type Error = (); - - fn try_from(value: ValueRef<'a>) -> Result { - match value { - ValueRef::BitVec(bv) => Ok(bv), - _ => Err(()), - } - } -} - -impl<'a> TryFrom> for ArrayValueRef<'a> { - type Error = (); - - fn try_from(value: ValueRef<'a>) -> Result { - match value { - ValueRef::Array(a) => Ok(a), - _ => Err(()), - } - } -} - -impl<'a> From> for ValueRef<'a> { - fn from(value: BitVecValueRef<'a>) -> Self { - ValueRef::BitVec(value) - } -} - -impl<'a> From> for ValueRef<'a> { - fn from(value: ArrayValueRef<'a>) -> Self { - ValueRef::Array(value) - } -} diff --git a/src/lib.rs b/src/lib.rs index 794375e..e212fb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ mod array; mod bv; -pub(crate) mod container; /// This type restricts the maximum width that a bit-vector type is allowed to have. pub type WidthInt = u32;