Fix kSeq, add default for f in LeftFold, add example for LeftFold

This commit is contained in:
sha512sum 2024-07-18 17:03:23 +00:00
parent 2be45e896a
commit 16889ef3b0
2 changed files with 29 additions and 27 deletions

View file

@ -5,5 +5,7 @@ auto main() -> int {
utempl::GetIndexesTuple<4>(), utempl::kWrapper<std::size_t{}>, []<std::size_t I>(utempl::Wrapper<I>, auto) -> utempl::Wrapper<I + 1> { utempl::GetIndexesTuple<4>(), utempl::kWrapper<std::size_t{}>, []<std::size_t I>(utempl::Wrapper<I>, auto) -> utempl::Wrapper<I + 1> {
return {}; return {};
}); });
static_assert(std::is_same_v<decltype(value), const utempl::Wrapper<static_cast<std::size_t>(4)>>); static_assert(std::is_same_v<decltype(value), const utempl::Wrapper<static_cast<std::size_t>(4)>>);
static_assert(std::is_same_v<decltype(utempl::LeftFold(utempl::Tuple{}, value)), const utempl::Wrapper<static_cast<std::size_t>(4)>&>);
}; };

View file

@ -9,6 +9,9 @@
namespace utempl { namespace utempl {
template <typename T>
using ForwardType = decltype(std::forward<T>(std::declval<T>()));
template <auto Value> template <auto Value>
struct Wrapper { struct Wrapper {
static constexpr auto kValue = Value; static constexpr auto kValue = Value;
@ -26,13 +29,22 @@ struct Wrapper {
template <auto Value> template <auto Value>
inline constexpr Wrapper<Value> kWrapper; inline constexpr Wrapper<Value> kWrapper;
template <typename T>
requires std::same_as<T, void> || requires { T{}; }
constexpr auto kDefaultCreator = [] {
return T{};
};
template <>
constexpr auto kDefaultCreator<void> = [] {};
namespace impl { namespace impl {
template <std::size_t N> template <std::size_t N>
struct kSeq { struct kSeq {
template <typename F> template <typename F>
friend constexpr auto operator|(F&& f, const kSeq<N>&) { friend constexpr auto operator|(F&& f, const kSeq<N>&) -> decltype(auto) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) { return [&]<std::size_t... Is>(std::index_sequence<Is...>) -> decltype(auto) {
return std::forward<F>(f)(kWrapper<Is>...); return std::forward<F>(f)(kWrapper<Is>...);
}(std::make_index_sequence<N>()); }(std::make_index_sequence<N>());
}; };
@ -430,9 +442,8 @@ struct LeftFold<T, F> {
T data; T data;
F f; F f;
template <typename TT> template <typename TT>
constexpr auto operator|(LeftFold<TT>&& other) { constexpr auto operator|(LeftFold<TT>&& other) -> LeftFold<std::invoke_result_t<F, T, TT>, F> {
using R = decltype(f(std::move(this->data), std::move(other.data))); return {.data = std::forward<F>(this->f)(std::forward<T>(this->data), std::forward<TT>(other.data)), .f = std::forward<F>(this->f)};
return LeftFold<R, F>{.data = f(std::move(this->data), std::move(other.data)), .f = this->f};
}; };
}; };
@ -447,9 +458,7 @@ template <typename F, typename T>
struct LeftFoldIsOk { struct LeftFoldIsOk {
static constexpr bool value = true; static constexpr bool value = true;
template <typename TT> template <typename TT>
consteval auto operator|(LeftFoldIsOk<F, TT>&& other) -> LeftFoldIsOk<F, std::invoke_result_t<F, T, TT>> consteval auto operator|(LeftFoldIsOk<F, TT>&& other) -> LeftFoldIsOk<F, std::invoke_result_t<F, T, TT>> {
requires Function<F, void(T, TT)>
{
return {}; return {};
}; };
consteval auto operator|(auto&&) -> LeftFoldIgnorer { consteval auto operator|(auto&&) -> LeftFoldIgnorer {
@ -464,23 +473,23 @@ concept LeftFoldConcept = decltype(Unpack(std::declval<Tuple>(), []<typename...
} // namespace impl } // namespace impl
template <TupleLike Tuple, std::move_constructible T, impl::LeftFoldConcept<T, Tuple> F> template <TupleLike Tuple, std::move_constructible T, impl::LeftFoldConcept<T, Tuple> F = decltype(kDefaultCreator<void>)&>
constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f) { constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f = kDefaultCreator<void>) -> decltype(auto) {
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) { return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) -> decltype(auto) {
return (impl::LeftFold<std::remove_cvref_t<T>, F>{.data = std::forward<T>(init), .f = std::forward<F>(f)} | ... | return (impl::LeftFold<ForwardType<T>, ForwardType<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<ForwardType<Ts>>{.data = std::forward<Ts>(args)})
.data; .data;
}); });
}; };
template <TupleLike Tuple, std::move_constructible T, impl::LeftFoldConcept<T, Tuple> F> template <TupleLike Tuple, std::move_constructible T, impl::LeftFoldConcept<T, Tuple> F>
constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) { constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) -> decltype(auto) {
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>
constexpr auto Reduce(T&& init, F&& f) { constexpr auto Reduce(T&& init, F&& f) -> decltype(auto) {
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) -> decltype(auto)
requires impl::LeftFoldConcept<F, T, 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));
@ -506,7 +515,7 @@ inline constexpr auto TupleCat(Tuples&&... tuples)
}; };
template <TupleLike... Tuples, typename F> template <TupleLike... Tuples, typename F>
inline constexpr auto Unpack(Tuples&&... tuples, F&& f) { inline constexpr auto Unpack(Tuples&&... tuples, F&& f) -> decltype(Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f))) {
return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f)); return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f));
}; };
@ -680,15 +689,6 @@ constexpr auto Enumerate(Tuple&& tuple) {
}); });
}; };
template <typename T>
requires std::same_as<T, void> || requires { T{}; }
constexpr auto kDefaultCreator = [] {
return T{};
};
template <>
constexpr auto kDefaultCreator<void> = [] {};
namespace impl { namespace impl {
template <typename Key, typename KeysTuple> template <typename Key, typename KeysTuple>