xrange.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #pragma once
  2. #include "typetraits.h"
  3. #include "utility.h"
  4. #include <util/system/yassert.h>
  5. #include <iterator>
  6. /** @file
  7. * Some similar for python xrange(): https://docs.python.org/2/library/functions.html#xrange
  8. * Discussion: https://clubs.at.yandex-team.ru/arcadia/6124
  9. *
  10. * Example usage:
  11. * for (auto i: xrange(MyVector.size())) { // instead for (size_t i = 0; i < MyVector.size(); ++i)
  12. * DoSomething(i, MyVector[i]);
  13. * }
  14. *
  15. * TVector<int> arithmeticSeq = xrange(10); // instead: TVector<int> arithmeticSeq; for(size_t i = 0; i < 10; ++i) { arithmeticSeq.push_back(i); }
  16. *
  17. */
  18. namespace NPrivate {
  19. template <typename T>
  20. class TSimpleXRange {
  21. using TDiff = decltype(T() - T());
  22. public:
  23. constexpr TSimpleXRange(T start, T finish) noexcept
  24. : Start(start)
  25. , Finish(Max(start, finish))
  26. {
  27. }
  28. class TIterator {
  29. public:
  30. using value_type = T;
  31. using difference_type = TDiff;
  32. using pointer = const T*;
  33. using reference = const T&;
  34. using iterator_category = std::random_access_iterator_tag;
  35. constexpr TIterator(T value) noexcept
  36. : Value(value)
  37. {
  38. }
  39. constexpr T operator*() const noexcept {
  40. return Value;
  41. }
  42. constexpr bool operator!=(const TIterator& other) const noexcept {
  43. return Value != other.Value;
  44. }
  45. constexpr bool operator==(const TIterator& other) const noexcept {
  46. return Value == other.Value;
  47. }
  48. TIterator& operator++() noexcept {
  49. ++Value;
  50. return *this;
  51. }
  52. TIterator& operator--() noexcept {
  53. --Value;
  54. return *this;
  55. }
  56. constexpr TDiff operator-(const TIterator& b) const noexcept {
  57. return Value - b.Value;
  58. }
  59. template <typename IntType>
  60. constexpr TIterator operator+(const IntType& b) const noexcept {
  61. return TIterator(Value + b);
  62. }
  63. template <typename IntType>
  64. TIterator& operator+=(const IntType& b) noexcept {
  65. Value += b;
  66. return *this;
  67. }
  68. template <typename IntType>
  69. constexpr TIterator operator-(const IntType& b) const noexcept {
  70. return TIterator(Value - b);
  71. }
  72. template <typename IntType>
  73. TIterator& operator-=(const IntType& b) noexcept {
  74. Value -= b;
  75. return *this;
  76. }
  77. constexpr bool operator<(const TIterator& b) const noexcept {
  78. return Value < b.Value;
  79. }
  80. private:
  81. T Value;
  82. };
  83. using value_type = T;
  84. using iterator = TIterator;
  85. using const_iterator = TIterator;
  86. constexpr TIterator begin() const noexcept {
  87. return TIterator(Start);
  88. }
  89. constexpr TIterator end() const noexcept {
  90. return TIterator(Finish);
  91. }
  92. constexpr T size() const noexcept {
  93. return Finish - Start;
  94. }
  95. template <class Container>
  96. operator Container() const {
  97. return Container(begin(), end());
  98. }
  99. private:
  100. T Start;
  101. T Finish;
  102. };
  103. template <typename T>
  104. class TSteppedXRange {
  105. using TDiff = decltype(T() - T());
  106. public:
  107. constexpr TSteppedXRange(T start, T finish, TDiff step) noexcept
  108. : Start_(start)
  109. , Step_(step)
  110. , Finish_(CalcRealFinish(Start_, finish, Step_))
  111. {
  112. static_assert(std::is_integral<T>::value || std::is_pointer<T>::value, "T should be integral type or pointer");
  113. }
  114. class TIterator {
  115. public:
  116. using value_type = T;
  117. using difference_type = TDiff;
  118. using pointer = const T*;
  119. using reference = const T&;
  120. using iterator_category = std::random_access_iterator_tag;
  121. constexpr TIterator(T value, const TSteppedXRange& parent) noexcept
  122. : Value_(value)
  123. , Parent_(&parent)
  124. {
  125. }
  126. constexpr T operator*() const noexcept {
  127. return Value_;
  128. }
  129. constexpr bool operator!=(const TIterator& other) const noexcept {
  130. return Value_ != other.Value_;
  131. }
  132. constexpr bool operator==(const TIterator& other) const noexcept {
  133. return Value_ == other.Value_;
  134. }
  135. TIterator& operator++() noexcept {
  136. Value_ += Parent_->Step_;
  137. return *this;
  138. }
  139. TIterator& operator--() noexcept {
  140. Value_ -= Parent_->Step_;
  141. return *this;
  142. }
  143. constexpr TDiff operator-(const TIterator& b) const noexcept {
  144. return (Value_ - b.Value_) / Parent_->Step_;
  145. }
  146. template <typename IntType>
  147. constexpr TIterator operator+(const IntType& b) const noexcept {
  148. return TIterator(*this) += b;
  149. }
  150. template <typename IntType>
  151. TIterator& operator+=(const IntType& b) noexcept {
  152. Value_ += b * Parent_->Step_;
  153. return *this;
  154. }
  155. template <typename IntType>
  156. constexpr TIterator operator-(const IntType& b) const noexcept {
  157. return TIterator(*this) -= b;
  158. }
  159. template <typename IntType>
  160. TIterator& operator-=(const IntType& b) noexcept {
  161. Value_ -= b * Parent_->Step_;
  162. return *this;
  163. }
  164. private:
  165. T Value_;
  166. const TSteppedXRange* Parent_;
  167. };
  168. using value_type = T;
  169. using iterator = TIterator;
  170. using const_iterator = TIterator;
  171. constexpr TIterator begin() const noexcept {
  172. return TIterator(Start_, *this);
  173. }
  174. constexpr TIterator end() const noexcept {
  175. return TIterator(Finish_, *this);
  176. }
  177. static T CalcRealFinish(T start, T expFinish, TDiff step) {
  178. Y_ASSERT(step != 0);
  179. if (step > 0) {
  180. if (expFinish > start) {
  181. return start + step * ((expFinish - 1 - start) / step + 1);
  182. }
  183. return start;
  184. }
  185. return start - TSteppedXRange<TDiff>::CalcRealFinish(0, start - expFinish, -step);
  186. }
  187. constexpr T size() const noexcept {
  188. return (Finish_ - Start_) / Step_;
  189. }
  190. template <class Container>
  191. operator Container() const {
  192. return Container(begin(), end());
  193. }
  194. private:
  195. const T Start_;
  196. const TDiff Step_;
  197. const T Finish_;
  198. };
  199. }
  200. /**
  201. * generate arithmetic progression that starts at start with certain step and stop at finish (not including)
  202. *
  203. * @param step must be non-zero
  204. */
  205. template <typename T>
  206. constexpr ::NPrivate::TSteppedXRange<T> xrange(T start, T finish, decltype(T() - T()) step) noexcept {
  207. return {start, finish, step};
  208. }
  209. /// generate sequence [start; finish)
  210. template <typename T>
  211. constexpr ::NPrivate::TSimpleXRange<T> xrange(T start, T finish) noexcept {
  212. return {start, finish};
  213. }
  214. /// generate sequence [0; finish)
  215. template <typename T>
  216. constexpr auto xrange(T finish) noexcept -> decltype(xrange(T(), finish)) {
  217. return xrange(T(), finish);
  218. }