Add .clang-format, .clang-tidy and fixes

This commit is contained in:
sha512sum 2024-07-04 14:17:21 +00:00
parent fd61eb5341
commit 9982b60400
15 changed files with 404 additions and 481 deletions

13
.clang-format Normal file
View file

@ -0,0 +1,13 @@
BasedOnStyle: Google
IndentWidth: 2
ColumnLimit: 140
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
BreakConstructorInitializers: AfterColon
AlwaysBreakAfterReturnType: None
SpaceBeforeParens: Never
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: Empty
BinPackArguments: false
BinPackParameters: false
AlwaysBreakTemplateDeclarations: true

1
.clang-tidy Normal file
View file

@ -0,0 +1 @@
Checks: '-*,google-*,cppcoreguidelines-*,-cppcoreguidelines-c-copy-assignment-signature,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-avoid-const-or-ref-data-members,modernize-*'

View file

@ -2,11 +2,8 @@
#include <utempl/meta_info.hpp> #include <utempl/meta_info.hpp>
#include <utempl/utils.hpp> #include <utempl/utils.hpp>
namespace utempl { namespace utempl {
namespace impl { namespace impl {
struct AttributesTag {}; struct AttributesTag {};
@ -14,40 +11,27 @@ struct AttributesTag {};
template <typename T> template <typename T>
struct AttributesCounterTag {}; struct AttributesCounterTag {};
} // namespace impl
template <typename T, typename..., auto f = [] {}, auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()>
} // namespace impl
template <
typename T,
typename...,
auto f = []{},
auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()
>
consteval auto OpenStruct() -> bool { consteval auto OpenStruct() -> bool {
return true; return true;
}; };
template < template <typename...,
typename..., auto f = [] {},
auto f = []{}, auto I = loopholes::CountValue<impl::AttributesTag, decltype(f)>(),
auto I = loopholes::CountValue<impl::AttributesTag, decltype(f)>(), auto II = (I >= 2) ? I - 2 : I - 1,
auto II = (I >= 2) ? I - 2 : I - 1, typename T = decltype(Magic(loopholes::Getter<MetaInfoKey<II, impl::AttributesTag>{}>{}))::Type,
typename T = decltype(Magic(loopholes::Getter<MetaInfoKey<II, impl::AttributesTag>{}>{}))::Type, auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()>
auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()
>
consteval auto CloseStruct() -> bool { consteval auto CloseStruct() -> bool {
return true; return true;
}; };
struct NoInfo { struct NoInfo {
consteval auto operator==(const NoInfo&) const -> bool = default; consteval auto operator==(const NoInfo&) const -> bool = default;
}; };
namespace impl { namespace impl {
template <typename... Ts> template <typename... Ts>
@ -60,59 +44,48 @@ struct FieldAttributeData<> {
using Type = NoInfo; using Type = NoInfo;
}; };
template <typename T,
template < typename... Ts,
typename T, auto f = [] {},
typename... Ts, typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type,
auto f = []{}, auto = AddTypeToTag<impl::AttributesCounterTag<Current>, typename FieldAttributeData<Ts...>::Type, decltype(f)>()>
typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type,
auto = AddTypeToTag<impl::AttributesCounterTag<Current>, typename FieldAttributeData<Ts...>::Type, decltype(f)>()
>
consteval auto FieldAttribute() -> T; consteval auto FieldAttribute() -> T;
} // namespace impl } // namespace impl
template <typename... Ts> template <typename... Ts>
using FieldAttribute = decltype(impl::FieldAttribute<Ts...>()); using FieldAttribute = decltype(impl::FieldAttribute<Ts...>());
#define ATTRIBUTE_STRUCT(name, ...) /* NOLINT */ \
\
struct name { \
static_assert(::utempl::OpenStruct<name>()); \
template <std::size_t N> \
static consteval auto GetAttribute(); \
__VA_ARGS__ \
static_assert(::utempl::CloseStruct()); \
}
#define ATTRIBUTE_STRUCT(name, ...) struct name { \ #define GENERIC_ATTRIBUTE(value) /* NOLINT */ \
static_assert(::utempl::OpenStruct<name>()); \ template <> \
template <std::size_t N> \ consteval auto GetAttribute<::utempl::loopholes::Counter< \
static consteval auto GetAttribute(); \ ::utempl::impl::AttributesCounterTag<decltype(::utempl::GetCurrentTagType<::utempl::impl::AttributesTag, decltype([] {})>())::Type>, \
__VA_ARGS__ \ decltype([] {})>()>() { \
static_assert(::utempl::CloseStruct());\ return value; \
} }
#define SKIP_ATTRIBUTE() /* NOLINT */ GENERIC_ATTRIBUTE(::utempl::NoInfo{})
#define GENERIC_ATTRIBUTE(value) \ template <typename T, auto f = [] {}, bool R = (loopholes::CountValue<impl::AttributesCounterTag<T>, decltype(f)>() > 0)>
template <> \
consteval auto GetAttribute< \
::utempl::loopholes::Counter< \
::utempl::impl::AttributesCounterTag<decltype(::utempl::GetCurrentTagType< \
::utempl::impl::AttributesTag, \
decltype([]{}) \
>())::Type \
>, \
decltype([]{}) >()>() { return value; }
#define SKIP_ATTRIBUTE() GENERIC_ATTRIBUTE(::utempl::NoInfo{})
template <
typename T,
auto f = []{},
bool R = (loopholes::CountValue<impl::AttributesCounterTag<T>, decltype(f)>() > 0)
>
concept HasAttributes = R; concept HasAttributes = R;
template <typename T> template <typename T>
concept HasMacroAttributes = requires {T::template GetAttribute<0>();}; concept HasMacroAttributes = requires { T::template GetAttribute<0>(); };
template <HasAttributes T> template <HasAttributes T>
consteval auto GetAttributes() requires HasMacroAttributes<T> { consteval auto GetAttributes()
requires HasMacroAttributes<T>
{
constexpr auto I = loopholes::CountValue<impl::AttributesCounterTag<T>>(); constexpr auto I = loopholes::CountValue<impl::AttributesCounterTag<T>>();
return [](auto... is) { return [](auto... is) {
return Tuple{T::template GetAttribute<is>()...}; return Tuple{T::template GetAttribute<is>()...};
@ -127,7 +100,4 @@ consteval auto GetAttributes() {
} | kSeq<I>; } | kSeq<I>;
}; };
} // namespace utempl
} // namespace utempl

View file

