Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!(core): update sew variants #261

Merged
merged 4 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading