use crate::Error;
use crate::Reset;
use bitvec::prelude::*;
use std::vec::Vec;
pub struct Vector<V> {
data: Vec<V>, update_flags: BitVec, valid_flags: BitVec, indices: Vec<usize>, is_updated: bool, }
impl<V> Default for Vector<V> {
fn default() -> Self {
Self::new()
}
}
impl<V> Vector<V> {
pub fn new() -> Self {
Self {
data: Vec::new(),
update_flags: BitVec::new(),
valid_flags: BitVec::new(),
indices: Vec::new(),
is_updated: false,
}
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: Vec::with_capacity(capacity),
update_flags: BitVec::with_capacity(capacity),
valid_flags: BitVec::with_capacity(capacity),
indices: Vec::with_capacity(capacity),
is_updated: false,
}
}
pub fn is_updated(&self) -> bool {
self.is_updated
}
pub fn all_updated(&self) -> bool {
self.is_updated && self.indices.is_empty()
}
pub fn clear(&mut self) {
self.data.clear();
self.update_flags.clear();
self.valid_flags.clear();
self.indices.clear();
self.is_updated = false;
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn iter(&self) -> std::slice::Iter<'_, V> {
self.data.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, V> {
if !self.all_updated() {
self.is_updated = true;
self.indices.clear();
self.update_flags.clear();
}
self.data.iter_mut()
}
pub fn get(&self, index: usize) -> Option<&V> {
self.data.get(index)
}
pub fn get_updated(&self, index: usize) -> Option<&V> {
if self.all_updated() || (self.update_flags.get(index).as_deref() == Some(&true)) {
self.data.get(index)
} else {
None
}
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut V> {
if index >= self.data.len() {
return None;
}
self.mark_dirty_internal(index);
self.data.get_mut(index)
}
fn mark_dirty_internal(&mut self, index: usize) {
if self.all_updated() {
return;
}
if index >= self.update_flags.len() {
self.update_flags.resize(self.data.len(), false);
}
if self.update_flags.get(index).as_deref() != Some(&true) {
self.update_flags.set(index, true);
self.indices.push(index);
self.is_updated = true;
if self.indices.len() == self.data.len() {
self.indices.clear();
self.update_flags.clear();
}
}
}
#[inline]
pub fn get_mut_untracked(&mut self, index: usize) -> Option<&mut V> {
self.data.get_mut(index)
}
pub fn push(&mut self, value: V) {
self.data.push(value);
self.valid_flags.push(false);
if self.all_updated() {
} else {
self.update_flags.push(true);
self.indices.push(self.data.len() - 1);
self.is_updated = true;
if self.indices.len() == self.data.len() {
self.indices.clear();
self.update_flags.clear();
}
}
}
pub fn push_committed(&mut self, value: V) {
self.data.push(value);
self.valid_flags.push(true);
if self.all_updated() {
} else {
self.update_flags.push(true);
self.indices.push(self.data.len() - 1);
self.is_updated = true;
if self.indices.len() == self.data.len() {
self.indices.clear();
self.update_flags.clear();
}
}
}
pub fn pop(&mut self) -> Option<V> {
let value = self.data.pop();
if value.is_some() {
let index = self.data.len();
self.valid_flags.pop();
if self.all_updated() {
} else {
self.update_flags.pop();
if let Some(pos) = self.indices.iter().position(|&i| i == index) {
let last = self.indices.len() - 1;
if pos != last {
self.indices.swap(pos, last);
}
self.indices.pop();
}
}
if self.data.is_empty() {
self.is_updated = false;
} else {
self.is_updated = self.all_updated() || !self.indices.is_empty();
}
}
value
}
#[inline]
pub fn is_valid(&self, index: usize) -> bool {
self.valid_flags
.get(index)
.as_deref()
.copied()
.unwrap_or(false)
}
#[inline]
pub fn get_valid(&self, index: usize) -> Option<&V> {
if self.is_valid(index) {
self.data.get(index)
} else {
None
}
}
pub fn commit(&mut self, index: usize, value: V) {
assert!(
index < self.data.len(),
"Vector::commit: index {} out of bounds (len = {})",
index,
self.data.len()
);
self.data[index] = value;
self.valid_flags.set(index, true);
self.mark_dirty_internal(index);
}
pub fn invalidate(&mut self, index: usize) {
assert!(
index < self.data.len(),
"Vector::invalidate: index {} out of bounds (len = {})",
index,
self.data.len()
);
self.valid_flags.set(index, false);
self.mark_dirty_internal(index);
}
#[must_use = "the returned SlotWriter must be consumed via commit() or invalidate()"]
pub fn slot_writer(&mut self, index: usize) -> SlotWriter<'_, V> {
assert!(
index < self.data.len(),
"Vector::slot_writer: index {} out of bounds (len = {})",
index,
self.data.len()
);
SlotWriter {
vector: self,
index,
consumed: false,
}
}
}
impl<V> Reset for Vector<V> {
type Error = Error;
fn reset(&mut self) -> Result<(), Error> {
self.update_flags.clear();
self.update_flags.resize(self.data.len(), false);
self.indices.clear();
self.is_updated = false;
Ok(())
}
}
#[must_use = "SlotWriter must be consumed via commit() or invalidate()"]
pub struct SlotWriter<'a, V> {
vector: &'a mut Vector<V>,
index: usize,
consumed: bool,
}
impl<'a, V> SlotWriter<'a, V> {
pub fn commit(mut self, value: V) {
self.vector.commit(self.index, value);
self.consumed = true;
}
pub fn invalidate(mut self) {
self.vector.invalidate(self.index);
self.consumed = true;
}
}
impl<'a, V> Drop for SlotWriter<'a, V> {
fn drop(&mut self) {
if !self.consumed {
debug_assert!(
false,
"SlotWriter at index {} dropped without commit() or invalidate()",
self.index
);
}
}
}
pub trait IterUpdated<'a, K: 'a, V: 'a> {
type Iter: Iterator<Item = (K, &'a V)>;
fn iter_updated(&'a self) -> Self::Iter;
}
impl<'a, V: 'a> IterUpdated<'a, usize, V> for Vector<V> {
type Iter = IterUpdatedItems<'a, V>;
fn iter_updated(&'a self) -> Self::Iter {
if self.all_updated() {
IterUpdatedItems {
vector: self,
indices_iter: None,
current_index: 0,
all_updated: true,
}
} else {
IterUpdatedItems {
vector: self,
indices_iter: Some(self.indices.iter()),
current_index: 0,
all_updated: false,
}
}
}
}
pub struct IterUpdatedItems<'a, V> {
vector: &'a Vector<V>,
indices_iter: Option<std::slice::Iter<'a, usize>>,
current_index: usize,
all_updated: bool,
}
impl<'a, V> Iterator for IterUpdatedItems<'a, V> {
type Item = (usize, &'a V);
fn next(&mut self) -> Option<Self::Item> {
if self.all_updated {
if self.current_index < self.vector.data.len() {
let index = self.current_index;
self.current_index += 1;
Some((index, &self.vector.data[index]))
} else {
None
}
} else if let Some(ref mut indices_iter) = self.indices_iter {
indices_iter
.next()
.map(|&index| (index, &self.vector.data[index]))
} else {
None
}
}
}
impl<V> Vector<V> {
pub fn iter_updated_valid(&self) -> IterUpdatedValidItems<'_, V> {
if self.all_updated() {
IterUpdatedValidItems {
vector: self,
indices_iter: None,
current_index: 0,
all_updated: true,
}
} else {
IterUpdatedValidItems {
vector: self,
indices_iter: Some(self.indices.iter()),
current_index: 0,
all_updated: false,
}
}
}
}
pub struct IterUpdatedValidItems<'a, V> {
vector: &'a Vector<V>,
indices_iter: Option<std::slice::Iter<'a, usize>>,
current_index: usize,
all_updated: bool,
}
impl<'a, V> Iterator for IterUpdatedValidItems<'a, V> {
type Item = (usize, Option<&'a V>);
fn next(&mut self) -> Option<Self::Item> {
let index = if self.all_updated {
if self.current_index < self.vector.data.len() {
let i = self.current_index;
self.current_index += 1;
i
} else {
return None;
}
} else if let Some(ref mut indices_iter) = self.indices_iter {
*indices_iter.next()?
} else {
return None;
};
let opt = if self.vector.is_valid(index) {
Some(&self.vector.data[index])
} else {
None
};
Some((index, opt))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_vector() {
let vec: Vector<i32> = Vector::new();
assert_eq!(vec.len(), 0);
assert!(vec.is_empty());
assert!(!vec.is_updated());
assert!(!vec.all_updated());
}
#[test]
fn test_with_capacity() {
let mut vec: Vector<i32> = Vector::with_capacity(10);
assert_eq!(vec.len(), 0);
assert_eq!(vec.data.capacity(), 10);
assert_eq!(vec.update_flags.len(), 0);
assert_eq!(vec.valid_flags.len(), 0);
assert_eq!(vec.indices.capacity(), 10);
assert!(!vec.is_valid(0));
vec.push_committed(42);
assert_eq!(vec.get_valid(0), Some(&42));
assert_eq!(vec.pop(), Some(42));
assert_eq!(vec.len(), 0);
assert!(!vec.is_valid(0));
}
#[test]
fn test_get_mut() {
let mut vec = Vector::new();
vec.push(10);
vec.push(20);
vec.push(30);
if let Some(val) = vec.get_mut(1) {
*val = 200;
}
assert_eq!(vec.get(1), Some(&200));
assert!(vec.is_updated());
assert_eq!(vec.indices.len(), 0);
assert!(vec.all_updated());
assert_eq!(vec.get_updated(1), Some(&200));
if let Some(val) = vec.get_mut(0) {
*val = 100;
}
assert_eq!(vec.get(0), Some(&100));
assert_eq!(vec.indices.len(), 0);
assert!(vec.all_updated());
}
#[test]
fn test_get_mut_untracked_does_not_mark_updated() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(String::from("a"));
vec.push(String::from("b"));
vec.reset()?;
if let Some(value) = vec.get_mut_untracked(1) {
value.clear();
}
assert_eq!(vec.get(1).map(String::as_str), Some(""));
assert!(!vec.is_updated());
assert!(!vec.all_updated());
assert!(vec.iter_updated().next().is_none());
Ok(())
}
#[test]
fn test_iter_updated() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.push(3);
if let Some(val) = vec.get_mut(1) {
*val = 20;
}
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert_eq!(updated.len(), 3);
assert_eq!(updated, vec![(0, 1), (1, 20), (2, 3)]);
vec.reset()?;
assert!(!vec.is_updated());
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert!(updated.is_empty());
if let Some(val) = vec.get_mut(1) {
*val = 200;
}
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert_eq!(updated.len(), 1);
assert_eq!(updated, vec![(1, 200)]);
Ok(())
}
#[test]
fn test_all_updated() {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.push(3);
for val in vec.iter_mut() {
*val += 10;
}
assert!(vec.all_updated());
assert_eq!(vec.indices.len(), 0);
assert_eq!(vec.update_flags.len(), 0);
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert_eq!(updated.len(), 3);
assert_eq!(updated, vec![(0, 11), (1, 12), (2, 13)]);
}
#[test]
fn test_reset() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.push(3);
assert!(vec.is_updated());
vec.reset()?;
assert!(!vec.is_updated());
assert!(!vec.all_updated());
assert_eq!(vec.indices.len(), 0);
assert_eq!(vec.update_flags.len(), 3);
assert_eq!(vec.get_updated(0), None);
if let Some(val) = vec.get_mut(1) {
*val = 20;
}
assert!(vec.is_updated());
assert!(!vec.all_updated());
assert_eq!(vec.get_updated(1), Some(&20));
Ok(())
}
#[test]
fn test_clear() {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.push(3);
vec.clear();
assert_eq!(vec.len(), 0);
assert!(vec.is_empty());
assert!(!vec.is_updated());
assert!(!vec.all_updated());
}
#[test]
fn test_pop() {
let mut vec = Vector::new();
vec.push(10);
vec.push(20);
vec.push(30);
let val = vec.pop();
assert_eq!(val, Some(30));
assert_eq!(vec.len(), 2);
assert!(vec.is_updated());
assert_eq!(vec.indices.len(), 0);
assert!(vec.all_updated());
vec.pop();
vec.pop();
assert!(vec.is_empty());
assert!(!vec.is_updated());
}
#[test]
fn test_get_out_of_bounds() {
let mut vec = Vector::new();
vec.push(1);
assert_eq!(vec.get(1), None);
assert_eq!(vec.get_mut(1), None);
assert_eq!(vec.get_updated(1), None);
}
#[test]
fn test_iter() {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.push(3);
let collected: Vec<&i32> = vec.iter().collect();
assert_eq!(collected, vec![&1, &2, &3]);
for val in vec.iter_mut() {
*val *= 2;
}
let collected: Vec<&i32> = vec.iter().collect();
assert_eq!(collected, vec![&2, &4, &6]);
}
#[test]
fn test_push_after_all_updated() {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.iter_mut().for_each(|_| {});
vec.push(3);
assert!(vec.all_updated());
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert_eq!(updated, vec![(0, 1), (1, 2), (2, 3)]);
}
#[test]
fn test_multiple_updates() {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.push(3);
if let Some(v) = vec.get_mut(0) {
*v = 10;
}
assert_eq!(vec.indices.len(), 0);
assert!(vec.all_updated());
if let Some(v) = vec.get_mut(1) {
*v = 20;
}
assert_eq!(vec.indices.len(), 0);
if let Some(v) = vec.get_mut(2) {
*v = 30
}
assert!(vec.all_updated());
assert_eq!(vec.indices.len(), 0);
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert_eq!(updated, vec![(0, 10), (1, 20), (2, 30)]);
}
#[test]
fn test_reset_after_all_updated() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.iter_mut().for_each(|v| *v += 1);
assert!(vec.all_updated());
vec.reset()?;
assert!(!vec.is_updated());
assert!(!vec.all_updated());
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert!(updated.is_empty());
if let Some(v) = vec.get_mut(0) {
*v = 10;
}
assert!(vec.is_updated());
assert!(!vec.all_updated());
let updated: Vec<(usize, i32)> = vec.iter_updated().map(|(i, &v)| (i, v)).collect();
assert_eq!(updated, vec![(0, 10)]);
Ok(())
}
#[test]
fn test_push_and_get() {
let mut vec = Vector::new();
vec.push(1);
vec.push(2);
vec.push(3);
assert_eq!(vec.len(), 3);
assert_eq!(vec.get(0), Some(&1));
assert_eq!(vec.get(1), Some(&2));
assert_eq!(vec.get(2), Some(&3));
assert_eq!(vec.get(3), None);
assert!(vec.is_updated());
assert!(vec.all_updated());
assert_eq!(vec.get_updated(0), Some(&1));
assert_eq!(vec.get_updated(1), Some(&2));
assert_eq!(vec.get_updated(2), Some(&3));
assert_eq!(vec.get_updated(3), None);
}
#[test]
fn validity_push_is_invalid_by_default() {
let mut vec = Vector::new();
vec.push(42);
assert!(!vec.is_valid(0));
assert_eq!(vec.get_valid(0), None);
assert!(!vec.is_valid(1));
assert_eq!(vec.get_valid(1), None);
}
#[test]
fn validity_push_committed_is_valid() {
let mut vec = Vector::new();
vec.push_committed(42);
assert!(vec.is_valid(0));
assert_eq!(vec.get_valid(0), Some(&42));
assert!(vec.is_updated());
}
#[test]
fn validity_commit_roundtrip() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(0); assert!(!vec.is_valid(0));
vec.commit(0, 42);
assert!(vec.is_valid(0));
assert_eq!(vec.get_valid(0), Some(&42));
assert!(vec.is_updated());
vec.reset()?;
assert!(!vec.is_updated());
assert!(vec.is_valid(0));
assert_eq!(vec.get_valid(0), Some(&42));
Ok(())
}
#[test]
fn validity_invalidate_marks_dirty_and_clears_valid() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push_committed(42);
vec.reset()?;
assert!(!vec.is_updated());
vec.invalidate(0);
assert!(!vec.is_valid(0));
assert_eq!(vec.get_valid(0), None);
assert_eq!(vec.get(0), Some(&42));
assert!(vec.is_updated());
Ok(())
}
#[test]
fn validity_reset_preserves_validity_clears_dirty() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(0);
vec.commit(0, 100);
vec.reset()?;
assert!(!vec.is_updated());
assert!(vec.is_valid(0)); assert_eq!(vec.get_valid(0), Some(&100));
Ok(())
}
#[test]
fn validity_slot_writer_commit_consumes_without_panic() {
let mut vec = Vector::new();
vec.push(0);
let writer = vec.slot_writer(0);
writer.commit(99);
assert_eq!(vec.get_valid(0), Some(&99));
}
#[test]
fn validity_slot_writer_invalidate_consumes_without_panic() {
let mut vec = Vector::new();
vec.push_committed(123);
let writer = vec.slot_writer(0);
writer.invalidate();
assert_eq!(vec.get_valid(0), None);
assert!(vec.is_updated());
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "SlotWriter at index 0 dropped without commit() or invalidate()")]
fn validity_slot_writer_drop_without_consume_panics_in_debug() {
let mut vec: Vector<i32> = Vector::new();
vec.push(0);
let _writer = vec.slot_writer(0);
}
#[test]
fn validity_iter_updated_valid_yields_option_per_slot() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(0); vec.push(0); vec.push(0); vec.commit(0, 10);
vec.commit(1, 20);
let collected: Vec<(usize, Option<i32>)> = vec
.iter_updated_valid()
.map(|(i, v)| (i, v.copied()))
.collect();
assert_eq!(
collected,
vec![(0, Some(10)), (1, Some(20)), (2, None)],
"all three slots are dirty; only the two committed ones expose Some(v)"
);
vec.reset()?;
let collected: Vec<(usize, Option<i32>)> = vec
.iter_updated_valid()
.map(|(i, v)| (i, v.copied()))
.collect();
assert!(collected.is_empty(), "after reset no slots are dirty");
vec.invalidate(0);
let collected: Vec<(usize, Option<i32>)> = vec
.iter_updated_valid()
.map(|(i, v)| (i, v.copied()))
.collect();
assert_eq!(collected, vec![(0, None)]);
Ok(())
}
#[test]
fn validity_get_mut_does_not_touch_validity_bit() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push(0);
vec.commit(0, 5);
vec.reset()?;
assert!(vec.is_valid(0));
if let Some(slot) = vec.get_mut(0) {
*slot = 999;
}
assert!(vec.is_updated());
assert!(vec.is_valid(0), "get_mut must NOT clear validity");
assert_eq!(vec.get_valid(0), Some(&999));
vec.push(0); if let Some(slot) = vec.get_mut(1) {
*slot = 42;
}
assert!(!vec.is_valid(1));
assert_eq!(vec.get_valid(1), None);
Ok(())
}
#[test]
fn validity_pop_keeps_remaining_bits_aligned() -> Result<(), Error> {
let mut vec = Vector::new();
vec.push_committed(1);
vec.push(0);
vec.push_committed(3);
vec.reset()?;
assert!(vec.is_valid(0));
assert!(!vec.is_valid(1));
assert!(vec.is_valid(2));
let popped = vec.pop();
assert_eq!(popped, Some(3));
assert_eq!(vec.len(), 2);
assert!(vec.is_valid(0));
assert!(!vec.is_valid(1));
Ok(())
}
#[test]
fn validity_clear_resets_everything() {
let mut vec = Vector::new();
vec.push_committed(1);
vec.push_committed(2);
vec.clear();
assert_eq!(vec.len(), 0);
assert!(vec.is_empty());
assert!(!vec.is_updated());
}
}