diff --git a/include/utempl/utils.hpp b/include/utempl/utils.hpp index 74adb92..91bdd03 100644 --- a/include/utempl/utils.hpp +++ b/include/utempl/utils.hpp @@ -94,19 +94,61 @@ struct TupleMaker> { }; template struct TupleMaker> { + template + static inline constexpr auto Make(Arg&& arg, Args&&... args) + requires (std::same_as, std::remove_cvref_t> && ...) { + return std::array{std::forward(arg), std::forward(args)...}; + }; +}; + +template +struct TupleTieMaker { +}; + +template +struct TupleTieMaker> { template - static inline constexpr auto Make(Args&&... args) { - return std::array{std::forward(args)...}; + static inline constexpr auto Make(Args&... args) -> std::tuple { + return {args...}; + }; +}; + +template +struct TupleTieMaker> { + template + static inline constexpr auto Make(Args&... args) -> Tuple { + return {args...}; + }; +}; + +template +struct TupleTieMaker> { + template + static inline constexpr auto Make(Arg& arg, Args&... args) -> std::array + requires (std::same_as, std::remove_cvref_t> && ...) { + return {arg, args...}; }; }; template , typename... Args> -inline constexpr auto MakeTuple(Args&&... args) { +inline constexpr auto MakeTuple(Args&&... args) + -> decltype(TupleMaker>::Make(std::forward(args)...)) { return TupleMaker>::Make(std::forward(args)...); }; +template , typename... Args> +inline constexpr auto MakeTie(Args&... args) + -> decltype(TupleTieMaker>::Make(args...)) { + return TupleTieMaker>::Make(args...); +}; + + + +template +concept HasMakeTie = requires(int& arg) {MakeTie(arg);}; + namespace impl { template @@ -162,6 +204,89 @@ template concept TupleLike = kForceEnableTuple> || (requires{Get<0>(MakeTuple(42));} && impl::IsSafeTuple>::value); +template +concept TupleTransformer = requires(F f, Tuple&& tuple) { + {f(std::move(tuple))}; +}; + +template +struct LazyTuple { + F f; + using ResultType = std::invoke_result_t; + std::optional result{std::nullopt}; + inline constexpr auto Evaluate() { + if(!this->result) { + this->result.emplace(this->f()); + }; + }; + inline constexpr auto operator()() -> decltype(auto) { + this->Evaluate(); + return *this->result; + }; + inline constexpr auto operator()() const -> decltype(auto) { + return this->f(); + }; + template + inline constexpr auto operator==(T&& other) + requires requires(ResultType result){result == std::forward(other);} { + return (*this)() == other; + }; + + template + inline constexpr auto operator==(T&& other) const + requires requires(ResultType result){result == std::forward(other);} { + return (*this)() == other; + }; + + inline constexpr operator std::invoke_result_t() { + return (*this)(); + }; + inline constexpr operator std::invoke_result_t() const { + return (*this)(); + }; + template + friend inline constexpr auto Get(LazyTuple&& tuple) -> decltype(auto) requires TupleLike { + return Get(std::move(tuple)()); + }; + template + friend inline constexpr auto Get(const LazyTuple&& tuple) -> decltype(auto) requires TupleLike { + return Get(std::move(tuple)()); + }; + template + friend inline constexpr auto Get(LazyTuple& tuple) -> decltype(auto) requires TupleLike { + return Get(tuple()); + }; + template + friend inline constexpr auto Get(const LazyTuple& tuple) -> decltype(auto) requires TupleLike { + return Get(tuple()); + }; + template + inline constexpr auto operator|(FF&& ff) { + auto f = [ff = std::forward(ff), self = (*this)](){ + return ff(self()); + }; + return LazyTuple{std::move(f)}; + }; +}; +template +struct TupleMaker> { + template + static inline constexpr auto Make(Ts&&... args) + requires requires {TupleMaker::ResultType>::Make(std::forward(args)...);} { + return TupleMaker::ResultType>::Make(std::forward(args)...); + }; +}; + + +template FF> +inline constexpr auto operator|(Tuple&& tuple, FF&& f) { + return LazyTuple{ + [tuple = std::forward(tuple), f = std::forward(f)]() -> decltype(auto) { + return f(std::move(tuple)); + }}; +}; + + template inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) { return [&](std::index_sequence) -> decltype(auto) { @@ -169,6 +294,13 @@ inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) { }(std::make_index_sequence>()); }; +template +inline constexpr auto Unpack(F&& f) { + return [f = std::forward(f)](Tuple&& tuple){ + return Unpack(std::forward(tuple), std::move(f)); + }; +}; + template @@ -179,11 +311,34 @@ inline constexpr auto Transform(Tuple&& container, F&& f, TypeList = {}) { }); }; +template +inline constexpr auto Transform(F&& f, TypeList result = {}) { + return [f = std::forward(f), result](Tuple&& tuple){ + if constexpr(!std::is_same_v) { + return Transform(std::forward(tuple), std::move(f), result); + } else { + return Transform(std::forward(tuple), std::move(f)); + }; + }; +}; + + template inline constexpr auto Map(Tuple&& tuple, F&& f, TypeList result = {}) { return Transform(std::forward(tuple), std::forward(f), result); }; +template +inline constexpr auto Map(F&& f, TypeList result = {}) { + return [f = std::forward(f), result](Tuple&& tuple){ + if constexpr(!std::is_same_v) { + return Map(std::forward(tuple), std::move(f), result); + } else { + return Map(std::forward(tuple), std::move(f)); + }; + }; +}; + template inline constexpr auto Reverse(Tuple&& tuple) { return [&](std::index_sequence) { @@ -191,6 +346,12 @@ inline constexpr auto Reverse(Tuple&& tuple) { }(std::make_index_sequence>()); }; +consteval auto Reverse() { + return [](Tuple&& tuple){ + return Reverse(std::forward(tuple)); + }; +}; + namespace impl { template @@ -292,6 +453,13 @@ inline constexpr auto FirstOf(Tuple&& tuple, T&& init) requires kEveryElement +inline constexpr auto FirstOf(T&& init) { + return [init = std::forward(init)](Tuple&& tuple) { + return FirstOf(std::forward(tuple), std::move(init)); + }; +}; + template inline constexpr auto Filter(Tuple&& tuple, auto&& f) { @@ -308,6 +476,13 @@ inline constexpr auto Filter(Tuple&& tuple, auto&& f) { ); }; +template +inline constexpr auto Filter(F&& f) { + return [f = std::forward(f)](Tuple&& tuple){ + return Filter(std::forward(tuple), std::move(f)); + }; +}; + template inline constexpr auto ForEach(Tuple&& tuple, auto&& f) { Unpack(std::forward(tuple), [&](Ts&&... args){ @@ -359,4 +534,25 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t { return std::ranges::find(bs, true) - bs.begin(); }); }; + +template +inline constexpr auto Take(Tuple&& tuple) { + if constexpr(std::is_lvalue_reference_v && HasMakeTie) { + return [&](std::index_sequence){ + return MakeTie(Get(std::forward(tuple))...); + }(std::make_index_sequence()); + } else { + return [&](std::index_sequence){ + return MakeTuple(Get(std::forward(tuple))...); + }(std::make_index_sequence()); + }; +}; + +template +consteval auto Take() { + return [&](Tuple&& tuple){ + return Take(std::forward(tuple)); + }; +}; + } // namespace utempl