2 * Copyright 2017-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include <folly/CPortability.h>
23 #include <folly/portability/SysTypes.h>
26 * Similar to Python's enumerate(), folly::enumerate() can be used to
27 * iterate a range with a for-range loop, and it also allows to
28 * retrieve the count of iterations so far.
32 * for (auto&& it : folly::enumerate(vec)) {
33 * // *it is a reference to the current element. Const if vec is const.
34 * // it->member can be used as well.
35 * // it.index contains the iteration count.
38 * If the iteration variable is const, the reference is too.
40 * for (const auto&& it : folly::enumerate(vec)) {
41 * // *it is always a const reference.
44 * @author Giuseppe Ottaviano <ott@fb.com>
56 struct MakeConst<T&> {
57 using type = const T&;
60 struct MakeConst<T*> {
61 using type = const T*;
64 // Raw pointers don't have an operator->() member function, so the
65 // second overload will be SFINAEd out in that case. Otherwise, the
66 // second is preferred in the partial order for getPointer(_, 0).
67 template <class Iterator>
68 FOLLY_ALWAYS_INLINE auto getPointer(const Iterator& it, long)
69 -> decltype(std::addressof(*it)) {
70 return std::addressof(*it);
72 template <class Iterator>
73 FOLLY_ALWAYS_INLINE auto getPointer(const Iterator& it, int)
74 -> decltype(it.operator->()) {
75 return it.operator->();
78 template <class Iterator>
81 explicit Enumerator(Iterator it) : it_(std::move(it)) {}
85 using difference_type = ssize_t;
86 using value_type = typename std::iterator_traits<Iterator>::value_type;
87 using reference = typename std::iterator_traits<Iterator>::reference;
88 using pointer = typename std::iterator_traits<Iterator>::pointer;
89 using iterator_category = std::input_iterator_tag;
91 FOLLY_ALWAYS_INLINE explicit Proxy(const Enumerator& e)
92 : it_(e.it_), index(e.idx_) {}
94 // Non-const Proxy: Forward constness from Iterator.
95 FOLLY_ALWAYS_INLINE reference operator*() {
98 FOLLY_ALWAYS_INLINE pointer operator->() {
99 return getPointer(it_, 0);
102 // Const Proxy: Force const references.
103 FOLLY_ALWAYS_INLINE typename MakeConst<reference>::type operator*() const {
106 FOLLY_ALWAYS_INLINE typename MakeConst<pointer>::type operator->() const {
107 return getPointer(it_, 0);
117 FOLLY_ALWAYS_INLINE Proxy operator*() const {
121 FOLLY_ALWAYS_INLINE Enumerator& operator++() {
127 template <typename OtherIterator>
128 FOLLY_ALWAYS_INLINE bool operator==(
129 const Enumerator<OtherIterator>& rhs) const {
130 return it_ == rhs.it_;
133 template <typename OtherIterator>
134 FOLLY_ALWAYS_INLINE bool operator!=(
135 const Enumerator<OtherIterator>& rhs) const {
136 return !(it_ == rhs.it_);
140 template <typename OtherIterator>
141 friend class Enumerator;
147 template <class Range>
148 class RangeEnumerator {
150 using BeginIteratorType = decltype(std::declval<Range>().begin());
151 using EndIteratorType = decltype(std::declval<Range>().end());
154 explicit RangeEnumerator(Range&& r) : r_(std::forward<Range>(r)) {}
156 Enumerator<BeginIteratorType> begin() {
157 return Enumerator<BeginIteratorType>(r_.begin());
159 Enumerator<EndIteratorType> end() {
160 return Enumerator<EndIteratorType>(r_.end());
164 } // namespace detail
166 template <class Range>
167 detail::RangeEnumerator<Range> enumerate(Range&& r) {
168 return detail::RangeEnumerator<Range>(std::forward<Range>(r));