Skip to content

Commit

Permalink
refactor!(core): update sew variants (#261)
Browse files Browse the repository at this point in the history
* update 1-(un)sews

* update 2-(un)sews

* update public api

* fix lints
  • Loading branch information
imrn99 authored Jan 2, 2025
1 parent 93416fb commit b27fc16
Show file tree
Hide file tree
Showing 3 changed files with 316 additions and 397 deletions.
117 changes: 19 additions & 98 deletions honeycomb-core/src/cmap/dim2/sews/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod one;
mod two;

use stm::{StmResult, Transaction};
use stm::Transaction;

use crate::{
cmap::{CMap2, CMapResult, DartIdType},
Expand Down Expand Up @@ -30,22 +30,26 @@ impl<T: CoordsFloat> CMap2<T> {
///
/// # Errors
///
/// This method should be called in a transactional context. The `Result` is then used to
/// validate the transaction; It should not be processed manually. The policy in case of
/// failure can be defined when creating the transaction, using `Transaction::with_control`.
/// This variant will abort the sew operation and raise an error if:
/// - the transaction cannot be completed,
/// - one (or more) attribute merge fails,
/// - for `I == 2`: orientation is inconsistent.
///
/// The returned error can be used in conjunction with transaction control to avoid any
/// modifications in case of failure at attribute level. The user can then choose, through its
/// transaction control policy, to retry or abort as he wishes (see `Transaction::with_control`).
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 3` or `I == 0`
/// - the two darts are not I-sewable,
/// - for `I == 2`: orientation is inconsistent.
/// - the two darts are not I-sewable,
pub fn sew<const I: u8>(
&self,
trans: &mut Transaction,
ld: DartIdType,
rd: DartIdType,
) -> StmResult<()> {
) -> CMapResult<()> {
// these assertions + match on a const are optimized away
assert!(I < 3);
assert_ne!(I, 0);
Expand Down Expand Up @@ -77,16 +81,20 @@ impl<T: CoordsFloat> CMap2<T> {
///
/// # Errors
///
/// This method should be called in a transactional context. The `Result` is then used to
/// validate the transaction; It should not be processed manually. The policy in case of
/// failure can be defined when creating the transaction, using `Transaction::with_control`.
/// This variant will abort the unsew operation and raise an error if:
/// - the transaction cannot be completed,
/// - one (or more) attribute split fails,
///
/// The returned error can be used in conjunction with transaction control to avoid any
/// modifications in case of failure at attribute level. The user can then choose, through its
/// transaction control policy, to retry or abort as he wishes (see `Transaction::with_control`).
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 3` or `I == 0`
/// - `ld` is already `I`-free,
pub fn unsew<const I: u8>(&self, trans: &mut Transaction, ld: DartIdType) -> StmResult<()> {
pub fn unsew<const I: u8>(&self, trans: &mut Transaction, ld: DartIdType) -> CMapResult<()> {
// these assertions + match on a const are optimized away
assert!(I < 3);
assert_ne!(I, 0);
Expand Down Expand Up @@ -152,91 +160,4 @@ impl<T: CoordsFloat> CMap2<T> {
_ => unreachable!(),
}
}

/// # `I`-sew operator.
///
/// This variant will abort the unsew operation and raise an error if attributes cannot be
/// merged correctly.
///
/// # Arguments
///
/// - `const I: u8` -- Sew dimension.
/// - `trans: &mut Transaction` -- Transaction associated to the operation.
/// - `ld: DartIdType` -- First dart ID.
/// - `rd: DartIdType` -- Second dart ID.
///
/// # Errors
///
/// This method will fail, returning an error, if:
/// - the transaction cannot be completed,
/// - one (or more) attribute merge fails,
/// - for `I == 2`: orientation is inconsistent.
///
/// The returned error can be used in conjunction with transaction control to avoid any
/// modifications in case of failure at attribute level. The user can then choose, through its
/// transaction control policy, to retry or abort as he wishes.
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 3` or `I == 0`
/// - the two darts are not I-sewable,
pub fn try_sew<const I: u8>(
&self,
trans: &mut Transaction,
ld: DartIdType,
rd: DartIdType,
) -> CMapResult<()> {
// these assertions + match on a const are optimized away
assert!(I < 3);
assert_ne!(I, 0);
match I {
1 => self.try_one_sew(trans, ld, rd),
2 => self.try_two_sew(trans, ld, rd),
_ => unreachable!(),
}
}

/// # `I`-unsew operator.
///
/// This variant will abort the unsew operation and raise an error if attributes cannot be
/// split correctly.
///
/// # Arguments
///
/// - `const I: u8` -- Unsew dimension.
/// - `trans: &mut Transaction` -- Transaction associated to the operation.
/// - `ld: DartIdType` -- First dart ID.
///
/// The second dart ID is fetched using `I` and `ld`.
///
/// # Errors
///
/// This method will fail, returning an error, if:
/// - the transaction cannot be completed,
/// - one (or more) attribute split fails,
///
/// The returned error can be used in conjunction with transaction control to avoid any
/// modifications in case of failure at attribute level. The user can then choose, through its
/// transaction control policy, to retry or abort as he wishes.
///
/// # Panics
///
/// The method may panic if:
/// - `I >= 3` or `I == 0`
/// - `ld` is already `I`-free,
pub fn try_unsew<const I: u8>(
&self,
trans: &mut Transaction,
ld: DartIdType,
) -> CMapResult<()> {
// these assertions + match on a const are optimized away
assert!(I < 3);
assert_ne!(I, 0);
match I {
1 => self.try_one_unsew(trans, ld),
2 => self.try_two_unsew(trans, ld),
_ => unreachable!(),
}
}
}
119 changes: 52 additions & 67 deletions honeycomb-core/src/cmap/dim2/sews/one.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use stm::{atomically, StmResult, Transaction};
use stm::{atomically, Transaction};

use crate::{
attributes::UnknownAttributeStorage,
Expand All @@ -15,38 +15,6 @@ impl<T: CoordsFloat> CMap2<T> {
trans: &mut Transaction,
lhs_dart_id: DartIdType,
rhs_dart_id: DartIdType,
) -> StmResult<()> {
let b2lhs_dart_id = self.betas[(2, lhs_dart_id)].read(trans)?;
if b2lhs_dart_id == NULL_DART_ID {
self.betas.one_link_core(trans, lhs_dart_id, rhs_dart_id)
} else {
let b2lhs_vid_old = self.vertex_id_transac(trans, b2lhs_dart_id)?;
let rhs_vid_old = self.vertex_id_transac(trans, rhs_dart_id)?;

self.betas.one_link_core(trans, lhs_dart_id, rhs_dart_id)?;

let new_vid = self.vertex_id_transac(trans, rhs_dart_id)?;

// FIXME: VertexIdentifier should be cast to DartIdentifier
self.vertices
.merge(trans, new_vid, b2lhs_vid_old, rhs_vid_old)?;
self.attributes
.merge_vertex_attributes(trans, new_vid, b2lhs_vid_old, rhs_vid_old)?;
Ok(())
}
}

/// 1-sew implementation.
pub(super) fn force_one_sew(&self, lhs_dart_id: DartIdType, rhs_dart_id: DartIdType) {
atomically(|trans| self.one_sew(trans, lhs_dart_id, rhs_dart_id));
}

/// 1-sew defensive implementation.
pub(super) fn try_one_sew(
&self,
trans: &mut Transaction,
lhs_dart_id: DartIdType,
rhs_dart_id: DartIdType,
) -> CMapResult<()> {
let b2lhs_dart_id = self.betas[(2, lhs_dart_id)].read(trans)?;
if b2lhs_dart_id == NULL_DART_ID {
Expand All @@ -59,7 +27,6 @@ impl<T: CoordsFloat> CMap2<T> {

let new_vid = self.vertex_id_transac(trans, rhs_dart_id)?;

// TODO: these should be attempts, only succeding if it's a full merge
self.vertices
.try_merge(trans, new_vid, b2lhs_vid_old, rhs_vid_old)?;
self.attributes.try_merge_vertex_attributes(
Expand All @@ -71,6 +38,33 @@ impl<T: CoordsFloat> CMap2<T> {
}
Ok(())
}

/// 1-sew implementation.
pub(super) fn force_one_sew(&self, lhs_dart_id: DartIdType, rhs_dart_id: DartIdType) {
atomically(|trans| {
let b2lhs_dart_id = self.betas[(2, lhs_dart_id)].read(trans)?;
if b2lhs_dart_id == NULL_DART_ID {
self.betas.one_link_core(trans, lhs_dart_id, rhs_dart_id)
} else {
let b2lhs_vid_old = self.vertex_id_transac(trans, b2lhs_dart_id)?;
let rhs_vid_old = self.vertex_id_transac(trans, rhs_dart_id)?;

self.betas.one_link_core(trans, lhs_dart_id, rhs_dart_id)?;

let new_vid = self.vertex_id_transac(trans, rhs_dart_id)?;

self.vertices
.merge(trans, new_vid, b2lhs_vid_old, rhs_vid_old)?;
self.attributes.merge_vertex_attributes(
trans,
new_vid,
b2lhs_vid_old,
rhs_vid_old,
)?;
Ok(())
}
});
}
}

#[doc(hidden)]
Expand All @@ -81,7 +75,7 @@ impl<T: CoordsFloat> CMap2<T> {
&self,
trans: &mut Transaction,
lhs_dart_id: DartIdType,
) -> StmResult<()> {
) -> CMapResult<()> {
let b2lhs_dart_id = self.betas[(2, lhs_dart_id)].read(trans)?;
if b2lhs_dart_id == NULL_DART_ID {
self.betas.one_unlink_core(trans, lhs_dart_id)?;
Expand All @@ -92,48 +86,39 @@ impl<T: CoordsFloat> CMap2<T> {
// update the topology
self.betas.one_unlink_core(trans, lhs_dart_id)?;
// split vertices & attributes from the old ID to the new ones
// FIXME: VertexIdentifier should be cast to DartIdentifier
let (new_lhs, new_rhs) = (
self.vertex_id_transac(trans, b2lhs_dart_id)?,
self.vertex_id_transac(trans, rhs_dart_id)?,
);
self.vertices.split(trans, new_lhs, new_rhs, vid_old)?;
self.vertices.try_split(trans, new_lhs, new_rhs, vid_old)?;
self.attributes
.split_vertex_attributes(trans, new_lhs, new_rhs, vid_old)?;
.try_split_vertex_attributes(trans, new_lhs, new_rhs, vid_old)?;
}
Ok(())
}

/// 1-unsew implementation.
pub(super) fn force_one_unsew(&self, lhs_dart_id: DartIdType) {
atomically(|trans| self.one_unsew(trans, lhs_dart_id));
}

/// 1-unsew defensive implementation.
pub(super) fn try_one_unsew(
&self,
trans: &mut Transaction,
lhs_dart_id: DartIdType,
) -> CMapResult<()> {
let b2lhs_dart_id = self.betas[(2, lhs_dart_id)].read(trans)?;
if b2lhs_dart_id == NULL_DART_ID {
self.betas.one_unlink_core(trans, lhs_dart_id)?;
} else {
// fetch IDs before topology update
let rhs_dart_id = self.betas[(1, lhs_dart_id)].read(trans)?;
let vid_old = self.vertex_id_transac(trans, rhs_dart_id)?;
// update the topology
self.betas.one_unlink_core(trans, lhs_dart_id)?;
// split vertices & attributes from the old ID to the new ones
// TODO: these should be attempts, only succeding if splitting a value
let (new_lhs, new_rhs) = (
self.vertex_id_transac(trans, b2lhs_dart_id)?,
self.vertex_id_transac(trans, rhs_dart_id)?,
);
self.vertices.try_split(trans, new_lhs, new_rhs, vid_old)?;
self.attributes
.try_split_vertex_attributes(trans, new_lhs, new_rhs, vid_old)?;
}
Ok(())
atomically(|trans| {
let b2lhs_dart_id = self.betas[(2, lhs_dart_id)].read(trans)?;
if b2lhs_dart_id == NULL_DART_ID {
self.betas.one_unlink_core(trans, lhs_dart_id)?;
} else {
// fetch IDs before topology update
let rhs_dart_id = self.betas[(1, lhs_dart_id)].read(trans)?;
let vid_old = self.vertex_id_transac(trans, rhs_dart_id)?;
// update the topology
self.betas.one_unlink_core(trans, lhs_dart_id)?;
// split vertices & attributes from the old ID to the new ones
let (new_lhs, new_rhs) = (
self.vertex_id_transac(trans, b2lhs_dart_id)?,
self.vertex_id_transac(trans, rhs_dart_id)?,
);
self.vertices.split(trans, new_lhs, new_rhs, vid_old)?;
self.attributes
.split_vertex_attributes(trans, new_lhs, new_rhs, vid_old)?;
}
Ok(())
});
}
}
Loading

0 comments on commit b27fc16

Please sign in to comment.