Skip to content

Commit

Permalink
split folder hierachy into bv and array
Browse files Browse the repository at this point in the history
  • Loading branch information
ekiwi committed Sep 20, 2024
1 parent a6ffb75 commit 38aafcc
Show file tree
Hide file tree
Showing 19 changed files with 486 additions and 419 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "baa"
version = "0.9.5"
version = "0.10.0"
edition = "2021"
authors = ["Kevin Laeufer <[email protected]>"]
description = "BitVector and Array Arithmetic"
Expand Down
84 changes: 5 additions & 79 deletions src/value/borrowed.rs → src/array/borrowed.rs
Original file line number Diff line number Diff line change
@@ -1,85 +1,11 @@
// Copyright 2023-2024 The Regents of the University of California
// Copyright 2024 Cornell University
// released under BSD 3-Clause License
// author: Kevin Laeufer <[email protected]>
//
// Borrowed bit-vector and array values.

use crate::{
ArrayMutOps, ArrayOps, ArrayValue, BitVecMutOps, BitVecOps, BitVecValue, WidthInt, Word,
};

/// Bit-vector value that does not own its storage.
#[derive(Clone, Copy)]
pub struct BitVecValueRef<'a> {
pub(crate) width: WidthInt,
pub(crate) words: &'a [Word],
}

impl<'a> BitVecValueRef<'a> {
pub(crate) fn new(width: WidthInt, words: &'a [Word]) -> Self {
Self { width, words }
}
}

impl<'a> From<&'a BitVecValue> for BitVecValueRef<'a> {
fn from(value: &'a BitVecValue) -> Self {
Self::new(value.width, value.words.as_ref())
}
}

impl<'a> std::fmt::Debug for BitVecValueRef<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "BitVecValueRef({})", self.to_bit_str())
}
}

pub struct BitVecValueMutRef<'a> {
pub(crate) width: WidthInt,
pub(crate) words: &'a mut [Word],
}

impl<'a> BitVecValueMutRef<'a> {
pub(crate) fn new(width: WidthInt, words: &'a mut [Word]) -> Self {
Self { width, words }
}
}

impl<'a> From<&'a mut BitVecValue> for BitVecValueMutRef<'a> {
fn from(value: &'a mut BitVecValue) -> Self {
Self::new(value.width, value.words.as_mut())
}
}
impl<'a> std::fmt::Debug for BitVecValueMutRef<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "BitVecValueMutRef({})", self.to_bit_str())
}
}
// author: Kevin Laeufer <[email protected]>

impl<'a> BitVecOps for BitVecValueRef<'a> {
fn width(&self) -> WidthInt {
self.width
}

fn words(&self) -> &[Word] {
self.words
}
}

impl<'a> BitVecOps for BitVecValueMutRef<'a> {
fn width(&self) -> WidthInt {
self.width
}

fn words(&self) -> &[Word] {
self.words
}
}

impl<'a> BitVecMutOps for BitVecValueMutRef<'a> {
fn words_mut(&mut self) -> &mut [Word] {
self.words
}
}
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)]
Expand Down
158 changes: 158 additions & 0 deletions src/array/indexed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// Copyright 2023-2024 The Regents of the University of California
// Copyright 2024 Cornell University
// released under BSD 3-Clause License
// author: Kevin Laeufer <[email protected]>

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<usize> {
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<I, ArrayValueRef<'a>> for &'a [Word]
where
I: Borrow<ArrayValueIndex>,
{
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<I, ArrayValueMutRef<'a>> for &'a mut [Word]
where
I: Borrow<ArrayValueIndex>,
{
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<ArrayValueIndex>,
I2: Borrow<ArrayValueIndex>,
{
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::<WidthInt>(), 4);
assert_eq!(std::mem::size_of::<ArrayValueIndex>(), 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);
}
}
13 changes: 13 additions & 0 deletions src/array/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2024 Cornell University
// released under BSD 3-Clause License
// author: Kevin Laeufer <[email protected]>

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;
82 changes: 82 additions & 0 deletions src/array/ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2023-2024 The Regents of the University of California
// Copyright 2024 Cornell University
// released under BSD 3-Clause License
// author: Kevin Laeufer <[email protected]>
//
// Traits for operations on arrays.

use crate::{
ArrayValueRef, BitVecMutOps, BitVecOps, BitVecValueMutRef, BitVecValueRef, WidthInt, Word,
};

pub const DENSE_ARRAY_MAX_INDEX_WIDTH: WidthInt = 48;

/// Operations implemented by read-only array values with a dense representation.
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
}
#[inline]
fn num_elements(&self) -> usize {
1usize << self.index_width()
}
fn select<'a>(&self, index: impl Into<BitVecValueRef<'a>>) -> 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<R: ArrayOps + ?Sized>(&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<BitVecValueRef<'a>>,
data: impl Into<BitVecValueRef<'b>>,
) {
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<I: BitVecOps>(&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<ArrayValueRef<'a>>) {
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;
});
}
}
36 changes: 36 additions & 0 deletions src/array/owned.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2023-2024 The Regents of the University of California
// Copyright 2024 Cornell University
// released under BSD 3-Clause License
// author: Kevin Laeufer <[email protected]>

use crate::array::ops::{ArrayMutOps, ArrayOps};
use crate::{WidthInt, Word};

/// Owned dense bit-vector array.
#[derive(Clone)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub struct ArrayValue {
pub(crate) index_width: WidthInt,
pub(crate) data_width: WidthInt,
pub(crate) words: Vec<Word>,
}

impl ArrayOps for ArrayValue {
fn index_width(&self) -> WidthInt {
self.index_width
}

fn data_width(&self) -> WidthInt {
self.data_width
}

fn words(&self) -> &[Word] {
&self.words
}
}

impl ArrayMutOps for ArrayValue {
fn words_mut(&mut self) -> &mut [Word] {
&mut self.words
}
}
Loading

0 comments on commit 38aafcc

Please sign in to comment.