Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:09:46

0001 // Copyright (C) 2022 T. Zachary Laine
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
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     /** An implementation of `std::bind_back()` from C++23. */
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     /** A backwards-compatible implementation of C++23's
0135         `std::ranges::range_adaptor_closure`.  `range_adaptor_closure` may be
0136         a struct template or may be an alias, as required to maintain
0137         compatibility with the standard library's view adaptors. */
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     //[closure_defn
0227     /** An invocable consisting of a contained invocable `f`.  Calling
0228         `operator()` with some argument `t` calls `f(t)` and returns the
0229         result.  This type is typically used to capture a the result of a call
0230         to `bind_back()`. */
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     //[adaptor_defn
0295     /** Adapts an invocable `f` as a view adaptor.  Calling
0296         `operator(args...)` will either: call `f(args...)` and return the
0297         result, if `f(args...)` is well-formed; or return
0298         `closure(stl_interfaces::bind_back(f, args...))` otherwise. */
0299     template<typename F>
0300     struct adaptor
0301     {
0302         constexpr adaptor(F f) : f_(f) {}
0303 
0304         // clang-format off
0305         template<typename... Args>
0306         constexpr auto operator()(Args &&... args) const
0307         // clang-format on
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