@ -1,18 +1,19 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <algorithm> #include <algorithm>
namespace utempl { namespace utempl {
template <std::size_t> template <std::size_t>
struct ConstexprString; struct ConstexprString;
} // namespace utempl } // namespace utempl
template <std::size_t Size> template <std::size_t Size>
struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std::string_view> { struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std::string_view> {
constexpr auto parse(format_parse_context& ctx) const { constexpr auto parse(format_parse_context& ctx) const {
return ctx.begin(); return ctx.begin();
}; };
inline constexpr auto format(const utempl::ConstexprString<Size>& str, auto& ctx) const { constexpr auto format(const utempl::ConstexprString<Size>& str, auto& ctx) const {
return fmt::formatter<std::string_view>::format({str.begin()}, ctx); return fmt::formatter<std::string_view>::format({str.begin()}, ctx);
}; };
}; };
@ -22,66 +23,66 @@ namespace utempl {
template <std::size_t Size> template <std::size_t Size>
struct ConstexprString { struct ConstexprString {
std::array<char, Size> data; std::array<char, Size> data;
inline constexpr auto begin() -> char* { constexpr auto begin() -> char* {
return this->data.begin(); return this->data.begin();
}; };
inline constexpr auto begin() const -> const char* { [[nodiscard]] constexpr auto begin() const -> const char* {
return this->data.begin(); return this->data.begin();
}; };
inline constexpr auto end() -> char* { [[nodiscard]] constexpr auto end() -> char* {
return this->data.end(); return this->data.end();
}; };
inline constexpr auto end() const -> const char* { [[nodiscard]] constexpr auto end() const -> const char* {
return this->data.end(); return this->data.end();
}; };
static constexpr auto kSize = Size == 0 ? 0 : Size - 1; static constexpr auto kSize = Size == 0 ? 0 : Size - 1;
inline constexpr ConstexprString() = default; explicit constexpr ConstexprString() = default;
inline constexpr ConstexprString(const char (&data)[Size]) : data{} { constexpr ConstexprString(const char (&data)[Size]) : data{} { // NOLINT
std::ranges::copy_n(data, Size, this->data.begin()); std::ranges::copy_n(data, Size, this->data.begin());
}; };
inline constexpr ConstexprString(std::string data) : data{} { explicit constexpr ConstexprString(std::string data) : data{} {
std::ranges::copy_n(data.begin(), Size, this->data.begin()); std::ranges::copy_n(data.begin(), Size, this->data.begin());
}; };
inline constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {}; explicit constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {};
inline constexpr auto size() const { constexpr auto size() const {
return Size == 0 ? 0 : Size - 1; return Size == 0 ? 0 : Size - 1;
}; };
inline constexpr operator std::string_view() const & { constexpr operator std::string_view() const& { // NOLINT
return {this->begin()}; return {this->begin()};
}; };
inline constexpr bool operator==(std::string_view other) const { constexpr auto operator==(std::string_view other) const -> bool {
return static_cast<std::string_view>(*this) == other; return static_cast<std::string_view>(*this) == other;
}; };
inline constexpr bool operator==(const ConstexprString<Size>& other) const { constexpr auto operator==(const ConstexprString<Size>& other) const {
return static_cast<std::string_view>(*this) == static_cast<std::string_view>(other); return static_cast<std::string_view>(*this) == static_cast<std::string_view>(other);
}; };
template <std::size_t SSize> template <std::size_t SSize>
inline constexpr bool operator==(const ConstexprString<SSize>& other) const { constexpr auto operator==(const ConstexprString<SSize>& other) const -> bool {
return false; return false;
}; };
inline constexpr bool operator==(const std::string& other) const { constexpr auto operator==(const std::string& other) const -> bool {
return static_cast<std::string_view>(*this) == other; return static_cast<std::string_view>(*this) == other;
}; };
template <std::size_t SSize> template <std::size_t SSize>
inline constexpr auto operator+(const ConstexprString<SSize>& other) -> ConstexprString<Size + SSize - 1> { constexpr auto operator+(const ConstexprString<SSize>& other) -> ConstexprString<Size + SSize - 1> {
ConstexprString<Size + SSize - 1> response; ConstexprString<Size + SSize - 1> response;
std::ranges::copy_n(this->begin(), Size - 1, response.begin()); std::ranges::copy_n(this->begin(), Size - 1, response.begin());
std::ranges::copy_n(other.begin(), SSize, response.begin() + Size - 1); std::ranges::copy_n(other.begin(), SSize, response.begin() + Size - 1);
return response; return response;
}; };
inline constexpr ConstexprString(const ConstexprString&) = default; constexpr ConstexprString(const ConstexprString&) = default;
inline constexpr ConstexprString(ConstexprString&&) = default; constexpr ConstexprString(ConstexprString&&) = default;
}; };
template <std::size_t N> template <std::size_t N>
inline constexpr auto operator<<(std::ostream& stream, const ConstexprString<N>& str) -> std::ostream& { constexpr auto operator<<(std::ostream& stream, const ConstexprString<N>& str) -> std::ostream& {
stream << static_cast<std::string_view>(str); stream << static_cast<std::string_view>(str);
return stream; return stream;
}; };
template <std::size_t Count> template <std::size_t Count>
inline constexpr auto CreateStringWith(char c) { constexpr auto CreateStringWith(char c) {
ConstexprString<Count + 1> str = {}; ConstexprString<Count + 1> str{};
for(std::size_t i = 0; i < Count; i++) { for(std::size_t i = 0; i < Count; i++) {
str.data[i] = c; str.data[i] = c;
}; };
@ -89,8 +90,6 @@ inline constexpr auto CreateStringWith(char c) {
return str; return str;
}; };
template <std::size_t Size> template <std::size_t Size>
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>; ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>; // NOLINT
} // namespace utempl } // namespace utempl

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <utempl/constexpr_string.hpp>
#include <boost/pfr.hpp> #include <boost/pfr.hpp>
#include <type_traits> #include <type_traits>
#include <utempl/constexpr_string.hpp>
namespace utempl { namespace utempl {
@ -12,7 +12,7 @@ consteval auto FindField() -> std::size_t {
}; };
template <ConstexprString name, typename T> template <ConstexprString name, typename T>
inline constexpr auto Get(T&& arg) { constexpr auto Get(T&& arg) {
return boost::pfr::get<FindField<name, T>()>(std::forward<T>(arg)); return boost::pfr::get<FindField<name, T>()>(std::forward<T>(arg));
}; };
@ -21,76 +21,76 @@ struct EmptyField {};
namespace impl { namespace impl {
template <ConstexprString name, typename T> template <ConstexprString name, typename T>
inline constexpr auto TryGet(T&& arg) constexpr auto TryGet(T&& arg) -> decltype(boost::pfr::get<FindField<name, T>()>(std::forward<T>(arg)))
-> decltype(boost::pfr::get<FindField<name, T>()>(std::forward<T>(arg))) requires(FindField<name, T>() < boost::pfr::tuple_size_v<std::remove_cvref_t<T>>)
requires(FindField<name, T>() < boost::pfr::tuple_size_v<std::remove_cvref_t<T>>) { {
constexpr auto I = FindField<name, T>(); constexpr auto I = FindField<name, T>();
return boost::pfr::get<I>(std::forward<T>(arg)); return boost::pfr::get<I>(std::forward<T>(arg));
}; };
template <ConstexprString name, typename T> template <ConstexprString name, typename T>
inline constexpr auto TryGet(T&& arg) { constexpr auto TryGet(T&& arg) {
return EmptyField<name>{}; return EmptyField<name>{};
}; };
template <typename To, typename Transformer, typename From> template <typename To, typename Transformer, typename From>
inline constexpr auto Transform(Transformer&& transformer, From&& from) { constexpr auto Transform(Transformer&& transformer, From&& from) {
return [&]<auto... Is>(std::index_sequence<Is...>){ return [&]<auto... Is>(std::index_sequence<Is...>) {
return To{transformer(TryGet<ConstexprString<boost::pfr::get_name<Is, To>().size() + 1>{boost::pfr::get_name<Is, To>().begin()}>(from))...}; return To{
transformer(TryGet<ConstexprString<boost::pfr::get_name<Is, To>().size() + 1>{boost::pfr::get_name<Is, To>().begin()}>(from))...};
}(std::make_index_sequence<boost::pfr::tuple_size_v<To>>()); }(std::make_index_sequence<boost::pfr::tuple_size_v<To>>());
}; };
} // namespace impl } // namespace impl
struct DefaultFieldTransformer { struct DefaultFieldTransformer {
inline constexpr auto operator()(auto&& arg) -> auto&& { constexpr auto operator()(auto&& arg) -> auto&& {
return arg; return arg;
}; };
inline constexpr auto operator()(auto& arg) -> auto& { constexpr auto operator()(auto& arg) -> auto& {
return arg; return arg;
}; };
template <ConstexprString str> template <ConstexprString str>
inline constexpr auto operator()(EmptyField<str> arg) { constexpr auto operator()(EmptyField<str> arg) {
static_assert(str == "This Field Not Found"); static_assert(str == "This Field Not Found");
}; };
}; };
template <typename Value, typename Transformer = DefaultFieldTransformer> template <typename Value, typename Transformer = DefaultFieldTransformer>
struct GoInterface : Value { struct GoInterface : Value {
inline constexpr GoInterface(Value&& value) : constexpr GoInterface(Value&& value) : Value(std::move(value)) {}; // NOLINT
Value(std::move(value)) {}; constexpr GoInterface(const Value& value) : Value(value) {}; // NOLINT
inline constexpr GoInterface(const Value& value) :
Value(value) {};
template <typename T> template <typename T>
inline constexpr GoInterface(T&& value) : constexpr GoInterface(T&& value) : Value(impl::Transform<Value>(Transformer{}, std::forward<T>(value))){}; // NOLINT
Value(impl::Transform<Value>(Transformer{}, std::forward<T>(value))) {}; constexpr auto operator=(const GoInterface&) -> GoInterface& = default;
inline constexpr auto operator=(const GoInterface&) -> GoInterface& = default; constexpr auto operator=(GoInterface&&) -> GoInterface& = default;
inline constexpr auto operator=(GoInterface&&) -> GoInterface& = default; constexpr auto operator==(const Value& other) const -> bool
inline constexpr auto operator==(const Value& other) const -> bool requires requires(const Value& a) { a == a; }
requires requires(const Value& a){a == a;} { {
return static_cast<const Value&>(*this) == other; return static_cast<const Value&>(*this) == other;
}; };
inline constexpr auto operator==(const GoInterface& other) const -> bool { constexpr auto operator==(const GoInterface& other) const -> bool {
return *this == static_cast<const Value&>(other); return *this == static_cast<const Value&>(other);
}; };
template <typename T> template <typename T>
inline constexpr auto operator==(T&& other) const -> bool { constexpr auto operator==(T&& other) const -> bool {
return [&]<auto... Is>(std::index_sequence<Is...>){ return [&]<auto... Is>(std::index_sequence<Is...>) {
using Type = std::remove_cvref_t<T>; using Type = std::remove_cvref_t<T>;
Transformer transformer; Transformer transformer;
// + 1 - NULL Terminator // + 1 - NULL Terminator
return ((boost::pfr::get<Is>(static_cast<const Value&>(*this)) == return (
transformer(impl::TryGet<ConstexprString<boost::pfr::get_name<Is, Type>().size() + 1>{boost::pfr::get_name<Is, Type>().begin()}>(other))) && ...); (boost::pfr::get<Is>(static_cast<const Value&>(*this)) ==
transformer(impl::TryGet<ConstexprString<boost::pfr::get_name<Is, Type>().size() + 1>{boost::pfr::get_name<Is, Type>().begin()}>(
other))) &&
...);
}(std::make_index_sequence<boost::pfr::tuple_size_v<Value>>()); }(std::make_index_sequence<boost::pfr::tuple_size_v<Value>>());
}; };
template <typename T> template <typename T>
inline constexpr auto operator==(T&& other) const -> bool constexpr auto operator==(T&& other) const -> bool
requires (requires(const Value& value){value == other;}) { requires(requires(const Value& value) { value == other; })
{
return static_cast<const Value&>(*this) == other; return static_cast<const Value&>(*this) == other;
}; };
}; };
} // namespace utempl } // namespace utempl

View file

@ -9,10 +9,11 @@ struct Getter {
}; };
template <auto I, auto Value = 0> template <auto I, auto Value = 0>
struct Injector { struct Injector {
friend constexpr auto Magic(Getter<I>) {return Value;}; friend constexpr auto Magic(Getter<I>) {
return Value;
};
}; };
template <auto, typename = void, typename... Ts> template <auto, typename = void, typename... Ts>
struct InjectedImpl { struct InjectedImpl {
static constexpr bool value = false; static constexpr bool value = false;
@ -25,7 +26,4 @@ struct InjectedImpl<V, std::void_t<decltype(Magic(Getter<V>{}))>, Ts...> {
template <auto I, typename... Ts> template <auto I, typename... Ts>
concept Injected = InjectedImpl<I, void, Ts...>::value; concept Injected = InjectedImpl<I, void, Ts...>::value;
} // namespace utempl::loopholes
} // namespace utempl::loopholes

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <utempl/loopholes/core.hpp>
#include <cstddef> #include <cstddef>
#include <tuple> #include <tuple>
#include <utempl/loopholes/core.hpp>
namespace utempl::loopholes { namespace utempl::loopholes {
@ -12,7 +12,7 @@ struct TagWithValue {};
template <bool Add, typename Tag, std::size_t I, typename... Ts> template <bool Add, typename Tag, std::size_t I, typename... Ts>
consteval auto Counter() -> std::size_t { consteval auto Counter() -> std::size_t {
if constexpr(requires{Magic(Getter<TagWithValue<Tag, I>{}>{});}) { if constexpr(requires { Magic(Getter<TagWithValue<Tag, I>{}>{}); }) {
return Counter<Add, Tag, I + 1, Ts...>(); return Counter<Add, Tag, I + 1, Ts...>();
}; };
if constexpr(Add) { if constexpr(Add) {
@ -22,32 +22,20 @@ consteval auto Counter() -> std::size_t {
}; };
}; };
} // namespace impl
} // namespace impl;
// For incerement counter need a unique Ts... // For incerement counter need a unique Ts...
template < template <typename Tag, typename... Ts, std::size_t R = impl::Counter<true, Tag, 0, Ts...>()>
typename Tag,
typename... Ts,
std::size_t R = impl::Counter<true, Tag, 0, Ts...>()
>
consteval auto Counter(auto...) -> std::size_t { consteval auto Counter(auto...) -> std::size_t {
return R; return R;
}; };
// Without increment // Without increment
template < template <typename Tag, typename... Ts, std::size_t R = impl::Counter<false, Tag, 0, Ts...>()>
typename Tag,
typename... Ts,
std::size_t R = impl::Counter<false, Tag, 0, Ts...>()
>
consteval auto CountValue(auto...) -> std::size_t { consteval auto CountValue(auto...) -> std::size_t {
return R; return R;
}; };
/* /*
static_assert(Counter<void>() == 0); static_assert(Counter<void>() == 0);
static_assert(Counter<void, void>() == 1); static_assert(Counter<void, void>() == 1);
@ -55,4 +43,4 @@ static_assert(CountValue<void>() == 2);
static_assert(CountValue<void, void>() == 2); static_assert(CountValue<void, void>() == 2);
*/ */
} // namespace utempl::loopholes } // namespace utempl::loopholes

View file

@ -1,30 +1,30 @@
#pragma once #pragma once
#include <utempl/optional.hpp> #include <fmt/compile.h>
#include <fmt/format.h>
#include <array>
#include <iostream>
#include <utempl/constexpr_string.hpp> #include <utempl/constexpr_string.hpp>
#include <utempl/optional.hpp>
#include <utempl/tuple.hpp> #include <utempl/tuple.hpp>
#include <utempl/utils.hpp> #include <utempl/utils.hpp>
#include <iostream>
#include <array>
#include <fmt/format.h>
#include <fmt/compile.h>
namespace utempl { namespace utempl {
constexpr std::size_t CountDigits(std::size_t num) { constexpr auto CountDigits(std::size_t num) -> std::size_t {
std::size_t count = 0; std::size_t count = 0;
do { do { // NOLINT
++count; ++count;
num /= 10; num /= 10; // NOLINT
} while (num != 0); } while(num != 0);
return count; return count;
}; };
constexpr std::size_t GetDigit(std::size_t num, std::size_t index) { constexpr auto GetDigit(std::size_t num, std::size_t index) -> std::size_t {
for (std::size_t i = 0; i < index; ++i) { for(std::size_t i = 0; i < index; ++i) {
num /= 10; num /= 10; // NOLINT
} }
return num % 10; return num % 10; // NOLINT
}; };
template <std::size_t num> template <std::size_t num>
@ -44,7 +44,6 @@ constexpr auto GetMax(Range&& range) {
return response; return response;
}; };
namespace menu { namespace menu {
namespace impl { namespace impl {
@ -53,38 +52,27 @@ template <std::size_t N1, std::size_t N2>
struct CallbackMessage { struct CallbackMessage {
ConstexprString<N1> message; ConstexprString<N1> message;
Optional<ConstexprString<N2>> need; Optional<ConstexprString<N2>> need;
consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) : consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) : // NOLINT
message(std::move(message)) message(std::move(message)), need(std::move(need)) {};
,need(std::move(need)) {}; consteval CallbackMessage(const char (&message)[N1]) : message(std::move(message)), need(std::nullopt) {}; // NOLINT
consteval CallbackMessage(const char (&message)[N1]) :
message(std::move(message))
,need(std::nullopt) {};
}; };
template <std::size_t N1, std::size_t N2> template <std::size_t N1, std::size_t N2>
CallbackMessage(const char(&)[N1], const char(&)[N2]) -> CallbackMessage<N2, N1>; CallbackMessage(const char (&)[N1], const char (&)[N2]) -> CallbackMessage<N2, N1>; // NOLINT
template <std::size_t N1> template <std::size_t N1>
CallbackMessage(const char(&)[N1]) -> CallbackMessage<N1, 0>; CallbackMessage(const char (&)[N1]) -> CallbackMessage<N1, 0>; // NOLINT
} // namespace impl
} // namespace impl
template <Tuple storage = Tuple{}, typename... Fs> template <Tuple storage = Tuple{}, typename... Fs>
struct Menu { struct Menu {
private: private:
template <ConstexprString fmt, ConstexprString message, ConstexprString alignment, ConstexprString neededInput> template <ConstexprString fmt, ConstexprString message, ConstexprString alignment, ConstexprString neededInput>
static consteval auto FormatMessage() { static consteval auto FormatMessage() {
// + 1 - NULL Terminator // + 1 - NULL Terminator
constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin()) constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment) + 1;
,neededInput std::array<char, size> data{};
,message fmt::format_to(data.begin(), FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment);
,alignment) + 1;
char data[size]{};
fmt::format_to(data, FMT_COMPILE(fmt.data.begin())
,neededInput
,message
,alignment);
return ConstexprString<size>(data); return ConstexprString<size>(data);
}; };
template <ConstexprString fmt, std::size_t I> template <ConstexprString fmt, std::size_t I>
@ -97,24 +85,29 @@ private:
return ToString<I>(); return ToString<I>();
}; };
}(); }();
constexpr ConstexprString alignment = CreateStringWith<GetMaxSize() - (Get<I>(storage).need ? Get<I>(storage).need->size() : CountDigits(I))>(' '); constexpr ConstexprString alignment =
CreateStringWith<GetMaxSize() - (Get<I>(storage).need ? Get<I>(storage).need->size() : CountDigits(I))>(' ');
return FormatMessage<fmt, message, alignment, neededInput>(); return FormatMessage<fmt, message, alignment, neededInput>();
}; };
public:
public:
Tuple<Fs...> functionStorage; Tuple<Fs...> functionStorage;
static consteval auto GetMaxSize() -> std::size_t { static consteval auto GetMaxSize() -> std::size_t {
return [&]<auto... Is>(std::index_sequence<Is...>){ return [&]<auto... Is>(std::index_sequence<Is...>) {
constexpr auto list = ListFromTuple(storage); constexpr auto list = ListFromTuple(storage);
return GetMax(std::array{(std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize != 0 ? std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize : CountDigits(Is))...}); return GetMax(std::array{(std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize != 0
? std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize
: CountDigits(Is))...});
}(std::index_sequence_for<Fs...>()); }(std::index_sequence_for<Fs...>());
}; };
template <impl::CallbackMessage message, std::invocable F> template <impl::CallbackMessage message, std::invocable F>
constexpr auto With(F&& f) const { constexpr auto With(F&& f) const {
return Menu<storage + Tuple{message}, Fs..., std::remove_cvref_t<F>>{.functionStorage = this->functionStorage + Tuple(std::forward<F>(f))}; return Menu<storage + Tuple{message}, Fs..., std::remove_cvref_t<F>>{.functionStorage =
this->functionStorage + Tuple(std::forward<F>(f))};
}; };
template <ConstexprString fmt, ConstexprString enter = "|> "> template <ConstexprString fmt, ConstexprString enter = "|> ">
inline constexpr auto Run(std::istream& in = std::cin, std::FILE* out = stdout) const -> std::size_t { constexpr auto Run(std::istream& in = std::cin, std::FILE* out = stdout) const -> std::size_t {
return [&]<auto... Is>(std::index_sequence<Is...>) -> std::size_t { return [&]<auto... Is>(std::index_sequence<Is...>) -> std::size_t {
constexpr auto message = ((FormatMessageFor<fmt, Is>() + ...) + enter); constexpr auto message = ((FormatMessageFor<fmt, Is>() + ...) + enter);
auto result = std::fwrite(message.begin(), 1, message.size(), out); auto result = std::fwrite(message.begin(), 1, message.size(), out);
@ -126,24 +119,23 @@ public:
}; };
std::string input; std::string input;
std::getline(in, input); std::getline(in, input);
([&]<auto I, impl::CallbackMessage message = Get<I>(storage)>(Wrapper<I>) { (
if constexpr(message.need) { [&]<auto I, impl::CallbackMessage message = Get<I>(storage)>(Wrapper<I>) {
if(*message.need == input) { if constexpr(message.need) {
Get<I>(this->functionStorage)(); if(*message.need == input) {
}; Get<I>(this->functionStorage)();
} else { };
if(ToString<I>() == input) { } else {
Get<I>(this->functionStorage)(); if(ToString<I>() == input) {
}; Get<I>(this->functionStorage)();
}; };
}(Wrapper<Is>{}), ...); };
}(Wrapper<Is>{}),
...);
return 0; return 0;
}(std::index_sequence_for<Fs...>()); }(std::index_sequence_for<Fs...>());
}; };
}; };
} // namespace menu } // namespace menu
} // namespace utempl } // namespace utempl

