view_adaptor.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // Copyright (C) 2022 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_STL_INTERFACES_VIEW_ADAPTOR_HPP
  7. #define BOOST_STL_INTERFACES_VIEW_ADAPTOR_HPP
  8. #include <boost/stl_interfaces/config.hpp>
  9. #include <boost/stl_interfaces/detail/view_closure.hpp>
  10. #include <boost/type_traits/is_detected.hpp>
  11. #include <tuple>
  12. #include <type_traits>
  13. #if !defined(BOOST_STL_INTERFACES_DOXYGEN)
  14. #if defined(__cpp_lib_ranges) && 202202L <= __cpp_lib_ranges
  15. #define BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 1
  16. #else
  17. #define BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 0
  18. #endif
  19. #if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
  20. BOOST_STL_INTERFACES_USE_CONCEPTS && defined(BOOST_GCC) && 14 <= __GNUC__
  21. #define BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE 1
  22. #elif !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
  23. BOOST_STL_INTERFACES_USE_CONCEPTS && defined(BOOST_GCC) && 12 <= __GNUC__
  24. #define BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 1
  25. #else
  26. #define BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 0
  27. #define BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE 0
  28. #endif
  29. #if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
  30. defined(_MSC_VER) && _MSC_VER <= 1929
  31. #define BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE 1
  32. #else
  33. #define BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE 0
  34. #endif
  35. #if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
  36. !BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE && \
  37. !BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE && \
  38. !BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE
  39. #define BOOST_STL_INTERFACES_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE 1
  40. #else
  41. #define BOOST_STL_INTERFACES_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE 0
  42. #endif
  43. #endif
  44. namespace boost { namespace stl_interfaces {
  45. namespace detail {
  46. template<typename F, typename... Args>
  47. using invocable_expr =
  48. decltype(std::declval<F>()(std::declval<Args>()...));
  49. template<typename F, typename... Args>
  50. constexpr bool is_invocable_v =
  51. is_detected_v<invocable_expr, F, Args...>;
  52. template<typename Func, typename... CapturedArgs>
  53. struct bind_back_t
  54. {
  55. static_assert(std::is_move_constructible<Func>::value, "");
  56. #if defined(__cpp_fold_expressions)
  57. static_assert(
  58. (std::is_move_constructible<CapturedArgs>::value && ...), "");
  59. #endif
  60. template<typename F, typename... Args>
  61. explicit constexpr bind_back_t(int, F && f, Args &&... args) :
  62. f_((F &&) f), bound_args_((Args &&) args...)
  63. {
  64. static_assert(sizeof...(Args) == sizeof...(CapturedArgs), "");
  65. }
  66. template<typename... Args>
  67. constexpr decltype(auto) operator()(Args &&... args) &
  68. {
  69. return call_impl(*this, indices(), (Args &&) args...);
  70. }
  71. template<typename... Args>
  72. constexpr decltype(auto) operator()(Args &&... args) const &
  73. {
  74. return call_impl(*this, indices(), (Args &&) args...);
  75. }
  76. template<typename... Args>
  77. constexpr decltype(auto) operator()(Args &&... args) &&
  78. {
  79. return call_impl(
  80. std::move(*this), indices(), (Args &&) args...);
  81. }
  82. template<typename... Args>
  83. constexpr decltype(auto) operator()(Args &&... args) const &&
  84. {
  85. return call_impl(
  86. std::move(*this), indices(), (Args &&) args...);
  87. }
  88. private:
  89. using indices = std::index_sequence_for<CapturedArgs...>;
  90. template<typename T, size_t... I, typename... Args>
  91. static constexpr decltype(auto)
  92. call_impl(T && this_, std::index_sequence<I...>, Args &&... args)
  93. {
  94. return ((T &&) this_)
  95. .f_((Args &&) args...,
  96. std::get<I>(((T &&) this_).bound_args_)...);
  97. }
  98. [[no_unique_address]] Func f_;
  99. std::tuple<CapturedArgs...> bound_args_;
  100. };
  101. template<typename Func, typename... Args>
  102. using bind_back_result =
  103. bind_back_t<std::decay_t<Func>, std::decay_t<Args>...>;
  104. }
  105. /** An implementation of `std::bind_back()` from C++23. */
  106. template<typename Func, typename... Args>
  107. constexpr auto bind_back(Func && f, Args &&... args)
  108. {
  109. return detail::bind_back_result<Func, Args...>(
  110. 0, (Func &&) f, (Args &&) args...);
  111. }
  112. #if BOOST_STL_INTERFACES_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE || \
  113. defined(BOOST_STL_INTERFACES_DOXYGEN)
  114. /** A backwards-compatible implementation of C++23's
  115. `std::ranges::range_adaptor_closure`. `range_adaptor_closure` may be
  116. a struct template or may be an alias, as required to maintain
  117. compatibility with the standard library's view adaptors. */
  118. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  119. template<typename D>
  120. requires std::is_class_v<D> && std::same_as<D, std::remove_cv_t<D>>
  121. #else
  122. template<
  123. typename D,
  124. typename Enable = std::enable_if_t<
  125. std::is_class<D>::value &&
  126. std::is_same<D, std::remove_cv_t<D>>::value>>
  127. #endif
  128. struct range_adaptor_closure;
  129. namespace detail {
  130. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  131. template<typename T>
  132. concept range_adaptor_closure_ = std::derived_from<
  133. std::remove_cvref_t<T>,
  134. range_adaptor_closure<std::remove_cvref_t<T>>>;
  135. #else
  136. template<typename T>
  137. using range_adaptor_closure_tag_expr = typename range_adaptor_closure<
  138. T>::inheritance_tag_with_an_unlikely_name_;
  139. template<typename T>
  140. constexpr bool range_adaptor_closure_ =
  141. is_detected_v<range_adaptor_closure_tag_expr, remove_cvref_t<T>>;
  142. #endif
  143. }
  144. #endif
  145. #if BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE
  146. template<typename D>
  147. using range_adaptor_closure = std::ranges::range_adaptor_closure<D>;
  148. #elif BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC14_RANGE_ADAPTOR_CLOSURE
  149. template<typename D>
  150. using range_adaptor_closure = std::views::__adaptor::_RangeAdaptorClosure<D>;
  151. #elif BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE
  152. template<typename D>
  153. using range_adaptor_closure = std::views::__adaptor::_RangeAdaptorClosure;
  154. #elif BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE
  155. template<typename D>
  156. using range_adaptor_closure = detail::pipeable<D>;
  157. #else
  158. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  159. template<typename D>
  160. requires std::is_class_v<D> && std::same_as<D, std::remove_cv_t<D>>
  161. #else
  162. template<typename D, typename>
  163. #endif
  164. struct range_adaptor_closure
  165. {
  166. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  167. template<typename T>
  168. requires std::invocable<D, T>
  169. #else
  170. template<
  171. typename T,
  172. typename Enable = std::enable_if_t<detail::is_invocable_v<D, T>>>
  173. #endif
  174. [[nodiscard]] friend constexpr decltype(auto) operator|(T && t, D && d)
  175. {
  176. return std::move(d)((T &&) t);
  177. }
  178. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  179. template<typename T>
  180. requires std::invocable<D const &, T>
  181. #else
  182. template<
  183. typename T,
  184. typename Enable =
  185. std::enable_if_t<detail::is_invocable_v<D const &, T>>>
  186. #endif
  187. [[nodiscard]] friend constexpr decltype(auto)
  188. operator|(T && t, D const & d)
  189. {
  190. return d((T &&) t);
  191. }
  192. using inheritance_tag_with_an_unlikely_name_ = int;
  193. };
  194. #endif
  195. //[closure_defn
  196. /** An invocable consisting of a contained invocable `f`. Calling
  197. `operator()` with some argument `t` calls `f(t)` and returns the
  198. result. This type is typically used to capture a the result of a call
  199. to `bind_back()`. */
  200. template<typename F>
  201. struct closure : range_adaptor_closure<closure<F>>
  202. {
  203. constexpr closure(F f) : f_(std::move(f)) {}
  204. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  205. template<typename T>
  206. requires std::invocable<F const &, T>
  207. #else
  208. template<
  209. typename T,
  210. typename Enable =
  211. std::enable_if_t<detail::is_invocable_v<F const &, T>>>
  212. #endif
  213. constexpr decltype(auto) operator()(T && t) const &
  214. {
  215. return f_((T &&) t);
  216. }
  217. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  218. template<typename T>
  219. requires std::invocable<F &&, T>
  220. #else
  221. template<
  222. typename T,
  223. typename Enable = std::enable_if_t<detail::is_invocable_v<F &&, T>>>
  224. #endif
  225. constexpr decltype(auto) operator()(T && t) &&
  226. {
  227. return std::move(f_)((T &&) t);
  228. }
  229. private:
  230. [[no_unique_address]] F f_;
  231. };
  232. //]
  233. namespace detail {
  234. #if !BOOST_STL_INTERFACES_USE_CONCEPTS
  235. template<typename F, bool Invocable, typename... Args>
  236. struct adaptor_impl
  237. {
  238. static constexpr decltype(auto) call(F const & f, Args &&... args)
  239. {
  240. return f((Args &&) args...);
  241. }
  242. };
  243. template<typename F, typename... Args>
  244. struct adaptor_impl<F, false, Args...>
  245. {
  246. static constexpr auto call(F const & f, Args &&... args)
  247. {
  248. using closure_func =
  249. std::decay_t<decltype(stl_interfaces::bind_back(
  250. f, (Args &&) args...))>;
  251. return closure<closure_func>(
  252. stl_interfaces::bind_back(f, (Args &&) args...));
  253. }
  254. };
  255. #endif
  256. }
  257. //[adaptor_defn
  258. /** Adapts an invocable `f` as a view adaptor. Calling
  259. `operator(args...)` will either: call `f(args...)` and return the
  260. result, if `f(args...)` is well-formed; or return
  261. `closure(stl_interfaces::bind_back(f, args...))` otherwise. */
  262. template<typename F>
  263. struct adaptor
  264. {
  265. constexpr adaptor(F f) : f_(std::move(f)) {}
  266. // clang-format off
  267. template<typename... Args>
  268. constexpr auto operator()(Args &&... args) const
  269. // clang-format on
  270. {
  271. #if BOOST_STL_INTERFACES_USE_CONCEPTS
  272. if constexpr (std::is_invocable_v<F const &, Args...>) {
  273. return f_((Args &&) args...);
  274. } else {
  275. return closure(
  276. stl_interfaces::bind_back(f_, (Args &&) args...));
  277. }
  278. #else
  279. return detail::adaptor_impl<
  280. F const &,
  281. detail::is_invocable_v<F const &, Args...>,
  282. Args...>::call(f_, (Args &&) args...);
  283. #endif
  284. }
  285. private:
  286. [[no_unique_address]] F f_;
  287. };
  288. //]
  289. }}
  290. #endif