Enumerate.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * Copyright 2016-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <iterator>
  18. #include <memory>
  19. #include <folly/CPortability.h>
  20. #include <folly/portability/SysTypes.h>
  21. /**
  22. * Similar to Python's enumerate(), folly::enumerate() can be used to
  23. * iterate a range with a for-range loop, and it also allows to
  24. * retrieve the count of iterations so far.
  25. *
  26. * For example:
  27. *
  28. * for (auto&& it : folly::enumerate(vec)) {
  29. * // *it is a reference to the current element. Const if vec is const.
  30. * // it->member can be used as well.
  31. * // it.index contains the iteration count.
  32. * }
  33. *
  34. * If the iteration variable is const, the reference is too.
  35. *
  36. * for (const auto&& it : folly::enumerate(vec)) {
  37. * // *it is always a const reference.
  38. * }
  39. *
  40. * @author Giuseppe Ottaviano <ott@fb.com>
  41. */
  42. namespace folly {
  43. namespace detail {
  44. template <class T>
  45. struct MakeConst {
  46. using type = const T;
  47. };
  48. template <class T>
  49. struct MakeConst<T&> {
  50. using type = const T&;
  51. };
  52. template <class T>
  53. struct MakeConst<T*> {
  54. using type = const T*;
  55. };
  56. // Raw pointers don't have an operator->() member function, so the
  57. // second overload will be SFINAEd out in that case. Otherwise, the
  58. // second is preferred in the partial order for getPointer(_, 0).
  59. template <class Iterator>
  60. FOLLY_ALWAYS_INLINE auto getPointer(const Iterator& it, long)
  61. -> decltype(std::addressof(*it)) {
  62. return std::addressof(*it);
  63. }
  64. template <class Iterator>
  65. FOLLY_ALWAYS_INLINE auto getPointer(const Iterator& it, int)
  66. -> decltype(it.operator->()) {
  67. return it.operator->();
  68. }
  69. template <class Iterator>
  70. class Enumerator {
  71. public:
  72. explicit Enumerator(Iterator it) : it_(std::move(it)) {}
  73. class Proxy {
  74. public:
  75. using difference_type = ssize_t;
  76. using value_type = typename std::iterator_traits<Iterator>::value_type;
  77. using reference = typename std::iterator_traits<Iterator>::reference;
  78. using pointer = typename std::iterator_traits<Iterator>::pointer;
  79. using iterator_category = std::input_iterator_tag;
  80. FOLLY_ALWAYS_INLINE explicit Proxy(const Enumerator& e)
  81. : it_(e.it_), index(e.idx_) {}
  82. // Non-const Proxy: Forward constness from Iterator.
  83. FOLLY_ALWAYS_INLINE reference operator*() {
  84. return *it_;
  85. }
  86. FOLLY_ALWAYS_INLINE pointer operator->() {
  87. return getPointer(it_, 0);
  88. }
  89. // Const Proxy: Force const references.
  90. FOLLY_ALWAYS_INLINE typename MakeConst<reference>::type operator*() const {
  91. return *it_;
  92. }
  93. FOLLY_ALWAYS_INLINE typename MakeConst<pointer>::type operator->() const {
  94. return getPointer(it_, 0);
  95. }
  96. private:
  97. const Iterator& it_;
  98. public:
  99. const size_t index;
  100. };
  101. FOLLY_ALWAYS_INLINE Proxy operator*() const {
  102. return Proxy(*this);
  103. }
  104. FOLLY_ALWAYS_INLINE Enumerator& operator++() {
  105. ++it_;
  106. ++idx_;
  107. return *this;
  108. }
  109. template <typename OtherIterator>
  110. FOLLY_ALWAYS_INLINE bool operator==(
  111. const Enumerator<OtherIterator>& rhs) const {
  112. return it_ == rhs.it_;
  113. }
  114. template <typename OtherIterator>
  115. FOLLY_ALWAYS_INLINE bool operator!=(
  116. const Enumerator<OtherIterator>& rhs) const {
  117. return !(it_ == rhs.it_);
  118. }
  119. private:
  120. template <typename OtherIterator>
  121. friend class Enumerator;
  122. Iterator it_;
  123. size_t idx_ = 0;
  124. };
  125. template <class Range>
  126. class RangeEnumerator {
  127. Range r_;
  128. using BeginIteratorType = decltype(std::declval<Range>().begin());
  129. using EndIteratorType = decltype(std::declval<Range>().end());
  130. public:
  131. explicit RangeEnumerator(Range&& r) : r_(std::forward<Range>(r)) {}
  132. Enumerator<BeginIteratorType> begin() {
  133. return Enumerator<BeginIteratorType>(r_.begin());
  134. }
  135. Enumerator<EndIteratorType> end() {
  136. return Enumerator<EndIteratorType>(r_.end());
  137. }
  138. };
  139. } // namespace detail
  140. template <class Range>
  141. detail::RangeEnumerator<Range> enumerate(Range&& r) {
  142. return detail::RangeEnumerator<Range>(std::forward<Range>(r));
  143. }
  144. } // namespace folly