View file

@ -7,37 +7,33 @@ namespace utempl {
namespace impl { namespace impl {
struct Types {}; struct Types {};
} // namespace impl } // namespace impl
template <std::size_t Id, typename Tag> template <std::size_t Id, typename Tag>
struct MetaInfoKey {}; struct MetaInfoKey {};
template <typename T, typename Tag = impl::Types> template <typename T, typename Tag = impl::Types>
struct MetaInfo { struct MetaInfo {
static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>(); static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>();
using Type = T; using Type = T;
private:
private:
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{}; static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
}; };
template <typename T, typename Tag = impl::Types> template <typename T, typename Tag = impl::Types>
inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId; inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId;
template < template <typename Tag,
typename Tag, typename T,
typename T, typename... Ts,
typename... Ts, typename... TTs,
typename... TTs, std::size_t Id = loopholes::Counter<Tag, T, Ts..., TTs...>(),
std::size_t Id = loopholes::Counter<Tag, T, Ts..., TTs...>(), auto = loopholes::Injector<MetaInfoKey<Id, Tag>{}, TypeList<T>{}>{}>
auto = loopholes::Injector<MetaInfoKey<Id, Tag>{}, TypeList<T>{}>{} consteval auto AddTypeToTag(TTs&&...) -> std::size_t {
>
consteval std::size_t AddTypeToTag(TTs&&...) {
return Id; return Id;
}; };
template <std::size_t Id, typename Tag = impl::Types> template <std::size_t Id, typename Tag = impl::Types>
using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>; using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>;
@ -47,12 +43,13 @@ using GetType = GetMetaInfo<Id, Tag>::Type;
namespace impl { namespace impl {
template <typename Tag, std::size_t I = 0, typename... Ts, typename G> template <typename Tag, std::size_t I = 0, typename... Ts, typename G>
static consteval auto GetTypeListForTag(G g) requires (I == 0 || static consteval auto GetTypeListForTag(G g)
requires {Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});}) { requires(I == 0 || requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); })
if constexpr(I == 0 && !requires {Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});}) { {
if constexpr(I == 0 && !requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); }) {
return TypeList{}; return TypeList{};
} else { } else {
if constexpr(requires{GetTypeListForTag<Tag, I + 1, Ts...>(g);}) { if constexpr(requires { GetTypeListForTag<Tag, I + 1, Ts...>(g); }) {
constexpr auto type = Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); constexpr auto type = Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});
return GetTypeListForTag<Tag, I + 1, Ts..., typename decltype(type)::Type>(g); return GetTypeListForTag<Tag, I + 1, Ts..., typename decltype(type)::Type>(g);
} else { } else {
@ -62,24 +59,18 @@ static consteval auto GetTypeListForTag(G g) requires (I == 0 ||
}; };
}; };
} // namespace impl
} // namespace impl
template <typename Tag = impl::Types, typename... Ts> template <typename Tag = impl::Types, typename... Ts>
consteval auto GetTypeListForTag() { consteval auto GetTypeListForTag() {
return impl::GetTypeListForTag<Tag>(TypeList<Ts...>{}); return impl::GetTypeListForTag<Tag>(TypeList<Ts...>{});
}; };
template < template <typename Tag, typename... Ts, auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1>
typename Tag,
typename... Ts,
auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1
>
consteval auto GetCurrentTagType() { consteval auto GetCurrentTagType() {
return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>()); return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>());
}; };
/* /*
static_assert(kTypeId<int> == 0); static_assert(kTypeId<int> == 0);
static_assert(kTypeId<void> == 1); static_assert(kTypeId<void> == 1);
@ -88,5 +79,4 @@ static_assert(std::is_same_v<decltype(GetTypeListForTag()), TypeList<int, void,
*/ */
} // namespace utempl
} // namespace utempl

