ApplyTuple.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * Copyright 2012-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. #pragma once
  17. #include <functional>
  18. #include <tuple>
  19. #include <utility>
  20. #include <folly/Traits.h>
  21. #include <folly/Utility.h>
  22. #include <folly/functional/Invoke.h>
  23. namespace folly {
  24. //////////////////////////////////////////////////////////////////////
  25. /**
  26. * Helper to generate an index sequence from a tuple like type
  27. */
  28. template <typename Tuple>
  29. using index_sequence_for_tuple =
  30. make_index_sequence<std::tuple_size<Tuple>::value>;
  31. namespace detail {
  32. namespace apply_tuple {
  33. namespace adl {
  34. using std::get;
  35. struct ApplyInvoke {
  36. template <typename T>
  37. using seq = index_sequence_for_tuple<std::remove_reference_t<T>>;
  38. template <typename F, typename T, std::size_t... I>
  39. static constexpr auto invoke_(F&& f, T&& t, index_sequence<I...>) noexcept(
  40. is_nothrow_invocable<F&&, decltype(get<I>(std::declval<T>()))...>::value)
  41. -> invoke_result_t<F&&, decltype(get<I>(std::declval<T>()))...> {
  42. return invoke(static_cast<F&&>(f), get<I>(static_cast<T&&>(t))...);
  43. }
  44. };
  45. template <
  46. typename Tuple,
  47. std::size_t... Indices,
  48. typename ReturnTuple =
  49. std::tuple<decltype(get<Indices>(std::declval<Tuple>()))...>>
  50. auto forward_tuple(Tuple&& tuple, index_sequence<Indices...>) -> ReturnTuple {
  51. return ReturnTuple{get<Indices>(std::forward<Tuple>(tuple))...};
  52. }
  53. } // namespace adl
  54. } // namespace apply_tuple
  55. } // namespace detail
  56. struct ApplyInvoke : private detail::apply_tuple::adl::ApplyInvoke {
  57. public:
  58. template <typename F, typename T>
  59. constexpr auto operator()(F&& f, T&& t) const noexcept(
  60. noexcept(invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{})))
  61. -> decltype(invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{})) {
  62. return invoke_(static_cast<F&&>(f), static_cast<T&&>(t), seq<T>{});
  63. }
  64. };
  65. //////////////////////////////////////////////////////////////////////
  66. #if __cpp_lib_apply >= 201603
  67. /* using override */ using std::apply;
  68. #else // __cpp_lib_apply >= 201603
  69. // mimic: std::apply, C++17
  70. template <typename F, typename Tuple>
  71. constexpr decltype(auto) apply(F&& func, Tuple&& tuple) {
  72. return ApplyInvoke{}(static_cast<F&&>(func), static_cast<Tuple&&>(tuple));
  73. }
  74. #endif // __cpp_lib_apply >= 201603
  75. /**
  76. * Get a tuple of references from the passed tuple, forwarding will be applied
  77. * on the individual types of the tuple based on the value category of the
  78. * passed tuple
  79. *
  80. * For example
  81. *
  82. * forward_tuple(std::make_tuple(1, 2))
  83. *
  84. * Returns a std::tuple<int&&, int&&>,
  85. *
  86. * auto tuple = std::make_tuple(1, 2);
  87. * forward_tuple(tuple)
  88. *
  89. * Returns a std::tuple<int&, int&>
  90. */
  91. template <typename Tuple>
  92. auto forward_tuple(Tuple&& tuple) noexcept
  93. -> decltype(detail::apply_tuple::adl::forward_tuple(
  94. std::declval<Tuple>(),
  95. std::declval<
  96. index_sequence_for_tuple<std::remove_reference_t<Tuple>>>())) {
  97. return detail::apply_tuple::adl::forward_tuple(
  98. std::forward<Tuple>(tuple),
  99. index_sequence_for_tuple<std::remove_reference_t<Tuple>>{});
  100. }
  101. /**
  102. * Mimic the invoke suite of traits for tuple based apply invocation
  103. */
  104. template <typename F, typename Tuple>
  105. struct apply_result : invoke_result<ApplyInvoke, F, Tuple> {};
  106. template <typename F, typename Tuple>
  107. using apply_result_t = invoke_result_t<ApplyInvoke, F, Tuple>;
  108. template <typename F, typename Tuple>
  109. struct is_applicable : is_invocable<ApplyInvoke, F, Tuple> {};
  110. template <typename R, typename F, typename Tuple>
  111. struct is_applicable_r : is_invocable_r<R, ApplyInvoke, F, Tuple> {};
  112. template <typename F, typename Tuple>
  113. struct is_nothrow_applicable : is_nothrow_invocable<ApplyInvoke, F, Tuple> {};
  114. template <typename R, typename F, typename Tuple>
  115. struct is_nothrow_applicable_r
  116. : is_nothrow_invocable_r<R, ApplyInvoke, F, Tuple> {};
  117. namespace detail {
  118. namespace apply_tuple {
  119. template <class F>
  120. class Uncurry {
  121. public:
  122. explicit Uncurry(F&& func) : func_(std::move(func)) {}
  123. explicit Uncurry(const F& func) : func_(func) {}
  124. template <class Tuple>
  125. auto operator()(Tuple&& tuple) const
  126. -> decltype(apply(std::declval<F>(), std::forward<Tuple>(tuple))) {
  127. return apply(func_, std::forward<Tuple>(tuple));
  128. }
  129. private:
  130. F func_;
  131. };
  132. } // namespace apply_tuple
  133. } // namespace detail
  134. /**
  135. * Wraps a function taking N arguments into a function which accepts a tuple of
  136. * N arguments. Note: This function will also accept an std::pair if N == 2.
  137. *
  138. * For example, given the below code:
  139. *
  140. * std::vector<std::tuple<int, int, int>> rows = ...;
  141. * auto test = [](std::tuple<int, int, int>& row) {
  142. * return std::get<0>(row) * std::get<1>(row) * std::get<2>(row) == 24;
  143. * };
  144. * auto found = std::find_if(rows.begin(), rows.end(), test);
  145. *
  146. *
  147. * 'test' could be rewritten as:
  148. *
  149. * auto test =
  150. * folly::uncurry([](int a, int b, int c) { return a * b * c == 24; });
  151. *
  152. */
  153. template <class F>
  154. auto uncurry(F&& f)
  155. -> detail::apply_tuple::Uncurry<typename std::decay<F>::type> {
  156. return detail::apply_tuple::Uncurry<typename std::decay<F>::type>(
  157. std::forward<F>(f));
  158. }
  159. #if __cpp_lib_make_from_tuple || (_MSC_VER >= 1910 && _MSVC_LANG > 201402)
  160. /* using override */ using std::make_from_tuple;
  161. #else
  162. namespace detail {
  163. namespace apply_tuple {
  164. template <class T>
  165. struct Construct {
  166. template <class... Args>
  167. constexpr T operator()(Args&&... args) const {
  168. return T(std::forward<Args>(args)...);
  169. }
  170. };
  171. } // namespace apply_tuple
  172. } // namespace detail
  173. // mimic: std::make_from_tuple, C++17
  174. template <class T, class Tuple>
  175. constexpr T make_from_tuple(Tuple&& t) {
  176. return apply(detail::apply_tuple::Construct<T>(), std::forward<Tuple>(t));
  177. }
  178. #endif
  179. //////////////////////////////////////////////////////////////////////
  180. } // namespace folly