proxygen
Foreach-inl.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 
17 #include <cassert>
18 #include <cstdint>
19 #include <initializer_list>
20 #include <iterator>
21 #include <tuple>
22 #include <type_traits>
23 #include <utility>
24 
25 #include <folly/Portability.h>
26 #include <folly/Traits.h>
27 #include <folly/Utility.h>
29 
30 namespace folly {
31 
32 namespace for_each_detail {
33 
34 namespace adl {
35 
36 /* using override */
37 using std::begin;
38 /* using override */
39 using std::end;
40 /* using override */
41 using std::get;
42 
49 template <std::size_t Index, typename Type>
50 auto adl_get(Type&& instance) -> decltype(get<Index>(std::declval<Type>())) {
51  return get<Index>(std::forward<Type>(instance));
52 }
53 template <typename Type>
54 auto adl_begin(Type&& instance) -> decltype(begin(instance)) {
55  return begin(instance);
56 }
57 template <typename Type>
58 auto adl_end(Type&& instance) -> decltype(end(instance)) {
59  return end(instance);
60 }
61 
62 } // namespace adl
63 
67 template <typename T>
69  void_t<decltype(std::declval<T>().template get<0>())>;
70 template <typename, typename T>
72 template <typename T>
74 
80 template <
81  std::size_t Index,
82  typename Type,
84 auto get_impl(Type&& instance)
85  -> decltype(adl::adl_get<Index>(static_cast<Type&&>(instance))) {
86  return adl::adl_get<Index>(static_cast<Type&&>(instance));
87 }
88 template <
89  std::size_t Index,
90  typename Type,
92 auto get_impl(Type&& instance)
93  -> decltype(static_cast<Type&&>(instance).template get<Index>()) {
94  return static_cast<Type&&>(instance).template get<Index>();
95 }
96 
101 using EnableIfTuple = void_t<
102  decltype(get_impl<0>(std::declval<T>())),
104 template <typename, typename T>
106 template <typename T>
107 struct IsTuple<EnableIfTuple<T>, T> : std::true_type {};
108 
113 using EnableIfRange = void_t<
114  decltype(adl::adl_begin(std::declval<T>())),
115  decltype(adl::adl_end(std::declval<T>()))>;
116 template <typename, typename T>
118 template <typename T>
119 struct IsRange<EnableIfRange<T>, T> : std::true_type {};
120 
121 struct TupleTag {};
122 struct RangeTag {};
123 
127 template <typename Sequence>
128 using SequenceTag =
130 
131 struct BeginAddTag {};
132 struct IndexingTag {};
133 
134 template <typename Func, typename Item, typename Iter>
135 using ForEachImplTag = std::conditional_t<
138  std::conditional_t<
139  is_invocable<Func, Item, index_constant<0>>::value,
141  std::conditional_t<
144  void>>>;
145 
146 template <
147  typename Func,
148  typename... Args,
149  std::enable_if_t<is_invocable_r<LoopControl, Func, Args...>::value, int> =
150  0>
151 LoopControl invoke_returning_loop_control(Func&& f, Args&&... a) {
152  return static_cast<Func&&>(f)(static_cast<Args&&>(a)...);
153 }
154 template <
155  typename Func,
156  typename... Args,
157  std::enable_if_t<!is_invocable_r<LoopControl, Func, Args...>::value, int> =
158  0>
159 LoopControl invoke_returning_loop_control(Func&& f, Args&&... a) {
160  static_assert(
161  std::is_void<invoke_result_t<Func, Args...>>::value,
162  "return either LoopControl or void");
163  return static_cast<Func&&>(f)(static_cast<Args&&>(a)...), loop_continue;
164 }
165 
169 template <typename Sequence, typename Func>
170 void for_each_range_impl(index_constant<3>, Sequence&& range, Func& func) {
171  auto first = adl::adl_begin(range);
172  auto last = adl::adl_end(range);
173  for (auto index = std::size_t{0}; first != last; ++index) {
174  auto next = std::next(first);
175  auto control = invoke_returning_loop_control(func, *first, index, first);
176  if (loop_break == control) {
177  break;
178  }
179  first = next;
180  }
181 }
182 template <typename Sequence, typename Func>
183 void for_each_range_impl(index_constant<2>, Sequence&& range, Func& func) {
184  // make a three arg adaptor for the function passed in so that the main
185  // implementation function can be used
186  auto three_arg_adaptor = [&func](
187  auto&& ele, auto index, auto) -> decltype(auto) {
188  return func(std::forward<decltype(ele)>(ele), index);
189  };
191  index_constant<3>{}, std::forward<Sequence>(range), three_arg_adaptor);
192 }
193 
194 template <typename Sequence, typename Func>
195 void for_each_range_impl(index_constant<1>, Sequence&& range, Func& func) {
196  // make a three argument adaptor for the function passed in that just ignores
197  // the second and third argument
198  auto three_arg_adaptor = [&func](auto&& ele, auto, auto) -> decltype(auto) {
199  return func(std::forward<decltype(ele)>(ele));
200  };
202  index_constant<3>{}, std::forward<Sequence>(range), three_arg_adaptor);
203 }
204 
208 template <typename Sequence, typename Func, std::size_t... Indices>
211  Sequence&& seq,
212  Func& func) {
213  using _ = int[];
214 
215  // unroll the loop in an initializer list construction parameter expansion
216  // pack
217  auto control = loop_continue;
218 
219  // cast to void to ignore the result; use the int[] initialization to do the
220  // loop execution, the ternary conditional will decide whether or not to
221  // evaluate the result
222  //
223  // if func does not return loop-control, expect the optimizer to see through
224  // invoke_returning_loop_control always returning loop_continue
225  void(
226  _{(((control == loop_continue)
227  ? (control = invoke_returning_loop_control(
228  func,
229  get_impl<Indices>(std::forward<Sequence>(seq)),
231  : (loop_continue)),
232  0)...});
233 }
234 
243 template <typename Sequence, typename Func>
244 void for_each_tuple_impl(index_constant<2>, Sequence&& seq, Func& func) {
245  // pass the length as an index sequence to the implementation as an
246  // optimization over manual template "tail recursion" unrolling
249  make_index_sequence<size::value>{}, std::forward<Sequence>(seq), func);
250 }
251 template <typename Sequence, typename Func>
252 void for_each_tuple_impl(index_constant<1>, Sequence&& seq, Func& func) {
253  // make an adaptor for the function passed in, in case it can only be passed
254  // on argument
255  auto two_arg_adaptor = [&func](auto&& ele, auto) -> decltype(auto) {
256  return func(std::forward<decltype(ele)>(ele));
257  };
259  index_constant<2>{}, std::forward<Sequence>(seq), two_arg_adaptor);
260 }
261 
269 template <typename Sequence, typename Func>
270 static void for_each_impl(TupleTag, Sequence&& range, Func& func) {
271  using type = decltype(get_impl<0>(std::declval<Sequence>()));
273  static_assert(!std::is_same<tag, void>::value, "unknown invocability");
274  for_each_tuple_impl(tag{}, std::forward<Sequence>(range), func);
275 }
276 template <typename Sequence, typename Func>
277 static void for_each_impl(RangeTag, Sequence&& range, Func& func) {
278  using iter = decltype(adl::adl_begin(std::declval<Sequence>()));
279  using type = decltype(*std::declval<iter>());
281  static_assert(!std::is_same<tag, void>::value, "unknown invocability");
282  for_each_range_impl(tag{}, std::forward<Sequence>(range), func);
283 }
284 
285 template <typename Sequence, typename Index>
286 decltype(auto) fetch_impl(IndexingTag, Sequence&& sequence, Index&& index) {
287  return std::forward<Sequence>(sequence)[std::forward<Index>(index)];
288 }
289 template <typename Sequence, typename Index>
290 decltype(auto) fetch_impl(BeginAddTag, Sequence&& sequence, Index index) {
291  return *(adl::adl_begin(std::forward<Sequence>(sequence)) + index);
292 }
293 
294 template <typename Sequence, typename Index>
295 decltype(auto) fetch_impl(TupleTag, Sequence&& sequence, Index index) {
296  return get_impl<index>(std::forward<Sequence>(sequence));
297 }
298 template <typename Sequence, typename Index>
299 decltype(auto) fetch_impl(RangeTag, Sequence&& sequence, Index&& index) {
300  using iter = decltype(adl::adl_begin(std::declval<Sequence>()));
301  using iter_traits = std::iterator_traits<remove_cvref_t<iter>>;
302  using iter_cat = typename iter_traits::iterator_category;
303  using tag = std::conditional_t<
305  BeginAddTag,
306  IndexingTag>;
307  return fetch_impl(
308  tag{}, std::forward<Sequence>(sequence), std::forward<Index>(index));
309 }
310 
311 } // namespace for_each_detail
312 
313 template <typename Sequence, typename Func>
314 FOLLY_CPP14_CONSTEXPR Func for_each(Sequence&& sequence, Func func) {
315  namespace fed = for_each_detail;
316  using tag = fed::SequenceTag<Sequence>;
317  fed::for_each_impl(tag{}, std::forward<Sequence>(sequence), func);
318  return func;
319 }
320 
321 template <typename Sequence, typename Index>
322 FOLLY_CPP14_CONSTEXPR decltype(auto) fetch(Sequence&& sequence, Index&& index) {
323  namespace fed = for_each_detail;
324  using tag = fed::SequenceTag<Sequence>;
326  tag{}, std::forward<Sequence>(sequence), std::forward<Index>(index));
327 }
328 
329 } // namespace folly
void_t< decltype(get_impl< 0 >(std::declval< T >())), decltype(std::tuple_size< T >::value)> EnableIfTuple
Definition: Foreach-inl.h:103
static void for_each_impl(RangeTag, Sequence &&range, Func &func)
Definition: Foreach-inl.h:277
auto f
static void for_each_impl(TupleTag, Sequence &&range, Func &func)
Definition: Foreach-inl.h:270
typename invoke_result< F, Args... >::type invoke_result_t
Definition: Invoke.h:142
LoopControl invoke_returning_loop_control(Func &&f, Args &&...a)
Definition: Foreach-inl.h:151
auto get_impl(Type &&instance) -> decltype(adl::adl_get< Index >(static_cast< Type && >(instance)))
Definition: Foreach-inl.h:84
constexpr auto loop_continue
Definition: Foreach.h:98
PskType type
#define FOLLY_CPP14_CONSTEXPR
Definition: Portability.h:424
std::integral_constant< std::size_t, I > index_constant
Definition: Traits.h:150
void_t< decltype(adl::adl_begin(std::declval< T >())), decltype(adl::adl_end(std::declval< T >()))> EnableIfRange
Definition: Foreach-inl.h:115
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
Gen seq(Value first, Value last)
Definition: Base.h:484
auto adl_end(Type &&instance) -> decltype(end(instance))
Definition: Foreach-inl.h:58
void for_each_range_impl(index_constant< 3 >, Sequence &&range, Func &func)
Definition: Foreach-inl.h:170
folly::std T
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
bool_constant< true > true_type
Definition: gtest-port.h:2210
void for_each_tuple_impl(index_sequence< Indices... >, Sequence &&seq, Func &func)
Definition: Foreach-inl.h:209
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
Function< void()> Func
Definition: Executor.h:27
decltype(auto) fetch_impl(IndexingTag, Sequence &&sequence, Index &&index)
Definition: Foreach-inl.h:286
def Iter(n, format, sep='')
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
make_integer_sequence< std::size_t, Size > make_index_sequence
Definition: Utility.h:209
constexpr Range< Iter > range(Iter first, Iter last)
Definition: Range.h:1114
std::conditional_t< is_invocable< Func, Item, index_constant< 0 >, Iter >::value, index_constant< 3 >, std::conditional_t< is_invocable< Func, Item, index_constant< 0 >>::value, index_constant< 2 >, std::conditional_t< is_invocable< Func, Item >::value, index_constant< 1 >, void >>> ForEachImplTag
Definition: Foreach-inl.h:144
type_t< void, Ts... > void_t
Definition: Traits.h:302
char a
static const char *const value
Definition: Conv.cpp:50
auto adl_get(Type &&instance) -> decltype(get< Index >(std::declval< Type >()))
Definition: Foreach-inl.h:50
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
Definition: gtest-port.h:2209
const internal::AnythingMatcher _
auto adl_begin(Type &&instance) -> decltype(begin(instance))
Definition: Foreach-inl.h:54
decltype(auto) FOLLY_CPP14_CONSTEXPR fetch(Sequence &&sequence, Index &&index)
Definition: Foreach-inl.h:322
std::conditional_t< IsRange< void, Sequence >::value, RangeTag, TupleTag > SequenceTag
Definition: Foreach-inl.h:129
PUSHMI_INLINE_VAR constexpr detail::get_fn< T > get
Definition: submit.h:391
void_t< decltype(std::declval< T >().template get< 0 >())> EnableIfMemberGetFound
Definition: Foreach-inl.h:69
constexpr auto loop_break
Definition: Foreach.h:97
FOLLY_CPP14_CONSTEXPR Func for_each(Sequence &&sequence, Func func)
Definition: Foreach-inl.h:314
constexpr detail::First first
Definition: Base-inl.h:2553
def next(obj)
Definition: ast.py:58