File indexing completed on 2025-12-16 10:09:46
0001
0002
0003
0004
0005
0006 #ifndef BOOST_STL_INTERFACES_VIEW_ADAPTOR_HPP
0007 #define BOOST_STL_INTERFACES_VIEW_ADAPTOR_HPP
0008
0009 #include <boost/stl_interfaces/config.hpp>
0010 #include <boost/stl_interfaces/detail/view_closure.hpp>
0011
0012 #include <boost/type_traits/is_detected.hpp>
0013
0014 #include <tuple>
0015 #include <type_traits>
0016
0017
0018 #if !defined(BOOST_STL_INTERFACES_DOXYGEN)
0019
0020 #if defined(__cpp_lib_ranges) && 202202L <= __cpp_lib_ranges
0021 #define BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 1
0022 #else
0023 #define BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE 0
0024 #endif
0025
0026 #if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
0027 BOOST_STL_INTERFACES_USE_CONCEPTS && defined(BOOST_GCC) && 12 <= __GNUC__
0028 #define BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 1
0029 #else
0030 #define BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE 0
0031 #endif
0032
0033 #if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
0034 defined(_MSC_VER) && _MSC_VER <= 1929
0035 #define BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE 1
0036 #else
0037 #define BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE 0
0038 #endif
0039
0040 #if !BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE && \
0041 !BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE && \
0042 !BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE
0043 #define BOOST_STL_INTERFACES_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE 1
0044 #else
0045 #define BOOST_STL_INTERFACES_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE 0
0046 #endif
0047
0048 #endif
0049
0050
0051 namespace boost { namespace stl_interfaces {
0052 namespace detail {
0053 template<typename F, typename... Args>
0054 using invocable_expr =
0055 decltype(std::declval<F>()(std::declval<Args>()...));
0056 template<typename F, typename... Args>
0057 constexpr bool is_invocable_v =
0058 is_detected_v<invocable_expr, F, Args...>;
0059
0060 template<typename Func, typename... CapturedArgs>
0061 struct bind_back_t
0062 {
0063 static_assert(std::is_move_constructible<Func>::value, "");
0064 #if defined(__cpp_fold_expressions)
0065 static_assert(
0066 (std::is_move_constructible<CapturedArgs>::value && ...), "");
0067 #endif
0068
0069 template<typename F, typename... Args>
0070 explicit constexpr bind_back_t(int, F && f, Args &&... args) :
0071 f_((F &&) f), bound_args_((Args &&) args...)
0072 {
0073 static_assert(sizeof...(Args) == sizeof...(CapturedArgs), "");
0074 }
0075
0076 template<typename... Args>
0077 constexpr decltype(auto) operator()(Args &&... args) &
0078 {
0079 return call_impl(*this, indices(), (Args &&) args...);
0080 }
0081
0082 template<typename... Args>
0083 constexpr decltype(auto) operator()(Args &&... args) const &
0084 {
0085 return call_impl(*this, indices(), (Args &&) args...);
0086 }
0087
0088 template<typename... Args>
0089 constexpr decltype(auto) operator()(Args &&... args) &&
0090 {
0091 return call_impl(
0092 std::move(*this), indices(), (Args &&) args...);
0093 }
0094
0095 template<typename... Args>
0096 constexpr decltype(auto) operator()(Args &&... args) const &&
0097 {
0098 return call_impl(
0099 std::move(*this), indices(), (Args &&) args...);
0100 }
0101
0102 private:
0103 using indices = std::index_sequence_for<CapturedArgs...>;
0104
0105 template<typename T, size_t... I, typename... Args>
0106 static constexpr decltype(auto)
0107 call_impl(T && this_, std::index_sequence<I...>, Args &&... args)
0108 {
0109 return ((T &&) this_)
0110 .f_((Args &&) args...,
0111 std::get<I>(((T &&) this_).bound_args_)...);
0112 }
0113
0114 [[no_unique_address]] Func f_;
0115 std::tuple<CapturedArgs...> bound_args_;
0116 };
0117
0118 template<typename Func, typename... Args>
0119 using bind_back_result =
0120 bind_back_t<std::decay_t<Func>, std::decay_t<Args>...>;
0121 }
0122
0123
0124 template<typename Func, typename... Args>
0125 constexpr auto bind_back(Func && f, Args &&... args)
0126 {
0127 return detail::bind_back_result<Func, Args...>(
0128 0, (Func &&) f, (Args &&) args...);
0129 }
0130
0131 #if BOOST_STL_INTERFACES_DEFINE_CUSTOM_RANGE_ADAPTOR_CLOSURE || \
0132 defined(BOOST_STL_INTERFACES_DOXYGEN)
0133
0134
0135
0136
0137
0138 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0139 template<typename D>
0140 requires std::is_class_v<D> && std::same_as<D, std::remove_cv_t<D>>
0141 #else
0142 template<
0143 typename D,
0144 typename Enable = std::enable_if_t<
0145 std::is_class<D>::value &&
0146 std::is_same<D, std::remove_cv_t<D>>::value>>
0147 #endif
0148 struct range_adaptor_closure;
0149
0150 namespace detail {
0151 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0152 template<typename T>
0153 concept range_adaptor_closure_ = std::derived_from<
0154 std::remove_cvref_t<T>,
0155 range_adaptor_closure<std::remove_cvref_t<T>>>;
0156 #else
0157 template<typename T>
0158 using range_adaptor_closure_tag_expr = typename range_adaptor_closure<
0159 T>::inheritance_tag_with_an_unlikely_name_;
0160 template<typename T>
0161 constexpr bool range_adaptor_closure_ =
0162 is_detected_v<range_adaptor_closure_tag_expr, remove_cvref_t<T>>;
0163 #endif
0164 }
0165
0166 #endif
0167
0168 #if BOOST_STL_INTERFACES_USE_CPP23_STD_RANGE_ADAPTOR_CLOSURE
0169
0170 template<typename D>
0171 using range_adaptor_closure = std::ranges::range_adaptor_closure<D>;
0172
0173 #elif BOOST_STL_INTERFACES_USE_LIBSTDCPP_GCC12_RANGE_ADAPTOR_CLOSURE
0174
0175 template<typename D>
0176 using range_adaptor_closure = std::views::__adaptor::_RangeAdaptorClosure;
0177
0178 #elif BOOST_STL_INTERFACES_NEED_VS_COMPATIBLE_RANGE_ADAPTOR_CLOSURE
0179
0180 template<typename D>
0181 using range_adaptor_closure = detail::pipeable<D>;
0182
0183 #else
0184
0185 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0186 template<typename D>
0187 requires std::is_class_v<D> && std::same_as<D, std::remove_cv_t<D>>
0188 #else
0189 template<typename D, typename>
0190 #endif
0191 struct range_adaptor_closure
0192 {
0193 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0194 template<typename T>
0195 requires std::invocable<D, T>
0196 #else
0197 template<
0198 typename T,
0199 typename Enable = std::enable_if_t<detail::is_invocable_v<D, T>>>
0200 #endif
0201 [[nodiscard]] friend constexpr decltype(auto) operator|(T && t, D && d)
0202 {
0203 return std::move(d)((T &&) t);
0204 }
0205
0206 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0207 template<typename T>
0208 requires std::invocable<D const &, T>
0209 #else
0210 template<
0211 typename T,
0212 typename Enable =
0213 std::enable_if_t<detail::is_invocable_v<D const &, T>>>
0214 #endif
0215 [[nodiscard]] friend constexpr decltype(auto)
0216 operator|(T && t, D const & d)
0217 {
0218 return d((T &&) t);
0219 }
0220
0221 using inheritance_tag_with_an_unlikely_name_ = int;
0222 };
0223
0224 #endif
0225
0226
0227
0228
0229
0230
0231 template<typename F>
0232 struct closure : range_adaptor_closure<closure<F>>
0233 {
0234 constexpr closure(F f) : f_(f) {}
0235
0236 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0237 template<typename T>
0238 requires std::invocable<F const &, T>
0239 #else
0240 template<
0241 typename T,
0242 typename Enable =
0243 std::enable_if_t<detail::is_invocable_v<F const &, T>>>
0244 #endif
0245 constexpr decltype(auto) operator()(T && t) const &
0246 {
0247 return f_((T &&) t);
0248 }
0249
0250 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0251 template<typename T>
0252 requires std::invocable<F &&, T>
0253 #else
0254 template<
0255 typename T,
0256 typename Enable = std::enable_if_t<detail::is_invocable_v<F &&, T>>>
0257 #endif
0258 constexpr decltype(auto) operator()(T && t) &&
0259 {
0260 return std::move(f_)((T &&) t);
0261 }
0262
0263 private:
0264 [[no_unique_address]] F f_;
0265 };
0266
0267
0268 namespace detail {
0269 #if !BOOST_STL_INTERFACES_USE_CONCEPTS
0270 template<typename F, bool Invocable, typename... Args>
0271 struct adaptor_impl
0272 {
0273 static constexpr decltype(auto) call(F const & f, Args &&... args)
0274 {
0275 return f((Args &&) args...);
0276 }
0277 };
0278
0279 template<typename F, typename... Args>
0280 struct adaptor_impl<F, false, Args...>
0281 {
0282 static constexpr auto call(F const & f, Args &&... args)
0283 {
0284 using closure_func =
0285 std::decay_t<decltype(stl_interfaces::bind_back(
0286 f, (Args &&) args...))>;
0287 return closure<closure_func>(
0288 stl_interfaces::bind_back(f, (Args &&) args...));
0289 }
0290 };
0291 #endif
0292 }
0293
0294
0295
0296
0297
0298
0299 template<typename F>
0300 struct adaptor
0301 {
0302 constexpr adaptor(F f) : f_(f) {}
0303
0304
0305 template<typename... Args>
0306 constexpr auto operator()(Args &&... args) const
0307
0308 {
0309 #if BOOST_STL_INTERFACES_USE_CONCEPTS
0310 if constexpr (std::is_invocable_v<F const &, Args...>) {
0311 return f_((Args &&) args...);
0312 } else {
0313 return closure(
0314 stl_interfaces::bind_back(f_, (Args &&) args...));
0315 }
0316 #else
0317 return detail::adaptor_impl<
0318 F const &,
0319 detail::is_invocable_v<F const &, Args...>,
0320 Args...>::call(f_, (Args &&) args...);
0321 #endif
0322 }
0323
0324 private:
0325 [[no_unique_address]] F f_;
0326 };
0327
0328
0329 }}
0330
0331 #endif