iterator.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #pragma once
  2. #include <iterator>
  3. #include <utility>
  4. namespace NStlIterator {
  5. template <class T>
  6. class TProxy {
  7. public:
  8. TProxy() = default;
  9. TProxy(T&& value)
  10. : Value_(std::move(value))
  11. {
  12. }
  13. const T* operator->() const noexcept {
  14. return &Value_;
  15. }
  16. const T& operator*() const noexcept {
  17. return Value_;
  18. }
  19. bool operator==(const TProxy& rhs) const {
  20. return Value_ == rhs.Value_;
  21. }
  22. private:
  23. T Value_;
  24. };
  25. } // namespace NStlIterator
  26. /**
  27. * Range adaptor that turns a derived class with a Java-style iteration
  28. * interface into an STL range.
  29. *
  30. * Derived class is expected to define:
  31. * \code
  32. * TSomething* Next();
  33. * \endcode
  34. *
  35. * `Next()` returning `nullptr` signals end of range. Note that you can also use
  36. * pointer-like types instead of actual pointers (e.g. `TAtomicSharedPtr`).
  37. *
  38. * Since iteration state is stored inside the derived class, the resulting range
  39. * is an input range (works for single pass algorithms only). Technically speaking,
  40. * if you're returning a non-const pointer from `Next`, it can also work as an output range.
  41. *
  42. * Example usage:
  43. * \code
  44. * class TSquaresGenerator: public TInputRangeAdaptor<TSquaresGenerator> {
  45. * public:
  46. * const double* Next() {
  47. * Current_ = State_ * State_;
  48. * State_ += 1.0;
  49. * // Never return nullptr => we have infinite range!
  50. * return &Current_;
  51. * }
  52. *
  53. * private:
  54. * double State_ = 0.0;
  55. * double Current_ = 0.0;
  56. * }
  57. * \endcode
  58. */
  59. template <class TSlave>
  60. class TInputRangeAdaptor {
  61. public: // TODO: private
  62. class TIterator {
  63. public:
  64. static constexpr bool IsNoexceptNext = noexcept(std::declval<TSlave>().Next());
  65. using difference_type = std::ptrdiff_t;
  66. using pointer = decltype(std::declval<TSlave>().Next());
  67. using reference = decltype(*std::declval<TSlave>().Next());
  68. using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
  69. using iterator_category = std::input_iterator_tag;
  70. inline TIterator() noexcept
  71. : Slave_(nullptr)
  72. , Cur_()
  73. {
  74. }
  75. inline TIterator(TSlave* slave) noexcept(IsNoexceptNext)
  76. : Slave_(slave)
  77. , Cur_(Slave_->Next())
  78. {
  79. }
  80. inline bool operator==(const TIterator& it) const noexcept {
  81. return Cur_ == it.Cur_;
  82. }
  83. inline bool operator!=(const TIterator& it) const noexcept {
  84. return !(*this == it);
  85. }
  86. inline pointer operator->() const noexcept {
  87. return Cur_;
  88. }
  89. inline reference operator*() const noexcept {
  90. return *Cur_;
  91. }
  92. inline TIterator& operator++() noexcept(IsNoexceptNext) {
  93. Cur_ = Slave_->Next();
  94. return *this;
  95. }
  96. private:
  97. TSlave* Slave_;
  98. pointer Cur_;
  99. };
  100. public:
  101. using const_iterator = TIterator;
  102. using iterator = const_iterator;
  103. inline iterator begin() const noexcept(TIterator::IsNoexceptNext) {
  104. return TIterator(const_cast<TSlave*>(static_cast<const TSlave*>(this)));
  105. }
  106. inline iterator end() const noexcept {
  107. return TIterator();
  108. }
  109. };
  110. /**
  111. * Transform given reverse iterator into forward iterator pointing to the same element.
  112. *
  113. * @see http://stackoverflow.com/a/1830240
  114. */
  115. template <class TIterator>
  116. auto ToForwardIterator(TIterator iter) {
  117. return std::next(iter).base();
  118. }