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 } // namespace impl
template <typename T, typename..., auto f = [] {}, auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()>
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,14 +44,11 @@ struct FieldAttributeData<> {
using Type = NoInfo; using Type = NoInfo;
}; };
template <typename T,
template <
typename T,
typename... Ts, typename... Ts,
auto f = [] {}, auto f = [] {},
typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type, typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type,
auto = AddTypeToTag<impl::AttributesCounterTag<Current>, typename FieldAttributeData<Ts...>::Type, decltype(f)>() auto = AddTypeToTag<impl::AttributesCounterTag<Current>, typename FieldAttributeData<Ts...>::Type, decltype(f)>()>
>
consteval auto FieldAttribute() -> T; consteval auto FieldAttribute() -> T;
} // namespace impl } // namespace impl
@ -75,8 +56,9 @@ consteval auto FieldAttribute() -> T;
template <typename... Ts> template <typename... Ts>
using FieldAttribute = decltype(impl::FieldAttribute<Ts...>()); using FieldAttribute = decltype(impl::FieldAttribute<Ts...>());
#define ATTRIBUTE_STRUCT(name, ...) /* NOLINT */ \
#define ATTRIBUTE_STRUCT(name, ...) struct name { \ \
struct name { \
static_assert(::utempl::OpenStruct<name>()); \ static_assert(::utempl::OpenStruct<name>()); \
template <std::size_t N> \ template <std::size_t N> \
static consteval auto GetAttribute(); \ static consteval auto GetAttribute(); \
@ -84,35 +66,26 @@ static consteval auto GetAttribute(); \
static_assert(::utempl::CloseStruct()); \ static_assert(::utempl::CloseStruct()); \
} }
#define GENERIC_ATTRIBUTE(value) /* NOLINT */ \
#define GENERIC_ATTRIBUTE(value) \
template <> \ template <> \
consteval auto GetAttribute< \ consteval auto GetAttribute<::utempl::loopholes::Counter< \
::utempl::loopholes::Counter< \ ::utempl::impl::AttributesCounterTag<decltype(::utempl::GetCurrentTagType<::utempl::impl::AttributesTag, decltype([] {})>())::Type>, \
::utempl::impl::AttributesCounterTag<decltype(::utempl::GetCurrentTagType< \ decltype([] {})>()>() { \
::utempl::impl::AttributesTag, \ return value; \
decltype([]{}) \ }
>())::Type \
>, \
decltype([]{}) >()>() { return value; }
#define SKIP_ATTRIBUTE() GENERIC_ATTRIBUTE(::utempl::NoInfo{}) #define SKIP_ATTRIBUTE() /* NOLINT */ GENERIC_ATTRIBUTE(::utempl::NoInfo{})
template <typename T, auto f = [] {}, bool R = (loopholes::CountValue<impl::AttributesCounterTag<T>, decltype(f)>() > 0)>
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,5 +1,6 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <algorithm> #include <algorithm>
namespace utempl { namespace utempl {
@ -12,7 +13,7 @@ struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std
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,9 +9,10 @@ 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 {
@ -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 {
@ -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);

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,7 +119,8 @@ 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>) { (
[&]<auto I, impl::CallbackMessage message = Get<I>(storage)>(Wrapper<I>) {
if constexpr(message.need) { if constexpr(message.need) {
if(*message.need == input) { if(*message.need == input) {
Get<I>(this->functionStorage)(); Get<I>(this->functionStorage)();
@ -136,14 +130,12 @@ public:
Get<I>(this->functionStorage)(); 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

@ -9,15 +9,14 @@ 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>{}>{};
}; };
@ -25,19 +24,16 @@ private:
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,8 +43,9 @@ 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 {
@ -62,7 +59,6 @@ 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>
@ -70,16 +66,11 @@ 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,40 +4,40 @@
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();
}; };
}; };

View file

@ -3,7 +3,7 @@
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()...;
}; };

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,11 +28,10 @@ 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;

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,16 +10,15 @@ 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
@ -28,65 +27,69 @@ 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;
}; };
}; };

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,8 +41,6 @@ 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 {
@ -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 {
@ -43,14 +43,12 @@ struct kSeq {
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;
@ -65,7 +63,9 @@ consteval auto operator"" _c() {
} // 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,7 +73,6 @@ 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...>) {
@ -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,27 +154,22 @@ 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); };
@ -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,8 +208,10 @@ 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;
}; };
@ -231,10 +223,9 @@ 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) {
@ -260,36 +251,46 @@ 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>
@ -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) {
@ -333,12 +332,9 @@ inline constexpr auto Unpack(F&& 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))...);
}); });
}; };
@ -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;
}); });
}; };
@ -441,7 +430,6 @@ inline constexpr auto Reduce(T&& init, F&& 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...>) {
@ -450,9 +438,10 @@ inline constexpr auto TupleCat(Tuple&& tuple, Tuple2&& 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)...}, {
return LeftFold(Tuple{std::forward<Tuples>(tuples)...},
MakeTuple<decltype(Arg<0>(std::forward<Tuples>(tuples)...))>(), MakeTuple<decltype(Arg<0>(std::forward<Tuples>(tuples)...))>(),
[]<TupleLike Tup, TupleLike Tup2>(Tup&& tup, Tup2&& tup2) { []<TupleLike Tup, TupleLike Tup2>(Tup&& tup, Tup2&& tup2) {
return TupleCat(std::forward<Tup>(tup), std::forward<Tup2>(tup2)); return TupleCat(std::forward<Tup>(tup), std::forward<Tup2>(tup2));
@ -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...};
@ -487,20 +475,16 @@ consteval auto PartialCallerF(TypeList<Ts...>) {
}; };
}; };
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,20 +494,16 @@ 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>(),
[&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
if constexpr(decltype(f(std::forward<T>(add))){}) { if constexpr(decltype(f(std::forward<T>(add))){}) {
return TupleCat(std::forward<Accumulator>(accumulator), std::forward<T>(add)); return TupleCat(std::forward<Accumulator>(accumulator), std::forward<T>(add));
} else { } else {
return accumulator; return accumulator;
}; };
} });
);
}; };
template <typename F> template <typename F>
@ -540,12 +520,11 @@ inline constexpr auto ForEach(Tuple&& tuple, auto&& f) {
}); });
}; };
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...>());
@ -579,8 +558,7 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
}, },
[](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();
}); });
}; };
@ -619,5 +597,4 @@ inline constexpr auto Generate(T&& value) {
} | kSeq<N>; } | kSeq<N>;
}; };
} // namespace utempl } // namespace utempl