X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FApplyTuple.h;h=cce6fec07d6e3e23bf0e6a574f8ac352535953db;hb=d8ed7cbc7118c84655fb51da6d1c0f32701dc763;hp=3fe30c3d1b996c04c9de8f0d210e89e3828b25f7;hpb=22afce906d7e98d95f8c45c3301072d9fd891d41;p=folly.git diff --git a/folly/ApplyTuple.h b/folly/ApplyTuple.h index 3fe30c3d..cce6fec0 100644 --- a/folly/ApplyTuple.h +++ b/folly/ApplyTuple.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,87 +25,140 @@ * ASSERT(x == 24); */ -#ifndef FOLLY_APPLYTUPLE_H_ -#define FOLLY_APPLYTUPLE_H_ +#pragma once -#include #include -#include +#include +#include + +#include namespace folly { ////////////////////////////////////////////////////////////////////// namespace detail { +namespace apply_tuple { + +inline constexpr std::size_t sum() { + return 0; +} +template +inline constexpr std::size_t sum(std::size_t v1, Args... vs) { + return v1 + sum(vs...); +} + +template +struct TupleSizeSum { + static constexpr auto value = sum(std::tuple_size::value...); +}; + +template +using MakeIndexSequenceFromTuple = folly::make_index_sequence< + TupleSizeSum::type...>::value>; // This is to allow using this with pointers to member functions, // where the first argument in the tuple will be the this pointer. -template F& makeCallable(F& f) { return f; } -template -auto makeCallable(R (C::*d)(A...)) -> decltype(std::mem_fn(d)) { +template +inline constexpr F&& makeCallable(F&& f) { + return std::forward(f); +} +template +inline constexpr auto makeCallable(M(C::*d)) -> decltype(std::mem_fn(d)) { return std::mem_fn(d); } -template -struct DerefSize - : std::tuple_size::type> -{}; - -// CallTuple recursively unpacks tuple arguments so we can forward -// them into the function. -template -struct CallTuple { - template - static typename std::enable_if< - (sizeof...(Unpacked) < DerefSize::value), - Ret - >::type call(const F& f, Tuple&& t, Unpacked&&... unp) { - typedef typename std::tuple_element< - sizeof...(Unpacked), - typename std::remove_reference::type - >::type ElementType; - return CallTuple::call(f, std::forward(t), - std::forward(unp)..., - std::forward(std::get(t)) - ); - } - - template - static typename std::enable_if< - (sizeof...(Unpacked) == DerefSize::value), - Ret - >::type call(const F& f, Tuple&& t, Unpacked&&... unp) { - return makeCallable(f)(std::forward(unp)...); - } -}; - -// The point of this meta function is to extract the contents of the -// tuple as a parameter pack so we can pass it into std::result_of<>. -template struct ReturnValue {}; -template -struct ReturnValue> { - typedef typename std::result_of::type type; -}; +template +inline constexpr auto call(F&& f, Tuple&& t, folly::index_sequence) + -> decltype( + std::forward(f)(std::get(std::forward(t))...)) { + return std::forward(f)(std::get(std::forward(t))...); +} +template +inline constexpr auto forwardTuple(Tuple&& t, folly::index_sequence) + -> decltype( + std::forward_as_tuple(std::get(std::forward(t))...)) { + return std::forward_as_tuple(std::get(std::forward(t))...); } +} // namespace apply_tuple +} // namespace detail + ////////////////////////////////////////////////////////////////////// -template -typename detail::ReturnValue< - typename std::decay::type, - typename std::remove_reference::type ->::type -applyTuple(const Callable& c, Tuple&& t) { - typedef typename detail::ReturnValue< - typename std::decay::type, - typename std::remove_reference::type - >::type RetT; - return detail::CallTuple::call(c, std::forward(t)); +/** + * Invoke a callable object with a set of arguments passed as a tuple, or a + * series of tuples + * + * Example: the following lines are equivalent + * func(1, 2, 3, "foo"); + * applyTuple(func, std::make_tuple(1, 2, 3, "foo")); + * applyTuple(func, std::make_tuple(1, 2), std::make_tuple(3, "foo")); + */ + +template +inline constexpr auto applyTuple(F&& f, Tuples&&... t) + -> decltype(detail::apply_tuple::call( + detail::apply_tuple::makeCallable(std::forward(f)), + std::tuple_cat(detail::apply_tuple::forwardTuple( + std::forward(t), + detail::apply_tuple::MakeIndexSequenceFromTuple{})...), + detail::apply_tuple::MakeIndexSequenceFromTuple{})) { + return detail::apply_tuple::call( + detail::apply_tuple::makeCallable(std::forward(f)), + std::tuple_cat(detail::apply_tuple::forwardTuple( + std::forward(t), + detail::apply_tuple::MakeIndexSequenceFromTuple{})...), + detail::apply_tuple::MakeIndexSequenceFromTuple{}); } -////////////////////////////////////////////////////////////////////// +namespace detail { +namespace apply_tuple { + +template +class Uncurry { + public: + explicit Uncurry(F&& func) : func_(std::move(func)) {} + explicit Uncurry(const F& func) : func_(func) {} + + template + auto operator()(Tuple&& tuple) const + -> decltype(applyTuple(std::declval(), std::forward(tuple))) { + return applyTuple(func_, std::forward(tuple)); + } + + private: + F func_; +}; +} // namespace apply_tuple +} // namespace detail +/** + * Wraps a function taking N arguments into a function which accepts a tuple of + * N arguments. Note: This function will also accept an std::pair if N == 2. + * + * For example, given the below code: + * + * std::vector> rows = ...; + * auto test = [](std::tuple& row) { + * return std::get<0>(row) * std::get<1>(row) * std::get<2>(row) == 24; + * }; + * auto found = std::find_if(rows.begin(), rows.end(), test); + * + * + * 'test' could be rewritten as: + * + * auto test = + * folly::uncurry([](int a, int b, int c) { return a * b * c == 24; }); + * + */ +template +auto uncurry(F&& f) + -> detail::apply_tuple::Uncurry::type> { + return detail::apply_tuple::Uncurry::type>( + std::forward(f)); } -#endif +////////////////////////////////////////////////////////////////////// +}