2 * Copyright 2017 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.
20 * This header is deprecated
22 * Use range-based for loops, and if necessary Ranges-v3.
24 * Some of the messaging here presumes that you have coded:
26 * #include <range/v3/all.hpp>
27 * using namespace ranges;
30 #include <folly/Preprocessor.h>
31 #include <type_traits>
34 * Form a local variable name from "FOR_EACH_" x __LINE__, so that
35 * FOR_EACH can be nested without creating shadowed declarations.
37 #define _FE_ANON(x) FB_CONCATENATE(FOR_EACH_, FB_CONCATENATE(x, __LINE__))
40 * If you just want the element values, please use:
42 * for (auto&& element : collection)
44 * If you need access to the iterators please write an explicit iterator loop
46 #define FOR_EACH(i, c) \
47 if (bool _FE_ANON(s1_) = false) {} else \
48 for (auto && _FE_ANON(s2_) = (c); \
49 !_FE_ANON(s1_); _FE_ANON(s1_) = true) \
50 for (auto i = _FE_ANON(s2_).begin(); \
51 i != _FE_ANON(s2_).end(); ++i)
54 * If you just want the element values, please use this (ranges-v3) construct:
56 * for (auto&& element : collection | view::reverse)
58 * If you need access to the iterators please write an explicit iterator loop
60 #define FOR_EACH_R(i, c) \
61 if (bool _FE_ANON(s1_) = false) {} else \
62 for (auto && _FE_ANON(s2_) = (c); \
63 !_FE_ANON(s1_); _FE_ANON(s1_) = true) \
64 for (auto i = _FE_ANON(s2_).rbegin(); \
65 i != _FE_ANON(s2_).rend(); ++i)
68 * If you just want the element values, please use this (ranges-v3) construct:
70 * for (auto&& element : collection | view::zip(view::ints))
72 * If you need access to the iterators please write an explicit iterator loop
73 * and use a counter variable
75 #define FOR_EACH_ENUMERATE(count, i, c) \
76 if (bool _FE_ANON(s1_) = false) {} else \
77 for (auto && FOR_EACH_state2 = (c); \
78 !_FE_ANON(s1_); _FE_ANON(s1_) = true) \
79 if (size_t _FE_ANON(n1_) = 0) {} else \
80 if (const size_t& count = _FE_ANON(n1_)) {} else \
81 for (auto i = FOR_EACH_state2.begin(); \
82 i != FOR_EACH_state2.end(); ++_FE_ANON(n1_), ++i)
84 * If you just want the keys, please use this (ranges-v3) construct:
86 * for (auto&& element : collection | view::keys)
88 * If you just want the values, please use this (ranges-v3) construct:
90 * for (auto&& element : collection | view::values)
92 * If you need to see both, use:
94 * for (auto&& element : collection) {
95 * auto const& key = element.first;
96 * auto& value = element.second;
101 #define FOR_EACH_KV(k, v, c) \
102 if (unsigned int _FE_ANON(s1_) = 0) {} else \
103 for (auto && _FE_ANON(s2_) = (c); \
104 !_FE_ANON(s1_); _FE_ANON(s1_) = 1) \
105 for (auto _FE_ANON(s3_) = _FE_ANON(s2_).begin(); \
106 _FE_ANON(s3_) != _FE_ANON(s2_).end(); \
108 ? ((_FE_ANON(s1_) = 0), ++_FE_ANON(s3_)) \
109 : (_FE_ANON(s3_) = _FE_ANON(s2_).end())) \
110 for (auto &k = _FE_ANON(s3_)->first; \
111 !_FE_ANON(s1_); ++_FE_ANON(s1_)) \
112 for (auto &v = _FE_ANON(s3_)->second; \
113 !_FE_ANON(s1_); ++_FE_ANON(s1_))
115 namespace folly { namespace detail {
117 // Boost 1.48 lacks has_less, we emulate a subset of it here.
118 template <typename T, typename U>
120 struct BiggerThanChar { char unused[2]; };
121 template <typename C, typename D> static char test(decltype(C() < D())*);
122 template <typename, typename> static BiggerThanChar test(...);
124 enum { value = sizeof(test<T, U>(0)) == 1 };
128 * notThereYet helps the FOR_EACH_RANGE macro by opportunistically
129 * using "<" instead of "!=" whenever available when checking for loop
130 * termination. This makes e.g. examples such as FOR_EACH_RANGE (i,
131 * 10, 5) execute zero iterations instead of looping virtually
132 * forever. At the same time, some iterator types define "!=" but not
133 * "<". The notThereYet function will dispatch differently for those.
135 * Below is the correct implementation of notThereYet. It is disabled
136 * because of a bug in Boost 1.46: The filesystem::path::iterator
137 * defines operator< (via boost::iterator_facade), but that in turn
138 * uses distance_to which is undefined for that particular
139 * iterator. So HasLess (defined above) identifies
140 * boost::filesystem::path as properly comparable with <, but in fact
141 * attempting to do so will yield a compile-time error.
143 * The else branch (active) contains a conservative
149 template <class T, class U>
150 typename std::enable_if<HasLess<T, U>::value, bool>::type
151 notThereYet(T& iter, const U& end) {
155 template <class T, class U>
156 typename std::enable_if<!HasLess<T, U>::value, bool>::type
157 notThereYet(T& iter, const U& end) {
163 template <class T, class U>
164 typename std::enable_if<
165 (std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) ||
166 (std::is_pointer<T>::value && std::is_pointer<U>::value),
168 notThereYet(T& iter, const U& end) {
172 template <class T, class U>
173 typename std::enable_if<
175 (std::is_arithmetic<T>::value && std::is_arithmetic<U>::value) ||
176 (std::is_pointer<T>::value && std::is_pointer<U>::value)
179 notThereYet(T& iter, const U& end) {
187 * downTo is similar to notThereYet, but in reverse - it helps the
188 * FOR_EACH_RANGE_R macro.
190 template <class T, class U>
191 typename std::enable_if<HasLess<U, T>::value, bool>::type
192 downTo(T& iter, const U& begin) {
193 return begin < iter--;
196 template <class T, class U>
197 typename std::enable_if<!HasLess<U, T>::value, bool>::type
198 downTo(T& iter, const U& begin) {
199 if (iter == begin) return false;
207 * Look at the Ranges-v3 views and you'll probably find an easier way to build
208 * the view you want but the equivalent is roughly:
210 * for (auto& element : make_iterator_range(begin, end))
212 #define FOR_EACH_RANGE(i, begin, end) \
213 for (auto i = (true ? (begin) : (end)); \
214 ::folly::detail::notThereYet(i, (end)); \
218 * Look at the Ranges-v3 views and you'll probably find an easier way to build
219 * the view you want but the equivalent is roughly:
221 * for (auto& element : make_iterator_range(begin, end) | view::reverse)
223 #define FOR_EACH_RANGE_R(i, begin, end) \
224 for (auto i = (false ? (begin) : (end)); ::folly::detail::downTo(i, (begin));)