#[cfg(feature = "par-internals")]
use rayon::prelude::*;
use crate::attributes::{AttrSparseVec, AttrStorageManager, UnknownAttributeStorage};
use crate::cmap::{
DartIdType, DartReleaseError, DartReservationError,
components::{betas::BetaFunctions, unused::UnusedDarts},
};
use crate::geometry::{CoordsFloat, Vertex2};
use crate::stm::{
StmClosureResult, Transaction, TransactionClosureResult, abort, atomically_with_err,
};
use super::CMAP2_BETA;
pub struct CMap2<T: CoordsFloat> {
pub(super) attributes: AttrStorageManager,
pub(super) vertices: AttrSparseVec<Vertex2<T>>,
pub(super) unused_darts: UnusedDarts,
pub(super) betas: BetaFunctions<CMAP2_BETA>,
pub(super) n_darts: usize,
}
unsafe impl<T: CoordsFloat> Send for CMap2<T> {}
unsafe impl<T: CoordsFloat> Sync for CMap2<T> {}
#[doc(hidden)]
impl<T: CoordsFloat> CMap2<T> {
#[allow(unused)]
#[must_use = "unused return value"]
pub(crate) fn new(n_darts: usize) -> Self {
Self {
attributes: AttrStorageManager::default(),
vertices: AttrSparseVec::new(n_darts + 1),
unused_darts: UnusedDarts::new(n_darts + 1),
betas: BetaFunctions::new(n_darts + 1),
n_darts: n_darts + 1,
}
}
#[must_use = "unused return value"]
pub(crate) fn new_with_undefined_attributes(
n_darts: usize,
mut attr_storage_manager: AttrStorageManager,
) -> Self {
attr_storage_manager.extend_storages(n_darts + 1);
Self {
attributes: attr_storage_manager,
vertices: AttrSparseVec::new(n_darts + 1),
unused_darts: UnusedDarts::new(n_darts + 1),
betas: BetaFunctions::new(n_darts + 1),
n_darts: n_darts + 1,
}
}
}
impl<T: CoordsFloat> CMap2<T> {
#[must_use = "unused return value"]
pub fn n_darts(&self) -> usize {
self.n_darts
}
#[cfg(not(feature = "par-internals"))]
#[must_use = "unused return value"]
pub fn n_unused_darts(&self) -> usize {
self.unused_darts.iter().filter(|v| v.read_atomic()).count()
}
#[cfg(feature = "par-internals")]
#[must_use = "unused return value"]
pub fn n_unused_darts(&self) -> usize {
self.unused_darts
.par_iter()
.filter(|v| v.read_atomic())
.count()
}
#[must_use = "unused return value"]
pub fn is_unused(&self, d: DartIdType) -> bool {
self.unused_darts[d].read_atomic()
}
#[must_use = "unused return value"]
pub fn is_unused_tx(&self, t: &mut Transaction, d: DartIdType) -> StmClosureResult<bool> {
self.unused_darts[d].read(t)
}
fn allocate_darts_core(&mut self, n_darts: usize, unused: bool) -> DartIdType {
let new_id = self.n_darts as DartIdType;
self.n_darts += n_darts;
self.betas.extend(n_darts);
self.unused_darts.extend_with(n_darts, unused);
self.vertices.extend(n_darts);
self.attributes.extend_storages(n_darts);
new_id
}
pub fn allocate_used_darts(&mut self, n_darts: usize) -> DartIdType {
self.allocate_darts_core(n_darts, false)
}
pub fn allocate_unused_darts(&mut self, n_darts: usize) -> DartIdType {
self.allocate_darts_core(n_darts, true)
}
#[allow(clippy::missing_errors_doc)]
pub fn reserve_darts(&self, n_darts: usize) -> Result<Vec<DartIdType>, DartReservationError> {
atomically_with_err(|t| self.reserve_darts_tx(t, n_darts))
}
#[allow(clippy::missing_errors_doc)]
pub fn reserve_darts_tx(
&self,
t: &mut Transaction,
n_darts: usize,
) -> TransactionClosureResult<Vec<DartIdType>, DartReservationError> {
let mut res = Vec::with_capacity(n_darts);
for d in 1..self.n_darts() as DartIdType {
if self.is_unused_tx(t, d)? {
self.claim_dart_tx(t, d)?;
res.push(d);
if res.len() == n_darts {
return Ok(res);
}
}
}
abort(DartReservationError(n_darts))
}
#[allow(clippy::missing_errors_doc)]
pub fn reserve_darts_from_tx(
&self,
t: &mut Transaction,
n_darts: usize,
from: DartIdType,
) -> TransactionClosureResult<Vec<DartIdType>, DartReservationError> {
let mut res = Vec::with_capacity(n_darts);
for d in (from..self.n_darts() as DartIdType).chain(1..from) {
if self.is_unused_tx(t, d)? {
self.claim_dart_tx(t, d)?;
res.push(d);
if res.len() == n_darts {
return Ok(res);
}
}
}
abort(DartReservationError(n_darts))
}
pub fn claim_dart_tx(&self, t: &mut Transaction, dart_id: DartIdType) -> StmClosureResult<()> {
self.unused_darts[dart_id].write(t, false)
}
#[allow(clippy::missing_errors_doc)]
pub fn release_dart(&self, dart_id: DartIdType) -> Result<bool, DartReleaseError> {
atomically_with_err(|t| self.release_dart_tx(t, dart_id))
}
#[allow(clippy::missing_errors_doc)]
pub fn release_dart_tx(
&self,
t: &mut Transaction,
dart_id: DartIdType,
) -> TransactionClosureResult<bool, DartReleaseError> {
if !self.is_free_tx(t, dart_id)? {
abort(DartReleaseError(dart_id))?;
}
self.attributes.clear_attribute_values(t, dart_id)?;
self.vertices.clear_slot(t, dart_id)?;
Ok(self.unused_darts[dart_id].exchange(t, true)?) }
}