VTK  9.0.1
vtkCollectionRange.h
Go to the documentation of this file.
1 /*=========================================================================
2 
3  Program: Visualization Toolkit
4  Module: vtkCollectionRange.h
5 
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10  This software is distributed WITHOUT ANY WARRANTY; without even
11  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12  PURPOSE. See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #ifndef vtkCollectionRange_h
17 #define vtkCollectionRange_h
18 
19 #ifndef __VTK_WRAP__
20 
21 #include "vtkCollection.h"
22 #include "vtkMeta.h"
23 #include "vtkRange.h"
24 #include "vtkSmartPointer.h"
25 
26 #include <cassert>
27 
28 namespace vtk
29 {
30 namespace detail
31 {
32 
33 template <typename CollectionType>
35 template <typename CollectionType>
37 
38 //------------------------------------------------------------------------------
39 // Detect vtkCollection types
40 template <typename T>
41 struct IsCollection : std::is_base_of<vtkCollection, T>
42 {
43 };
44 
45 template <typename CollectionType, typename T = CollectionType>
47 
48 //------------------------------------------------------------------------------
49 // Detect the type of items held by the collection by checking the return type
50 // of GetNextItem(), or GetNextItemAsObject() as a fallback.
51 template <typename CollectionType>
53 {
54  static_assert(IsCollection<CollectionType>::value, "Invalid vtkCollection subclass.");
55 
56 private:
57  // The GetType methods are only used in a decltype context and are left
58  // unimplemented as we only care about their signatures. They are used to
59  // determine the type of object held by the collection.
60  //
61  // By passing literal 0 as the argument, the overload taking `int` is
62  // preferred and returns the same type as CollectionType::GetNextItem, which
63  // is usually the exact type held by the collection (e.g.
64  // vtkRendererCollection::GetNextItem returns vtkRenderer*).
65  //
66  // If the collection class does not define GetNextItem, SFINAE removes the
67  // preferred `int` overload, and the `...` overload is used instead. This
68  // method returns the same type as vtkCollection::GetNextItemAsObject, which
69  // is vtkObject*. This lets us define a more derived collection item type
70  // when possible, while falling back to the general vtkObject if a more
71  // refined type is not known.
72 
73  // not implemented
74  template <typename T>
75  static auto GetType(...) -> decltype(std::declval<T>().GetNextItemAsObject());
76 
77  // not implemented
78  template <typename T>
79  static auto GetType(int) -> decltype(std::declval<T>().GetNextItem());
80 
81  using PointerType = decltype(GetType<CollectionType>(0));
82 
83 public:
84  // Just use std::remove pointer, vtk::detail::StripPointer is overkill.
86 };
87 
88 //------------------------------------------------------------------------------
89 // Collection iterator. Reference, value, and pointer types are all ItemType
90 // pointers, since:
91 // a) values: ItemType* instead of ItemType because vtkObjects can't be
92 // copied/assigned.
93 // b) references: No good usecase to change the pointers held by the collection
94 // by returning ItemType*&, nor would returning ItemType& be useful, since
95 // it'd have to be dereferenced anyway to pass it anywhere, and vtkObjects
96 // are conventionally held by address.
97 // c) pointers: Returning ItemType** from operator-> would be useless.
98 //
99 // There are no const_reference, etc, since VTK is not const correct and marking
100 // vtkObjects consts makes them unusable.
101 template <typename CollectionType>
102 struct CollectionIterator
103  : public std::iterator<std::forward_iterator_tag,
104  typename GetCollectionItemType<CollectionType>::Type*, int,
105  typename GetCollectionItemType<CollectionType>::Type*,
106  typename GetCollectionItemType<CollectionType>::Type*>
107 {
108  static_assert(IsCollection<CollectionType>::value, "Invalid vtkCollection subclass.");
109 
110 private:
111  using ItemType = typename GetCollectionItemType<CollectionType>::Type;
112  using Superclass = std::iterator<std::forward_iterator_tag, ItemType*, int, ItemType*, ItemType*>;
113 
114 public:
115  using iterator_category = typename Superclass::iterator_category;
116  using value_type = typename Superclass::value_type;
117  using difference_type = typename Superclass::difference_type;
118  using pointer = typename Superclass::pointer;
120 
121  CollectionIterator() noexcept : Element(nullptr) {}
122 
123  CollectionIterator(const CollectionIterator& o) noexcept = default;
124  CollectionIterator& operator=(const CollectionIterator& o) noexcept = default;
125 
126  CollectionIterator& operator++() noexcept // prefix
127  {
128  this->Increment();
129  return *this;
130  }
131 
132  CollectionIterator operator++(int) noexcept // postfix
133  {
134  auto elem = this->Element;
135  this->Increment();
136  return CollectionIterator{ elem };
137  }
138 
139  reference operator*() const noexcept { return this->GetItem(); }
140 
141  pointer operator->() const noexcept { return this->GetItem(); }
142 
143  friend bool operator==(const CollectionIterator& lhs, const CollectionIterator& rhs) noexcept
144  {
145  return lhs.Element == rhs.Element;
146  }
147 
148  friend bool operator!=(const CollectionIterator& lhs, const CollectionIterator& rhs) noexcept
149  {
150  return lhs.Element != rhs.Element;
151  }
152 
153  friend void swap(CollectionIterator& lhs, CollectionIterator& rhs) noexcept
154  {
155  using std::swap;
156  swap(lhs.Element, rhs.Element);
157  }
158 
159  friend struct CollectionRange<CollectionType>;
160 
161 protected:
162  CollectionIterator(vtkCollectionElement* element) noexcept : Element(element) {}
163 
164 private:
165  void Increment() noexcept
166  { // incrementing an invalid iterator is UB, no need to check for non-null.
167  this->Element = this->Element->Next;
168  }
169 
170  ItemType* GetItem() const noexcept { return static_cast<ItemType*>(this->Element->Item); }
171 
172  vtkCollectionElement* Element;
173 };
174 
175 //------------------------------------------------------------------------------
176 // Collection range proxy.
177 // The const_iterators/references are the same as the non-const versions, since
178 // vtkObjects marked const are unusable.
179 template <typename CollectionType>
180 struct CollectionRange
181 {
182  static_assert(IsCollection<CollectionType>::value, "Invalid vtkCollection subclass.");
183 
185 
186  // NOTE: The const items are the same as the mutable ones, since const
187  // vtkObjects are generally unusable.
188  using size_type = int; // int is used by the vtkCollection API.
191  using reference = ItemType*;
194 
195  CollectionRange(CollectionType* coll) noexcept : Collection(coll) { assert(this->Collection); }
196 
197  CollectionType* GetCollection() const noexcept { return this->Collection; }
198 
199  size_type size() const noexcept { return this->Collection->GetNumberOfItems(); }
200 
201  iterator begin() const
202  {
204  this->Collection->InitTraversal(cookie);
205  // The cookie is a linked list node pointer, vtkCollectionElement:
206  return iterator{ static_cast<vtkCollectionElement*>(cookie) };
207  }
208 
209  iterator end() const { return iterator{ nullptr }; }
210 
211  // Note: These return mutable objects because const vtkObject are unusable.
213  {
215  this->Collection->InitTraversal(cookie);
216  // The cookie is a linked list node pointer, vtkCollectionElement:
217  return const_iterator{ static_cast<vtkCollectionElement*>(cookie) };
218  }
219 
220  // Note: These return mutable objects because const vtkObjects are unusable.
221  const_iterator cend() const { return const_iterator{ nullptr }; }
222 
223 private:
225 };
226 
227 }
228 } // end namespace vtk::detail
229 
230 #endif // __VTK_WRAP__
231 
232 #endif // vtkCollectionRange_h
233 
234 // VTK-HeaderTest-Exclude: vtkCollectionRange.h
typename std::remove_pointer< PointerType >::type Type
void * vtkCollectionSimpleIterator
Definition: vtkCollection.h:48
const_iterator cbegin() const
typename std::enable_if< IsCollection< CollectionType >::value, T >::type EnableIfIsCollection
typename Superclass::difference_type difference_type
friend void swap(CollectionIterator &lhs, CollectionIterator &rhs) noexcept
Specialization of tuple ranges and iterators for vtkAOSDataArrayTemplate.
CollectionIterator & operator++() noexcept
typename Superclass::pointer pointer
pointer operator->() const noexcept
const_iterator cend() const
friend bool operator!=(const CollectionIterator &lhs, const CollectionIterator &rhs) noexcept
size_type size() const noexcept
typename Superclass::iterator_category iterator_category
CollectionIterator operator++(int) noexcept
CollectionIterator & operator=(const CollectionIterator &o) noexcept=default
CollectionIterator(vtkCollectionElement *element) noexcept
typename GetCollectionItemType< CollectionType >::Type ItemType
vtkCollectionElement * Next
Definition: vtkCollection.h:46
reference operator*() const noexcept
CollectionType * GetCollection() const noexcept
CollectionRange(CollectionType *coll) noexcept
typename Superclass::reference reference
friend bool operator==(const CollectionIterator &lhs, const CollectionIterator &rhs) noexcept
typename Superclass::value_type value_type