Commit 8f2ad2b9 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Assorted fixes to for_each and fetch comments

Summary: [Folly] Assorted fixes to for_each and fetch comments

Reviewed By: aary

Differential Revision: D9632155

fbshipit-source-id: 64932770d3476cdd06c5fa9eb9bd845600f18fff
parent ebc7efbb
...@@ -41,9 +41,9 @@ using std::get; ...@@ -41,9 +41,9 @@ using std::get;
/** /**
* The adl_ functions below lookup the function name in the namespace of the * The adl_ functions below lookup the function name in the namespace of the
* type of the object being passed into the function. If no function with * type of the object being passed into the function. If no function with that
* that name exists for the passed object then the default std:: versions are * name exists for the passed object then the default std:: versions are going
* going to be called * to be called
*/ */
template <std::size_t Index, typename Type> template <std::size_t Index, typename Type>
auto adl_get(Type&& instance) -> decltype(get<Index>(std::declval<Type>())) { auto adl_get(Type&& instance) -> decltype(get<Index>(std::declval<Type>())) {
...@@ -61,22 +61,21 @@ auto adl_end(Type&& instance) -> decltype(end(instance)) { ...@@ -61,22 +61,21 @@ auto adl_end(Type&& instance) -> decltype(end(instance)) {
} // namespace adl } // namespace adl
/** /**
* Enable if the range supports fetching via non member get<>() * Enable if the tuple supports fetching via non member get<>()
*/ */
template <typename T> template <typename T>
using EnableIfNonMemberGetFound = using EnableIfNonMemberGetFound =
void_t<decltype(adl::adl_get<0>(std::declval<T>()))>; void_t<decltype(adl::adl_get<0>(std::declval<T>()))>;
/** /**
* Enable if the range supports fetching via a member get<>() * Enable if the tuple supports fetching via a member get<>()
*/ */
template <typename T> template <typename T>
using EnableIfMemberGetFound = using EnableIfMemberGetFound =
void_t<decltype(std::declval<T>().template get<0>())>; void_t<decltype(std::declval<T>().template get<0>())>;
/** /**
* A get that tries ADL get<> first and if that is not found tries to execute * A get that tries member get<> first and if that is not found tries ADL get<>.
* a member function get<> on the instance, just as proposed by the structured * This mechanism is as found in the structured bindings proposal here 11.5.3.
* bindings proposal here 11.5.3
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf
*/ */
template <std::size_t Index, typename Type, typename = void> template <std::size_t Index, typename Type, typename = void>
...@@ -97,10 +96,7 @@ struct Get<Index, Type, EnableIfMemberGetFound<Type>> { ...@@ -97,10 +96,7 @@ struct Get<Index, Type, EnableIfMemberGetFound<Type>> {
}; };
/** /**
* Concepts-ish * Check if the sequence is a tuple
*/
/**
* Check if the range is a tuple or a range
*/ */
template <typename Type, typename T = typename std::decay<Type>::type> template <typename Type, typename T = typename std::decay<Type>::type>
using EnableIfTuple = void_t< using EnableIfTuple = void_t<
...@@ -108,7 +104,7 @@ using EnableIfTuple = void_t< ...@@ -108,7 +104,7 @@ using EnableIfTuple = void_t<
decltype(std::tuple_size<T>::value)>; decltype(std::tuple_size<T>::value)>;
/** /**
* Check if the range is a range * Check if the sequence is a range
*/ */
template <typename Type, typename T = typename std::decay<Type>::type> template <typename Type, typename T = typename std::decay<Type>::type>
using EnableIfRange = void_t< using EnableIfRange = void_t<
...@@ -116,7 +112,7 @@ using EnableIfRange = void_t< ...@@ -116,7 +112,7 @@ using EnableIfRange = void_t<
decltype(adl::adl_end(std::declval<T>()))>; decltype(adl::adl_end(std::declval<T>()))>;
/** /**
* Forwards the return value of the first element of the range, used to * Forwards the return value of the first element of the sequence, used to
* determine the type of the first element in the range in SFINAE use cases * determine the type of the first element in the range in SFINAE use cases
*/ */
template <typename Sequence, typename = void> template <typename Sequence, typename = void>
...@@ -131,10 +127,10 @@ struct DeclvalSequence<Sequence, EnableIfTuple<Sequence>> { ...@@ -131,10 +127,10 @@ struct DeclvalSequence<Sequence, EnableIfTuple<Sequence>> {
/** /**
* Check if the functor accepts one or two arguments, one of the first element * Check if the functor accepts one or two arguments, one of the first element
* in the range, assuming that all the other elements can also be passed to the * in the sequence, assuming that all the other elements can also be passed to
* functor, and the second being an instantiation of std::integral_constant, * the functor, and the second being an instantiation of std::integral_constant,
* and the third being an instantiation of LoopControl, to provide * and the third being an instantiation of LoopControl, to provide breakability
* breakability to the loop * to the loop
*/ */
template <typename Sequence, typename Func> template <typename Sequence, typename Func>
using EnableIfAcceptsOneArgument = void_t<decltype(std::declval<Func>()( using EnableIfAcceptsOneArgument = void_t<decltype(std::declval<Func>()(
...@@ -175,7 +171,7 @@ using EnableIfHasIndexingOperator = ...@@ -175,7 +171,7 @@ using EnableIfHasIndexingOperator =
/** /**
* Implementation for the range iteration, this provides specializations in * Implementation for the range iteration, this provides specializations in
* the case where the function returns a break or continue. * the case where the function returns a break or continue
*/ */
template <typename Seq, typename F, typename = void> template <typename Seq, typename F, typename = void>
struct ForEachRange { struct ForEachRange {
...@@ -323,11 +319,10 @@ void for_each_tuple_impl(Sequence&& seq, Func& func) { ...@@ -323,11 +319,10 @@ void for_each_tuple_impl(Sequence&& seq, Func& func) {
/** /**
* Top level handlers for the for_each loop, the basic specialization handles * Top level handlers for the for_each loop, the basic specialization handles
* ranges and the specialized version handles compile time ranges (tuple like) * tuples and the specialized version handles ranges
* *
* This implies that if a range is a compile time range, its compile time * This implies that if type is both a range and a tuple, it is treated as a
* get<> API (whether through a member function or through a ADL looked up * range rather than as a tuple
* method) will be used in preference over iterators
*/ */
template <typename R, typename = void> template <typename R, typename = void>
struct ForEachImpl { struct ForEachImpl {
......
...@@ -36,20 +36,24 @@ namespace folly { ...@@ -36,20 +36,24 @@ namespace folly {
* folly::for_each(one, func); * folly::for_each(one, func);
* folly::for_each(two, func); * folly::for_each(two, func);
* *
* The for_each function allows iteration through sequences, these * The for_each function allows iteration through sequences, these can either be
* can either be runtime sequences (i.e. entities for which std::begin and * runtime sequences (i.e. entities for which std::begin and std::end work) or
* std::end work) or compile time sequences (as deemed by the presence of * compile time sequences (as deemed by the presence of std::tuple_length<> and
* std::tuple_length<>, get<> (ADL resolved) functions) * member get<> or ADL get<> functions).
* *
* The function is made to provide a convenient library based alternative to * If a sequence type is both a runtime sequence (aka range) and a compile-time
* the proposal p0589r0, which aims to generalize the range based for loop * sequence (aka tuple), then it is treated as a range in preference to a tuple.
* even further to work with compile time sequences. * 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 * 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, * access to the index within the range. This provides easy access to that, even
* even with compile time sequences. * with compile time sequences.
* *
* And breaking out is easy * And breaking out is easy:
* *
* auto range_one = std::vector<int>{1, 2, 3}; * auto range_one = std::vector<int>{1, 2, 3};
* auto range_two = std::make_tuple(1, 2, 3); * auto range_two = std::make_tuple(1, 2, 3);
...@@ -63,17 +67,16 @@ namespace folly { ...@@ -63,17 +67,16 @@ namespace folly {
* folly_for_each(range_one, func); * folly_for_each(range_one, func);
* folly_for_each(range_two, func); * folly_for_each(range_two, func);
* *
* A simple use case would be when using futures, if the user was doing calls * A simple use case would be when using futures, if the user was doing calls to
* to n servers then they would accept the callback with the futures like this * n servers then they would accept the callback with the futures like this:
* *
* auto vec = std::vector<std::future<int>>{request_one(), ...}; * auto vec = std::vector<std::future<int>>{request_one(), ...};
* when_all(vec.begin(), vec.end()).then([](auto futures) { * when_all(vec.begin(), vec.end()).then([](auto futures) {
* folly::for_each(futures, [](auto& fut) { ... }); * folly::for_each(futures, [](auto& fut) { ... });
* }); * });
* *
* Now when this code switches to use tuples instead of the runtime * Now when this code switches to use tuples instead of the runtime std::vector,
* std::vector, then the loop does not need to change, the code will still * then the loop does not need to change, the code will still work just fine:
* work just fine
* *
* when_all(future_one, future_two, future_three).then([](auto futures) { * when_all(future_one, future_two, future_three).then([](auto futures) {
* folly::for_each(futures, [](auto& fut) { ... }); * folly::for_each(futures, [](auto& fut) { ... });
...@@ -85,7 +88,7 @@ FOLLY_CPP14_CONSTEXPR Func for_each(Range&& range, Func func); ...@@ -85,7 +88,7 @@ FOLLY_CPP14_CONSTEXPR Func for_each(Range&& range, Func func);
/** /**
* The user should return loop_break and loop_continue if they want to iterate * 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 * in such a way that they can preemptively stop the loop and break out when
* certain conditions are met * certain conditions are met.
*/ */
namespace for_each_detail { namespace for_each_detail {
enum class LoopControl : bool { BREAK, CONTINUE }; enum class LoopControl : bool { BREAK, CONTINUE };
...@@ -96,11 +99,11 @@ constexpr auto loop_continue = for_each_detail::LoopControl::CONTINUE; ...@@ -96,11 +99,11 @@ constexpr auto loop_continue = for_each_detail::LoopControl::CONTINUE;
/** /**
* Utility method to help access elements of a sequence with one uniform * Utility method to help access elements of a sequence with one uniform
* interface * interface.
* *
* This can be useful for example when you are looping through a sequence and * 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 * want to modify another sequence based on the information in the current
* sequence * sequence:
* *
* auto range_one = std::make_tuple(1, 2, 3); * auto range_one = std::make_tuple(1, 2, 3);
* auto range_two = std::make_tuple(4, 5, 6); * auto range_two = std::make_tuple(4, 5, 6);
...@@ -108,12 +111,12 @@ constexpr auto loop_continue = for_each_detail::LoopControl::CONTINUE; ...@@ -108,12 +111,12 @@ constexpr auto loop_continue = for_each_detail::LoopControl::CONTINUE;
* folly::fetch(range_two, index) = ele; * folly::fetch(range_two, index) = ele;
* }); * });
* *
* For non-tuple like ranges, this works by first trying to use the iterator * For ranges, this works by first trying to use the iterator class if the
* class if the iterator has been marked to be a random access iterator. This * iterator has been marked to be a random access iterator. This should be
* should be inspectable via the std::iterator_traits traits class. If the * inspectable via the std::iterator_traits traits class. If the iterator class
* iterator class is not present or is not a random access iterator then the * is not present or is not a random access iterator then the implementation
* implementation falls back to trying to use the indexing operator * falls back to trying to use the indexing operator (operator[]) to fetch the
* (operator[]) to fetch the required element * required element.
*/ */
template <typename Sequence, typename Index> template <typename Sequence, typename Index>
FOLLY_CPP14_CONSTEXPR decltype(auto) fetch(Sequence&& sequence, Index&& index); FOLLY_CPP14_CONSTEXPR decltype(auto) fetch(Sequence&& sequence, Index&& index);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment