/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include namespace folly { /** * @function for_each * * folly::for_each is a generalized iteration algorithm. Example: * * auto one = std::make_tuple(1, 2, 3); * auto two = std::vector{1, 2, 3}; * auto func = [](auto element, auto index) { * cout << index << " : " << element << endl; * }; * folly::for_each(one, func); * folly::for_each(two, func); * * The for_each function allows iteration through sequences, these can either be * runtime sequences (i.e. entities for which std::begin and std::end work) or * compile time sequences (as deemed by the presence of std::tuple_length<> and * member get<> or ADL get<> functions). * * If a sequence type is both a runtime sequence (aka range) and a compile-time * sequence (aka tuple), then it is treated as a range in preference to a tuple. * An example of such a type is std::array. * * The function is made to provide a convenient library based alternative to the * proposal p0589r0, which aims to generalize the range based for loop even * further to work with compile time sequences. * * A drawback of using range based for loops is that sometimes you do not have * access to the index within the range. This provides easy access to that, even * with compile time sequences. * * And breaking out is easy: * * auto range_one = std::vector{1, 2, 3}; * auto range_two = std::make_tuple(1, 2, 3); * auto func = [](auto ele, auto index) { * cout << "Element at index " << index << " : " << ele; * if (index == 1) { * return folly::loop_break; * } * return folly::loop_continue; * }; * folly_for_each(range_one, func); * folly_for_each(range_two, func); * * A simple use case would be when using futures, if the user was doing calls to * n servers then they would accept the callback with the futures like this: * * auto vec = std::vector>{request_one(), ...}; * when_all(vec.begin(), vec.end()).then([](auto futures) { * folly::for_each(futures, [](auto& fut) { ... }); * }); * * Now when this code switches to use tuples instead of the runtime std::vector, * then the loop does not need to change, the code will still work just fine: * * when_all(future_one, future_two, future_three).then([](auto futures) { * folly::for_each(futures, [](auto& fut) { ... }); * }); */ template constexpr Func for_each(Range&& range, Func func); /** * The user should return loop_break and loop_continue if they want to iterate * in such a way that they can preemptively stop the loop and break out when * certain conditions are met. */ namespace for_each_detail { enum class LoopControl : bool { BREAK, CONTINUE }; } // namespace for_each_detail constexpr auto loop_break = for_each_detail::LoopControl::BREAK; constexpr auto loop_continue = for_each_detail::LoopControl::CONTINUE; /** * Utility method to help access elements of a sequence with one uniform * interface. * * This can be useful for example when you are looping through a sequence and * want to modify another sequence based on the information in the current * sequence: * * auto range_one = std::make_tuple(1, 2, 3); * auto range_two = std::make_tuple(4, 5, 6); * folly::for_each(range_one, [&range_two](auto ele, auto index) { * folly::fetch(range_two, index) = ele; * }); * * For ranges, this works by first trying to use the iterator class if the * iterator has been marked to be a random access iterator. This should be * inspectable via the std::iterator_traits traits class. If the iterator class * is not present or is not a random access iterator then the implementation * falls back to trying to use the indexing operator (operator[]) to fetch the * required element. */ template constexpr decltype(auto) fetch(Sequence&& sequence, Index&& index); } // namespace folly /** * Everything below is deprecated. */ /* * Form a local variable name from "FOR_EACH_" x __LINE__, so that * FOR_EACH can be nested without creating shadowed declarations. */ #define _FE_ANON(x) FB_CONCATENATE(FOR_EACH_, FB_CONCATENATE(x, __LINE__)) /* * If you just want the element values, please use: * * for (auto&& element : collection) * * If you need access to the iterators please write an explicit iterator loop */ #define FOR_EACH(i, c) \ if (bool _FE_ANON(s1_) = false) { \ } else \ for (auto&& _FE_ANON(s2_) = (c); !_FE_ANON(s1_); _FE_ANON(s1_) = true) \ for (auto i = _FE_ANON(s2_).begin(); i != _FE_ANON(s2_).end(); ++i) /* * If you just want the element values, please use this (ranges-v3) construct: * * for (auto&& element : collection | views::reverse) * * If you need access to the iterators please write an explicit iterator loop */ #define FOR_EACH_R(i, c) \ if (bool _FE_ANON(s1_) = false) { \ } else \ for (auto&& _FE_ANON(s2_) = (c); !_FE_ANON(s1_); _FE_ANON(s1_) = true) \ for (auto i = _FE_ANON(s2_).rbegin(); i != _FE_ANON(s2_).rend(); ++i) /* * If you just want the element values, please use this construct: * * for (auto&& element : folly::enumerate(collection)) * * If you need access to the iterators please write an explicit iterator loop * and use a counter variable */ #define FOR_EACH_ENUMERATE(count, i, c) \ if (bool _FE_ANON(s1_) = false) { \ } else \ for (auto&& FOR_EACH_state2 = (c); !_FE_ANON(s1_); _FE_ANON(s1_) = true) \ if (size_t _FE_ANON(n1_) = 0) { \ } else if (const size_t& count = _FE_ANON(n1_)) { \ } else \ for (auto i = FOR_EACH_state2.begin(); i != FOR_EACH_state2.end(); \ ++_FE_ANON(n1_), ++i) /** * If you just want the keys, please use this (ranges-v3) construct: * * for (auto&& element : collection | views::keys) * * If you just want the values, please use this (ranges-v3) construct: * * for (auto&& element : collection | views::values) * * If you need to see both, use: * * for (auto&& element : collection) { * auto const& key = element.first; * auto& value = element.second; * ...... * } * */ #define FOR_EACH_KV(k, v, c) \ if (unsigned int _FE_ANON(s1_) = 0) { \ } else \ for (auto&& _FE_ANON(s2_) = (c); !_FE_ANON(s1_); _FE_ANON(s1_) = 1) \ for (auto _FE_ANON(s3_) = _FE_ANON(s2_).begin(); \ _FE_ANON(s3_) != _FE_ANON(s2_).end(); \ _FE_ANON(s1_) == 2 ? ((_FE_ANON(s1_) = 0), ++_FE_ANON(s3_)) \ : (_FE_ANON(s3_) = _FE_ANON(s2_).end())) \ for (auto& k = _FE_ANON(s3_)->first; !_FE_ANON(s1_); ++_FE_ANON(s1_)) \ for (auto& v = _FE_ANON(s3_)->second; !_FE_ANON(s1_); ++_FE_ANON(s1_)) namespace folly { namespace detail { /** * notThereYet helps the FOR_EACH_RANGE macro by opportunistically * using "<" instead of "!=" whenever available when checking for loop * termination. This makes e.g. examples such as FOR_EACH_RANGE (i, * 10, 5) execute zero iterations instead of looping virtually * forever. At the same time, some iterator types define "!=" but not * "<". The notThereYet function will dispatch differently for those. * * The code below uses `<` for a conservative subset of types for which * it is known to be valid. */ template typename std::enable_if< (std::is_arithmetic::value && std::is_arithmetic::value) || (std::is_pointer::value && std::is_pointer::value), bool>::type notThereYet(T& iter, const U& end) { return iter < end; } template typename std::enable_if< !((std::is_arithmetic::value && std::is_arithmetic::value) || (std::is_pointer::value && std::is_pointer::value)), bool>::type notThereYet(T& iter, const U& end) { return iter != end; } } // namespace detail } // namespace folly /* * Look at the Ranges-v3 views and you'll probably find an easier way to build * the view you want but the equivalent is roughly: * * for (auto& element : make_subrange(begin, end)) */ #define FOR_EACH_RANGE(i, begin, end) \ for (auto i = (true ? (begin) : (end)); \ ::folly::detail::notThereYet(i, (end)); \ ++i) #include