3#include "MorphologicalTree.hpp"
35 class EditSessionPause {
38 bool wasEditing_ =
false;
42 : tree_(tree), wasEditing_(tree.editSessionOpen_) {
43 tree_.editSessionOpen_ =
false;
46 ~EditSessionPause()
noexcept {
47 tree_.editSessionOpen_ = wasEditing_;
55 tree_->beginEditSession();
62 if (!active_ || tree_ ==
nullptr) {
63 throw std::logic_error(
"TreeEditor operation requires an active edit session.");
77 other.tree_ =
nullptr;
78 other.active_ =
false;
100 return t.createDetachedNode();
109 throw std::invalid_argument(
"TreeEditor::detach requires a live node.");
112 throw std::invalid_argument(
"TreeEditor::detach cannot detach the connected root.");
126 throw std::invalid_argument(
"TreeEditor::reparent requires live node ids.");
129 throw std::invalid_argument(
"TreeEditor::reparent cannot move the connected root.");
132 throw std::invalid_argument(
"TreeEditor::reparent requires distinct node ids.");
146 throw std::invalid_argument(
"TreeEditor::attach requires live node ids.");
149 throw std::invalid_argument(
"TreeEditor::attach requires distinct node ids.");
152 throw std::invalid_argument(
"TreeEditor::attach expects a detached self-parented node.");
167 throw std::invalid_argument(
"TreeEditor::moveChildren requires live node ids.");
170 throw std::invalid_argument(
"TreeEditor::moveChildren requires distinct node ids.");
184 throw std::invalid_argument(
"TreeEditor::moveProperPart requires live node ids.");
187 throw std::invalid_argument(
"TreeEditor::moveProperPart requires distinct source and target nodes.");
190 throw std::invalid_argument(
"TreeEditor::moveProperPart requires a valid proper-part id.");
204 throw std::invalid_argument(
"TreeEditor::moveProperParts requires live node ids.");
207 throw std::invalid_argument(
"TreeEditor::moveProperParts requires distinct source and target nodes.");
218 throw std::invalid_argument(
"TreeEditor::removeChild requires live node ids.");
221 throw std::invalid_argument(
"TreeEditor::removeChild requires a direct parent-child relation.");
232 throw std::invalid_argument(
"TreeEditor::releaseNode requires a live node.");
235 throw std::invalid_argument(
"TreeEditor::releaseNode cannot release the connected root.");
238 throw std::invalid_argument(
"TreeEditor::releaseNode expects a detached self-parented node.");
252 throw std::invalid_argument(
"TreeEditor::setRoot requires a live node.");
262 EditSessionPause
pause(
t);
271 EditSessionPause
pause(
t);
286 if (!active_ || tree_ ==
nullptr) {
287 return {
false,
"TreeEditor validation requires an active edit session."};
300 tree_->endEditSession();
314 throw std::runtime_error(
result.message);
326 if (active_ && tree_ !=
nullptr) {
327#if defined(MMCFILTERS_ENABLE_ASSERTS)
329 assert(
result.ok &&
"TreeEditor::commitUnchecked requires a valid tree when MMCFILTERS_ENABLE_ASSERTS is enabled.");
331 tree_->endEditSession();
Mutable morphological tree built directly on proper parts and dense node ids.
TreeEditor edit()
Opens the only public entrypoint for staged structural mutations.
bool hasDetachedAliveNodes() const noexcept
Returns whether the tree currently contains alive detached nodes.
TreeValidationResult validateConnectedRootedTreeResult() const noexcept
Runs strong validation and returns the result instead of throwing.
Thin edit-session facade for multi-step topology updates.
TreeValidationResult validate() const noexcept
Runs strong validation without closing the session.
void detach(NodeId nodeId)
Detaches one non-root node from the connected rooted component.
bool hasDetachedAliveNodes() const noexcept
Returns whether the staged edit still has detached alive nodes.
void mergeNodeIntoParent(NodeId nodeId)
Applies the committed-safe parent merge inside the staged edit.
void reparent(NodeId nodeId, NodeId newParentId)
Reparents one live non-root node under another live node.
void attach(NodeId parentId, NodeId detachedNodeId)
Attaches one detached node back under the connected rooted tree.
NodeId createDetachedNode()
Creates a live detached node in the topological hierarchy.
void setRoot(NodeId nodeId)
Promotes nodeId to become the connected root.
void removeChild(NodeId parentNodeId, NodeId childId, bool releaseNodeFlag)
Detaches a direct child from its parent and optionally releases an empty detached slot.
void moveProperParts(NodeId targetNodeId, NodeId sourceNodeId)
Transfers every direct proper part from sourceNodeId to targetNodeId.
~TreeEditor()=default
Leaves an unfinished edit session open.
void releaseNode(NodeId nodeId)
Releases an empty detached non-root node slot.
TreeEditor(TreeEditor &&other) noexcept
Transfers the open edit-session handle without closing it.
void commit()
Finalizes the edit by validating that the tree is connected again.
void moveProperPart(NodeId targetNodeId, NodeId sourceNodeId, NodeId properPartId)
Transfers one direct proper part from sourceNodeId to targetNodeId.
void moveChildren(NodeId parentId, NodeId sourceId)
Transfers every direct child of sourceId under parentId.
void commitUnchecked() noexcept
Finalizes a staged edit without running the linear validation.
void pruneNode(NodeId nodeId)
Applies the committed-safe subtree prune inside the staged edit.
TreeValidationResult validateAndCommit() noexcept
Validates and closes the edit session on success.
Owning result for one computed scalar attribute layout and buffer.
Non-throwing validation result returned by edit-session checks.