/*========================================================================= Program: Visualization Toolkit Module: vtkCompositeDataSetRange.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #ifndef vtkCompositeDataSetRange_h #define vtkCompositeDataSetRange_h #include "vtkCompositeDataIterator.h" #include "vtkCompositeDataSet.h" #include "vtkCompositeDataSetNodeReference.h" #include "vtkMeta.h" #include "vtkRange.h" #include "vtkSmartPointer.h" #include #ifndef __VTK_WRAP__ namespace vtk { // Pass these to vtk::Range(cds, options): enum class CompositeDataSetOptions : unsigned int { None = 0, SkipEmptyNodes = 1 << 1 // Skip null datasets. }; } // end namespace vtk (for bitflag op definition) VTK_GENERATE_BITFLAG_OPS(vtk::CompositeDataSetOptions) namespace vtk { namespace detail { struct CompositeDataSetRange; struct CompositeDataSetIterator; using CompositeDataSetIteratorReference = vtk::CompositeDataSetNodeReference; //------------------------------------------------------------------------------ // vtkCompositeDataSet iterator. Returns vtk::CompositeDataSetNodeReference. struct CompositeDataSetIterator : public std::iterator { private: using Superclass = std::iterator; using InternalIterator = vtkCompositeDataIterator; using SmartIterator = vtkSmartPointer; public: using iterator_category = typename Superclass::iterator_category; using value_type = typename Superclass::value_type; using difference_type = typename Superclass::difference_type; using pointer = typename Superclass::pointer; using reference = typename Superclass::reference; CompositeDataSetIterator(const CompositeDataSetIterator& o) : Iterator(o.Iterator ? SmartIterator::Take(o.Iterator->NewInstance()) : nullptr) { this->CopyState(o.Iterator); } CompositeDataSetIterator(CompositeDataSetIterator&&) noexcept = default; CompositeDataSetIterator& operator=(const CompositeDataSetIterator& o) { this->Iterator = o.Iterator ? SmartIterator::Take(o.Iterator->NewInstance()) : nullptr; this->CopyState(o.Iterator); return *this; } CompositeDataSetIterator& operator++() // prefix { this->Increment(); return *this; } CompositeDataSetIterator operator++(int) // postfix { CompositeDataSetIterator other(*this); this->Increment(); return other; } reference operator*() const { return this->GetData(); } pointer operator->() const { return this->GetData(); } friend bool operator==(const CompositeDataSetIterator& lhs, const CompositeDataSetIterator& rhs) { // A null internal iterator means it is an 'end' sentinal. InternalIterator* l = lhs.Iterator; InternalIterator* r = rhs.Iterator; if (!r && !l) { // end == end return true; } else if (!r) { // right is end return l->IsDoneWithTraversal() != 0; } else if (!l) { // left is end return r->IsDoneWithTraversal() != 0; } else { // Both iterators are valid, check unique idx: return r->GetCurrentFlatIndex() == l->GetCurrentFlatIndex(); } } friend bool operator!=(const CompositeDataSetIterator& lhs, const CompositeDataSetIterator& rhs) { return !(lhs == rhs); // let the compiler handle this one =) } friend void swap(CompositeDataSetIterator& lhs, CompositeDataSetIterator& rhs) noexcept { using std::swap; swap(lhs.Iterator, rhs.Iterator); } friend struct CompositeDataSetRange; protected: // Note: This takes ownership of iter and manages its lifetime. // Iter should not be used past this point by the caller. CompositeDataSetIterator(SmartIterator&& iter) noexcept : Iterator(std::move(iter)) {} // Note: Iterators constructed using this ctor will be considered // 'end' iterators via a sentinal pattern. CompositeDataSetIterator() noexcept : Iterator(nullptr) {} private: void CopyState(InternalIterator* source) { if (source) { assert(this->Iterator != nullptr); this->Iterator->SetDataSet(source->GetDataSet()); this->Iterator->SetSkipEmptyNodes(source->GetSkipEmptyNodes()); this->Iterator->InitTraversal(); this->AdvanceTo(source->GetCurrentFlatIndex()); } } void AdvanceTo(const unsigned int flatIdx) { assert(this->Iterator != nullptr); assert(this->Iterator->GetCurrentFlatIndex() <= flatIdx); while (this->Iterator->GetCurrentFlatIndex() < flatIdx) { this->Increment(); } } void Increment() { assert(this->Iterator != nullptr); assert(!this->Iterator->IsDoneWithTraversal()); this->Iterator->GoToNextItem(); } CompositeDataSetIteratorReference GetData() const { assert(this->Iterator != nullptr); assert(!this->Iterator->IsDoneWithTraversal()); return CompositeDataSetIteratorReference{ this->Iterator }; } mutable SmartIterator Iterator; }; //------------------------------------------------------------------------------ // CompositeDataSet range proxy. // The const_iterators/references are the same as the non-const versions, since // vtkObjects marked const are unusable. struct CompositeDataSetRange { private: using InternalIterator = vtkCompositeDataIterator; using SmartIterator = vtkSmartPointer; public: using size_type = int; using iterator = CompositeDataSetIterator; using const_iterator = CompositeDataSetIterator; using reference = CompositeDataSetIteratorReference; using const_reference = const CompositeDataSetIteratorReference; using value_type = vtkDataObject*; CompositeDataSetRange( vtkCompositeDataSet* cds, CompositeDataSetOptions opts = CompositeDataSetOptions::None) : CompositeDataSet(cds) , Options(opts) { assert(this->CompositeDataSet); } vtkCompositeDataSet* GetCompositeDataSet() const noexcept { return this->CompositeDataSet; } CompositeDataSetOptions GetOptions() const noexcept { return this->Options; } // This is O(N), since the size requires traversal due to various options. size_type size() const { size_type result = 0; auto iter = this->NewIterator(); iter->InitTraversal(); while (!iter->IsDoneWithTraversal()) { ++result; iter->GoToNextItem(); } return result; } iterator begin() const { return CompositeDataSetIterator{ this->NewIterator() }; } iterator end() const { return CompositeDataSetIterator{}; } // Note: These return mutable objects because const vtkObject are unusable. const_iterator cbegin() const { return CompositeDataSetIterator{ this->NewIterator() }; } // Note: These return mutable objects because const vtkObjects are unusable. const_iterator cend() const { return CompositeDataSetIterator{}; } private: SmartIterator NewIterator() const { using Opts = vtk::CompositeDataSetOptions; auto result = SmartIterator::Take(this->CompositeDataSet->NewIterator()); result->SetSkipEmptyNodes((this->Options & Opts::SkipEmptyNodes) != Opts::None); result->InitTraversal(); return result; } mutable vtkSmartPointer CompositeDataSet; CompositeDataSetOptions Options; }; } } // end namespace vtk::detail #endif // __VTK_WRAP__ #endif // vtkCompositeDataSetRange_h // VTK-HeaderTest-Exclude: vtkCompositeDataSetRange.h