iterator.h 3.7 KB

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