use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Range;
use crate::basic_types::PredicateId;
use crate::containers::HashMap;
use crate::containers::StorageKey;
use crate::propagators::nogoods::NogoodId;
#[derive(Clone, Default, Debug)]
pub(crate) struct ArenaAllocator {
nogoods: Vec<PredicateId>,
nogood_id_to_index: HashMap<NogoodId, NogoodIndex>,
current_index: u32,
initial_capacity: usize,
}
#[derive(Clone, Copy, Debug, Hash)]
pub(crate) struct NogoodIndex(u32);
impl StorageKey for NogoodIndex {
fn index(&self) -> usize {
self.0 as usize
}
fn create_from_index(index: usize) -> Self {
NogoodIndex(index as u32)
}
}
impl ArenaAllocator {
pub(crate) fn new(capacity: usize) -> Self {
Self {
nogoods: Vec::default(),
nogood_id_to_index: HashMap::default(),
current_index: 0,
initial_capacity: capacity,
}
}
pub(crate) fn insert(&mut self, nogood: Vec<PredicateId>) -> NogoodId {
if self.nogoods.is_empty() {
self.nogoods.reserve_exact(self.initial_capacity);
}
let nogood_id = NogoodId::create_from_index(self.nogoods.len());
let _ = self
.nogood_id_to_index
.insert(nogood_id, NogoodIndex(self.current_index));
self.current_index += 1;
self.nogoods
.push(PredicateId::create_from_index(nogood.len()));
self.nogoods.extend(nogood);
nogood_id
}
pub(crate) fn get_nogood_index(&self, nogood_id: &NogoodId) -> NogoodIndex {
*self
.nogood_id_to_index
.get(nogood_id)
.expect("Expected nogood predicate to exist")
}
pub(crate) fn nogoods_ids(&self) -> impl Iterator<Item = NogoodId> + '_ {
NogoodIdIterator {
nogoods: &self.nogoods,
current_index: 0,
}
}
fn len_of_nogood(&self, nogood_id: NogoodId) -> usize {
self.nogoods[nogood_id.index()].index()
}
fn calculate_range_of_nogood(&self, nogood_id: NogoodId) -> Range<usize> {
let len = self.len_of_nogood(nogood_id);
nogood_id.index() + 1..nogood_id.index() + 1 + len
}
}
impl Index<NogoodId> for ArenaAllocator {
type Output = [PredicateId];
fn index(&self, index: NogoodId) -> &Self::Output {
let nogood_range = self.calculate_range_of_nogood(index);
&self.nogoods[nogood_range]
}
}
impl IndexMut<NogoodId> for ArenaAllocator {
fn index_mut(&mut self, index: NogoodId) -> &mut Self::Output {
let nogood_range = self.calculate_range_of_nogood(index);
&mut self.nogoods[nogood_range]
}
}
pub(crate) struct NogoodIdIterator<'a> {
nogoods: &'a Vec<PredicateId>,
current_index: usize,
}
impl Iterator for NogoodIdIterator<'_> {
type Item = NogoodId;
fn next(&mut self) -> Option<Self::Item> {
if self.current_index >= self.nogoods.len() {
return None;
}
let id = NogoodId::create_from_index(self.current_index);
self.current_index += self.nogoods[self.current_index].id as usize + 1;
Some(id)
}
}