HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
iterator.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_BASE_TF_ITERATOR_H
8 #define PXR_BASE_TF_ITERATOR_H
9 
10 /// \file tf/iterator.h
11 /// \ingroup group_tf_Containers
12 /// A simple iterator adapter for \c STL containers.
13 
14 #include "pxr/pxr.h"
15 #include "pxr/base/arch/hints.h"
17 
18 #include <iterator>
19 #include <type_traits>
20 #include <utility>
21 
23 
24 // May be specialized by container proxies and container "views" to indicate
25 // they should be copied for TfIterator iteration.
26 template <class T>
27 struct Tf_ShouldIterateOverCopy : std::false_type {};
28 
29 // IteratorInterface abstracts the differences between forward/backward and
30 // const/non-const iteration so that TfIterator doesn't have to think about
31 // them. It simply provides the IteratorType (which is either iterator,
32 // const_iterator, reverse_iterator, or reverse_const_iterator) and Begin and
33 // End which call the correct functions in the container (begin, rbegin, end,
34 // rend).
35 template <class T, bool Reverse>
37  typedef typename T::iterator IteratorType;
38  static IteratorType Begin(T &c) { return c.begin(); }
39  static IteratorType End(T &c) { return c.end(); }
40 };
41 
42 template <class T, bool Reverse>
43 struct Tf_IteratorInterface<const T, Reverse> {
44  typedef typename T::const_iterator IteratorType;
45  static IteratorType Begin(T const &c) { return c.begin(); }
46  static IteratorType End(T const &c) { return c.end(); }
47 };
48 
49 template <class T>
50 struct Tf_IteratorInterface<T, true> {
51  typedef typename T::reverse_iterator IteratorType;
52  static IteratorType Begin(T &c) { return c.rbegin(); }
53  static IteratorType End(T &c) { return c.rend(); }
54 };
55 
56 template <class T>
57 struct Tf_IteratorInterface<const T, true> {
58  typedef typename T::const_reverse_iterator IteratorType;
59  static IteratorType Begin(T const &c) { return c.rbegin(); }
60  static IteratorType End(T const &c) { return c.rend(); }
61 };
62 
63 /// \class TfIterator
64 /// \ingroup group_tf_Containers group_tf_Stl
65 ///
66 /// A simple iterator adapter for \c STL containers.
67 ///
68 /// \c TfIterator iterates over the elements in an \c STL container, according
69 /// to the semantics of the \ref iterator_pattern "simple iterator pattern".
70 /// The following examples compare the \c TfIterator to \c STL, highlighting
71 /// the brevity of the \c TfIterator interface.
72 /// \code
73 /// std::vector<int> vector;
74 /// std::set<int> set;
75 ///
76 /// // TfIterator 'while' loop
77 /// TfIterator< std::vector<int> > i(vector);
78 /// while (i) {
79 /// int x = *i++;
80 /// }
81 ///
82 /// // STL 'while' loop
83 /// std::vector<int>::iterator i = vector.begin();
84 /// while (i != vector.end()) {
85 /// int x = *i++;
86 /// }
87 ///
88 /// // TfIterator 'for' loop
89 /// std::set<int> set;
90 /// for (TfIterator< const std::set<int> > j = set; j; ++j) {
91 /// int x = *j;
92 /// }
93 ///
94 /// // STL 'for' loop
95 /// std::set<int> set;
96 /// for (std::set<int>::iterator j = set.begin(); j != set.end(); ++j) {
97 /// int x = *j;
98 /// }
99 /// \endcode
100 ///
101 /// Note that using the \c TF_FOR_ALL() macro, even more brevity is possible.
102 /// For example, to print out all items of a \c set<int> \c s, we could write
103 /// \code
104 /// TF_FOR_ALL(i, s)
105 /// printf("%d\n", *i);
106 /// \endcode
107 ///
108 /// Typically, a \c TfIterator is used to traverse all of the elements in an
109 /// \c STL container. For ordered sets, other uses include iterating over a
110 /// subset of the elements in the container, and using a \c TfIterator as a
111 /// sentinel.
112 /// \code
113 /// // Iterate over subset
114 /// TfIterator< std::vector<int> > start, finish;
115 /// TfIterator< std::vector<int> > iterator(start, finish);
116 ///
117 /// // TfIterator sentinel
118 /// TfIterator< std::vector<int> > sentinel(finish, finish);
119 /// while (iterator != sentinel) {
120 /// int x = *iterator++;
121 /// }
122 /// \endcode
123 ///
124 /// \anchor iterator_pattern
125 /// <b>The Simple Iterator Pattern</b>
126 ///
127 /// The \e simple \e iterator pattern generalizes pointer semantics to
128 /// traverse a set of elements, much like \c STL iterators. However, the
129 /// simple iterator pattern subscribes to a simpler subset of pointer
130 /// operations: pointer assignment (\c operator=), auto-increment (\c
131 /// operator++), dereferencing (\c operator*), redirection (\c operator->),
132 /// and null pointer comparison (\c operator! and \c operator \c bool). The
133 /// simpler interface improves code legibility for the typical set traversals
134 /// for which iterators are most commonly used. It is particularly useful for
135 /// specifying iterators over sets of elements that are maintained by a user
136 /// object, since the interface calls for only one \c GetIterator() entry
137 /// point rather than dual \c begin() and \c end() calls. This is especially
138 /// desirable when the object owns many different sets.
139 /// \code
140 /// // The simple iterator pattern.
141 /// class Iterator {
142 /// Iterator(); // default c'tor
143 /// Iterator(const Iterator&); // copy c'tor
144 /// Iterator& operator=(const Iterator &); // assignment
145 /// Iterator& operator++(); // pre-increment
146 /// Iterator operator++(int); // post-increment
147 /// reference operator *(); // dereference
148 /// pointer operator->(); // redirection
149 /// bool operator==(const Iterator &) const; // equality
150 /// bool operator!=(const Iterator &) const; // inequality
151 /// bool operator!() const // is exhausted
152 /// operator bool() const; // is not exhausted
153 /// };
154 /// \endcode
155 ///
156 /// \param T container type
157 ///
158 template <class T, bool Reverse=false>
159 class TfIterator {
160 
161  // Forward declare implementation structs.
162  struct _IteratorPairAndCopy;
163  struct _IteratorPair;
164 
165  // Select the correct data storage depending on whether we should iterate
166  // over a copy of the container.
167  typedef typename std::conditional<
169  _IteratorPairAndCopy, _IteratorPair
170  >::type _Data;
171 
172 public:
173  // Choose either iterator or const_iterator for Iterator depending on
174  // whether T is const.
177 
179 
180  /// Default constructor. This iterator is uninitialized.
182 
183  /// Constructs an iterator to traverse each element of the specified
184  /// \c STL container object.
185  /// \param container container object
186  TfIterator(T &container) : _data(container) {}
187 
188  /// Allow rvalues only if the container type T should be copied by TfIterator.
189  TfIterator(T &&container)
190  : _data(container)
191  {
192  static_assert(
194  "TfIterator only allows rvalues that it has been told to copy "
195  "via Tf_ShouldIterateOverCopy");
196  }
197 
198  /// Constructs an iterator to traverse a subset of the elements in a
199  /// container. This iterator is exhausted when it reaches the end
200  /// iterator.
201  /// \param begin iterator at the beginning of the sequence
202  /// \param end iterator at the end of the sequence
204  : _data(begin, end)
205  {
206  }
207 
208  /// Returns true if this iterator is exhausted.
209  /// \return true if this iterator is exhausted
210  bool operator!() const {
211  return _data.current == _data.end;
212  }
213 
214  /// Returns true if this Iterator.has the same position in the sequence as
215  /// the specified iterator. The end of the sequence need not be the same.
216  /// \param iterator iterator to compare
217  /// \return true if this Iterator.has the same position as \e iterator
218  bool operator==(const TfIterator& iterator) const {
219  return _data.current == iterator._data.current;
220  }
221 
222  /// Returns false if (*this == \a iterator) returns true, returns true
223  /// otherwise.
224  bool operator!=(const TfIterator& iterator) const {
225  return !(*this == iterator);
226  }
227 
228  /// Pre-increment operator. Advances this iterator to the next element in
229  /// the sequence.
230  /// \return this iterator
232  if (!*this) {
233  TF_CODING_ERROR("iterator exhausted");
234  return *this;
235  }
236 
237  ++_data.current;
238  return *this;
239  }
240 
241  /// Post-increment operator. Advances this iterator to the next element in
242  /// the sequence, and returns a copy of this iterator prior to the increment.
243  /// \return copy of this iterator prior to increment
245  TfIterator iterator = *this;
246  ++(*this);
247  return iterator;
248  }
249 
250  /// Returns the element referenced by this iterator.
251  /// \return element
253  if (ARCH_UNLIKELY(!*this))
254  TF_FATAL_ERROR("iterator exhausted");
255  return *_data.current;
256  }
257 
258  /// Returns the element referenced by this iterator.
259  /// \return element
261  if (ARCH_UNLIKELY(!*this))
262  TF_FATAL_ERROR("iterator exhausted");
263  return *_data.current;
264  }
265 
266  /// Returns a pointer to the element referenced by this iterator.
267  /// \return pointer to element
269  if (ARCH_UNLIKELY(!*this))
270  TF_FATAL_ERROR("iterator exhausted");
271  return _data.current;
272  }
273 
274  /// Explicit bool conversion operator.
275  /// The Iterator object converts to true if it has not been exhausted.
276  explicit operator bool() const {
277  return !(_data.current == _data.end);
278  }
279 
280  /// Returns an \c STL iterator that has the same position as this
281  /// iterator.
282  /// \return \c STL iterator at the same position as this iterator
283  operator Iterator() const {
284  return _data.current;
285  }
286 
287  /// Returns an \c STL iterator that has the same position as this
288  /// iterator.
289  /// \return \c STL iterator at the same position as this iterator
290  const Iterator& base() const {
291  return _data.current;
292  }
293 
294  /// Returns an iterator that is positioned at the next element in the
295  /// sequence.
296  /// \return iterator at next element in the sequence
297  TfIterator GetNext() const {
298  TfIterator next = *this;
299  ++next;
300  return next;
301  }
302 
303  private: // state
304 
305  // Normal iteration just holds onto the begin/end pair of iterators.
306  struct _IteratorPair {
307  _IteratorPair() {}
308  explicit _IteratorPair(T &c) {
309  // Use assignment rather than initializer-list here to work around
310  // a GCC 4.1.2 bug when using TfIterator with TfHashMap.
311  current = IterInterface::Begin(c);
312  end = IterInterface::End(c);
313  }
314  _IteratorPair(Iterator const &b, Iterator const &e) :
315  current(b), end(e) {}
316  Iterator current;
317  Iterator end;
318  };
319 
320  // Iterating over copies which is appropriate for proxies retains a copy of
321  // 'container' and iterators into the copy.
322  struct _IteratorPairAndCopy : public _IteratorPair {
323  _IteratorPairAndCopy() {}
324  explicit _IteratorPairAndCopy(T const &c) : _IteratorPair(), _copy(c) {
325  current = IterInterface::Begin(_copy);
326  end = IterInterface::End(_copy);
327  }
328  using _IteratorPair::current;
329  using _IteratorPair::end;
330  private:
331  T _copy;
332  };
333 
334  _Data _data;
335 
336 };
337 
338 /// Helper functions for creating TfIterator objects.
339 /// \ingroup group_tf_Containers
340 template <class T>
342 TfMakeIterator(T&& container)
343 {
345  std::forward<T>(container));
346 }
347 
348 template <class T>
350 TfMakeReverseIterator(T&& container)
351 {
353  std::forward<T>(container));
354 }
355 
356 /// Macro for iterating over a container.
357 ///
358 /// For any container \c c of type \c T, the following loop
359 /// \code
360 /// for (TfIterator<T> i = c.begin(); i; ++i) {
361 /// ...
362 /// }
363 /// \endcode
364 /// is equivalent to
365 /// \code
366 /// TF_FOR_ALL(i, c) {
367 /// ...
368 /// }
369 /// \endcode
370 ///
371 /// \ingroup group_tf_Containers
372 /// \hideinitializer
373 #define TF_FOR_ALL(iter, c) \
374  for (auto iter = TfMakeIterator(c); iter; ++iter)
375 
376 /// Macro for iterating over a container in reverse.
377 ///
378 /// Operates like \a TF_FOR_ALL, but iterates the container in reverse order.
379 ///
380 /// \ingroup group_tf_Containers
381 /// \hideinitializer
382 #define TF_REVERSE_FOR_ALL(iter, c) \
383  for (auto iter = TfMakeReverseIterator(c); iter; ++iter)
384 
385 /// Returns the number of elements in a statically sized array.
386 ///
387 /// This function is an implementation of the array version of C++17's
388 /// std::size()
389 template <class T, size_t N>
390 constexpr size_t TfArraySize(const T (&array)[N]) noexcept
391 {
392  return N;
393 }
394 
395 /// A reverse iterator adapter for `std::reverse_iterator` that provides
396 /// an `operator->` compatible with proxy reference types.
397 /// This should only be used when the underlying iterator's reference
398 /// is a value type and should become unnecessary in newer compilers and C++20.
399 /// This implementation was written for use with random access iterators but
400 /// could be extended to bidirectional iterators if necessary.
401 template <typename UnderlyingIterator>
403  private std::reverse_iterator<UnderlyingIterator> {
404  // private API for interacting with an STL reverse_iterator of the
405  // UnderlyingIterator
406  using ReverseIterator = std::reverse_iterator<UnderlyingIterator>;
407  const ReverseIterator& _reverse_iterator() const { return *this; }
408  ReverseIterator& _reverse_iterator() { return *this; }
409  explicit Tf_ProxyReferenceReverseIterator(const ReverseIterator& it)
410  : ReverseIterator(it) {}
411  explicit Tf_ProxyReferenceReverseIterator(ReverseIterator&& it)
412  : ReverseIterator(it) {}
413 public:
414  using iterator_type = typename ReverseIterator::iterator_type;
415  using iterator_category = typename ReverseIterator::iterator_category;
419  using difference_type = typename ReverseIterator::difference_type;
420 
422  "Tf_ProxyReferenceReverseIterator should only be used "
423  "when the underlying iterator's reference type is a "
424  "proxy (MyTypeRef) and not a true reference (MyType&)."
425  "Use std::reverse_iterator instead.");
426  static_assert(std::is_same<iterator_category,
427  std::random_access_iterator_tag>::value,
428  "Tf_ProxyReferenceReverseIterator must wrap a random "
429  "access iterator.");
430 
432  explicit Tf_ProxyReferenceReverseIterator(UnderlyingIterator it) :
433  ReverseIterator(it) {
434  }
435 
436  // Operators and functions which can just use the underlying STL
437  // implementation
438  using ReverseIterator::base;
439  using ReverseIterator::operator*;
440  using ReverseIterator::operator[];
441 
442  /// Customize operator-> to support proxied reference types
443  /// Compatible with the C++20 specification.
444  pointer operator->() const { return std::prev(base()).operator->(); }
445 
446  // Many methods can use the underlying STL implementation but need to
447  // avoid returning a `std::reverse_iterator`
449  ++_reverse_iterator();
450  return *this;
451  }
452 
454  Tf_ProxyReferenceReverseIterator result{_reverse_iterator()};
455  ++_reverse_iterator();
456  return result;
457  }
458 
460  --_reverse_iterator();
461  return *this;
462  }
463 
465  Tf_ProxyReferenceReverseIterator result{_reverse_iterator()};
466  --_reverse_iterator();
467  return result;
468  }
469 
471  return Tf_ProxyReferenceReverseIterator(_reverse_iterator() + increment);
472  }
473 
475  return Tf_ProxyReferenceReverseIterator(_reverse_iterator() - decrement);
476  }
477 
478  template <typename OtherIt>
480  const Tf_ProxyReferenceReverseIterator<OtherIt>& other) const {
481  return _reverse_iterator() - other._reverse_iterator();
482  }
483 
485  _reverse_iterator() += increment;
486  return *this;
487  }
488 
490  _reverse_iterator() -= decrement;
491  return *this;
492  }
493 
495  operator+(const difference_type increment,
496  const Tf_ProxyReferenceReverseIterator& iterator) {
498  increment + iterator._reverse_iterator());
499  }
500 
501  // Comparison operators defer to the STL implementation
502  template <typename OtherIt>
503  inline friend bool operator==(const Tf_ProxyReferenceReverseIterator& lhs,
505  return lhs._reverse_iterator() == rhs._reverse_iterator();
506  }
507 
508  template <typename OtherIt>
509  inline friend bool operator!=(const Tf_ProxyReferenceReverseIterator& lhs,
511  return lhs._reverse_iterator() != rhs._reverse_iterator();
512  }
513 
514  template <typename OtherIt>
515  inline friend bool operator<(const Tf_ProxyReferenceReverseIterator& lhs,
517  return lhs._reverse_iterator() < rhs._reverse_iterator();
518  }
519 
520  template <typename OtherIt>
521  inline friend bool operator>(const Tf_ProxyReferenceReverseIterator& lhs,
523  return lhs._reverse_iterator() > rhs._reverse_iterator();
524  }
525 
526  template <typename OtherIt>
527  inline friend bool operator<=(const Tf_ProxyReferenceReverseIterator& lhs,
529  return lhs._reverse_iterator() <= rhs._reverse_iterator();
530  }
531 
532  template <typename OtherIt>
533  inline friend bool operator>=(const Tf_ProxyReferenceReverseIterator& lhs,
535  return lhs._reverse_iterator() >= rhs._reverse_iterator();
536  }
537 };
538 
540 
541 #endif // PXR_BASE_TF_ITERATOR_H
type
Definition: core.h:556
TfIterator< typename std::remove_reference< T >::type, true > TfMakeReverseIterator(T &&container)
Definition: iterator.h:350
pointer operator->() const
Definition: iterator.h:444
TfIterator GetNext() const
Definition: iterator.h:297
typename ReverseIterator::iterator_category iterator_category
Definition: iterator.h:415
static IteratorType Begin(T &c)
Definition: iterator.h:52
constexpr size_t TfArraySize(const T(&array)[N]) noexcept
Definition: iterator.h:390
Tf_ProxyReferenceReverseIterator & operator-=(difference_type decrement)
Definition: iterator.h:489
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool operator!=(const TfIterator &iterator) const
Definition: iterator.h:224
Reference operator*()
Definition: iterator.h:252
#define TF_CODING_ERROR
friend bool operator<(const Tf_ProxyReferenceReverseIterator &lhs, const Tf_ProxyReferenceReverseIterator< OtherIt > &rhs)
Definition: iterator.h:515
TfIterator()
Default constructor. This iterator is uninitialized.
Definition: iterator.h:181
TfIterator(Iterator const &begin, Iterator const &end)
Definition: iterator.h:203
Tf_ProxyReferenceReverseIterator(UnderlyingIterator it)
Definition: iterator.h:432
typename ReverseIterator::difference_type difference_type
Definition: iterator.h:419
**But if you need a result
Definition: thread.h:622
friend bool operator>=(const Tf_ProxyReferenceReverseIterator &lhs, const Tf_ProxyReferenceReverseIterator< OtherIt > &rhs)
Definition: iterator.h:533
uint64 value_type
Definition: GA_PrimCompat.h:29
OutGridT const XformOp bool bool
TfIterator(T &container)
Definition: iterator.h:186
TfIterator(T &&container)
Allow rvalues only if the container type T should be copied by TfIterator.
Definition: iterator.h:189
typename ReverseIterator::pointer pointer
Definition: iterator.h:418
typename ReverseIterator::value_type value_type
Definition: iterator.h:416
#define ARCH_UNLIKELY(x)
Definition: hints.h:30
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
Tf_ProxyReferenceReverseIterator & operator+=(difference_type increment)
Definition: iterator.h:484
const Iterator & base() const
Definition: iterator.h:290
GLuint GLuint end
Definition: glcorearb.h:475
static IteratorType Begin(T const &c)
Definition: iterator.h:45
static IteratorType End(T const &c)
Definition: iterator.h:60
#define TF_FATAL_ERROR
Tf_ProxyReferenceReverseIterator operator-(difference_type decrement) const
Definition: iterator.h:474
static IteratorType End(T &c)
Definition: iterator.h:39
bool operator==(const TfIterator &iterator) const
Definition: iterator.h:218
Tf_ProxyReferenceReverseIterator operator+(difference_type increment) const
Definition: iterator.h:470
T::reverse_iterator IteratorType
Definition: iterator.h:51
Tf_ProxyReferenceReverseIterator & operator++()
Definition: iterator.h:448
typename ReverseIterator::iterator_type iterator_type
Definition: iterator.h:414
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
friend Tf_ProxyReferenceReverseIterator operator+(const difference_type increment, const Tf_ProxyReferenceReverseIterator &iterator)
Definition: iterator.h:495
T::iterator IteratorType
Definition: iterator.h:37
friend bool operator==(const Tf_ProxyReferenceReverseIterator &lhs, const Tf_ProxyReferenceReverseIterator< OtherIt > &rhs)
Definition: iterator.h:503
friend bool operator<=(const Tf_ProxyReferenceReverseIterator &lhs, const Tf_ProxyReferenceReverseIterator< OtherIt > &rhs)
Definition: iterator.h:527
GLenum void ** pointer
Definition: glcorearb.h:810
std::iterator_traits< Iterator >::reference Reference
Definition: iterator.h:178
static IteratorType Begin(T &c)
Definition: iterator.h:38
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
static IteratorType Begin(T const &c)
Definition: iterator.h:59
Reference operator*() const
Definition: iterator.h:260
bool operator!() const
Definition: iterator.h:210
Tf_ProxyReferenceReverseIterator operator++(int)
Definition: iterator.h:453
Tf_ProxyReferenceReverseIterator operator--(int)
Definition: iterator.h:464
static IteratorType End(T &c)
Definition: iterator.h:53
Tf_ProxyReferenceReverseIterator & operator--()
Definition: iterator.h:459
TfIterator & operator++()
Definition: iterator.h:231
friend bool operator>(const Tf_ProxyReferenceReverseIterator &lhs, const Tf_ProxyReferenceReverseIterator< OtherIt > &rhs)
Definition: iterator.h:521
TfIterator operator++(int)
Definition: iterator.h:244
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
GA_API const UT_StringHolder N
static IteratorType End(T const &c)
Definition: iterator.h:46
typename ReverseIterator::reference reference
Definition: iterator.h:417
Tf_IteratorInterface< T, Reverse > IterInterface
Definition: iterator.h:175
difference_type operator-(const Tf_ProxyReferenceReverseIterator< OtherIt > &other) const
Definition: iterator.h:479
IterInterface::IteratorType Iterator
Definition: iterator.h:176
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate and *a name There is also one special expression reference
Iterator & operator->()
Definition: iterator.h:268
T::const_reverse_iterator IteratorType
Definition: iterator.h:58
TfIterator< typename std::remove_reference< T >::type > TfMakeIterator(T &&container)
Definition: iterator.h:342
friend bool operator!=(const Tf_ProxyReferenceReverseIterator &lhs, const Tf_ProxyReferenceReverseIterator< OtherIt > &rhs)
Definition: iterator.h:509
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:566