Add concepts for functions

This commit is contained in:
sha512sum 2024-07-15 15:56:00 +00:00
parent e7cf38e2a9
commit eaddebf1e5

View file

@ -150,16 +150,6 @@ struct TupleTieMaker<Tuple<Ts...>> {
}; };
}; };
template <typename T, std::size_t N>
struct TupleTieMaker<std::array<T, N>> {
template <typename Arg, typename... Args>
static inline constexpr auto Make(Arg& arg, Args&... args) -> std::array<Arg&, sizeof...(Args) + 1>
requires(std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...)
{
return {arg, args...};
};
};
template <typename T = Tuple<>, typename... Args> template <typename T = Tuple<>, typename... Args>
inline constexpr auto MakeTuple(Args&&... args) -> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) { inline constexpr auto MakeTuple(Args&&... args) -> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) {
return TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...); return TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...);
@ -293,9 +283,9 @@ struct LazyTuple {
{ {
return Get<I>(tuple()); return Get<I>(tuple());
}; };
template <typename FF> template <std::invocable<std::invoke_result_t<F>> FF>
inline constexpr auto operator|(FF&& ff) { constexpr auto operator|(FF&& ff) {
auto f = [ff = std::forward<FF>(ff), self = (*this)]() { auto f = [ff = std::forward<FF>(ff), self = (*this)] {
return ff(self()); return ff(self());
}; };
return LazyTuple<decltype(f)>{std::move(f)}; return LazyTuple<decltype(f)>{std::move(f)};
@ -318,7 +308,28 @@ inline constexpr auto operator|(Tuple&& tuple, FF&& f) {
}}; }};
}; };
template <TupleLike Tuple, typename F> namespace impl {
template <typename F, typename Tuple>
concept UnpackConcept = []<std::size_t... Is>(std::index_sequence<Is...>) {
return std::invocable<F, decltype(Get<Is>(std::declval<Tuple>()))...>;
}(std::make_index_sequence<kTupleSize<Tuple>>());
template <typename F, typename Tuple>
concept TransformConcept = []<std::size_t... Is>(std::index_sequence<Is...>) {
return ((std::invocable<F, decltype(Get<Is>(std::declval<Tuple>()))> &&
!std::same_as<std::invoke_result_t<F, decltype(Get<Is>(std::declval<Tuple>()))>, void>) &&
...);
}(std::make_index_sequence<kTupleSize<Tuple>>());
template <typename F, typename Tuple>
concept ForEachConcept = []<std::size_t... Is>(std::index_sequence<Is...>) {
return (std::invocable<F, decltype(Get<Is>(std::declval<Tuple>()))> && ...);
}(std::make_index_sequence<kTupleSize<Tuple>>());
} // namespace impl
template <TupleLike Tuple, impl::UnpackConcept<Tuple> F>
inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) { inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
return [&](auto... is) -> decltype(auto) { return [&](auto... is) -> decltype(auto) {
return f(Get<is>(std::forward<Tuple>(tuple))...); return f(Get<is>(std::forward<Tuple>(tuple))...);
@ -326,55 +337,57 @@ inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
}; };
template <typename F> template <typename F>
inline constexpr auto Unpack(F&& f) { constexpr auto Unpack(F&& f) {
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) { return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) -> decltype(auto)
requires impl::UnpackConcept<F, Tuple>
{
return Unpack(std::forward<Tuple>(tuple), std::move(f)); return Unpack(std::forward<Tuple>(tuple), std::move(f));
}; };
}; };
template <TupleLike Tuple, typename R = Tuple, typename F> template <TupleLike Tuple, TupleLike R = Tuple, impl::TransformConcept<Tuple> F>
inline constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) { constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) {
return Unpack(std::forward<Tuple>(container), [&]<typename... Ts>(Ts&&... args) { return Unpack(std::forward<Tuple>(container), [&]<typename... Ts>(Ts&&... args) {
return MakeTuple<R>(f(std::forward<Ts>(args))...); return MakeTuple<R>(f(std::forward<Ts>(args))...);
}); });
}; };
template <typename F, typename R = void> template <typename F, typename R = void>
inline constexpr auto Transform(F&& f, TypeList<R> result = {}) { constexpr auto Transform(F&& f, TypeList<R> result = {}) {
return [f = std::forward<F>(f), result]<TupleLike Tuple>(Tuple&& tuple) { return [f = std::forward<F>(f), result]<TupleLike TTuple, typename RR = decltype([] {
if constexpr(!std::is_same_v<R, void>) { if constexpr(std::same_as<R, void>) {
return Transform(std::forward<Tuple>(tuple), std::move(f), result); return kType<TTuple>;
} else { } else {
return Transform(std::forward<Tuple>(tuple), std::move(f)); return kType<R>;
}; };
}())::Type>(TTuple&& tuple)
requires impl::TransformConcept<F, TTuple>
{
return Transform(std::forward<TTuple>(tuple), std::move(f), kType<RR>);
}; };
}; };
template <TupleLike Tuple, typename R = Tuple, typename F> template <TupleLike Tuple, TupleLike R = Tuple, impl::TransformConcept<Tuple> F>
inline constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> result = {}) { constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> result = {}) {
return Transform(std::forward<Tuple>(tuple), std::forward<F>(f), result); return Transform(std::forward<Tuple>(tuple), std::forward<F>(f), result);
}; };
template <typename F, typename R = void> template <typename F, typename R = void>
inline constexpr auto Map(F&& f, TypeList<R> result = {}) { constexpr auto Map(F&& f, TypeList<R> result = {}) -> decltype(Transform(std::forward<F>(f), result)) {
return [f = std::forward<F>(f), result]<TupleLike Tuple>(Tuple&& tuple) { return Transform(std::forward<F>(f), result);
if constexpr(!std::is_same_v<R, void>) {
return Map(std::forward<Tuple>(tuple), std::move(f), result);
} else {
return Map(std::forward<Tuple>(tuple), std::move(f));
};
};
}; };
template <auto Tuple, typename To = decltype(Tuple)> template <auto Tuple, TupleLike To = decltype(Tuple)>
consteval auto PackConstexprWrapper() { consteval auto PackConstexprWrapper()
requires TupleLike<decltype(Tuple)>
{
return [&]<std::size_t... Is>(std::index_sequence<Is...>) { return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return MakeTuple<To>(kWrapper<Get<Is>(Tuple)>...); return MakeTuple<To>(kWrapper<Get<Is>(Tuple)>...);
}(std::make_index_sequence<kTupleSize<decltype(Tuple)>>()); }(std::make_index_sequence<kTupleSize<decltype(Tuple)>>());
}; };
template <TupleLike Tuple> template <TupleLike Tuple>
inline constexpr auto Reverse(Tuple&& tuple) { constexpr auto Reverse(Tuple&& tuple) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) { return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return MakeTuple<Tuple>(Get<kTupleSize<Tuple> - Is - 1>(std::forward<Tuple>(tuple))...); return MakeTuple<Tuple>(Get<kTupleSize<Tuple> - Is - 1>(std::forward<Tuple>(tuple))...);
}(std::make_index_sequence<kTupleSize<Tuple>>()); }(std::make_index_sequence<kTupleSize<Tuple>>());
@ -399,33 +412,40 @@ struct LeftFold<T> {
template <typename T, typename F> template <typename T, typename F>
struct LeftFold<T, F> { struct LeftFold<T, F> {
T data; T data;
const F& f; F f;
template <typename TT> template <typename TT>
inline constexpr auto operator|(LeftFold<TT>&& other) { constexpr auto operator|(LeftFold<TT>&& other) {
using R = decltype(f(std::move(this->data), std::move(other.data))); using R = decltype(f(std::move(this->data), std::move(other.data)));
return LeftFold<R, F>{.data = f(std::move(this->data), std::move(other.data)), .f = this->f}; return LeftFold<R, F>{.data = f(std::move(this->data), std::move(other.data)), .f = this->f};
}; };
}; };
template <typename F, typename T, typename Tuple>
concept LeftFoldConcept = decltype(Unpack(std::declval<Tuple>(), []<typename... Ts>(Ts&&...) {
return kWrapper<(std::convertible_to<std::invoke_result_t<F, T, Ts>, T> && ...)>;
}))::kValue;
} // namespace impl } // namespace impl
template <TupleLike Tuple, typename T, typename F> template <TupleLike Tuple, std::move_constructible T, impl::LeftFoldConcept<T, Tuple> F>
inline constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f) { constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f) {
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) { return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
return (impl::LeftFold<std::remove_cvref_t<T>, std::remove_cvref_t<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)} | ... | return (impl::LeftFold<std::remove_cvref_t<T>, F>{.data = std::forward<T>(init), .f = std::forward<F>(f)} | ... |
impl::LeftFold<std::remove_cvref_t<Ts>>{.data = std::forward<Ts>(args)}) impl::LeftFold<std::remove_cvref_t<Ts>>{.data = std::forward<Ts>(args)})
.data; .data;
}); });
}; };
template <TupleLike Tuple, typename T, typename F> template <TupleLike Tuple, std::move_constructible T, impl::LeftFoldConcept<T, Tuple> F>
inline constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) { constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) {
return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), std::forward<F>(f)); return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), std::forward<F>(f));
}; };
template <typename T, typename F> template <typename T, typename F>
inline constexpr auto Reduce(T&& init, F&& f) { constexpr auto Reduce(T&& init, F&& f) {
return [init = std::forward<T>(init), f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) { return [init = std::forward<T>(init), f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple)
requires impl::LeftFoldConcept<F, T, Tuple>
{
return Reduce(std::forward<Tuple>(tuple), std::move(init), std::move(f)); return Reduce(std::forward<Tuple>(tuple), std::move(init), std::move(f));
}; };
}; };
@ -475,15 +495,15 @@ consteval auto PartialCallerF(TypeList<Ts...>) {
}; };
}; };
template <TupleLike Tuple, typename T> template <TupleLike Tuple, std::move_constructible T>
inline constexpr auto FirstOf(Tuple&& tuple, T&& init) inline constexpr auto FirstOf(Tuple&& tuple, T&& init)
requires kEveryElement<std::is_invocable, Tuple> requires kEveryElement<std::is_invocable, Tuple>
{ {
return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), []<typename TT, typename F>(TT&& value, F&& f) -> TT { return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), []<typename TT, typename F>(TT&& value, F&& f) -> TT {
if(value) { if(value) {
return value; return std::forward<TT>(value);
}; };
return f(); return std::forward<F>(f)();
}); });
}; };
@ -494,8 +514,17 @@ inline constexpr auto FirstOf(T&& init) {
}; };
}; };
template <TupleLike Tuple> namespace impl {
inline constexpr auto Filter(Tuple&& tuple, auto&& f) {
template <typename F, typename Tuple>
concept FilterConcept = decltype(Unpack(std::declval<Tuple>(), []<typename... Ts>(Ts&&...) {
return kWrapper<((std::invocable<F, Ts> && std::convertible_to<std::invoke_result_t<F, Ts>, bool>) && ...)>;
}))::kValue;
} // namespace impl
template <TupleLike Tuple, impl::FilterConcept<Tuple> F>
constexpr auto Filter(Tuple&& tuple, F&& f) {
return LeftFold( return LeftFold(
std::forward<Tuple>(tuple), MakeTuple<Tuple>(), [&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) { std::forward<Tuple>(tuple), MakeTuple<Tuple>(), [&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
if constexpr(decltype(f(std::forward<T>(add))){}) { if constexpr(decltype(f(std::forward<T>(add))){}) {
@ -507,14 +536,16 @@ inline constexpr auto Filter(Tuple&& tuple, auto&& f) {
}; };
template <typename F> template <typename F>
inline constexpr auto Filter(F&& f) { constexpr auto Filter(F&& f) {
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) { return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple)
requires impl::FilterConcept<F, Tuple>
{
return Filter(std::forward<Tuple>(tuple), std::move(f)); return Filter(std::forward<Tuple>(tuple), std::move(f));
}; };
}; };
template <TupleLike Tuple> template <TupleLike Tuple, impl::ForEachConcept<Tuple> F>
inline constexpr auto ForEach(Tuple&& tuple, auto&& f) { constexpr auto ForEach(Tuple&& tuple, F&& f) {
Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) { Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
(f(std::forward<Ts>(args)), ...); (f(std::forward<Ts>(args)), ...);
}); });
@ -583,7 +614,7 @@ consteval auto Take() {
}; };
}; };
template <TupleLike Tuple, typename T> template <TupleLike Tuple, std::move_constructible T>
inline constexpr auto operator<<(Tuple&& tuple, T&& t) { inline constexpr auto operator<<(Tuple&& tuple, T&& t) {
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) { return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
return MakeTuple<Tuple>(std::forward<Ts>(args)..., std::forward<T>(t)); return MakeTuple<Tuple>(std::forward<Ts>(args)..., std::forward<T>(t));
@ -591,11 +622,17 @@ inline constexpr auto operator<<(Tuple&& tuple, T&& t) {
}; };
template <std::size_t N, TupleLike Tuple = Tuple<>, typename T> template <std::size_t N, TupleLike Tuple = Tuple<>, typename T>
inline constexpr auto Generate(T&& value) { inline constexpr auto Generate(T&& value)
requires(std::copyable<T> || N == 1 && std::move_constructible<T>)
{
if constexpr(N == 1) {
return MakeTuple<Tuple>(std::forward<T>(value));
} else {
return [&](auto... is) { return [&](auto... is) {
return MakeTuple<Tuple>((std::ignore = is, value)...); return MakeTuple<Tuple>((std::ignore = is, value)...);
} | kSeq<N>; } | kSeq<N>;
}; };
};
template <TupleLike Tuple> template <TupleLike Tuple>
constexpr auto Enumerate(Tuple&& tuple) { constexpr auto Enumerate(Tuple&& tuple) {
@ -607,15 +644,30 @@ constexpr auto Enumerate(Tuple&& tuple) {
}; };
template <typename T> template <typename T>
requires requires { T{}; }
constexpr auto kDefaultCreator = [] { constexpr auto kDefaultCreator = [] {
return T{}; return T{};
}; };
template <typename R, namespace impl {
template <typename Key, typename KeysTuple>
concept ComparableSwitchConcept = decltype(Unpack(std::declval<KeysTuple>(), []<typename... Ts>(Ts&&... args) {
return kWrapper<(requires { args == std::declval<Key>(); } && ...)>;
}))::kValue;
template <typename F, typename ValuesTuple, typename R>
concept CallableSwitchConcept = decltype(Unpack(std::declval<ValuesTuple>(), []<typename... Ts>(Ts&&...) {
return kWrapper<(std::convertible_to<std::invoke_result_t<F, Ts>, std::optional<R>> && ...)>;
}))::kValue;
} // namespace impl
template <std::move_constructible R,
TupleLike KeysTuple, TupleLike KeysTuple,
TupleLike ValuesTuple, TupleLike ValuesTuple,
typename Key, impl::ComparableSwitchConcept<KeysTuple> Key,
typename F, impl::CallableSwitchConcept<ValuesTuple, R> F,
std::invocable Default = decltype(kDefaultCreator<R>)> std::invocable Default = decltype(kDefaultCreator<R>)>
constexpr auto Switch(KeysTuple&& keysTuple, ValuesTuple&& valuesTuple, Key&& key, F&& f, Default&& def = {}) { constexpr auto Switch(KeysTuple&& keysTuple, ValuesTuple&& valuesTuple, Key&& key, F&& f, Default&& def = {}) {
return Unpack(std::forward<KeysTuple>(keysTuple), [&]<typename... Keys>(Keys&&... keys) { return Unpack(std::forward<KeysTuple>(keysTuple), [&]<typename... Keys>(Keys&&... keys) {