View file

@ -4,42 +4,42 @@
namespace utempl { namespace utempl {
template <typename T> template <typename T>
struct Optional { struct Optional { // NOLINT
bool flag = false; bool flag = false;
union { union {
char null; char null;
T _value; T _value;
}; };
inline constexpr Optional() = default; constexpr Optional() = default;
inline constexpr Optional(const Optional&) = default; constexpr Optional(const Optional&) = default;
inline constexpr Optional(Optional&&) = default; constexpr Optional(Optional&&) = default;
inline constexpr Optional(T&& arg) : _value(std::move(arg)), flag(true) {}; explicit constexpr Optional(T&& arg) : _value(std::move(arg)), flag(true) {};
inline constexpr Optional(const T& arg) : _value(arg), flag(true) {}; explicit constexpr Optional(const T& arg) : _value(arg), flag(true) {};
inline constexpr Optional(std::nullopt_t) : flag(false), null(0) {}; explicit constexpr Optional(std::nullopt_t) : null(0) {};
inline constexpr auto has_value() const -> bool { [[nodiscard]] constexpr auto has_value() const -> bool {
return this->flag; return this->flag;
}; };
inline constexpr auto value() -> T& { constexpr auto value() -> T& {
return this->_value; return this->_value;
}; };
inline constexpr auto operator*() -> T& { constexpr auto operator*() -> T& {
return this->value(); return this->value();
}; };
inline constexpr auto operator->() -> T* { constexpr auto operator->() -> T* {
return &this->value(); return &this->value();
}; };
inline constexpr auto value() const -> const T& { constexpr auto value() const -> const T& {
return this->_value; return this->_value;
}; };
inline constexpr auto operator*() const -> const T& { constexpr auto operator*() const -> const T& {
return this->value(); return this->value();
}; };
inline constexpr auto operator->() const -> const T* { constexpr auto operator->() const -> const T* {
return &this->value(); return &this->value();
}; };
inline constexpr explicit operator bool() const { constexpr explicit operator bool() const {
return this->has_value(); return this->has_value();
}; };
}; };
} // namespace utempl } // namespace utempl

View file

@ -3,11 +3,11 @@
namespace utempl { namespace utempl {
template <typename... Fs> template <typename... Fs>
inline constexpr auto Overloaded(Fs&&... fs) { constexpr auto Overloaded(Fs&&... fs) {
struct Overloaded : public std::remove_cvref_t<Fs>... { struct Overloaded : public std::remove_cvref_t<Fs>... {
using Fs::operator()...; using Fs::operator()...;
}; };
return Overloaded{std::forward<Fs>(fs)...}; return Overloaded{std::forward<Fs>(fs)...};
}; };
} // namespace utempl } // namespace utempl

View file

@ -6,10 +6,10 @@ struct ReferenceWrapper;
template <typename T> template <typename T>
struct ReferenceWrapper<T&&> { struct ReferenceWrapper<T&&> {
inline constexpr auto operator*() -> T& { constexpr auto operator*() -> T& {
return this->value; return this->value;
}; };
inline constexpr auto operator->() -> T* { constexpr auto operator->() -> T* {
return &this->value; return &this->value;
}; };
T&& value; T&& value;
@ -17,10 +17,10 @@ struct ReferenceWrapper<T&&> {
template <typename T> template <typename T>
struct ReferenceWrapper<const T&> { struct ReferenceWrapper<const T&> {
inline constexpr auto operator*() -> const T& { constexpr auto operator*() -> const T& {
return this->value; return this->value;
}; };
inline constexpr auto operator->() -> const T* { constexpr auto operator->() -> const T* {
return &this->value; return &this->value;
}; };
const T& value; const T& value;
@ -28,14 +28,13 @@ struct ReferenceWrapper<const T&> {
template <typename T> template <typename T>
struct ReferenceWrapper<T&> { struct ReferenceWrapper<T&> {
constexpr auto operator*() -> T& {
inline constexpr auto operator*() -> T& {
return this->value; return this->value;
}; };
inline constexpr auto operator->() -> T* { constexpr auto operator->() -> T* {
return &this->value; return &this->value;
}; };
T& value; T& value;
}; };
} // namespace utempl } // namespace utempl

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <utempl/type_list.hpp>
#include <utempl/overloaded.hpp> #include <utempl/overloaded.hpp>
#include <utempl/type_list.hpp>
namespace utempl { namespace utempl {
template <auto> template <auto>
@ -10,83 +10,86 @@ namespace impl {
template <auto, typename T> template <auto, typename T>
struct TupleLeaf { struct TupleLeaf {
T value; T value;
inline constexpr bool operator==(const TupleLeaf&) const = default; constexpr auto operator==(const TupleLeaf&) const -> bool = default;
}; };
template <typename, typename...> template <typename, typename...>
struct TupleHelper; struct TupleHelper;
template <std::size_t... Is, typename... Ts> template <std::size_t... Is, typename... Ts>
struct TupleHelper<std::index_sequence<Is...>, Ts...> : public impl::TupleLeaf<Is, Ts>... { struct TupleHelper<std::index_sequence<Is...>, Ts...> : public impl::TupleLeaf<Is, Ts>... {
inline constexpr bool operator==(const TupleHelper&) const = default; constexpr auto operator==(const TupleHelper&) const -> bool = default;
}; };
} // namespace impl } // namespace impl
template <typename... Ts> template <typename... Ts>
struct Tuple; struct Tuple;
template <std::size_t I, typename... Ts> template <std::size_t I, typename... Ts>
inline constexpr auto Get(Tuple<Ts...>& tuple) -> auto& requires (I < sizeof...(Ts)) { constexpr auto Get(Tuple<Ts...>& tuple) -> auto&
requires(I < sizeof...(Ts))
{
using Type = decltype(Get<I>(TypeList<Ts...>{})); using Type = decltype(Get<I>(TypeList<Ts...>{}));
return static_cast<impl::TupleLeaf<I, Type>&>(tuple).value; return static_cast<impl::TupleLeaf<I, Type>&>(tuple).value;
}; };
template <std::size_t I, typename... Ts> template <std::size_t I, typename... Ts>
inline constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto& requires (I < sizeof...(Ts)) { constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto&
requires(I < sizeof...(Ts))
{
using Type = decltype(Get<I>(TypeList<Ts...>{})); using Type = decltype(Get<I>(TypeList<Ts...>{}));
return static_cast<const impl::TupleLeaf<I, Type>&>(tuple).value; return static_cast<const impl::TupleLeaf<I, Type>&>(tuple).value;
}; };
template <std::size_t I, typename... Ts> template <std::size_t I, typename... Ts>
inline constexpr auto Get(Tuple<Ts...>&& tuple) -> decltype(auto) requires (I < sizeof...(Ts)) { constexpr auto Get(Tuple<Ts...>&& tuple) -> decltype(auto)
requires(I < sizeof...(Ts))
{
using Type = decltype(Get<I>(TypeList<Ts...>{})); using Type = decltype(Get<I>(TypeList<Ts...>{}));
return std::move(static_cast<impl::TupleLeaf<I, Type>&&>(tuple).value); return std::move(static_cast<impl::TupleLeaf<I, Type>&&>(tuple).value);
}; };
template <std::size_t I, typename T> template <std::size_t I, typename T>
inline constexpr auto Get(T&& arg) -> decltype(get<I>(std::forward<T>(arg))) { constexpr auto Get(T&& arg) -> decltype(get<I>(std::forward<T>(arg))) {
return get<I>(std::forward<T>(arg)); return get<I>(std::forward<T>(arg));
}; };
template <typename... Ts> template <typename... Ts>
struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> { struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
template <typename... TTs> template <typename... TTs>
inline constexpr Tuple(TTs&&... args) : constexpr Tuple(TTs&&... args) /* NOLINT */ : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
template <std::invocable... Fs> template <std::invocable... Fs>
inline constexpr Tuple(Fs&&... fs) requires (!std::invocable<Ts> || ...) : constexpr Tuple(Fs&&... fs) // NOLINT
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{fs()}...} {}; requires(!std::invocable<Ts> || ...)
inline constexpr Tuple(Ts&&... args) : : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{fs()}...} {};
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{args}...} {}; constexpr Tuple(Ts&&... args) : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{args}...} {}; // NOLINT
inline constexpr Tuple(const Tuple&) = default; constexpr Tuple(const Tuple&) = default;
inline constexpr Tuple(Tuple&&) = default; constexpr Tuple(Tuple&&) = default;
inline constexpr Tuple(Tuple&) = default; constexpr Tuple(Tuple&) = default;
inline constexpr Tuple& operator=(const Tuple&) = default; constexpr auto operator=(const Tuple&) -> Tuple& = default;
inline constexpr Tuple& operator=(Tuple&&) = default; constexpr auto operator=(Tuple&&) -> Tuple& = default;
inline constexpr Tuple& operator=(Tuple&) = default; constexpr auto operator=(Tuple&) -> Tuple& = default;
inline constexpr Tuple() : constexpr Tuple() : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>() {};
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>() {}; constexpr auto operator==(const Tuple<Ts...>& other) const -> bool {
inline constexpr bool operator==(const Tuple<Ts...>& other) const { return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
return ((Get<Is>(*this) == Get<Is>(other)) && ...); return ((Get<Is>(*this) == Get<Is>(other)) && ...);
}(std::index_sequence_for<Ts...>()); }(std::index_sequence_for<Ts...>());
}; };
template <typename... TTs> template <typename... TTs>
inline constexpr auto operator+(const Tuple<TTs...>& other) const -> Tuple<Ts..., TTs...> { constexpr auto operator+(const Tuple<TTs...>& other) const -> Tuple<Ts..., TTs...> {
return [&]<std::size_t... Is, std::size_t... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) -> Tuple<Ts..., TTs...> { return [&]<std::size_t... Is, std::size_t... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) -> Tuple<Ts..., TTs...> {
return {Get<Is>(*this)..., Get<IIs>(other)...}; return {Get<Is>(*this)..., Get<IIs>(other)...};
}(std::index_sequence_for<Ts...>(), std::index_sequence_for<TTs...>()); }(std::index_sequence_for<Ts...>(), std::index_sequence_for<TTs...>());
}; };
template <auto I> template <auto I>
inline constexpr auto operator[](Wrapper<I>) const -> const auto& { constexpr auto operator[](Wrapper<I>) const -> const auto& {
return Get<I>(*this); return Get<I>(*this);
}; };
template <auto I> template <auto I>
inline constexpr auto operator[](Wrapper<I>) -> auto& { constexpr auto operator[](Wrapper<I>) -> auto& {
return Get<I>(*this); return Get<I>(*this);
}; };
}; };
@ -94,10 +97,10 @@ struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
template <> template <>
struct Tuple<> { struct Tuple<> {
template <typename... Ts> template <typename... Ts>
inline constexpr auto operator+(const Tuple<Ts...>& other) const -> Tuple<Ts...> { constexpr auto operator+(const Tuple<Ts...>& other) const -> Tuple<Ts...> {
return other; return other;
}; };
inline constexpr auto operator==(const Tuple<>&) const { constexpr auto operator==(const Tuple<>&) const {
return true; return true;
}; };
}; };
@ -109,4 +112,4 @@ consteval auto ListFromTuple(Tuple<Ts...>) -> TypeList<Ts...> {
return {}; return {};
}; };
} // namespace utempl } // namespace utempl

