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 {
pub(crate) nogoods: Vec<PredicateId>,
pub(crate) nogood_id_to_index: HashMap<NogoodId, NogoodIndex>,
current_index: u32,
initial_capacity: usize,
}
const OFFSET: usize = 2;
#[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.push(PredicateId::create_from_index(2));
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() + OFFSET..nogood_id.index() + OFFSET + len
}
#[allow(unused, reason = "Currently inlined due to borrow issues")]
pub(crate) fn calculate_range_of_nogood_including_last_traversed(
&self,
nogood_id: NogoodId,
) -> Range<usize> {
let len = self.len_of_nogood(nogood_id);
nogood_id.index() + OFFSET - 1..nogood_id.index() + OFFSET + len
}
pub(crate) fn get_nogood(&self, nogood_id: NogoodId) -> &[PredicateId] {
let nogood_range = self.calculate_range_of_nogood(nogood_id);
&self.nogoods[nogood_range]
}
#[allow(unused, reason = "Standard API")]
pub(crate) fn get_nogood_mut(&mut self, nogood_id: NogoodId) -> &mut [PredicateId] {
let nogood_range = self.calculate_range_of_nogood(nogood_id);
&mut self.nogoods[nogood_range]
}
#[allow(unused, reason = "Currently inlined due to borrow issues")]
pub(crate) fn get_nogood_mut_with_last_traversed(
&mut self,
nogood_id: NogoodId,
) -> (&mut u32, &mut [PredicateId]) {
let nogood_range = self.calculate_range_of_nogood_including_last_traversed(nogood_id);
self.nogoods[nogood_range]
.split_first_mut()
.map(|(last_traversed, nogood)| (&mut last_traversed.id, nogood))
.expect("Expected nogood to be at least of length two")
}
}
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 + OFFSET;
Some(id)
}
}