149 lines
4.3 KiB
C++
149 lines
4.3 KiB
C++
// Copyright (C) 2022 T. Zachary Laine
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
#ifndef BOOST_STL_INTERFACES_DETAIL_PIPEABLE_VIEW_HPP
|
|
#define BOOST_STL_INTERFACES_DETAIL_PIPEABLE_VIEW_HPP
|
|
|
|
#include <boost/stl_interfaces/config.hpp>
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
namespace boost { namespace stl_interfaces { namespace detail {
|
|
|
|
template<typename T>
|
|
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
|
|
|
struct pipeable_base;
|
|
|
|
#if BOOST_STL_INTERFACES_USE_CONCEPTS
|
|
template<typename T>
|
|
concept pipeable_ = std::derived_from<T, pipeable_base> &&
|
|
std::is_object_v<T> && std::copy_constructible<T>;
|
|
#else
|
|
template<typename T>
|
|
constexpr bool pipeable_ = std::is_base_of<pipeable_base, T>::value &&
|
|
std::is_object<T>::value && std::is_copy_constructible<T>::value;
|
|
#endif
|
|
|
|
#if BOOST_STL_INTERFACES_USE_CONCEPTS
|
|
template<pipeable_ T, pipeable_ U>
|
|
#else
|
|
template<
|
|
typename T,
|
|
typename U,
|
|
typename Enable = std::enable_if_t<pipeable_<T> && pipeable_<U>>>
|
|
#endif
|
|
struct view_pipeline;
|
|
|
|
struct pipeable_base
|
|
{
|
|
#if BOOST_STL_INTERFACES_USE_CONCEPTS
|
|
template<pipeable_ T, pipeable_ U>
|
|
requires std::constructible_from<std::remove_cvref_t<T>, T> &&
|
|
std::constructible_from<std::remove_cvref_t<U>, U>
|
|
#else
|
|
template<
|
|
typename T,
|
|
typename U,
|
|
typename Enable = std::enable_if_t<
|
|
pipeable_<T> && pipeable_<U> &&
|
|
std::is_constructible<remove_cvref_t<T>, T>::value &&
|
|
std::is_constructible<remove_cvref_t<U>, U>::value>>
|
|
#endif
|
|
friend constexpr auto operator|(T && t, U && u)
|
|
{
|
|
return view_pipeline<T, U>{(T &&) t, (U &&) u};
|
|
}
|
|
};
|
|
|
|
template<typename Derived>
|
|
struct pipeable : pipeable_base
|
|
{
|
|
template<typename R>
|
|
friend constexpr auto operator|(R && r, Derived & d)
|
|
-> decltype(((Derived &&) d)((R &&) r))
|
|
{
|
|
return ((Derived &&) d)((R &&) r);
|
|
}
|
|
|
|
template<typename R>
|
|
friend constexpr auto operator|(R && r, Derived const & d)
|
|
-> decltype(((Derived &&) d)((R &&) r))
|
|
{
|
|
return ((Derived &&) d)((R &&) r);
|
|
}
|
|
|
|
template<typename R>
|
|
friend constexpr auto operator|(R && r, Derived && d)
|
|
-> decltype(((Derived &&) d)((R &&) r))
|
|
{
|
|
return ((Derived &&) d)((R &&) r);
|
|
}
|
|
};
|
|
|
|
#if BOOST_STL_INTERFACES_USE_CONCEPTS
|
|
template<pipeable_ T, pipeable_ U>
|
|
#else
|
|
template<typename T, typename U, typename>
|
|
#endif
|
|
struct view_pipeline : pipeable<view_pipeline<T, U>>
|
|
{
|
|
view_pipeline() = default;
|
|
|
|
constexpr view_pipeline(T && t, U && u) :
|
|
left_(std::move(t)), right_(std::move(u))
|
|
{}
|
|
|
|
#if BOOST_STL_INTERFACES_USE_CONCEPTS
|
|
template<std::ranges::viewable_range R>
|
|
requires std::invocable<T &, R> &&
|
|
std::invocable<U &, std::invoke_result_t<T &, R>>
|
|
constexpr decltype(auto) operator()(R && r) &
|
|
#else
|
|
template<typename R>
|
|
constexpr auto
|
|
operator()(R && r) & -> decltype(this->right_(this->left_((R &&) r)))
|
|
#endif
|
|
{
|
|
return right_(left_((R &&) r));
|
|
}
|
|
|
|
#if BOOST_STL_INTERFACES_USE_CONCEPTS
|
|
template<std::ranges::viewable_range R>
|
|
requires std::invocable<T const &, R> &&
|
|
std::invocable<U const &, std::invoke_result_t<T const &, R>>
|
|
constexpr decltype(auto) operator()(R && r) const &
|
|
#else
|
|
template<typename R>
|
|
constexpr auto operator()(
|
|
R && r) const & -> decltype(this->right_(this->left_((R &&) r)))
|
|
#endif
|
|
{
|
|
return right_(left_((R &&) r));
|
|
}
|
|
|
|
#if BOOST_STL_INTERFACES_USE_CONCEPTS
|
|
template<std::ranges::viewable_range R>
|
|
requires std::invocable<T, R> &&
|
|
std::invocable<U, std::invoke_result_t<T, R>>
|
|
constexpr decltype(auto) operator()(R && r) &&
|
|
#else
|
|
template<typename R>
|
|
constexpr auto operator()(R && r) && -> decltype(std::move(
|
|
this->right_)(std::move(this->left_)((R &&) r)))
|
|
#endif
|
|
{
|
|
return std::move(right_)(std::move(left_)((R &&) r));
|
|
}
|
|
|
|
T left_;
|
|
U right_;
|
|
};
|
|
|
|
}}}
|
|
|
|
#endif
|