2025-01-12 19:51:34 +08:00

149 lines
4.7 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://llvm.org/LICENSE.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <unifex/config.hpp>
#include <unifex/std_concepts.hpp>
#include <unifex/type_traits.hpp>
#include <type_traits>
#include <tuple>
#include <unifex/detail/prologue.hpp>
namespace unifex {
namespace _compose {
struct _fn {
template <typename Target, typename Other, typename Self>
auto operator()(Target&& target, Other&& other, Self&& self) const
noexcept(
is_nothrow_callable_v<Other, Target> &&
is_nothrow_callable_v<Self, callable_result_t<Other, Target>>)
-> callable_result_t<Self, callable_result_t<Other, Target>> {
return ((Self&&) self)(((Other&&) other)((Target&&) target));
}
};
} // namespace _compose
namespace _bind_back {
template <typename Cpo, typename Target>
struct _apply_fn_impl {
struct type;
};
template <typename Cpo, typename... ArgN>
using _apply_fn = typename _apply_fn_impl<Cpo, ArgN...>::type;
template <typename Cpo, typename Target>
struct _apply_fn_impl<Cpo, Target>::type {
Cpo&& cpo_;
Target&& target_;
template (typename... ArgN)
(requires callable<Cpo, Target, ArgN...>)
auto operator()(ArgN&&... argN)
noexcept(is_nothrow_callable_v<Cpo, Target, ArgN...>)
-> callable_result_t<Cpo, Target, ArgN...> {
return ((Cpo&&) cpo_)((Target&&) target_, (ArgN&&) argN...);
}
};
struct _result_base {};
template <typename Cpo, typename... ArgN>
struct _result_impl {
struct type;
};
template <typename Cpo, typename... ArgN>
using _result = typename _result_impl<Cpo, ArgN...>::type;
template <typename Cpo, typename... ArgN>
struct _result_impl<Cpo, ArgN...>::type : _result_base {
UNIFEX_NO_UNIQUE_ADDRESS Cpo cpo_;
std::tuple<ArgN...> argN_;
template (typename Target)
(requires (!derived_from<remove_cvref_t<Target>, _result_base>) AND
callable<Cpo const&, Target, ArgN const&...>)
decltype(auto) operator()(Target&& target) const &
noexcept(is_nothrow_callable_v<Cpo const&, Target, ArgN const&...>) {
return std::apply(_apply_fn<Cpo const&, Target>{cpo_, (Target&&) target}, argN_);
}
template (typename Target)
(requires (!derived_from<remove_cvref_t<Target>, _result_base>) AND
callable<Cpo, Target, ArgN...>)
decltype(auto) operator()(Target&& target) &&
noexcept(is_nothrow_callable_v<Cpo, Target, ArgN...>) {
return std::apply(
_apply_fn<Cpo, Target>{(Cpo&&) cpo_, (Target&&) target},
std::move(argN_));
}
template (typename Target, typename Self)
(requires (!derived_from<remove_cvref_t<Target>, _result_base>) AND
same_as<remove_cvref_t<Self>, type> AND
callable<member_t<Self, Cpo>, Target, member_t<Self, ArgN>...>)
friend decltype(auto) operator|(Target&& target, Self&& self)
noexcept(
is_nothrow_callable_v<member_t<Self, Cpo>, Target, member_t<Self, ArgN>...>) {
return std::apply(
_apply_fn<member_t<Self, Cpo>, Target>{((Self&&) self).cpo_, (Target&&) target},
((Self&&) self).argN_);
}
template (typename Other, typename Self)
(requires derived_from<remove_cvref_t<Other>, _result_base> AND
same_as<remove_cvref_t<Self>, type>)
friend decltype(auto) operator|(Other&& other, Self&& self)
noexcept(noexcept(
_result<_compose::_fn, remove_cvref_t<Other>, type>{
{}, // _result_base
{}, // _compose::_fn
{(Other&&) other, (Self&&) self}})) {
return _result<_compose::_fn, remove_cvref_t<Other>, type>{
{}, // _result_base
{}, // _compose::_fn
{(Other&&) other, (Self&&) self}};
}
};
inline const struct _fn {
template <typename Cpo, typename... ArgN>
constexpr auto operator()(Cpo cpo, ArgN&&... argN) const
noexcept(noexcept(
_result<Cpo, std::decay_t<ArgN>...>{{}, (Cpo&&) cpo, {(ArgN &&) argN...}}))
-> _result<Cpo, std::decay_t<ArgN>...> {
return _result<Cpo, std::decay_t<ArgN>...>{{}, (Cpo&&) cpo, {(ArgN &&) argN...}};
}
} bind_back{};
} // namespace _bind_back
using _bind_back::bind_back;
template <typename Cpo, typename... ArgN>
using bind_back_result_t =
_bind_back::_result<std::decay_t<Cpo>, std::decay_t<ArgN>...>;
} // namespace unifex
#include <unifex/detail/epilogue.hpp>