/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkTreeIteratorBase_hxx #define itkTreeIteratorBase_hxx #include "itkTreeChangeEvent.h" /** There are some weird circular #include dependencies between TreeChangeEvent * and TreeIteratorBase that cause the HeaderTest to fail without these forward * declarations. */ template class ITK_TEMPLATE_EXPORT TreeNodeChangeEvent; template class ITK_TEMPLATE_EXPORT TreeAddEvent; template class ITK_TEMPLATE_EXPORT TreePruneEvent; template class ITK_TEMPLATE_EXPORT TreeRemoveEvent; namespace itk { template TreeIteratorBase::TreeIteratorBase(TTreeType * tree, const TreeNodeType * start) { if (start) { m_Root = start; } else { m_Root = dynamic_cast(tree->GetRoot()); } m_Position = const_cast(m_Root); m_Tree = tree; m_Begin = m_Position; } template TreeIteratorBase::TreeIteratorBase(const TTreeType * tree, const TreeNodeType * start) { if (start) { m_Root = start; } else { m_Root = const_cast(dynamic_cast(tree->GetRoot())); } m_Position = const_cast(m_Root); m_Tree = const_cast(tree); m_Begin = m_Position; } template auto TreeIteratorBase::Get() const -> const ValueType & { return m_Position->Get(); } template void TreeIteratorBase::Set(ValueType element) { // itkAssertInDebugAndIgnoreInReleaseMacro(m_Position); m_Position->Set(element); m_Tree->Modified(); m_Tree->InvokeEvent(TreeNodeChangeEvent(*this)); } template bool TreeIteratorBase::Add(ValueType element) { if (m_Position == nullptr && m_Root == nullptr) { bool returnValue = const_cast(m_Tree)->SetRoot(element); // signal AddEvent for self m_Root = dynamic_cast(const_cast(m_Tree)->GetRoot()); m_Position = const_cast(m_Root); m_Tree->Modified(); m_Tree->InvokeEvent(TreeAddEvent(*this)); return returnValue; } else if (m_Position == nullptr) { return false; } auto node = TreeNodeType::New(); node->Set(element); m_Position->AddChild(node); m_Tree->Modified(); // signal AddEvent for new child TreeIteratorBase * childIterator = Clone(); childIterator->m_Position = dynamic_cast(m_Position->GetChild(m_Position->ChildPosition(node))); // signal "child has been added deleted" m_Tree->InvokeEvent(TreeAddEvent(*childIterator)); delete childIterator; return true; } template bool TreeIteratorBase::Add(int itkNotUsed(childPosition), ValueType element) { if (m_Position) { auto node = TreeNodeType::New(); node->Set(element); m_Position->AddChild(node); m_Tree->Modified(); // signal AddEvent TreeIteratorBase * childIterator = Clone(); childIterator->m_Position = dynamic_cast(m_Position->GetChild(m_Position->ChildPosition(node))); // signal "child has been added deleted" m_Tree->InvokeEvent(TreeAddEvent(*childIterator)); delete childIterator; return true; } return false; } template bool TreeIteratorBase::IsLeaf() const { return !(m_Position->HasChildren()); } template bool TreeIteratorBase::IsRoot() const { if (m_Root == nullptr) { return false; } if (m_Position == m_Root) { return true; } return false; } template bool TreeIteratorBase::Add(TTreeType & subTree) { if (subTree.Count() == 0) { return false; } if (!subTree.GetRoot()) { return false; } if (m_Root == nullptr) { m_Root = static_cast(subTree.GetRoot()); } else { if (m_Position == nullptr) { return false; } m_Position->AddChild(const_cast(static_cast(subTree.GetRoot()))); } return true; } template TTreeType * TreeIteratorBase::GetSubTree() const { auto tree = TTreeType::New(); tree->SetRoot(m_Position); tree->SetSubtree(true); return tree; } template bool TreeIteratorBase::HasChild(int number) const { if (m_Position == nullptr) { return false; } if (m_Position->GetChild(number) != nullptr) { return true; } return false; } template int TreeIteratorBase::ChildPosition(ValueType element) const { if (!m_Position) { return -1; } return m_Position->ChildPosition(element); } template bool TreeIteratorBase::RemoveChild(int number) { if (!HasChild(number)) { return false; } auto * child = dynamic_cast(m_Position->GetChild(number)); if (child != nullptr) { // signal PruneEvent (node plus all children are removed) TreeIteratorBase * childIterator = Clone(); childIterator->m_Position = child; // signal "child has been added deleted" m_Tree->InvokeEvent(TreePruneEvent(*childIterator)); delete childIterator; // and really remove child (and subitems) const_cast(m_Position)->Remove(child); m_Tree->Modified(); return true; } return false; } template int TreeIteratorBase::CountChildren() const { if (m_Position == nullptr) { return -1; } return m_Position->CountChildren(); } template bool TreeIteratorBase::HasParent() const { return (m_Position != nullptr && m_Position->GetParent() != nullptr); } template bool TreeIteratorBase::Disconnect() { if (m_Position == nullptr) { return false; } if (m_Position->HasParent() == false) { return false; } // keep node alive just a bit longer typename TreeNodeType::Pointer position = m_Position; auto * parent = dynamic_cast(m_Position->GetParent()); parent->Remove(const_cast(m_Position)); m_Tree->Modified(); while (m_Position->CountChildren() > 0) { // always add first child in list, because AddChild() removes the added node // from // its former parent (== m_position) auto * child = dynamic_cast(m_Position->GetChild(0)); parent->AddChild(child); } m_Tree->InvokeEvent(TreeRemoveEvent(*this)); m_Position = nullptr; return true; } template TreeIteratorBase * TreeIteratorBase::Children() { itkGenericOutputMacro("Not implemented yet"); itk::ExceptionObject e_(__FILE__, __LINE__, "Not implemented yet", ITK_LOCATION); throw e_; /* Explicit naming to work around Intel compiler bug. */ return nullptr; } template auto TreeIteratorBase::GetParent() const -> const TreeNodeType * { if (m_Position == nullptr) { return nullptr; } return m_Position->GetParent(); } template TreeIteratorBase * TreeIteratorBase::Parents() { itkGenericOutputMacro("Not implemented yet"); itk::ExceptionObject e_(__FILE__, __LINE__, "Not implemented yet", ITK_LOCATION); throw e_; /* Explicit naming to work around Intel compiler bug. */ return nullptr; } template bool TreeIteratorBase::GoToChild(ChildIdentifier number) { if (m_Position == nullptr) { return false; } auto * next = dynamic_cast(m_Position->GetChild(number)); if (next == nullptr) { return false; } m_Position = next; return true; } template bool TreeIteratorBase::GoToParent() { if (m_Position == nullptr) { return false; } if (!m_Position->HasParent()) { return false; } m_Position = dynamic_cast(m_Position->GetParent()); return true; } template TreeIteratorBase * TreeIteratorBase::GetChild(int number) const { if (!m_Position) { return nullptr; } auto * child = dynamic_cast(m_Position->GetChild(number)); if (!child) { return nullptr; } // return new WalkTreeIterator( child, m_Root, m_Tree, getType() // ); return nullptr; } template int TreeIteratorBase::Count() { int size = 0; this->GoToBegin(); if (!m_Position->HasChildren()) { return 0; } while (this->Next()) { ++size; } return size; } template auto TreeIteratorBase::GetNode() -> TreeNodeType * { return const_cast(m_Position); } template auto TreeIteratorBase::GetNode() const -> const TreeNodeType * { return m_Position; } template auto TreeIteratorBase::GetRoot() -> TreeNodeType * { return const_cast(m_Root); } template auto TreeIteratorBase::GetRoot() const -> const TreeNodeType * { return m_Root; } template bool TreeIteratorBase::Remove() { if (m_Position == nullptr) { return false; } // keep node alive just a bit longer (for the notification) typename TreeNodeType::Pointer position = m_Position; if (m_Position->HasParent()) { TreeNodeType * parent = m_Position->GetParent(); // removes this node (and implicitly all children, too) parent->Remove(m_Position); } else if (m_Root == m_Position) { m_Root = nullptr; m_Tree->SetRoot((TreeNodeType *)nullptr); // this won't do anything if root is already != nullptr ==> root cannot be // removed } m_Position->SetParent(nullptr); // we don't have a parent anymore m_Tree->InvokeEvent(TreePruneEvent(*this)); while (m_Position->CountChildren() > 0) // remove all children { // always remove first child (id 0) auto * child = dynamic_cast(m_Position->GetChild(0)); m_Position->Remove(child); } position = nullptr; m_Position = nullptr; // Smart pointer, deletes *m_Position m_Tree->Modified(); return true; } template TTreeType * TreeIteratorBase::GetTree() const { return m_Tree; } } // namespace itk #endif