View file

@ -1,10 +1,9 @@
#pragma once #pragma once
#include <concepts>
#include <utility>
#include <array>
#include <utempl/overloaded.hpp>
#include <algorithm> #include <algorithm>
#include <array>
#include <concepts>
#include <utempl/overloaded.hpp>
#include <utility>
namespace utempl { namespace utempl {
@ -24,10 +23,12 @@ inline constexpr auto kTypeList = TypeList<Ts...>{};
template <typename T> template <typename T>
concept IsTypeList = Overloaded( concept IsTypeList = Overloaded(
[]<typename... Ts>(TypeList<TypeList<Ts...>>) {return true;}, []<typename... Ts>(TypeList<TypeList<Ts...>>) {
[](auto&&) {return false;} return true;
)(kType<std::remove_cvref_t<T>>); },
[](auto&&) {
return false;
})(kType<std::remove_cvref_t<T>>);
namespace impl { namespace impl {
@ -40,9 +41,7 @@ struct Caster {};
template <std::size_t... Is, typename... Ts> template <std::size_t... Is, typename... Ts>
struct Caster<std::index_sequence<Is...>, Ts...> : IndexedType<Is, Ts>... {}; struct Caster<std::index_sequence<Is...>, Ts...> : IndexedType<Is, Ts>... {};
} // namespace impl
} // namespace impl
template <typename... Ts, typename... TTs> template <typename... Ts, typename... TTs>
consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool { consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool {
return std::same_as<decltype(first), decltype(second)>; return std::same_as<decltype(first), decltype(second)>;
@ -54,8 +53,7 @@ consteval auto operator+(const TypeList<Ts...>&, const TypeList<TTs...>&) -> Typ
}; };
template <std::size_t I, typename... Ts> template <std::size_t I, typename... Ts>
consteval auto Get(TypeList<Ts...>) -> decltype( consteval auto Get(TypeList<Ts...>) -> decltype([]<typename T>(impl::IndexedType<I, T>&&) -> T {
[]<typename T>(impl::IndexedType<I, T>&&) -> T {
}(impl::Caster<std::index_sequence_for<Ts...>, Ts...>{})); }(impl::Caster<std::index_sequence_for<Ts...>, Ts...>{}));
template <typename T, typename... Ts> template <typename T, typename... Ts>
@ -70,7 +68,6 @@ consteval auto Find(TypeList<Ts...>) -> std::size_t {
return std::ranges::find(arr, true) - arr.begin(); return std::ranges::find(arr, true) - arr.begin();
}; };
template <typename... Ts> template <typename... Ts>
consteval auto Reverse(TypeList<Ts...> list) { consteval auto Reverse(TypeList<Ts...> list) {
return [&]<auto... Is>(std::index_sequence<Is...>) -> TypeList<decltype(Get<sizeof...(Ts) - Is - 1>(list))...> { return [&]<auto... Is>(std::index_sequence<Is...>) -> TypeList<decltype(Get<sizeof...(Ts) - Is - 1>(list))...> {
@ -84,24 +81,20 @@ consteval auto Transform(TypeList<Ts...>, auto&& f) -> TypeList<decltype(f(TypeL
}; };
template <typename... Ts> template <typename... Ts>
consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) { consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) {
return ( return ((kTypeList<> +
(kTypeList<> [](auto&& list) {
+ [](auto&& list) { if constexpr(decltype(f(list))::kValue) {
if constexpr(decltype(f(list))::kValue) { return list;
return list; } else {
} else { return kTypeList<>;
return kTypeList<>; }
} }(kType<Ts>)) +
}(kType<Ts>) ...);
)
+ ...);
}; };
template <typename... Ts> template <typename... Ts>
consteval auto Size(TypeList<Ts...>) -> std::size_t { consteval auto Size(TypeList<Ts...>) -> std::size_t {
return sizeof...(Ts); return sizeof...(Ts);
}; };
} // namespace utempl
} // namespace utempl

View file

@ -1,11 +1,11 @@
#pragma once #pragma once
#include <utempl/tuple.hpp>
#include <utempl/overloaded.hpp>
#include <utempl/constexpr_string.hpp>
#include <ranges>
#include <optional>
#include <fmt/format.h> #include <fmt/format.h>
#include <optional>
#include <ranges>
#include <utempl/constexpr_string.hpp>
#include <utempl/overloaded.hpp>
#include <utempl/tuple.hpp>
namespace utempl { namespace utempl {
@ -15,7 +15,7 @@ struct Wrapper {
inline constexpr auto operator==(auto&& arg) const { inline constexpr auto operator==(auto&& arg) const {
return arg == Value; return arg == Value;
}; };
consteval operator decltype(Value)() const { consteval operator decltype(Value)() const { // NOLINT
return Value; return Value;
}; };
consteval auto operator*() const { consteval auto operator*() const {
@ -32,25 +32,23 @@ 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>&) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>){ return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return std::forward<F>(f)(kWrapper<Is>...); return std::forward<F>(f)(kWrapper<Is>...);
}(std::make_index_sequence<N>()); }(std::make_index_sequence<N>());
}; };
}; };
} // namespace impl } // namespace impl
template <std::size_t N> template <std::size_t N>
inline constexpr impl::kSeq<N> kSeq; inline constexpr impl::kSeq<N> kSeq;
template <ConstexprString string, typename T = std::size_t> template <ConstexprString string, typename T = std::size_t>
consteval auto ParseNumber() -> T { consteval auto ParseNumber() -> T {
T response{}; T response{};
for(const auto& c : string) { for(const auto& c : string) {
if (c >= '0' && c <= '9') { if(c >= '0' && c <= '9') {
response = response * 10 + (c - '0'); response = response * 10 + (c - '0'); // NOLINT
}; };
}; };
return response; return response;
@ -62,10 +60,12 @@ consteval auto operator"" _c() {
return Wrapper<ParseNumber<ConstexprString<sizeof...(cs)>({cs...})>()>{}; return Wrapper<ParseNumber<ConstexprString<sizeof...(cs)>({cs...})>()>{};
}; };
} // namespace literals } // namespace literals
template <std::size_t I, typename... Ts> template <std::size_t I, typename... Ts>
inline constexpr auto Arg(Ts&&... args) -> decltype(auto) requires (I < sizeof...(Ts)) { inline constexpr auto Arg(Ts&&... args) -> decltype(auto)
requires(I < sizeof...(Ts))
{
return [&]<auto... Is>(std::index_sequence<Is...>) -> decltype(auto) { return [&]<auto... Is>(std::index_sequence<Is...>) -> decltype(auto) {
return [](decltype(Caster(Is))..., auto&& response, ...) -> decltype(auto) { return [](decltype(Caster(Is))..., auto&& response, ...) -> decltype(auto) {
return response; return response;
@ -73,10 +73,9 @@ inline constexpr auto Arg(Ts&&... args) -> decltype(auto) requires (I < sizeof..
}(std::make_index_sequence<I>()); }(std::make_index_sequence<I>());
}; };
template <std::size_t Count> template <std::size_t Count>
inline constexpr auto Times(auto&& f) { inline constexpr auto Times(auto&& f) {
[&]<auto... Is>(std::index_sequence<Is...>){ [&]<auto... Is>(std::index_sequence<Is...>) {
(Arg<0>(f, Is)(), ...); (Arg<0>(f, Is)(), ...);
}(std::make_index_sequence<Count>()); }(std::make_index_sequence<Count>());
}; };
@ -87,7 +86,6 @@ inline constexpr std::size_t kTupleSize = []() -> std::size_t {
return 0; return 0;
}(); }();
template <typename T> template <typename T>
inline constexpr std::size_t kTupleSize<T&&> = kTupleSize<std::remove_reference_t<T>>; inline constexpr std::size_t kTupleSize<T&&> = kTupleSize<std::remove_reference_t<T>>;
@ -104,8 +102,7 @@ template <template <typename, std::size_t> typename Array, typename T, std::size
inline constexpr std::size_t kTupleSize<Array<T, N>> = N; inline constexpr std::size_t kTupleSize<Array<T, N>> = N;
template <typename T> template <typename T>
struct TupleMaker { struct TupleMaker {};
};
template <typename... Ts> template <typename... Ts>
struct TupleMaker<std::tuple<Ts...>> { struct TupleMaker<std::tuple<Ts...>> {
@ -125,7 +122,8 @@ template <typename T, std::size_t N>
struct TupleMaker<std::array<T, N>> { struct TupleMaker<std::array<T, N>> {
template <typename Arg, typename... Args> template <typename Arg, typename... Args>
static inline constexpr auto Make(Arg&& arg, Args&&... args) static inline constexpr auto Make(Arg&& arg, Args&&... args)
requires (std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...) { requires(std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...)
{
return std::array{std::forward<Arg>(arg), std::forward<Args>(args)...}; return std::array{std::forward<Arg>(arg), std::forward<Args>(args)...};
}; };
static constexpr auto Make() -> std::array<T, 0> { static constexpr auto Make() -> std::array<T, 0> {
@ -134,8 +132,7 @@ struct TupleMaker<std::array<T, N>> {
}; };
template <typename T> template <typename T>
struct TupleTieMaker { struct TupleTieMaker {};
};
template <typename... Ts> template <typename... Ts>
struct TupleTieMaker<std::tuple<Ts...>> { struct TupleTieMaker<std::tuple<Ts...>> {
@ -157,29 +154,24 @@ template <typename T, std::size_t N>
struct TupleTieMaker<std::array<T, N>> { struct TupleTieMaker<std::array<T, N>> {
template <typename Arg, typename... Args> template <typename Arg, typename... Args>
static inline constexpr auto Make(Arg& arg, Args&... args) -> std::array<Arg&, sizeof...(Args) + 1> 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>> && ...) { requires(std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...)
{
return {arg, args...}; return {arg, args...};
}; };
}; };
template <typename T = Tuple<>, typename... Args> template <typename T = Tuple<>, typename... Args>
inline constexpr auto MakeTuple(Args&&... args) inline constexpr auto MakeTuple(Args&&... args) -> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<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)...);
}; };
template <typename T = Tuple<>, typename... Args> template <typename T = Tuple<>, typename... Args>
inline constexpr auto MakeTie(Args&... args) inline constexpr auto MakeTie(Args&... args) -> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
-> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
return TupleTieMaker<std::remove_cvref_t<T>>::Make(args...); return TupleTieMaker<std::remove_cvref_t<T>>::Make(args...);
}; };
template <typename T> template <typename T>
concept HasMakeTie = requires(int& arg) {MakeTie<T>(arg);}; concept HasMakeTie = requires(int& arg) { MakeTie<T>(arg); };
namespace impl { namespace impl {
@ -188,7 +180,6 @@ struct Getter {
friend consteval auto Magic(Getter<T>); friend consteval auto Magic(Getter<T>);
}; };
template <typename T, auto Insert> template <typename T, auto Insert>
struct Inserter { struct Inserter {
friend consteval auto Magic(Getter<T>) -> decltype(auto) { friend consteval auto Magic(Getter<T>) -> decltype(auto) {
@ -196,7 +187,6 @@ struct Inserter {
}; };
}; };
template <typename T> template <typename T>
struct SafeTupleChecker { struct SafeTupleChecker {
consteval SafeTupleChecker(SafeTupleChecker&&) { consteval SafeTupleChecker(SafeTupleChecker&&) {
@ -218,12 +208,14 @@ struct IsSafeTuple {
}; };
template <typename T> template <typename T>
struct IsSafeTuple<T, bool(TrueF(Get<0>(std::move(Get<0>(Tuple{MakeTuple<T>(0, kSafeTupleChecker<T>)})))) struct IsSafeTuple<
&& Magic(Getter<SafeTupleChecker<T>>{})) ? false : false> { T,
bool(TrueF(Get<0>(std::move(Get<0>(Tuple{MakeTuple<T>(0, kSafeTupleChecker<T>)})))) && Magic(Getter<SafeTupleChecker<T>>{})) ? false
: false> {
static constexpr bool value = false; static constexpr bool value = false;
}; };
} // namespace impl } // namespace impl
template <typename T> template <typename T>
inline constexpr bool kForceEnableTuple = false; inline constexpr bool kForceEnableTuple = false;
@ -231,14 +223,13 @@ inline constexpr bool kForceEnableTuple = false;
template <typename T, std::size_t N> template <typename T, std::size_t N>
inline constexpr bool kForceEnableTuple<std::array<T, N>> = true; inline constexpr bool kForceEnableTuple<std::array<T, N>> = true;
template <typename T> template <typename T>
concept TupleLike = kForceEnableTuple<std::remove_cvref_t<T>> || (requires{Get<0>(MakeTuple<T>(42));} && impl::IsSafeTuple<std::remove_cvref_t<T>>::value); concept TupleLike = kForceEnableTuple<std::remove_cvref_t<T>> ||
(requires { Get<0>(MakeTuple<T>(42)); } && impl::IsSafeTuple<std::remove_cvref_t<T>>::value); // NOLINT
template <typename F, typename Tuple> template <typename F, typename Tuple>
concept TupleTransformer = requires(F f, Tuple&& tuple) { concept TupleTransformer = requires(F f, Tuple&& tuple) {
{f(std::move(tuple))}; { f(std::move(tuple)) };
}; };
template <std::invocable F> template <std::invocable F>
@ -260,41 +251,51 @@ struct LazyTuple {
}; };
template <typename T> template <typename T>
inline constexpr auto operator==(T&& other) inline constexpr auto operator==(T&& other)
requires requires(ResultType result){result == std::forward<T>(other);} { requires requires(ResultType result) { result == std::forward<T>(other); }
{
return (*this)() == other; return (*this)() == other;
}; };
template <typename T> template <typename T>
inline constexpr auto operator==(T&& other) const inline constexpr auto operator==(T&& other) const
requires requires(ResultType result){result == std::forward<T>(other);} { requires requires(ResultType result) { result == std::forward<T>(other); }
{
return (*this)() == other; return (*this)() == other;
}; };
inline constexpr operator std::invoke_result_t<F>() { inline constexpr operator std::invoke_result_t<F>() { // NOLINT
return (*this)(); return (*this)();
}; };
inline constexpr operator std::invoke_result_t<F>() const { inline constexpr operator std::invoke_result_t<F>() const { // NOLINT
return (*this)(); return (*this)();
}; };
template <std::size_t I> template <std::size_t I>
friend inline constexpr auto Get(LazyTuple&& tuple) -> decltype(auto) requires TupleLike<ResultType> { friend inline constexpr auto Get(LazyTuple&& tuple) -> decltype(auto)
requires TupleLike<ResultType>
{
return Get<I>(std::move(tuple)()); return Get<I>(std::move(tuple)());
}; };
template <std::size_t I> template <std::size_t I>
friend inline constexpr auto Get(const LazyTuple&& tuple) -> decltype(auto) requires TupleLike<ResultType> { friend inline constexpr auto Get(const LazyTuple&& tuple) -> decltype(auto)
requires TupleLike<ResultType>
{
return Get<I>(std::move(tuple)()); return Get<I>(std::move(tuple)());
}; };
template <std::size_t I> template <std::size_t I>
friend inline constexpr auto Get(LazyTuple& tuple) -> decltype(auto) requires TupleLike<ResultType> { friend inline constexpr auto Get(LazyTuple& tuple) -> decltype(auto)
requires TupleLike<ResultType>
{
return Get<I>(tuple()); return Get<I>(tuple());
}; };
template <std::size_t I> template <std::size_t I>
friend inline constexpr auto Get(const LazyTuple& tuple) -> decltype(auto) requires TupleLike<ResultType> { friend inline constexpr auto Get(const LazyTuple& tuple) -> decltype(auto)
requires TupleLike<ResultType>
{
return Get<I>(tuple()); return Get<I>(tuple());
}; };
template <typename FF> template <typename FF>
inline constexpr auto operator|(FF&& ff) { inline 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)};
@ -304,21 +305,19 @@ template <std::invocable F>
struct TupleMaker<LazyTuple<F>> { struct TupleMaker<LazyTuple<F>> {
template <typename... Ts> template <typename... Ts>
static inline constexpr auto Make(Ts&&... args) static inline constexpr auto Make(Ts&&... args)
requires requires {TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...);} { requires requires { TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...); }
{
return TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...); return TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...);
}; };
}; };
template <TupleLike Tuple, TupleTransformer<Tuple> FF> template <TupleLike Tuple, TupleTransformer<Tuple> FF>
inline constexpr auto operator|(Tuple&& tuple, FF&& f) { inline constexpr auto operator|(Tuple&& tuple, FF&& f) {
return LazyTuple{ return LazyTuple{[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) {
[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) { return f(std::move(tuple));
return f(std::move(tuple)); }};
}};
}; };
template <TupleLike Tuple, typename F> template <TupleLike Tuple, typename 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) {
@ -328,24 +327,21 @@ inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
template <typename F> template <typename F>
inline constexpr auto Unpack(F&& f) { inline 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) {
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, typename R = Tuple, typename F>
inline constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) { inline constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) {
return Unpack(std::forward<Tuple>(container), return Unpack(std::forward<Tuple>(container), [&]<typename... Ts>(Ts&&... args) {
[&]<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 = {}) { inline 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 Tuple>(Tuple&& tuple) {
if constexpr(!std::is_same_v<R, void>) { if constexpr(!std::is_same_v<R, void>) {
return Transform(std::forward<Tuple>(tuple), std::move(f), result); return Transform(std::forward<Tuple>(tuple), std::move(f), result);
} else { } else {
@ -354,7 +350,6 @@ inline constexpr auto Transform(F&& f, TypeList<R> result = {}) {
}; };
}; };
template <TupleLike Tuple, typename R = Tuple, typename F> template <TupleLike Tuple, typename R = Tuple, typename F>
inline constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> result = {}) { inline 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);
@ -378,7 +373,6 @@ consteval auto PackConstexprWrapper() {
}(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) { inline constexpr auto Reverse(Tuple&& tuple) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) { return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
@ -413,19 +407,14 @@ struct LeftFold<T, F> {
}; };
}; };
} // namespace impl
} // namespace impl
template <TupleLike Tuple, typename T, typename F> template <TupleLike Tuple, typename T, typename F>
inline constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f) { inline 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 ( return (impl::LeftFold<std::remove_cvref_t<T>, std::remove_cvref_t<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)} | ... |
impl::LeftFold<std::remove_cvref_t<T>, std::remove_cvref_t<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)} impl::LeftFold<std::remove_cvref_t<Ts>>{.data = std::forward<Ts>(args)})
| ... .data;
| impl::LeftFold<std::remove_cvref_t<Ts>>{.data = std::forward<Ts>(args)}
).data;
}); });
}; };
@ -436,27 +425,27 @@ inline constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) {
template <typename T, typename F> template <typename T, typename F>
inline constexpr auto Reduce(T&& init, F&& f) { inline 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) {
return Reduce(std::forward<Tuple>(tuple), std::move(init), std::move(f)); return Reduce(std::forward<Tuple>(tuple), std::move(init), std::move(f));
}; };
}; };
template <TupleLike Tuple, TupleLike Tuple2> template <TupleLike Tuple, TupleLike Tuple2>
inline constexpr auto TupleCat(Tuple&& tuple, Tuple2&& tuple2) { inline constexpr auto TupleCat(Tuple&& tuple, Tuple2&& tuple2) {
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>){ return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) {
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))..., Get<IIs>(std::forward<Tuple2>(tuple2))...); return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))..., Get<IIs>(std::forward<Tuple2>(tuple2))...);
}(std::make_index_sequence<kTupleSize<Tuple>>(), std::make_index_sequence<kTupleSize<Tuple2>>()); }(std::make_index_sequence<kTupleSize<Tuple>>(), std::make_index_sequence<kTupleSize<Tuple2>>());
}; };
template <TupleLike... Tuples> template <TupleLike... Tuples>
inline constexpr auto TupleCat(Tuples&&... tuples) requires (sizeof...(tuples) >= 1) { inline constexpr auto TupleCat(Tuples&&... tuples)
return LeftFold( requires(sizeof...(tuples) >= 1)
Tuple{std::forward<Tuples>(tuples)...}, {
MakeTuple<decltype(Arg<0>(std::forward<Tuples>(tuples)...))>(), return LeftFold(Tuple{std::forward<Tuples>(tuples)...},
[]<TupleLike Tup, TupleLike Tup2>(Tup&& tup, Tup2&& tup2){ MakeTuple<decltype(Arg<0>(std::forward<Tuples>(tuples)...))>(),
return TupleCat(std::forward<Tup>(tup), std::forward<Tup2>(tup2)); []<TupleLike Tup, TupleLike Tup2>(Tup&& tup, Tup2&& tup2) {
}); return TupleCat(std::forward<Tup>(tup), std::forward<Tup2>(tup2));
});
}; };
template <TupleLike... Tuples, typename F> template <TupleLike... Tuples, typename F>
@ -464,7 +453,6 @@ inline constexpr auto Unpack(Tuples&&... tuples, F&& f) {
return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f)); return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f));
}; };
template <typename... Ts> template <typename... Ts>
inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> { inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
return {args...}; return {args...};
@ -472,8 +460,8 @@ inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
template <template <typename...> typename F, TupleLike Tuple> template <template <typename...> typename F, TupleLike Tuple>
inline constexpr bool kEveryElement = [](auto... is) { inline constexpr bool kEveryElement = [](auto... is) {
return (F<std::decay_t<decltype(Get<is>(std::declval<Tuple>()))>>::value && ...); return (F<std::decay_t<decltype(Get<is>(std::declval<Tuple>()))>>::value && ...);
} | kSeq<kTupleSize<Tuple>>; } | kSeq<kTupleSize<Tuple>>;
template <template <typename...> typename F, typename... Ts> template <template <typename...> typename F, typename... Ts>
struct PartialCaller { struct PartialCaller {
@ -482,25 +470,21 @@ struct PartialCaller {
}; };
template <template <typename...> typename F, typename... Ts> template <template <typename...> typename F, typename... Ts>
consteval auto PartialCallerF(TypeList<Ts...>) { consteval auto PartialCallerF(TypeList<Ts...>) {
return []<typename... TTs>(TypeList<TTs...>){ return []<typename... TTs>(TypeList<TTs...>) {
return F<Ts..., TTs...>{}; return F<Ts..., TTs...>{};
}; };
}; };
template <TupleLike Tuple, typename T> template <TupleLike Tuple, typename T>
inline constexpr auto FirstOf(Tuple&& tuple, T&& init) requires kEveryElement<std::is_invocable, Tuple> { inline constexpr auto FirstOf(Tuple&& tuple, T&& init)
return LeftFold( requires kEveryElement<std::is_invocable, Tuple>
std::forward<Tuple>(tuple), {
std::forward<T>(init), return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), []<typename TT, typename F>(TT&& value, F&& f) -> TT {
[]<typename TT, typename F>(TT&& value, F&& f) -> TT { if(value) {
if(value) { return value;
return value; };
}; return f();
return f(); });
}
);
}; };
template <typename T> template <typename T>
@ -510,48 +494,43 @@ inline constexpr auto FirstOf(T&& init) {
}; };
}; };
template <TupleLike Tuple> template <TupleLike Tuple>
inline constexpr auto Filter(Tuple&& tuple, auto&& f) { inline constexpr auto Filter(Tuple&& tuple, auto&& f) {
return LeftFold( return LeftFold(
std::forward<Tuple>(tuple), std::forward<Tuple>(tuple), MakeTuple<Tuple>(), [&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
MakeTuple<Tuple>(), if constexpr(decltype(f(std::forward<T>(add))){}) {
[&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) { return TupleCat(std::forward<Accumulator>(accumulator), std::forward<T>(add));
if constexpr(decltype(f(std::forward<T>(add))){}) { } else {
return TupleCat(std::forward<Accumulator>(accumulator), std::forward<T>(add)); return accumulator;
} else { };
return accumulator; });
};
}
);
}; };
template <typename F> template <typename F>
inline constexpr auto Filter(F&& f) { inline 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) {
return Filter(std::forward<Tuple>(tuple), std::move(f)); return Filter(std::forward<Tuple>(tuple), std::move(f));
}; };
}; };
template <TupleLike Tuple> template <TupleLike Tuple>
inline constexpr auto ForEach(Tuple&& tuple, auto&& f) { inline constexpr auto ForEach(Tuple&& tuple, auto&& 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)), ...);
}); });
}; };
template <typename F, typename... Ts> template <typename F, typename... Ts>
struct Curryer { struct Curryer {
F f; F f;
Tuple<Ts...> data; Tuple<Ts...> data;
inline constexpr operator std::invoke_result_t<F, Ts...>() const { inline constexpr operator std::invoke_result_t<F, Ts...>() const { // NOLINT
return [&]<auto... Is>(std::index_sequence<Is...>){ return [&]<auto... Is>(std::index_sequence<Is...>) {
return this->f(Get<Is>(this->data)...); return this->f(Get<Is>(this->data)...);
}(std::index_sequence_for<Ts...>()); }(std::index_sequence_for<Ts...>());
}; };
template <typename T> template <typename T>
inline constexpr auto operator()(T&& arg) const -> Curryer<F, Ts..., std::remove_cvref_t<T>>{ inline constexpr auto operator()(T&& arg) const -> Curryer<F, Ts..., std::remove_cvref_t<T>> {
return {.f = this->f, .data = this->data + Tuple{std::forward<T>(arg)}}; return {.f = this->f, .data = this->data + Tuple{std::forward<T>(arg)}};
}; };
}; };
@ -565,22 +544,21 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) { return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
using Type = std::remove_cvref_t<T>; using Type = std::remove_cvref_t<T>;
std::array<bool, kTupleSize<Tuple>> bs{Overloaded( std::array<bool, kTupleSize<Tuple>> bs{Overloaded(
[&](const Type& element) { [&](const Type& element) {
return element == find; return element == find;
}, },
[&](const Type&& element) { [&](const Type&& element) {
return element == find; return element == find;
}, },
[&](Type&& element) { [&](Type&& element) {
return element == find; return element == find;
}, },
[&](Type& element) { [&](Type& element) {
return element == find; return element == find;
}, },
[](auto&&) { [](auto&&) {
return false; return false;
} })(std::forward<Ts>(args))...};
)(std::forward<Ts>(args))...};
return std::ranges::find(bs, true) - bs.begin(); return std::ranges::find(bs, true) - bs.begin();
}); });
}; };
@ -588,11 +566,11 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
template <std::size_t N, TupleLike Tuple> template <std::size_t N, TupleLike Tuple>
inline constexpr auto Take(Tuple&& tuple) { inline constexpr auto Take(Tuple&& tuple) {
if constexpr(std::is_lvalue_reference_v<Tuple> && HasMakeTie<Tuple>) { if constexpr(std::is_lvalue_reference_v<Tuple> && HasMakeTie<Tuple>) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>){ return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return MakeTie<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...); return MakeTie<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...);
}(std::make_index_sequence<N>()); }(std::make_index_sequence<N>());
} else { } else {
return [&]<std::size_t... Is>(std::index_sequence<Is...>){ return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...); return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...);
}(std::make_index_sequence<N>()); }(std::make_index_sequence<N>());
}; };
@ -600,14 +578,14 @@ inline constexpr auto Take(Tuple&& tuple) {
template <std::size_t N> template <std::size_t N>
consteval auto Take() { consteval auto Take() {
return [&]<TupleLike Tuple>(Tuple&& tuple){ return [&]<TupleLike Tuple>(Tuple&& tuple) {
return Take<N>(std::forward<Tuple>(tuple)); return Take<N>(std::forward<Tuple>(tuple));
}; };
}; };
template <TupleLike Tuple, typename T> template <TupleLike Tuple, typename 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));
}); });
}; };
@ -619,5 +597,4 @@ inline constexpr auto Generate(T&& value) {
} | kSeq<N>; } | kSeq<N>;
}; };
} // namespace utempl
} // namespace utempl