All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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
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
22PXR_NAMESPACE_OPEN_SCOPE
23
24// May be specialized by container proxies and container "views" to indicate
25// they should be copied for TfIterator iteration.
26template <class T>
27struct 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).
35template <class T, bool Reverse>
36struct Tf_IteratorInterface {
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
42template <class T, bool Reverse>
43struct 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
49template <class T>
50struct 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
56template <class T>
57struct 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
158template <class T, bool Reverse=false>
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<
168 Tf_ShouldIterateOverCopy<T>::value,
169 _IteratorPairAndCopy, _IteratorPair
170 >::type _Data;
171
172public:
173 // Choose either iterator or const_iterator for Iterator depending on
174 // whether T is const.
175 typedef Tf_IteratorInterface<T, Reverse> IterInterface;
176 typedef typename IterInterface::IteratorType Iterator;
177
178 typedef typename std::iterator_traits<Iterator>::reference Reference;
179
182
186 TfIterator(T &container) : _data(container) {}
187
189 TfIterator(T &&container)
190 : _data(container)
191 {
192 static_assert(
193 Tf_ShouldIterateOverCopy<typename std::decay<T>::type>::value,
194 "TfIterator only allows rvalues that it has been told to copy "
195 "via Tf_ShouldIterateOverCopy");
196 }
197
203 TfIterator(Iterator const &begin, Iterator const &end)
204 : _data(begin, end)
205 {
206 }
207
210 bool operator!() const {
211 return _data.current == _data.end;
212 }
213
218 bool operator==(const TfIterator& iterator) const {
219 return _data.current == iterator._data.current;
220 }
221
224 bool operator!=(const TfIterator& iterator) const {
225 return !(*this == iterator);
226 }
227
232 if (!*this) {
233 TF_CODING_ERROR("iterator exhausted");
234 return *this;
235 }
236
237 ++_data.current;
238 return *this;
239 }
240
245 TfIterator iterator = *this;
246 ++(*this);
247 return iterator;
248 }
249
252 Reference operator*() {
253 if (ARCH_UNLIKELY(!*this))
254 TF_FATAL_ERROR("iterator exhausted");
255 return *_data.current;
256 }
257
260 Reference operator*() const {
261 if (ARCH_UNLIKELY(!*this))
262 TF_FATAL_ERROR("iterator exhausted");
263 return *_data.current;
264 }
265
268 Iterator& operator->() {
269 if (ARCH_UNLIKELY(!*this))
270 TF_FATAL_ERROR("iterator exhausted");
271 return _data.current;
272 }
273
276 explicit operator bool() const {
277 return !(_data.current == _data.end);
278 }
279
283 operator Iterator() const {
284 return _data.current;
285 }
286
290 const Iterator& base() const {
291 return _data.current;
292 }
293
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
340template <class T>
342TfMakeIterator(T&& container)
343{
345 std::forward<T>(container));
346}
347
348template <class T>
350TfMakeReverseIterator(T&& container)
351{
353 std::forward<T>(container));
354}
355
373#define TF_FOR_ALL(iter, c) \
374 for (auto iter = TfMakeIterator(c); iter; ++iter)
375
382#define TF_REVERSE_FOR_ALL(iter, c) \
383 for (auto iter = TfMakeReverseIterator(c); iter; ++iter)
384
389template <class T, size_t N>
390constexpr size_t TfArraySize(const T (&array)[N]) noexcept
391{
392 return N;
393}
394
401template <typename UnderlyingIterator>
402class Tf_ProxyReferenceReverseIterator :
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) {}
413public:
414 using iterator_type = typename ReverseIterator::iterator_type;
415 using iterator_category = typename ReverseIterator::iterator_category;
416 using value_type = typename ReverseIterator::value_type;
417 using reference = typename ReverseIterator::reference;
418 using pointer = typename ReverseIterator::pointer;
419 using difference_type = typename ReverseIterator::difference_type;
420
421 static_assert(!std::is_reference<reference>::value,
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
431 Tf_ProxyReferenceReverseIterator() = default;
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
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`
448 Tf_ProxyReferenceReverseIterator& operator++() {
449 ++_reverse_iterator();
450 return *this;
451 }
452
453 Tf_ProxyReferenceReverseIterator operator++(int) {
454 Tf_ProxyReferenceReverseIterator result{_reverse_iterator()};
455 ++_reverse_iterator();
456 return result;
457 }
458
459 Tf_ProxyReferenceReverseIterator& operator--() {
460 --_reverse_iterator();
461 return *this;
462 }
463
464 Tf_ProxyReferenceReverseIterator operator--(int) {
465 Tf_ProxyReferenceReverseIterator result{_reverse_iterator()};
466 --_reverse_iterator();
467 return result;
468 }
469
470 Tf_ProxyReferenceReverseIterator operator+(difference_type increment) const {
471 return Tf_ProxyReferenceReverseIterator(_reverse_iterator() + increment);
472 }
473
474 Tf_ProxyReferenceReverseIterator operator-(difference_type decrement) const {
475 return Tf_ProxyReferenceReverseIterator(_reverse_iterator() - decrement);
476 }
477
478 template <typename OtherIt>
479 difference_type operator-(
480 const Tf_ProxyReferenceReverseIterator<OtherIt>& other) const {
481 return _reverse_iterator() - other._reverse_iterator();
482 }
483
484 Tf_ProxyReferenceReverseIterator& operator+=(difference_type increment) {
485 _reverse_iterator() += increment;
486 return *this;
487 }
488
489 Tf_ProxyReferenceReverseIterator& operator-=(difference_type decrement) {
490 _reverse_iterator() -= decrement;
491 return *this;
492 }
493
494 inline friend Tf_ProxyReferenceReverseIterator
495 operator+(const difference_type increment,
496 const Tf_ProxyReferenceReverseIterator& iterator) {
497 return Tf_ProxyReferenceReverseIterator(
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,
504 const Tf_ProxyReferenceReverseIterator<OtherIt>& rhs) {
505 return lhs._reverse_iterator() == rhs._reverse_iterator();
506 }
507
508 template <typename OtherIt>
509 inline friend bool operator!=(const Tf_ProxyReferenceReverseIterator& lhs,
510 const Tf_ProxyReferenceReverseIterator<OtherIt>& rhs) {
511 return lhs._reverse_iterator() != rhs._reverse_iterator();
512 }
513
514 template <typename OtherIt>
515 inline friend bool operator<(const Tf_ProxyReferenceReverseIterator& lhs,
516 const Tf_ProxyReferenceReverseIterator<OtherIt>& rhs) {
517 return lhs._reverse_iterator() < rhs._reverse_iterator();
518 }
519
520 template <typename OtherIt>
521 inline friend bool operator>(const Tf_ProxyReferenceReverseIterator& lhs,
522 const Tf_ProxyReferenceReverseIterator<OtherIt>& rhs) {
523 return lhs._reverse_iterator() > rhs._reverse_iterator();
524 }
525
526 template <typename OtherIt>
527 inline friend bool operator<=(const Tf_ProxyReferenceReverseIterator& lhs,
528 const Tf_ProxyReferenceReverseIterator<OtherIt>& rhs) {
529 return lhs._reverse_iterator() <= rhs._reverse_iterator();
530 }
531
532 template <typename OtherIt>
533 inline friend bool operator>=(const Tf_ProxyReferenceReverseIterator& lhs,
534 const Tf_ProxyReferenceReverseIterator<OtherIt>& rhs) {
535 return lhs._reverse_iterator() >= rhs._reverse_iterator();
536 }
537};
538
539PXR_NAMESPACE_CLOSE_SCOPE
540
541#endif // PXR_BASE_TF_ITERATOR_H
constexpr size_t TfArraySize(const T(&array)[N]) noexcept
Returns the number of elements in a statically sized array.
Definition: iterator.h:390
A simple iterator adapter for STL containers.
Definition: iterator.h:159
TfIterator operator++(int)
Post-increment operator.
Definition: iterator.h:244
Reference operator*() const
Returns the element referenced by this iterator.
Definition: iterator.h:260
Iterator & operator->()
Returns a pointer to the element referenced by this iterator.
Definition: iterator.h:268
bool operator!() const
Returns true if this iterator is exhausted.
Definition: iterator.h:210
TfIterator & operator++()
Pre-increment operator.
Definition: iterator.h:231
TfIterator(T &&container)
Allow rvalues only if the container type T should be copied by TfIterator.
Definition: iterator.h:189
TfIterator GetNext() const
Returns an iterator that is positioned at the next element in the sequence.
Definition: iterator.h:297
bool operator!=(const TfIterator &iterator) const
Returns false if (*this == iterator) returns true, returns true otherwise.
Definition: iterator.h:224
TfIterator(Iterator const &begin, Iterator const &end)
Constructs an iterator to traverse a subset of the elements in a container.
Definition: iterator.h:203
TfIterator()
Default constructor. This iterator is uninitialized.
Definition: iterator.h:181
TfIterator(T &container)
Constructs an iterator to traverse each element of the specified STL container object.
Definition: iterator.h:186
Reference operator*()
Returns the element referenced by this iterator.
Definition: iterator.h:252
bool operator==(const TfIterator &iterator) const
Returns true if this Iterator.has the same position in the sequence as the specified iterator.
Definition: iterator.h:218
const Iterator & base() const
Returns an STL iterator that has the same position as this iterator.
Definition: iterator.h:290
Stripped down version of diagnostic.h that doesn't define std::string.
TfIterator< typename std::remove_reference< T >::type > TfMakeIterator(T &&container)
Helper functions for creating TfIterator objects.
Definition: iterator.h:342
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition: diagnostic.h:91
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:68
Compiler hints.