#![feature(iter_advance_by)]
#![forbid(unsafe_code)]
#![warn(missing_docs, broken_intra_doc_links)]
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering;
use std::borrow::Borrow;
use std::marker::PhantomData;
pub struct AtomicBitVec {
data: Vec<AtomicU64>
}
const fn next_mul_64(v: usize) -> usize {
(v + 64) & !63
}
impl AtomicBitVec {
pub const fn new() -> Self {
Self {
data: Vec::new()
}
}
pub fn size_in_mem(&self) -> usize {
std::mem::size_of::<Vec<AtomicU64>>() + self.data.len() * std::mem::size_of::<AtomicU64>()
}
pub fn with_bit_capacity(bit_cap: usize) -> Self {
let blocks = next_mul_64(bit_cap) / 64;
Self::with_capacity(blocks)
}
pub fn with_capacity(blocks: usize) -> Self {
Self {
data: Vec::with_capacity(blocks)
}
}
pub fn resize_blocks_with(&mut self, new_blocks: usize, f: impl FnMut() -> AtomicU64) {
self.data.resize_with(new_blocks, f)
}
pub fn resize_bits_with(&mut self, new_bits: usize, f: impl FnMut() -> AtomicU64) {
let blocks = next_mul_64(new_bits) / 64;
self.data.resize_with(blocks, f)
}
pub fn block_cnt(&self) -> usize {
self.data.len()
}
pub fn len(&self) -> usize {
self.block_cnt() * 64
}
pub fn set(&self, idx: usize, value: bool, ordering: Ordering) -> bool {
let (loc, mask) = Self::loc_and_mask(idx);
let dest: &AtomicU64 = &self.data[loc];
if value {
let prev = dest.fetch_or(mask, ordering);
prev & mask != 0
} else {
let unset_mask = !mask;
let prev = dest.fetch_and(unset_mask, ordering);
prev & mask != 0
}
}
pub fn get(&self, idx: usize, ordering: Ordering) -> bool {
let (loc, mask) = Self::loc_and_mask(idx);
let dest: &AtomicU64 = &self.data[loc];
dest.load(ordering) & mask != 0
}
pub fn iter<'a>(&'a self, ordering: Ordering) -> impl Iterator<Item=bool> + 'a {
Iter::new(self, ordering)
}
const fn loc_and_mask(idx: usize) -> (usize, u64) {
let mask = 1u64 << (idx & (64 - 1));
let block = idx >> (64u64.trailing_zeros());
(block, mask)
}
pub fn count_ones(&self, ordering: Ordering) -> u64 {
self.data.iter()
.map(|n| n.load(ordering).count_ones() as u64)
.sum()
}
}
pub struct Iter<'a, Inner> where Inner: Borrow<AtomicBitVec> + 'a {
src: Inner,
order: Ordering,
idx: usize,
back_idx: usize,
phony: PhantomData<&'a AtomicBitVec>,
}
impl<'a, Inner> Iter<'a, Inner> where Inner: Borrow<AtomicBitVec> + 'a {
pub(crate) fn src(&self) -> &AtomicBitVec {
self.src.borrow()
}
}
impl<'a> Iter<'a, &'a AtomicBitVec> {
pub(crate) fn new(orig: &'a AtomicBitVec, order: Ordering) -> Self {
let bit_size = orig.len();
Self {
src: orig,
order,
idx: 0,
back_idx: bit_size,
phony: PhantomData::default(),
}
}
}
impl IntoIterator for AtomicBitVec {
type Item = bool;
type IntoIter = Iter<'static, AtomicBitVec>;
fn into_iter(self) -> Self::IntoIter {
let bs = self.len();
Iter {
src: self,
order: Ordering::Acquire,
idx: 0,
back_idx: bs,
phony: Default::default(),
}
}
}
impl<'a, Inner> Iterator for Iter<'a, Inner> where Inner: Borrow<AtomicBitVec> + 'a {
type Item = bool;
fn next(&mut self) -> Option<Self::Item> {
if self.idx < self.back_idx {
let o = self.src().get(self.idx, self.order);
self.idx += 1;
Some(o)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let hint = self.back_idx - self.idx;
(hint, Some(hint))
}
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
if self.idx + n <= self.back_idx {
self.idx += n;
Ok(())
} else {
let e = self.back_idx - self.idx;
self.idx += n;
Err(e)
}
}
}
impl<'a, Inner> ExactSizeIterator for Iter<'a, Inner> where Inner: Borrow<AtomicBitVec> + 'a {}
impl<'a, Inner> DoubleEndedIterator for Iter<'a, Inner> where Inner: Borrow<AtomicBitVec> + 'a {
fn next_back(&mut self) -> Option<Self::Item> {
if self.idx < self.back_idx {
let o = self.src().get(self.back_idx - 1, self.order);
self.back_idx = self.back_idx.saturating_sub(1);
Some(o)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
static_assertions::assert_impl_all!(AtomicBitVec: Sync);
}