/* * 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 #include #include #include namespace folly { ////////////////////////////////////////////////////////////////////// /** * Helper to generate an index sequence from a tuple like type */ template using index_sequence_for_tuple = std::make_index_sequence::value>; namespace detail { namespace apply_tuple { namespace adl { using std::get; struct ApplyInvoke { template using seq = index_sequence_for_tuple>; template static constexpr auto invoke_(F&& f, T&& t, std::index_sequence) noexcept( is_nothrow_invocable(std::declval()))...>::value) -> invoke_result_t(std::declval()))...> { return invoke(static_cast(f), get(static_cast(t))...); } }; template < typename Tuple, std::size_t... Indices, typename ReturnTuple = std::tuple(std::declval()))...>> auto forward_tuple(Tuple&& tuple, std::index_sequence) -> ReturnTuple { return ReturnTuple{get(std::forward(tuple))...}; } } // namespace adl } // namespace apply_tuple } // namespace detail struct ApplyInvoke : private detail::apply_tuple::adl::ApplyInvoke { public: template constexpr auto operator()(F&& f, T&& t) const noexcept( noexcept(invoke_(static_cast(f), static_cast(t), seq{}))) -> decltype(invoke_(static_cast(f), static_cast(t), seq{})) { return invoke_(static_cast(f), static_cast(t), seq{}); } }; ////////////////////////////////////////////////////////////////////// // libc++ v3.9 has std::apply // android ndk r15c libc++ claims to be v3.9 but is missing std::apply #if __cpp_lib_apply >= 201603 || \ (((__ANDROID__ && _LIBCPP_VERSION > 3900) || \ (!__ANDROID__ && _LIBCPP_VERSION > 3800)) && \ _LIBCPP_STD_VER > 14) || \ (_MSC_VER && _HAS_CXX17) /* using override */ using std::apply; #else // __cpp_lib_apply >= 201603 // mimic: std::apply, C++17 template constexpr decltype(auto) apply(F&& func, Tuple&& tuple) { return ApplyInvoke{}(static_cast(func), static_cast(tuple)); } #endif // __cpp_lib_apply >= 201603 /** * Get a tuple of references from the passed tuple, forwarding will be applied * on the individual types of the tuple based on the value category of the * passed tuple * * For example * * forward_tuple(std::make_tuple(1, 2)) * * Returns a std::tuple, * * auto tuple = std::make_tuple(1, 2); * forward_tuple(tuple) * * Returns a std::tuple */ template auto forward_tuple(Tuple&& tuple) noexcept -> decltype(detail::apply_tuple::adl::forward_tuple( std::declval(), std::declval< index_sequence_for_tuple>>())) { return detail::apply_tuple::adl::forward_tuple( std::forward(tuple), index_sequence_for_tuple>{}); } /** * Mimic the invoke suite of traits for tuple based apply invocation */ template struct apply_result : invoke_result {}; template using apply_result_t = invoke_result_t; template struct is_applicable : is_invocable {}; template FOLLY_INLINE_VARIABLE constexpr bool is_applicable_v = is_applicable::value; template struct is_applicable_r : is_invocable_r {}; template FOLLY_INLINE_VARIABLE constexpr bool is_applicable_r_v = is_applicable_r::value; template struct is_nothrow_applicable : is_nothrow_invocable {}; template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_applicable_v = is_nothrow_applicable::value; template struct is_nothrow_applicable_r : is_nothrow_invocable_r {}; template FOLLY_INLINE_VARIABLE constexpr bool is_nothrow_applicable_r_v = is_nothrow_applicable_r::value; 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(apply(std::declval(), std::forward(tuple))) { return apply(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)); } #if __cpp_lib_make_from_tuple || (_MSC_VER >= 1910 && _MSVC_LANG > 201402) /* using override */ using std::make_from_tuple; #else namespace detail { namespace apply_tuple { template struct Construct { template constexpr T operator()(Args&&... args) const { return T(std::forward(args)...); } }; } // namespace apply_tuple } // namespace detail // mimic: std::make_from_tuple, C++17 template constexpr T make_from_tuple(Tuple&& t) { return apply(detail::apply_tuple::Construct(), std::forward(t)); } #endif ////////////////////////////////////////////////////////////////////// } // namespace folly