Add .clang-format, .clang-tidy and fixes
This commit is contained in:
parent
fd61eb5341
commit
9982b60400
15 changed files with 404 additions and 481 deletions
13
.clang-format
Normal file
13
.clang-format
Normal 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
1
.clang-tidy
Normal file
|
@ -0,0 +1 @@
|
|||
Checks: '-*,google-*,cppcoreguidelines-*,-cppcoreguidelines-c-copy-assignment-signature,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-avoid-const-or-ref-data-members,modernize-*'
|
|
@ -2,11 +2,8 @@
|
|||
#include <utempl/meta_info.hpp>
|
||||
#include <utempl/utils.hpp>
|
||||
|
||||
|
||||
namespace utempl {
|
||||
|
||||
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct AttributesTag {};
|
||||
|
@ -14,40 +11,27 @@ struct AttributesTag {};
|
|||
template <typename T>
|
||||
struct AttributesCounterTag {};
|
||||
|
||||
|
||||
|
||||
} // 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 {
|
||||
return true;
|
||||
};
|
||||
|
||||
template <
|
||||
typename...,
|
||||
template <typename...,
|
||||
auto f = [] {},
|
||||
auto I = loopholes::CountValue<impl::AttributesTag, decltype(f)>(),
|
||||
auto II = (I >= 2) ? I - 2 : I - 1,
|
||||
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 {
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct NoInfo {
|
||||
consteval auto operator==(const NoInfo&) const -> bool = default;
|
||||
};
|
||||
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <typename... Ts>
|
||||
|
@ -60,14 +44,11 @@ struct FieldAttributeData<> {
|
|||
using Type = NoInfo;
|
||||
};
|
||||
|
||||
|
||||
template <
|
||||
typename T,
|
||||
template <typename T,
|
||||
typename... Ts,
|
||||
auto f = [] {},
|
||||
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;
|
||||
|
||||
} // namespace impl
|
||||
|
@ -75,8 +56,9 @@ consteval auto FieldAttribute() -> T;
|
|||
template <typename... Ts>
|
||||
using FieldAttribute = decltype(impl::FieldAttribute<Ts...>());
|
||||
|
||||
|
||||
#define ATTRIBUTE_STRUCT(name, ...) struct name { \
|
||||
#define ATTRIBUTE_STRUCT(name, ...) /* NOLINT */ \
|
||||
\
|
||||
struct name { \
|
||||
static_assert(::utempl::OpenStruct<name>()); \
|
||||
template <std::size_t N> \
|
||||
static consteval auto GetAttribute(); \
|
||||
|
@ -84,35 +66,26 @@ static consteval auto GetAttribute(); \
|
|||
static_assert(::utempl::CloseStruct()); \
|
||||
}
|
||||
|
||||
|
||||
#define GENERIC_ATTRIBUTE(value) \
|
||||
#define GENERIC_ATTRIBUTE(value) /* NOLINT */ \
|
||||
template <> \
|
||||
consteval auto GetAttribute< \
|
||||
::utempl::loopholes::Counter< \
|
||||
::utempl::impl::AttributesCounterTag<decltype(::utempl::GetCurrentTagType< \
|
||||
::utempl::impl::AttributesTag, \
|
||||
decltype([]{}) \
|
||||
>())::Type \
|
||||
>, \
|
||||
decltype([]{}) >()>() { return value; }
|
||||
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{})
|
||||
#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;
|
||||
|
||||
template <typename T>
|
||||
concept HasMacroAttributes = requires { T::template GetAttribute<0>(); };
|
||||
|
||||
|
||||
|
||||
template <HasAttributes T>
|
||||
consteval auto GetAttributes() requires HasMacroAttributes<T> {
|
||||
consteval auto GetAttributes()
|
||||
requires HasMacroAttributes<T>
|
||||
{
|
||||
constexpr auto I = loopholes::CountValue<impl::AttributesCounterTag<T>>();
|
||||
return [](auto... is) {
|
||||
return Tuple{T::template GetAttribute<is>()...};
|
||||
|
@ -127,7 +100,4 @@ consteval auto GetAttributes() {
|
|||
} | kSeq<I>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace utempl
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace utempl {
|
||||
|
@ -12,7 +13,7 @@ struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std
|
|||
constexpr auto parse(format_parse_context& ctx) const {
|
||||
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);
|
||||
};
|
||||
};
|
||||
|
@ -22,66 +23,66 @@ namespace utempl {
|
|||
template <std::size_t Size>
|
||||
struct ConstexprString {
|
||||
std::array<char, Size> data;
|
||||
inline constexpr auto begin() -> char* {
|
||||
constexpr auto begin() -> char* {
|
||||
return this->data.begin();
|
||||
};
|
||||
inline constexpr auto begin() const -> const char* {
|
||||
[[nodiscard]] constexpr auto begin() const -> const char* {
|
||||
return this->data.begin();
|
||||
};
|
||||
inline constexpr auto end() -> char* {
|
||||
[[nodiscard]] constexpr auto end() -> char* {
|
||||
return this->data.end();
|
||||
};
|
||||
inline constexpr auto end() const -> const char* {
|
||||
[[nodiscard]] constexpr auto end() const -> const char* {
|
||||
return this->data.end();
|
||||
};
|
||||
static constexpr auto kSize = Size == 0 ? 0 : Size - 1;
|
||||
inline constexpr ConstexprString() = default;
|
||||
inline constexpr ConstexprString(const char (&data)[Size]) : data{} {
|
||||
explicit constexpr ConstexprString() = default;
|
||||
constexpr ConstexprString(const char (&data)[Size]) : data{} { // NOLINT
|
||||
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());
|
||||
};
|
||||
inline constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {};
|
||||
inline constexpr auto size() const {
|
||||
explicit constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {};
|
||||
constexpr auto size() const {
|
||||
return Size == 0 ? 0 : Size - 1;
|
||||
};
|
||||
inline constexpr operator std::string_view() const & {
|
||||
constexpr operator std::string_view() const& { // NOLINT
|
||||
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;
|
||||
};
|
||||
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);
|
||||
};
|
||||
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;
|
||||
};
|
||||
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;
|
||||
};
|
||||
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;
|
||||
std::ranges::copy_n(this->begin(), Size - 1, response.begin());
|
||||
std::ranges::copy_n(other.begin(), SSize, response.begin() + Size - 1);
|
||||
return response;
|
||||
};
|
||||
inline constexpr ConstexprString(const ConstexprString&) = default;
|
||||
inline constexpr ConstexprString(ConstexprString&&) = default;
|
||||
constexpr ConstexprString(const ConstexprString&) = default;
|
||||
constexpr ConstexprString(ConstexprString&&) = default;
|
||||
};
|
||||
|
||||
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);
|
||||
return stream;
|
||||
};
|
||||
|
||||
template <std::size_t Count>
|
||||
inline constexpr auto CreateStringWith(char c) {
|
||||
ConstexprString<Count + 1> str = {};
|
||||
constexpr auto CreateStringWith(char c) {
|
||||
ConstexprString<Count + 1> str{};
|
||||
for(std::size_t i = 0; i < Count; i++) {
|
||||
str.data[i] = c;
|
||||
};
|
||||
|
@ -89,8 +90,6 @@ inline constexpr auto CreateStringWith(char c) {
|
|||
return str;
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t Size>
|
||||
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>;
|
||||
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>; // NOLINT
|
||||
} // namespace utempl
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <utempl/constexpr_string.hpp>
|
||||
#include <boost/pfr.hpp>
|
||||
#include <type_traits>
|
||||
#include <utempl/constexpr_string.hpp>
|
||||
|
||||
namespace utempl {
|
||||
|
||||
|
@ -12,7 +12,7 @@ consteval auto FindField() -> std::size_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));
|
||||
};
|
||||
|
||||
|
@ -21,76 +21,76 @@ struct EmptyField {};
|
|||
|
||||
namespace impl {
|
||||
|
||||
|
||||
template <ConstexprString name, typename T>
|
||||
inline constexpr auto TryGet(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>>) {
|
||||
constexpr auto TryGet(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>>)
|
||||
{
|
||||
constexpr auto I = FindField<name, T>();
|
||||
return boost::pfr::get<I>(std::forward<T>(arg));
|
||||
};
|
||||
template <ConstexprString name, typename T>
|
||||
inline constexpr auto TryGet(T&& arg) {
|
||||
constexpr auto TryGet(T&& arg) {
|
||||
return EmptyField<name>{};
|
||||
};
|
||||
|
||||
|
||||
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 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>>());
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
struct DefaultFieldTransformer {
|
||||
inline constexpr auto operator()(auto&& arg) -> auto&& {
|
||||
constexpr auto operator()(auto&& arg) -> auto&& {
|
||||
return arg;
|
||||
};
|
||||
inline constexpr auto operator()(auto& arg) -> auto& {
|
||||
constexpr auto operator()(auto& arg) -> auto& {
|
||||
return arg;
|
||||
};
|
||||
template <ConstexprString str>
|
||||
inline constexpr auto operator()(EmptyField<str> arg) {
|
||||
constexpr auto operator()(EmptyField<str> arg) {
|
||||
static_assert(str == "This Field Not Found");
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Value, typename Transformer = DefaultFieldTransformer>
|
||||
struct GoInterface : Value {
|
||||
inline constexpr GoInterface(Value&& value) :
|
||||
Value(std::move(value)) {};
|
||||
inline constexpr GoInterface(const Value& value) :
|
||||
Value(value) {};
|
||||
constexpr GoInterface(Value&& value) : Value(std::move(value)) {}; // NOLINT
|
||||
constexpr GoInterface(const Value& value) : Value(value) {}; // NOLINT
|
||||
template <typename T>
|
||||
inline constexpr GoInterface(T&& value) :
|
||||
Value(impl::Transform<Value>(Transformer{}, std::forward<T>(value))) {};
|
||||
inline constexpr auto operator=(const GoInterface&) -> GoInterface& = default;
|
||||
inline constexpr auto operator=(GoInterface&&) -> GoInterface& = default;
|
||||
inline constexpr auto operator==(const Value& other) const -> bool
|
||||
requires requires(const Value& a){a == a;} {
|
||||
constexpr GoInterface(T&& value) : Value(impl::Transform<Value>(Transformer{}, std::forward<T>(value))){}; // NOLINT
|
||||
constexpr auto operator=(const GoInterface&) -> GoInterface& = default;
|
||||
constexpr auto operator=(GoInterface&&) -> GoInterface& = default;
|
||||
constexpr auto operator==(const Value& other) const -> bool
|
||||
requires requires(const Value& a) { a == a; }
|
||||
{
|
||||
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);
|
||||
};
|
||||
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...>) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
Transformer transformer;
|
||||
// + 1 - NULL Terminator
|
||||
return ((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))) && ...);
|
||||
return (
|
||||
(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>>());
|
||||
};
|
||||
template <typename T>
|
||||
inline constexpr auto operator==(T&& other) const -> bool
|
||||
requires (requires(const Value& value){value == other;}) {
|
||||
constexpr auto operator==(T&& other) const -> bool
|
||||
requires(requires(const Value& value) { value == other; })
|
||||
{
|
||||
return static_cast<const Value&>(*this) == other;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace utempl
|
||||
|
||||
|
|
|
@ -9,9 +9,10 @@ struct Getter {
|
|||
};
|
||||
template <auto I, auto Value = 0>
|
||||
struct Injector {
|
||||
friend constexpr auto Magic(Getter<I>) {return Value;};
|
||||
friend constexpr auto Magic(Getter<I>) {
|
||||
return Value;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <auto, typename = void, typename... Ts>
|
||||
struct InjectedImpl {
|
||||
|
@ -25,7 +26,4 @@ struct InjectedImpl<V, std::void_t<decltype(Magic(Getter<V>{}))>, Ts...> {
|
|||
template <auto I, typename... Ts>
|
||||
concept Injected = InjectedImpl<I, void, Ts...>::value;
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace utempl::loopholes
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <utempl/loopholes/core.hpp>
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <utempl/loopholes/core.hpp>
|
||||
|
||||
namespace utempl::loopholes {
|
||||
|
||||
|
@ -22,32 +22,20 @@ consteval auto Counter() -> std::size_t {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
} // namespace impl;
|
||||
} // namespace impl
|
||||
|
||||
// For incerement counter need a unique Ts...
|
||||
template <
|
||||
typename Tag,
|
||||
typename... Ts,
|
||||
std::size_t R = impl::Counter<true, Tag, 0, Ts...>()
|
||||
>
|
||||
template <typename Tag, typename... Ts, std::size_t R = impl::Counter<true, Tag, 0, Ts...>()>
|
||||
consteval auto Counter(auto...) -> std::size_t {
|
||||
return R;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Without increment
|
||||
template <
|
||||
typename Tag,
|
||||
typename... Ts,
|
||||
std::size_t R = impl::Counter<false, Tag, 0, Ts...>()
|
||||
>
|
||||
template <typename Tag, typename... Ts, std::size_t R = impl::Counter<false, Tag, 0, Ts...>()>
|
||||
consteval auto CountValue(auto...) -> std::size_t {
|
||||
return R;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
static_assert(Counter<void>() == 0);
|
||||
static_assert(Counter<void, void>() == 1);
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
#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/optional.hpp>
|
||||
#include <utempl/tuple.hpp>
|
||||
#include <utempl/utils.hpp>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/compile.h>
|
||||
|
||||
|
||||
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;
|
||||
do {
|
||||
do { // NOLINT
|
||||
++count;
|
||||
num /= 10;
|
||||
num /= 10; // NOLINT
|
||||
} while(num != 0);
|
||||
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) {
|
||||
num /= 10;
|
||||
num /= 10; // NOLINT
|
||||
}
|
||||
return num % 10;
|
||||
return num % 10; // NOLINT
|
||||
};
|
||||
|
||||
template <std::size_t num>
|
||||
|
@ -44,7 +44,6 @@ constexpr auto GetMax(Range&& range) {
|
|||
return response;
|
||||
};
|
||||
|
||||
|
||||
namespace menu {
|
||||
|
||||
namespace impl {
|
||||
|
@ -53,38 +52,27 @@ template <std::size_t N1, std::size_t N2>
|
|||
struct CallbackMessage {
|
||||
ConstexprString<N1> message;
|
||||
Optional<ConstexprString<N2>> need;
|
||||
consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) :
|
||||
message(std::move(message))
|
||||
,need(std::move(need)) {};
|
||||
consteval CallbackMessage(const char (&message)[N1]) :
|
||||
message(std::move(message))
|
||||
,need(std::nullopt) {};
|
||||
consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) : // NOLINT
|
||||
message(std::move(message)), need(std::move(need)) {};
|
||||
consteval CallbackMessage(const char (&message)[N1]) : message(std::move(message)), need(std::nullopt) {}; // NOLINT
|
||||
};
|
||||
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>
|
||||
CallbackMessage(const char(&)[N1]) -> CallbackMessage<N1, 0>;
|
||||
CallbackMessage(const char (&)[N1]) -> CallbackMessage<N1, 0>; // NOLINT
|
||||
|
||||
} // namespace impl
|
||||
|
||||
|
||||
|
||||
template <Tuple storage = Tuple{}, typename... Fs>
|
||||
struct Menu {
|
||||
private:
|
||||
template <ConstexprString fmt, ConstexprString message, ConstexprString alignment, ConstexprString neededInput>
|
||||
static consteval auto FormatMessage() {
|
||||
// + 1 - NULL Terminator
|
||||
constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin())
|
||||
,neededInput
|
||||
,message
|
||||
,alignment) + 1;
|
||||
char data[size]{};
|
||||
fmt::format_to(data, FMT_COMPILE(fmt.data.begin())
|
||||
,neededInput
|
||||
,message
|
||||
,alignment);
|
||||
constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment) + 1;
|
||||
std::array<char, size> data{};
|
||||
fmt::format_to(data.begin(), FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment);
|
||||
return ConstexprString<size>(data);
|
||||
};
|
||||
template <ConstexprString fmt, std::size_t I>
|
||||
|
@ -97,24 +85,29 @@ private:
|
|||
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>();
|
||||
};
|
||||
|
||||
public:
|
||||
Tuple<Fs...> functionStorage;
|
||||
|
||||
static consteval auto GetMaxSize() -> std::size_t {
|
||||
return [&]<auto... Is>(std::index_sequence<Is...>) {
|
||||
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...>());
|
||||
};
|
||||
template <impl::CallbackMessage message, std::invocable F>
|
||||
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 = "|> ">
|
||||
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 {
|
||||
constexpr auto message = ((FormatMessageFor<fmt, Is>() + ...) + enter);
|
||||
auto result = std::fwrite(message.begin(), 1, message.size(), out);
|
||||
|
@ -126,7 +119,8 @@ public:
|
|||
};
|
||||
std::string 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(*message.need == input) {
|
||||
Get<I>(this->functionStorage)();
|
||||
|
@ -136,14 +130,12 @@ public:
|
|||
Get<I>(this->functionStorage)();
|
||||
};
|
||||
};
|
||||
}(Wrapper<Is>{}), ...);
|
||||
}(Wrapper<Is>{}),
|
||||
...);
|
||||
return 0;
|
||||
}(std::index_sequence_for<Fs...>());
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
} // namespace menu
|
||||
} // namespace utempl
|
||||
|
||||
|
||||
|
|
|
@ -9,15 +9,14 @@ namespace impl {
|
|||
struct Types {};
|
||||
} // namespace impl
|
||||
|
||||
|
||||
template <std::size_t Id, typename Tag>
|
||||
struct MetaInfoKey {};
|
||||
|
||||
|
||||
template <typename T, typename Tag = impl::Types>
|
||||
struct MetaInfo {
|
||||
static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>();
|
||||
using Type = T;
|
||||
|
||||
private:
|
||||
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
|
||||
};
|
||||
|
@ -25,19 +24,16 @@ private:
|
|||
template <typename T, typename Tag = impl::Types>
|
||||
inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId;
|
||||
|
||||
template <
|
||||
typename Tag,
|
||||
template <typename Tag,
|
||||
typename T,
|
||||
typename... Ts,
|
||||
typename... TTs,
|
||||
std::size_t Id = loopholes::Counter<Tag, T, Ts..., TTs...>(),
|
||||
auto = loopholes::Injector<MetaInfoKey<Id, Tag>{}, TypeList<T>{}>{}
|
||||
>
|
||||
consteval std::size_t AddTypeToTag(TTs&&...) {
|
||||
auto = loopholes::Injector<MetaInfoKey<Id, Tag>{}, TypeList<T>{}>{}>
|
||||
consteval auto AddTypeToTag(TTs&&...) -> std::size_t {
|
||||
return Id;
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t Id, typename Tag = impl::Types>
|
||||
using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>;
|
||||
|
||||
|
@ -47,8 +43,9 @@ using GetType = GetMetaInfo<Id, Tag>::Type;
|
|||
namespace impl {
|
||||
|
||||
template <typename Tag, std::size_t I = 0, typename... Ts, typename G>
|
||||
static consteval auto GetTypeListForTag(G g) requires (I == 0 ||
|
||||
requires {Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});}) {
|
||||
static consteval auto GetTypeListForTag(G g)
|
||||
requires(I == 0 || requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); })
|
||||
{
|
||||
if constexpr(I == 0 && !requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); }) {
|
||||
return TypeList{};
|
||||
} else {
|
||||
|
@ -62,7 +59,6 @@ static consteval auto GetTypeListForTag(G g) requires (I == 0 ||
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <typename Tag = impl::Types, typename... Ts>
|
||||
|
@ -70,16 +66,11 @@ consteval auto GetTypeListForTag() {
|
|||
return impl::GetTypeListForTag<Tag>(TypeList<Ts...>{});
|
||||
};
|
||||
|
||||
template <
|
||||
typename Tag,
|
||||
typename... Ts,
|
||||
auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1
|
||||
>
|
||||
template <typename Tag, typename... Ts, auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1>
|
||||
consteval auto GetCurrentTagType() {
|
||||
return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>());
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
static_assert(kTypeId<int> == 0);
|
||||
static_assert(kTypeId<void> == 1);
|
||||
|
@ -88,5 +79,4 @@ static_assert(std::is_same_v<decltype(GetTypeListForTag()), TypeList<int, void,
|
|||
|
||||
*/
|
||||
|
||||
|
||||
} // namespace utempl
|
||||
|
|
|
@ -4,40 +4,40 @@
|
|||
namespace utempl {
|
||||
|
||||
template <typename T>
|
||||
struct Optional {
|
||||
struct Optional { // NOLINT
|
||||
bool flag = false;
|
||||
union {
|
||||
char null;
|
||||
T _value;
|
||||
};
|
||||
inline constexpr Optional() = default;
|
||||
inline constexpr Optional(const Optional&) = default;
|
||||
inline constexpr Optional(Optional&&) = default;
|
||||
inline constexpr Optional(T&& arg) : _value(std::move(arg)), flag(true) {};
|
||||
inline constexpr Optional(const T& arg) : _value(arg), flag(true) {};
|
||||
inline constexpr Optional(std::nullopt_t) : flag(false), null(0) {};
|
||||
inline constexpr auto has_value() const -> bool {
|
||||
constexpr Optional() = default;
|
||||
constexpr Optional(const Optional&) = default;
|
||||
constexpr Optional(Optional&&) = default;
|
||||
explicit constexpr Optional(T&& arg) : _value(std::move(arg)), flag(true) {};
|
||||
explicit constexpr Optional(const T& arg) : _value(arg), flag(true) {};
|
||||
explicit constexpr Optional(std::nullopt_t) : null(0) {};
|
||||
[[nodiscard]] constexpr auto has_value() const -> bool {
|
||||
return this->flag;
|
||||
};
|
||||
inline constexpr auto value() -> T& {
|
||||
constexpr auto value() -> T& {
|
||||
return this->_value;
|
||||
};
|
||||
inline constexpr auto operator*() -> T& {
|
||||
constexpr auto operator*() -> T& {
|
||||
return this->value();
|
||||
};
|
||||
inline constexpr auto operator->() -> T* {
|
||||
constexpr auto operator->() -> T* {
|
||||
return &this->value();
|
||||
};
|
||||
inline constexpr auto value() const -> const T& {
|
||||
constexpr auto value() const -> const T& {
|
||||
return this->_value;
|
||||
};
|
||||
inline constexpr auto operator*() const -> const T& {
|
||||
constexpr auto operator*() const -> const T& {
|
||||
return this->value();
|
||||
};
|
||||
inline constexpr auto operator->() const -> const T* {
|
||||
constexpr auto operator->() const -> const T* {
|
||||
return &this->value();
|
||||
};
|
||||
inline constexpr explicit operator bool() const {
|
||||
constexpr explicit operator bool() const {
|
||||
return this->has_value();
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace utempl {
|
||||
template <typename... Fs>
|
||||
inline constexpr auto Overloaded(Fs&&... fs) {
|
||||
constexpr auto Overloaded(Fs&&... fs) {
|
||||
struct Overloaded : public std::remove_cvref_t<Fs>... {
|
||||
using Fs::operator()...;
|
||||
};
|
||||
|
|
|
@ -6,10 +6,10 @@ struct ReferenceWrapper;
|
|||
|
||||
template <typename T>
|
||||
struct ReferenceWrapper<T&&> {
|
||||
inline constexpr auto operator*() -> T& {
|
||||
constexpr auto operator*() -> T& {
|
||||
return this->value;
|
||||
};
|
||||
inline constexpr auto operator->() -> T* {
|
||||
constexpr auto operator->() -> T* {
|
||||
return &this->value;
|
||||
};
|
||||
T&& value;
|
||||
|
@ -17,10 +17,10 @@ struct ReferenceWrapper<T&&> {
|
|||
|
||||
template <typename T>
|
||||
struct ReferenceWrapper<const T&> {
|
||||
inline constexpr auto operator*() -> const T& {
|
||||
constexpr auto operator*() -> const T& {
|
||||
return this->value;
|
||||
};
|
||||
inline constexpr auto operator->() -> const T* {
|
||||
constexpr auto operator->() -> const T* {
|
||||
return &this->value;
|
||||
};
|
||||
const T& value;
|
||||
|
@ -28,11 +28,10 @@ struct ReferenceWrapper<const T&> {
|
|||
|
||||
template <typename T>
|
||||
struct ReferenceWrapper<T&> {
|
||||
|
||||
inline constexpr auto operator*() -> T& {
|
||||
constexpr auto operator*() -> T& {
|
||||
return this->value;
|
||||
};
|
||||
inline constexpr auto operator->() -> T* {
|
||||
constexpr auto operator->() -> T* {
|
||||
return &this->value;
|
||||
};
|
||||
T& value;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
#include <utempl/type_list.hpp>
|
||||
#include <utempl/overloaded.hpp>
|
||||
#include <utempl/type_list.hpp>
|
||||
namespace utempl {
|
||||
|
||||
template <auto>
|
||||
|
@ -10,16 +10,15 @@ namespace impl {
|
|||
template <auto, typename T>
|
||||
struct TupleLeaf {
|
||||
T value;
|
||||
inline constexpr bool operator==(const TupleLeaf&) const = default;
|
||||
constexpr auto operator==(const TupleLeaf&) const -> bool = default;
|
||||
};
|
||||
|
||||
|
||||
template <typename, typename...>
|
||||
struct TupleHelper;
|
||||
|
||||
template <std::size_t... Is, typename... 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
|
||||
|
@ -28,65 +27,69 @@ template <typename... Ts>
|
|||
struct Tuple;
|
||||
|
||||
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...>{}));
|
||||
return static_cast<impl::TupleLeaf<I, Type>&>(tuple).value;
|
||||
};
|
||||
|
||||
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...>{}));
|
||||
return static_cast<const impl::TupleLeaf<I, Type>&>(tuple).value;
|
||||
};
|
||||
|
||||
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...>{}));
|
||||
return std::move(static_cast<impl::TupleLeaf<I, Type>&&>(tuple).value);
|
||||
};
|
||||
|
||||
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));
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
||||
template <typename... TTs>
|
||||
inline constexpr Tuple(TTs&&... args) :
|
||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
|
||||
constexpr Tuple(TTs&&... args) /* NOLINT */ : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
|
||||
template <std::invocable... Fs>
|
||||
inline constexpr Tuple(Fs&&... fs) requires (!std::invocable<Ts> || ...) :
|
||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{fs()}...} {};
|
||||
inline constexpr Tuple(Ts&&... args) :
|
||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{args}...} {};
|
||||
inline constexpr Tuple(const Tuple&) = default;
|
||||
inline constexpr Tuple(Tuple&&) = default;
|
||||
inline constexpr Tuple(Tuple&) = default;
|
||||
inline constexpr Tuple& operator=(const Tuple&) = default;
|
||||
inline constexpr Tuple& operator=(Tuple&&) = default;
|
||||
inline constexpr Tuple& operator=(Tuple&) = default;
|
||||
inline constexpr Tuple() :
|
||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>() {};
|
||||
inline constexpr bool operator==(const Tuple<Ts...>& other) const {
|
||||
constexpr Tuple(Fs&&... fs) // NOLINT
|
||||
requires(!std::invocable<Ts> || ...)
|
||||
: impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{fs()}...} {};
|
||||
constexpr Tuple(Ts&&... args) : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{args}...} {}; // NOLINT
|
||||
constexpr Tuple(const Tuple&) = default;
|
||||
constexpr Tuple(Tuple&&) = default;
|
||||
constexpr Tuple(Tuple&) = default;
|
||||
constexpr auto operator=(const Tuple&) -> Tuple& = default;
|
||||
constexpr auto operator=(Tuple&&) -> Tuple& = default;
|
||||
constexpr auto operator=(Tuple&) -> Tuple& = default;
|
||||
constexpr Tuple() : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>() {};
|
||||
constexpr auto operator==(const Tuple<Ts...>& other) const -> bool {
|
||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return ((Get<Is>(*this) == Get<Is>(other)) && ...);
|
||||
}(std::index_sequence_for<Ts...>());
|
||||
};
|
||||
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 {Get<Is>(*this)..., Get<IIs>(other)...};
|
||||
}(std::index_sequence_for<Ts...>(), std::index_sequence_for<TTs...>());
|
||||
};
|
||||
|
||||
template <auto I>
|
||||
inline constexpr auto operator[](Wrapper<I>) const -> const auto& {
|
||||
constexpr auto operator[](Wrapper<I>) const -> const auto& {
|
||||
return Get<I>(*this);
|
||||
};
|
||||
|
||||
template <auto I>
|
||||
inline constexpr auto operator[](Wrapper<I>) -> auto& {
|
||||
constexpr auto operator[](Wrapper<I>) -> auto& {
|
||||
return Get<I>(*this);
|
||||
};
|
||||
};
|
||||
|
@ -94,10 +97,10 @@ struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
|||
template <>
|
||||
struct Tuple<> {
|
||||
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;
|
||||
};
|
||||
inline constexpr auto operator==(const Tuple<>&) const {
|
||||
constexpr auto operator==(const Tuple<>&) const {
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#pragma once
|
||||
#include <concepts>
|
||||
#include <utility>
|
||||
#include <array>
|
||||
#include <utempl/overloaded.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <utempl/overloaded.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace utempl {
|
||||
|
||||
|
@ -24,10 +23,12 @@ inline constexpr auto kTypeList = TypeList<Ts...>{};
|
|||
|
||||
template <typename T>
|
||||
concept IsTypeList = Overloaded(
|
||||
[]<typename... Ts>(TypeList<TypeList<Ts...>>) {return true;},
|
||||
[](auto&&) {return false;}
|
||||
)(kType<std::remove_cvref_t<T>>);
|
||||
|
||||
[]<typename... Ts>(TypeList<TypeList<Ts...>>) {
|
||||
return true;
|
||||
},
|
||||
[](auto&&) {
|
||||
return false;
|
||||
})(kType<std::remove_cvref_t<T>>);
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
@ -40,8 +41,6 @@ struct Caster {};
|
|||
template <std::size_t... Is, typename... Ts>
|
||||
struct Caster<std::index_sequence<Is...>, Ts...> : IndexedType<Is, Ts>... {};
|
||||
|
||||
|
||||
|
||||
} // namespace impl
|
||||
template <typename... Ts, typename... TTs>
|
||||
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>
|
||||
consteval auto Get(TypeList<Ts...>) -> decltype(
|
||||
[]<typename T>(impl::IndexedType<I, T>&&) -> T {
|
||||
consteval auto Get(TypeList<Ts...>) -> decltype([]<typename T>(impl::IndexedType<I, T>&&) -> T {
|
||||
}(impl::Caster<std::index_sequence_for<Ts...>, 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();
|
||||
};
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
consteval auto Reverse(TypeList<Ts...> 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>
|
||||
consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) {
|
||||
return (
|
||||
(kTypeList<>
|
||||
+ [](auto&& list) {
|
||||
return ((kTypeList<> +
|
||||
[](auto&& list) {
|
||||
if constexpr(decltype(f(list))::kValue) {
|
||||
return list;
|
||||
} else {
|
||||
return kTypeList<>;
|
||||
}
|
||||
}(kType<Ts>)
|
||||
)
|
||||
+ ...);
|
||||
}(kType<Ts>)) +
|
||||
...);
|
||||
};
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
consteval auto Size(TypeList<Ts...>) -> std::size_t {
|
||||
return sizeof...(Ts);
|
||||
};
|
||||
|
||||
|
||||
} // namespace utempl
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#pragma once
|
||||
#include <utempl/tuple.hpp>
|
||||
#include <utempl/overloaded.hpp>
|
||||
#include <utempl/constexpr_string.hpp>
|
||||
#include <ranges>
|
||||
#include <optional>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <utempl/constexpr_string.hpp>
|
||||
#include <utempl/overloaded.hpp>
|
||||
#include <utempl/tuple.hpp>
|
||||
|
||||
namespace utempl {
|
||||
|
||||
|
@ -15,7 +15,7 @@ struct Wrapper {
|
|||
inline constexpr auto operator==(auto&& arg) const {
|
||||
return arg == Value;
|
||||
};
|
||||
consteval operator decltype(Value)() const {
|
||||
consteval operator decltype(Value)() const { // NOLINT
|
||||
return Value;
|
||||
};
|
||||
consteval auto operator*() const {
|
||||
|
@ -43,14 +43,12 @@ struct kSeq {
|
|||
template <std::size_t N>
|
||||
inline constexpr impl::kSeq<N> kSeq;
|
||||
|
||||
|
||||
|
||||
template <ConstexprString string, typename T = std::size_t>
|
||||
consteval auto ParseNumber() -> T {
|
||||
T response{};
|
||||
for(const auto& c : string) {
|
||||
if(c >= '0' && c <= '9') {
|
||||
response = response * 10 + (c - '0');
|
||||
response = response * 10 + (c - '0'); // NOLINT
|
||||
};
|
||||
};
|
||||
return response;
|
||||
|
@ -65,7 +63,9 @@ consteval auto operator"" _c() {
|
|||
} // namespace literals
|
||||
|
||||
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 [](decltype(Caster(Is))..., auto&& response, ...) -> decltype(auto) {
|
||||
return response;
|
||||
|
@ -73,7 +73,6 @@ inline constexpr auto Arg(Ts&&... args) -> decltype(auto) requires (I < sizeof..
|
|||
}(std::make_index_sequence<I>());
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t Count>
|
||||
inline constexpr auto Times(auto&& f) {
|
||||
[&]<auto... Is>(std::index_sequence<Is...>) {
|
||||
|
@ -87,7 +86,6 @@ inline constexpr std::size_t kTupleSize = []() -> std::size_t {
|
|||
return 0;
|
||||
}();
|
||||
|
||||
|
||||
template <typename 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;
|
||||
|
||||
template <typename T>
|
||||
struct TupleMaker {
|
||||
};
|
||||
struct TupleMaker {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct TupleMaker<std::tuple<Ts...>> {
|
||||
|
@ -125,7 +122,8 @@ template <typename T, std::size_t N>
|
|||
struct TupleMaker<std::array<T, N>> {
|
||||
template <typename Arg, typename... 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)...};
|
||||
};
|
||||
static constexpr auto Make() -> std::array<T, 0> {
|
||||
|
@ -134,8 +132,7 @@ struct TupleMaker<std::array<T, N>> {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
struct TupleTieMaker {
|
||||
};
|
||||
struct TupleTieMaker {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct TupleTieMaker<std::tuple<Ts...>> {
|
||||
|
@ -157,27 +154,22 @@ template <typename T, std::size_t N>
|
|||
struct TupleTieMaker<std::array<T, N>> {
|
||||
template <typename Arg, typename... Args>
|
||||
static inline constexpr auto Make(Arg& arg, Args&... args) -> std::array<Arg&, sizeof...(Args) + 1>
|
||||
requires (std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...) {
|
||||
requires(std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...)
|
||||
{
|
||||
return {arg, args...};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T = Tuple<>, typename... Args>
|
||||
inline constexpr auto MakeTuple(Args&&... args)
|
||||
-> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) {
|
||||
inline constexpr auto MakeTuple(Args&&... args) -> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) {
|
||||
return TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
template <typename T = Tuple<>, typename... Args>
|
||||
inline constexpr auto MakeTie(Args&... args)
|
||||
-> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
|
||||
inline constexpr auto MakeTie(Args&... args) -> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
|
||||
return TupleTieMaker<std::remove_cvref_t<T>>::Make(args...);
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept HasMakeTie = requires(int& arg) { MakeTie<T>(arg); };
|
||||
|
||||
|
@ -188,7 +180,6 @@ struct Getter {
|
|||
friend consteval auto Magic(Getter<T>);
|
||||
};
|
||||
|
||||
|
||||
template <typename T, auto Insert>
|
||||
struct Inserter {
|
||||
friend consteval auto Magic(Getter<T>) -> decltype(auto) {
|
||||
|
@ -196,7 +187,6 @@ struct Inserter {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct SafeTupleChecker {
|
||||
consteval SafeTupleChecker(SafeTupleChecker&&) {
|
||||
|
@ -218,8 +208,10 @@ struct IsSafeTuple {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
struct IsSafeTuple<T, bool(TrueF(Get<0>(std::move(Get<0>(Tuple{MakeTuple<T>(0, kSafeTupleChecker<T>)}))))
|
||||
&& Magic(Getter<SafeTupleChecker<T>>{})) ? false : false> {
|
||||
struct IsSafeTuple<
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -231,10 +223,9 @@ inline constexpr bool kForceEnableTuple = false;
|
|||
template <typename T, std::size_t N>
|
||||
inline constexpr bool kForceEnableTuple<std::array<T, N>> = true;
|
||||
|
||||
|
||||
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>
|
||||
concept TupleTransformer = requires(F f, Tuple&& tuple) {
|
||||
|
@ -260,36 +251,46 @@ struct LazyTuple {
|
|||
};
|
||||
template <typename T>
|
||||
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;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
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;
|
||||
};
|
||||
|
||||
inline constexpr operator std::invoke_result_t<F>() {
|
||||
inline constexpr operator std::invoke_result_t<F>() { // NOLINT
|
||||
return (*this)();
|
||||
};
|
||||
inline constexpr operator std::invoke_result_t<F>() const {
|
||||
inline constexpr operator std::invoke_result_t<F>() const { // NOLINT
|
||||
return (*this)();
|
||||
};
|
||||
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)());
|
||||
};
|
||||
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)());
|
||||
};
|
||||
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());
|
||||
};
|
||||
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());
|
||||
};
|
||||
template <typename FF>
|
||||
|
@ -304,21 +305,19 @@ template <std::invocable F>
|
|||
struct TupleMaker<LazyTuple<F>> {
|
||||
template <typename... Ts>
|
||||
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)...);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
template <TupleLike Tuple, TupleTransformer<Tuple> FF>
|
||||
inline constexpr auto operator|(Tuple&& tuple, FF&& f) {
|
||||
return LazyTuple{
|
||||
[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) {
|
||||
return LazyTuple{[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) {
|
||||
return f(std::move(tuple));
|
||||
}};
|
||||
};
|
||||
|
||||
|
||||
template <TupleLike Tuple, typename F>
|
||||
inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> 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>
|
||||
inline constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) {
|
||||
return Unpack(std::forward<Tuple>(container),
|
||||
[&]<typename... Ts>(Ts&&... args){
|
||||
return Unpack(std::forward<Tuple>(container), [&]<typename... Ts>(Ts&&... args) {
|
||||
return MakeTuple<R>(f(std::forward<Ts>(args))...);
|
||||
});
|
||||
};
|
||||
|
@ -354,7 +350,6 @@ inline constexpr auto Transform(F&& f, TypeList<R> result = {}) {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
template <TupleLike Tuple, typename R = Tuple, typename F>
|
||||
inline constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> 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)>>());
|
||||
};
|
||||
|
||||
|
||||
template <TupleLike Tuple>
|
||||
inline constexpr auto Reverse(Tuple&& tuple) {
|
||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
|
@ -413,19 +407,14 @@ struct LeftFold<T, F> {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace impl
|
||||
|
||||
|
||||
template <TupleLike Tuple, typename T, typename F>
|
||||
inline constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f) {
|
||||
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||
return (
|
||||
impl::LeftFold<std::remove_cvref_t<T>, std::remove_cvref_t<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)}
|
||||
| ...
|
||||
| impl::LeftFold<std::remove_cvref_t<Ts>>{.data = std::forward<Ts>(args)}
|
||||
).data;
|
||||
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<Ts>>{.data = std::forward<Ts>(args)})
|
||||
.data;
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -441,7 +430,6 @@ inline constexpr auto Reduce(T&& init, F&& f) {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
template <TupleLike Tuple, TupleLike Tuple2>
|
||||
inline constexpr auto TupleCat(Tuple&& tuple, Tuple2&& tuple2) {
|
||||
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>
|
||||
inline constexpr auto TupleCat(Tuples&&... tuples) requires (sizeof...(tuples) >= 1) {
|
||||
return LeftFold(
|
||||
Tuple{std::forward<Tuples>(tuples)...},
|
||||
inline constexpr auto TupleCat(Tuples&&... tuples)
|
||||
requires(sizeof...(tuples) >= 1)
|
||||
{
|
||||
return LeftFold(Tuple{std::forward<Tuples>(tuples)...},
|
||||
MakeTuple<decltype(Arg<0>(std::forward<Tuples>(tuples)...))>(),
|
||||
[]<TupleLike Tup, TupleLike Tup2>(Tup&& tup, 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));
|
||||
};
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
|
||||
return {args...};
|
||||
|
@ -487,20 +475,16 @@ consteval auto PartialCallerF(TypeList<Ts...>) {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <TupleLike Tuple, typename T>
|
||||
inline constexpr auto FirstOf(Tuple&& tuple, T&& init) requires kEveryElement<std::is_invocable, Tuple> {
|
||||
return LeftFold(
|
||||
std::forward<Tuple>(tuple),
|
||||
std::forward<T>(init),
|
||||
[]<typename TT, typename F>(TT&& value, F&& f) -> TT {
|
||||
inline constexpr auto FirstOf(Tuple&& tuple, T&& init)
|
||||
requires kEveryElement<std::is_invocable, Tuple>
|
||||
{
|
||||
return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), []<typename TT, typename F>(TT&& value, F&& f) -> TT {
|
||||
if(value) {
|
||||
return value;
|
||||
};
|
||||
return f();
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -510,20 +494,16 @@ inline constexpr auto FirstOf(T&& init) {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
template <TupleLike Tuple>
|
||||
inline constexpr auto Filter(Tuple&& tuple, auto&& f) {
|
||||
return LeftFold(
|
||||
std::forward<Tuple>(tuple),
|
||||
MakeTuple<Tuple>(),
|
||||
[&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
|
||||
std::forward<Tuple>(tuple), MakeTuple<Tuple>(), [&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
|
||||
if constexpr(decltype(f(std::forward<T>(add))){}) {
|
||||
return TupleCat(std::forward<Accumulator>(accumulator), std::forward<T>(add));
|
||||
} else {
|
||||
return accumulator;
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
|
@ -540,12 +520,11 @@ inline constexpr auto ForEach(Tuple&& tuple, auto&& f) {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
template <typename F, typename... Ts>
|
||||
struct Curryer {
|
||||
F f;
|
||||
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 this->f(Get<Is>(this->data)...);
|
||||
}(std::index_sequence_for<Ts...>());
|
||||
|
@ -579,8 +558,7 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
|
|||
},
|
||||
[](auto&&) {
|
||||
return false;
|
||||
}
|
||||
)(std::forward<Ts>(args))...};
|
||||
})(std::forward<Ts>(args))...};
|
||||
return std::ranges::find(bs, true) - bs.begin();
|
||||
});
|
||||
};
|
||||
|
@ -619,5 +597,4 @@ inline constexpr auto Generate(T&& value) {
|
|||
} | kSeq<N>;
|
||||
};
|
||||
|
||||
|
||||
} // namespace utempl
|
||||
|
|
Loading…
Reference in a new issue