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/meta_info.hpp>
|
||||||
#include <utempl/utils.hpp>
|
#include <utempl/utils.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
struct AttributesTag {};
|
struct AttributesTag {};
|
||||||
|
@ -14,40 +11,27 @@ struct AttributesTag {};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct AttributesCounterTag {};
|
struct AttributesCounterTag {};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
|
template <typename T, typename..., auto f = [] {}, auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()>
|
||||||
} // namespace impl
|
|
||||||
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename T,
|
|
||||||
typename...,
|
|
||||||
auto f = []{},
|
|
||||||
auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()
|
|
||||||
>
|
|
||||||
consteval auto OpenStruct() -> bool {
|
consteval auto OpenStruct() -> bool {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <
|
template <typename...,
|
||||||
typename...,
|
auto f = [] {},
|
||||||
auto f = []{},
|
auto I = loopholes::CountValue<impl::AttributesTag, decltype(f)>(),
|
||||||
auto I = loopholes::CountValue<impl::AttributesTag, decltype(f)>(),
|
auto II = (I >= 2) ? I - 2 : I - 1,
|
||||||
auto II = (I >= 2) ? I - 2 : I - 1,
|
typename T = decltype(Magic(loopholes::Getter<MetaInfoKey<II, impl::AttributesTag>{}>{}))::Type,
|
||||||
typename T = decltype(Magic(loopholes::Getter<MetaInfoKey<II, impl::AttributesTag>{}>{}))::Type,
|
auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()>
|
||||||
auto = AddTypeToTag<impl::AttributesTag, T, decltype(f)>()
|
|
||||||
>
|
|
||||||
consteval auto CloseStruct() -> bool {
|
consteval auto CloseStruct() -> bool {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct NoInfo {
|
struct NoInfo {
|
||||||
consteval auto operator==(const NoInfo&) const -> bool = default;
|
consteval auto operator==(const NoInfo&) const -> bool = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
|
@ -60,59 +44,48 @@ struct FieldAttributeData<> {
|
||||||
using Type = NoInfo;
|
using Type = NoInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T,
|
||||||
template <
|
typename... Ts,
|
||||||
typename T,
|
auto f = [] {},
|
||||||
typename... Ts,
|
typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type,
|
||||||
auto f = []{},
|
auto = AddTypeToTag<impl::AttributesCounterTag<Current>, typename FieldAttributeData<Ts...>::Type, decltype(f)>()>
|
||||||
typename Current = decltype(GetCurrentTagType<impl::AttributesTag, decltype(f)>())::Type,
|
|
||||||
auto = AddTypeToTag<impl::AttributesCounterTag<Current>, typename FieldAttributeData<Ts...>::Type, decltype(f)>()
|
|
||||||
>
|
|
||||||
consteval auto FieldAttribute() -> T;
|
consteval auto FieldAttribute() -> T;
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using FieldAttribute = decltype(impl::FieldAttribute<Ts...>());
|
using FieldAttribute = decltype(impl::FieldAttribute<Ts...>());
|
||||||
|
|
||||||
|
#define ATTRIBUTE_STRUCT(name, ...) /* NOLINT */ \
|
||||||
|
\
|
||||||
|
struct name { \
|
||||||
|
static_assert(::utempl::OpenStruct<name>()); \
|
||||||
|
template <std::size_t N> \
|
||||||
|
static consteval auto GetAttribute(); \
|
||||||
|
__VA_ARGS__ \
|
||||||
|
static_assert(::utempl::CloseStruct()); \
|
||||||
|
}
|
||||||
|
|
||||||
#define ATTRIBUTE_STRUCT(name, ...) struct name { \
|
#define GENERIC_ATTRIBUTE(value) /* NOLINT */ \
|
||||||
static_assert(::utempl::OpenStruct<name>()); \
|
template <> \
|
||||||
template <std::size_t N> \
|
consteval auto GetAttribute<::utempl::loopholes::Counter< \
|
||||||
static consteval auto GetAttribute(); \
|
::utempl::impl::AttributesCounterTag<decltype(::utempl::GetCurrentTagType<::utempl::impl::AttributesTag, decltype([] {})>())::Type>, \
|
||||||
__VA_ARGS__ \
|
decltype([] {})>()>() { \
|
||||||
static_assert(::utempl::CloseStruct());\
|
return value; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SKIP_ATTRIBUTE() /* NOLINT */ GENERIC_ATTRIBUTE(::utempl::NoInfo{})
|
||||||
|
|
||||||
#define GENERIC_ATTRIBUTE(value) \
|
template <typename T, auto f = [] {}, bool R = (loopholes::CountValue<impl::AttributesCounterTag<T>, decltype(f)>() > 0)>
|
||||||
template <> \
|
|
||||||
consteval auto GetAttribute< \
|
|
||||||
::utempl::loopholes::Counter< \
|
|
||||||
::utempl::impl::AttributesCounterTag<decltype(::utempl::GetCurrentTagType< \
|
|
||||||
::utempl::impl::AttributesTag, \
|
|
||||||
decltype([]{}) \
|
|
||||||
>())::Type \
|
|
||||||
>, \
|
|
||||||
decltype([]{}) >()>() { return value; }
|
|
||||||
|
|
||||||
#define SKIP_ATTRIBUTE() GENERIC_ATTRIBUTE(::utempl::NoInfo{})
|
|
||||||
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename T,
|
|
||||||
auto f = []{},
|
|
||||||
bool R = (loopholes::CountValue<impl::AttributesCounterTag<T>, decltype(f)>() > 0)
|
|
||||||
>
|
|
||||||
concept HasAttributes = R;
|
concept HasAttributes = R;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept HasMacroAttributes = requires {T::template GetAttribute<0>();};
|
concept HasMacroAttributes = requires { T::template GetAttribute<0>(); };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <HasAttributes T>
|
template <HasAttributes T>
|
||||||
consteval auto GetAttributes() requires HasMacroAttributes<T> {
|
consteval auto GetAttributes()
|
||||||
|
requires HasMacroAttributes<T>
|
||||||
|
{
|
||||||
constexpr auto I = loopholes::CountValue<impl::AttributesCounterTag<T>>();
|
constexpr auto I = loopholes::CountValue<impl::AttributesCounterTag<T>>();
|
||||||
return [](auto... is) {
|
return [](auto... is) {
|
||||||
return Tuple{T::template GetAttribute<is>()...};
|
return Tuple{T::template GetAttribute<is>()...};
|
||||||
|
@ -127,7 +100,4 @@ consteval auto GetAttributes() {
|
||||||
} | kSeq<I>;
|
} | kSeq<I>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace utempl
|
||||||
|
|
||||||
|
|
||||||
} // namespace utempl
|
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
template <std::size_t>
|
template <std::size_t>
|
||||||
struct ConstexprString;
|
struct ConstexprString;
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
||||||
template <std::size_t Size>
|
template <std::size_t Size>
|
||||||
struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std::string_view> {
|
struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std::string_view> {
|
||||||
constexpr auto parse(format_parse_context& ctx) const {
|
constexpr auto parse(format_parse_context& ctx) const {
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
};
|
};
|
||||||
inline constexpr auto format(const utempl::ConstexprString<Size>& str, auto& ctx) const {
|
constexpr auto format(const utempl::ConstexprString<Size>& str, auto& ctx) const {
|
||||||
return fmt::formatter<std::string_view>::format({str.begin()}, ctx);
|
return fmt::formatter<std::string_view>::format({str.begin()}, ctx);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -22,66 +23,66 @@ namespace utempl {
|
||||||
template <std::size_t Size>
|
template <std::size_t Size>
|
||||||
struct ConstexprString {
|
struct ConstexprString {
|
||||||
std::array<char, Size> data;
|
std::array<char, Size> data;
|
||||||
inline constexpr auto begin() -> char* {
|
constexpr auto begin() -> char* {
|
||||||
return this->data.begin();
|
return this->data.begin();
|
||||||
};
|
};
|
||||||
inline constexpr auto begin() const -> const char* {
|
[[nodiscard]] constexpr auto begin() const -> const char* {
|
||||||
return this->data.begin();
|
return this->data.begin();
|
||||||
};
|
};
|
||||||
inline constexpr auto end() -> char* {
|
[[nodiscard]] constexpr auto end() -> char* {
|
||||||
return this->data.end();
|
return this->data.end();
|
||||||
};
|
};
|
||||||
inline constexpr auto end() const -> const char* {
|
[[nodiscard]] constexpr auto end() const -> const char* {
|
||||||
return this->data.end();
|
return this->data.end();
|
||||||
};
|
};
|
||||||
static constexpr auto kSize = Size == 0 ? 0 : Size - 1;
|
static constexpr auto kSize = Size == 0 ? 0 : Size - 1;
|
||||||
inline constexpr ConstexprString() = default;
|
explicit constexpr ConstexprString() = default;
|
||||||
inline constexpr ConstexprString(const char (&data)[Size]) : data{} {
|
constexpr ConstexprString(const char (&data)[Size]) : data{} { // NOLINT
|
||||||
std::ranges::copy_n(data, Size, this->data.begin());
|
std::ranges::copy_n(data, Size, this->data.begin());
|
||||||
};
|
};
|
||||||
inline constexpr ConstexprString(std::string data) : data{} {
|
explicit constexpr ConstexprString(std::string data) : data{} {
|
||||||
std::ranges::copy_n(data.begin(), Size, this->data.begin());
|
std::ranges::copy_n(data.begin(), Size, this->data.begin());
|
||||||
};
|
};
|
||||||
inline constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {};
|
explicit constexpr ConstexprString(std::array<char, Size> data) : data(std::move(data)) {};
|
||||||
inline constexpr auto size() const {
|
constexpr auto size() const {
|
||||||
return Size == 0 ? 0 : Size - 1;
|
return Size == 0 ? 0 : Size - 1;
|
||||||
};
|
};
|
||||||
inline constexpr operator std::string_view() const & {
|
constexpr operator std::string_view() const& { // NOLINT
|
||||||
return {this->begin()};
|
return {this->begin()};
|
||||||
};
|
};
|
||||||
inline constexpr bool operator==(std::string_view other) const {
|
constexpr auto operator==(std::string_view other) const -> bool {
|
||||||
return static_cast<std::string_view>(*this) == other;
|
return static_cast<std::string_view>(*this) == other;
|
||||||
};
|
};
|
||||||
inline constexpr bool operator==(const ConstexprString<Size>& other) const {
|
constexpr auto operator==(const ConstexprString<Size>& other) const {
|
||||||
return static_cast<std::string_view>(*this) == static_cast<std::string_view>(other);
|
return static_cast<std::string_view>(*this) == static_cast<std::string_view>(other);
|
||||||
};
|
};
|
||||||
template <std::size_t SSize>
|
template <std::size_t SSize>
|
||||||
inline constexpr bool operator==(const ConstexprString<SSize>& other) const {
|
constexpr auto operator==(const ConstexprString<SSize>& other) const -> bool {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
inline constexpr bool operator==(const std::string& other) const {
|
constexpr auto operator==(const std::string& other) const -> bool {
|
||||||
return static_cast<std::string_view>(*this) == other;
|
return static_cast<std::string_view>(*this) == other;
|
||||||
};
|
};
|
||||||
template <std::size_t SSize>
|
template <std::size_t SSize>
|
||||||
inline constexpr auto operator+(const ConstexprString<SSize>& other) -> ConstexprString<Size + SSize - 1> {
|
constexpr auto operator+(const ConstexprString<SSize>& other) -> ConstexprString<Size + SSize - 1> {
|
||||||
ConstexprString<Size + SSize - 1> response;
|
ConstexprString<Size + SSize - 1> response;
|
||||||
std::ranges::copy_n(this->begin(), Size - 1, response.begin());
|
std::ranges::copy_n(this->begin(), Size - 1, response.begin());
|
||||||
std::ranges::copy_n(other.begin(), SSize, response.begin() + Size - 1);
|
std::ranges::copy_n(other.begin(), SSize, response.begin() + Size - 1);
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
inline constexpr ConstexprString(const ConstexprString&) = default;
|
constexpr ConstexprString(const ConstexprString&) = default;
|
||||||
inline constexpr ConstexprString(ConstexprString&&) = default;
|
constexpr ConstexprString(ConstexprString&&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
inline constexpr auto operator<<(std::ostream& stream, const ConstexprString<N>& str) -> std::ostream& {
|
constexpr auto operator<<(std::ostream& stream, const ConstexprString<N>& str) -> std::ostream& {
|
||||||
stream << static_cast<std::string_view>(str);
|
stream << static_cast<std::string_view>(str);
|
||||||
return stream;
|
return stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t Count>
|
template <std::size_t Count>
|
||||||
inline constexpr auto CreateStringWith(char c) {
|
constexpr auto CreateStringWith(char c) {
|
||||||
ConstexprString<Count + 1> str = {};
|
ConstexprString<Count + 1> str{};
|
||||||
for(std::size_t i = 0; i < Count; i++) {
|
for(std::size_t i = 0; i < Count; i++) {
|
||||||
str.data[i] = c;
|
str.data[i] = c;
|
||||||
};
|
};
|
||||||
|
@ -89,8 +90,6 @@ inline constexpr auto CreateStringWith(char c) {
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <std::size_t Size>
|
template <std::size_t Size>
|
||||||
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>;
|
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>; // NOLINT
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,11 @@ struct Getter {
|
||||||
};
|
};
|
||||||
template <auto I, auto Value = 0>
|
template <auto I, auto Value = 0>
|
||||||
struct Injector {
|
struct Injector {
|
||||||
friend constexpr auto Magic(Getter<I>) {return Value;};
|
friend constexpr auto Magic(Getter<I>) {
|
||||||
|
return Value;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <auto, typename = void, typename... Ts>
|
template <auto, typename = void, typename... Ts>
|
||||||
struct InjectedImpl {
|
struct InjectedImpl {
|
||||||
static constexpr bool value = false;
|
static constexpr bool value = false;
|
||||||
|
@ -25,7 +26,4 @@ struct InjectedImpl<V, std::void_t<decltype(Magic(Getter<V>{}))>, Ts...> {
|
||||||
template <auto I, typename... Ts>
|
template <auto I, typename... Ts>
|
||||||
concept Injected = InjectedImpl<I, void, Ts...>::value;
|
concept Injected = InjectedImpl<I, void, Ts...>::value;
|
||||||
|
|
||||||
|
} // namespace utempl::loopholes
|
||||||
|
|
||||||
|
|
||||||
} // namespace utempl::loopholes
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utempl/loopholes/core.hpp>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <utempl/loopholes/core.hpp>
|
||||||
|
|
||||||
namespace utempl::loopholes {
|
namespace utempl::loopholes {
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ struct TagWithValue {};
|
||||||
|
|
||||||
template <bool Add, typename Tag, std::size_t I, typename... Ts>
|
template <bool Add, typename Tag, std::size_t I, typename... Ts>
|
||||||
consteval auto Counter() -> std::size_t {
|
consteval auto Counter() -> std::size_t {
|
||||||
if constexpr(requires{Magic(Getter<TagWithValue<Tag, I>{}>{});}) {
|
if constexpr(requires { Magic(Getter<TagWithValue<Tag, I>{}>{}); }) {
|
||||||
return Counter<Add, Tag, I + 1, Ts...>();
|
return Counter<Add, Tag, I + 1, Ts...>();
|
||||||
};
|
};
|
||||||
if constexpr(Add) {
|
if constexpr(Add) {
|
||||||
|
@ -22,32 +22,20 @@ consteval auto Counter() -> std::size_t {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
} // namespace impl;
|
|
||||||
|
|
||||||
// For incerement counter need a unique Ts...
|
// For incerement counter need a unique Ts...
|
||||||
template <
|
template <typename Tag, typename... Ts, std::size_t R = impl::Counter<true, Tag, 0, Ts...>()>
|
||||||
typename Tag,
|
|
||||||
typename... Ts,
|
|
||||||
std::size_t R = impl::Counter<true, Tag, 0, Ts...>()
|
|
||||||
>
|
|
||||||
consteval auto Counter(auto...) -> std::size_t {
|
consteval auto Counter(auto...) -> std::size_t {
|
||||||
return R;
|
return R;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Without increment
|
// Without increment
|
||||||
template <
|
template <typename Tag, typename... Ts, std::size_t R = impl::Counter<false, Tag, 0, Ts...>()>
|
||||||
typename Tag,
|
|
||||||
typename... Ts,
|
|
||||||
std::size_t R = impl::Counter<false, Tag, 0, Ts...>()
|
|
||||||
>
|
|
||||||
consteval auto CountValue(auto...) -> std::size_t {
|
consteval auto CountValue(auto...) -> std::size_t {
|
||||||
return R;
|
return R;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static_assert(Counter<void>() == 0);
|
static_assert(Counter<void>() == 0);
|
||||||
static_assert(Counter<void, void>() == 1);
|
static_assert(Counter<void, void>() == 1);
|
||||||
|
@ -55,4 +43,4 @@ static_assert(CountValue<void>() == 2);
|
||||||
static_assert(CountValue<void, void>() == 2);
|
static_assert(CountValue<void, void>() == 2);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
} // namespace utempl::loopholes
|
} // namespace utempl::loopholes
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utempl/optional.hpp>
|
#include <fmt/compile.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <iostream>
|
||||||
#include <utempl/constexpr_string.hpp>
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
#include <utempl/optional.hpp>
|
||||||
#include <utempl/tuple.hpp>
|
#include <utempl/tuple.hpp>
|
||||||
#include <utempl/utils.hpp>
|
#include <utempl/utils.hpp>
|
||||||
#include <iostream>
|
|
||||||
#include <array>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
#include <fmt/compile.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
constexpr std::size_t CountDigits(std::size_t num) {
|
constexpr auto CountDigits(std::size_t num) -> std::size_t {
|
||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
do {
|
do { // NOLINT
|
||||||
++count;
|
++count;
|
||||||
num /= 10;
|
num /= 10; // NOLINT
|
||||||
} while (num != 0);
|
} while(num != 0);
|
||||||
return count;
|
return count;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr std::size_t GetDigit(std::size_t num, std::size_t index) {
|
constexpr auto GetDigit(std::size_t num, std::size_t index) -> std::size_t {
|
||||||
for (std::size_t i = 0; i < index; ++i) {
|
for(std::size_t i = 0; i < index; ++i) {
|
||||||
num /= 10;
|
num /= 10; // NOLINT
|
||||||
}
|
}
|
||||||
return num % 10;
|
return num % 10; // NOLINT
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t num>
|
template <std::size_t num>
|
||||||
|
@ -44,7 +44,6 @@ constexpr auto GetMax(Range&& range) {
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace menu {
|
namespace menu {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
@ -53,38 +52,27 @@ template <std::size_t N1, std::size_t N2>
|
||||||
struct CallbackMessage {
|
struct CallbackMessage {
|
||||||
ConstexprString<N1> message;
|
ConstexprString<N1> message;
|
||||||
Optional<ConstexprString<N2>> need;
|
Optional<ConstexprString<N2>> need;
|
||||||
consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) :
|
consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) : // NOLINT
|
||||||
message(std::move(message))
|
message(std::move(message)), need(std::move(need)) {};
|
||||||
,need(std::move(need)) {};
|
consteval CallbackMessage(const char (&message)[N1]) : message(std::move(message)), need(std::nullopt) {}; // NOLINT
|
||||||
consteval CallbackMessage(const char (&message)[N1]) :
|
|
||||||
message(std::move(message))
|
|
||||||
,need(std::nullopt) {};
|
|
||||||
};
|
};
|
||||||
template <std::size_t N1, std::size_t N2>
|
template <std::size_t N1, std::size_t N2>
|
||||||
CallbackMessage(const char(&)[N1], const char(&)[N2]) -> CallbackMessage<N2, N1>;
|
CallbackMessage(const char (&)[N1], const char (&)[N2]) -> CallbackMessage<N2, N1>; // NOLINT
|
||||||
|
|
||||||
template <std::size_t N1>
|
template <std::size_t N1>
|
||||||
CallbackMessage(const char(&)[N1]) -> CallbackMessage<N1, 0>;
|
CallbackMessage(const char (&)[N1]) -> CallbackMessage<N1, 0>; // NOLINT
|
||||||
|
|
||||||
} // namespace impl
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
template <Tuple storage = Tuple{}, typename... Fs>
|
template <Tuple storage = Tuple{}, typename... Fs>
|
||||||
struct Menu {
|
struct Menu {
|
||||||
private:
|
private:
|
||||||
template <ConstexprString fmt, ConstexprString message, ConstexprString alignment, ConstexprString neededInput>
|
template <ConstexprString fmt, ConstexprString message, ConstexprString alignment, ConstexprString neededInput>
|
||||||
static consteval auto FormatMessage() {
|
static consteval auto FormatMessage() {
|
||||||
// + 1 - NULL Terminator
|
// + 1 - NULL Terminator
|
||||||
constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin())
|
constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment) + 1;
|
||||||
,neededInput
|
std::array<char, size> data{};
|
||||||
,message
|
fmt::format_to(data.begin(), FMT_COMPILE(fmt.data.begin()), neededInput, message, alignment);
|
||||||
,alignment) + 1;
|
|
||||||
char data[size]{};
|
|
||||||
fmt::format_to(data, FMT_COMPILE(fmt.data.begin())
|
|
||||||
,neededInput
|
|
||||||
,message
|
|
||||||
,alignment);
|
|
||||||
return ConstexprString<size>(data);
|
return ConstexprString<size>(data);
|
||||||
};
|
};
|
||||||
template <ConstexprString fmt, std::size_t I>
|
template <ConstexprString fmt, std::size_t I>
|
||||||
|
@ -97,24 +85,29 @@ private:
|
||||||
return ToString<I>();
|
return ToString<I>();
|
||||||
};
|
};
|
||||||
}();
|
}();
|
||||||
constexpr ConstexprString alignment = CreateStringWith<GetMaxSize() - (Get<I>(storage).need ? Get<I>(storage).need->size() : CountDigits(I))>(' ');
|
constexpr ConstexprString alignment =
|
||||||
|
CreateStringWith<GetMaxSize() - (Get<I>(storage).need ? Get<I>(storage).need->size() : CountDigits(I))>(' ');
|
||||||
return FormatMessage<fmt, message, alignment, neededInput>();
|
return FormatMessage<fmt, message, alignment, neededInput>();
|
||||||
};
|
};
|
||||||
public:
|
|
||||||
|
public:
|
||||||
Tuple<Fs...> functionStorage;
|
Tuple<Fs...> functionStorage;
|
||||||
|
|
||||||
static consteval auto GetMaxSize() -> std::size_t {
|
static consteval auto GetMaxSize() -> std::size_t {
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>){
|
return [&]<auto... Is>(std::index_sequence<Is...>) {
|
||||||
constexpr auto list = ListFromTuple(storage);
|
constexpr auto list = ListFromTuple(storage);
|
||||||
return GetMax(std::array{(std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize != 0 ? std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize : CountDigits(Is))...});
|
return GetMax(std::array{(std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize != 0
|
||||||
|
? std::remove_cvref_t<decltype(*std::declval<decltype(Get<Is>(list))>().need)>::kSize
|
||||||
|
: CountDigits(Is))...});
|
||||||
}(std::index_sequence_for<Fs...>());
|
}(std::index_sequence_for<Fs...>());
|
||||||
};
|
};
|
||||||
template <impl::CallbackMessage message, std::invocable F>
|
template <impl::CallbackMessage message, std::invocable F>
|
||||||
constexpr auto With(F&& f) const {
|
constexpr auto With(F&& f) const {
|
||||||
return Menu<storage + Tuple{message}, Fs..., std::remove_cvref_t<F>>{.functionStorage = this->functionStorage + Tuple(std::forward<F>(f))};
|
return Menu<storage + Tuple{message}, Fs..., std::remove_cvref_t<F>>{.functionStorage =
|
||||||
|
this->functionStorage + Tuple(std::forward<F>(f))};
|
||||||
};
|
};
|
||||||
template <ConstexprString fmt, ConstexprString enter = "|> ">
|
template <ConstexprString fmt, ConstexprString enter = "|> ">
|
||||||
inline constexpr auto Run(std::istream& in = std::cin, std::FILE* out = stdout) const -> std::size_t {
|
constexpr auto Run(std::istream& in = std::cin, std::FILE* out = stdout) const -> std::size_t {
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>) -> std::size_t {
|
return [&]<auto... Is>(std::index_sequence<Is...>) -> std::size_t {
|
||||||
constexpr auto message = ((FormatMessageFor<fmt, Is>() + ...) + enter);
|
constexpr auto message = ((FormatMessageFor<fmt, Is>() + ...) + enter);
|
||||||
auto result = std::fwrite(message.begin(), 1, message.size(), out);
|
auto result = std::fwrite(message.begin(), 1, message.size(), out);
|
||||||
|
@ -126,24 +119,23 @@ public:
|
||||||
};
|
};
|
||||||
std::string input;
|
std::string input;
|
||||||
std::getline(in, input);
|
std::getline(in, input);
|
||||||
([&]<auto I, impl::CallbackMessage message = Get<I>(storage)>(Wrapper<I>) {
|
(
|
||||||
if constexpr(message.need) {
|
[&]<auto I, impl::CallbackMessage message = Get<I>(storage)>(Wrapper<I>) {
|
||||||
if(*message.need == input) {
|
if constexpr(message.need) {
|
||||||
Get<I>(this->functionStorage)();
|
if(*message.need == input) {
|
||||||
};
|
Get<I>(this->functionStorage)();
|
||||||
} else {
|
};
|
||||||
if(ToString<I>() == input) {
|
} else {
|
||||||
Get<I>(this->functionStorage)();
|
if(ToString<I>() == input) {
|
||||||
};
|
Get<I>(this->functionStorage)();
|
||||||
};
|
};
|
||||||
}(Wrapper<Is>{}), ...);
|
};
|
||||||
|
}(Wrapper<Is>{}),
|
||||||
|
...);
|
||||||
return 0;
|
return 0;
|
||||||
}(std::index_sequence_for<Fs...>());
|
}(std::index_sequence_for<Fs...>());
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace menu
|
} // namespace menu
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,37 +7,33 @@ namespace utempl {
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
struct Types {};
|
struct Types {};
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
|
|
||||||
template <std::size_t Id, typename Tag>
|
template <std::size_t Id, typename Tag>
|
||||||
struct MetaInfoKey {};
|
struct MetaInfoKey {};
|
||||||
|
|
||||||
|
|
||||||
template <typename T, typename Tag = impl::Types>
|
template <typename T, typename Tag = impl::Types>
|
||||||
struct MetaInfo {
|
struct MetaInfo {
|
||||||
static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>();
|
static constexpr std::size_t kTypeId = loopholes::Counter<Tag, T>();
|
||||||
using Type = T;
|
using Type = T;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
|
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Tag = impl::Types>
|
template <typename T, typename Tag = impl::Types>
|
||||||
inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId;
|
inline constexpr std::size_t kTypeId = MetaInfo<T, Tag>::kTypeId;
|
||||||
|
|
||||||
template <
|
template <typename Tag,
|
||||||
typename Tag,
|
typename T,
|
||||||
typename T,
|
typename... Ts,
|
||||||
typename... Ts,
|
typename... TTs,
|
||||||
typename... TTs,
|
std::size_t Id = loopholes::Counter<Tag, T, Ts..., TTs...>(),
|
||||||
std::size_t Id = loopholes::Counter<Tag, T, Ts..., TTs...>(),
|
auto = loopholes::Injector<MetaInfoKey<Id, Tag>{}, TypeList<T>{}>{}>
|
||||||
auto = loopholes::Injector<MetaInfoKey<Id, Tag>{}, TypeList<T>{}>{}
|
consteval auto AddTypeToTag(TTs&&...) -> std::size_t {
|
||||||
>
|
|
||||||
consteval std::size_t AddTypeToTag(TTs&&...) {
|
|
||||||
return Id;
|
return Id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <std::size_t Id, typename Tag = impl::Types>
|
template <std::size_t Id, typename Tag = impl::Types>
|
||||||
using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>;
|
using GetMetaInfo = MetaInfo<typename decltype(Magic(loopholes::Getter<MetaInfoKey<Id, Tag>{}>{}))::Type>;
|
||||||
|
|
||||||
|
@ -47,12 +43,13 @@ using GetType = GetMetaInfo<Id, Tag>::Type;
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
template <typename Tag, std::size_t I = 0, typename... Ts, typename G>
|
template <typename Tag, std::size_t I = 0, typename... Ts, typename G>
|
||||||
static consteval auto GetTypeListForTag(G g) requires (I == 0 ||
|
static consteval auto GetTypeListForTag(G g)
|
||||||
requires {Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});}) {
|
requires(I == 0 || requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); })
|
||||||
if constexpr(I == 0 && !requires {Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});}) {
|
{
|
||||||
|
if constexpr(I == 0 && !requires { Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{}); }) {
|
||||||
return TypeList{};
|
return TypeList{};
|
||||||
} else {
|
} else {
|
||||||
if constexpr(requires{GetTypeListForTag<Tag, I + 1, Ts...>(g);}) {
|
if constexpr(requires { GetTypeListForTag<Tag, I + 1, Ts...>(g); }) {
|
||||||
constexpr auto type = Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});
|
constexpr auto type = Magic(loopholes::Getter<MetaInfoKey<I, Tag>{}>{});
|
||||||
return GetTypeListForTag<Tag, I + 1, Ts..., typename decltype(type)::Type>(g);
|
return GetTypeListForTag<Tag, I + 1, Ts..., typename decltype(type)::Type>(g);
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,24 +59,18 @@ static consteval auto GetTypeListForTag(G g) requires (I == 0 ||
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
} // namespace impl
|
|
||||||
|
|
||||||
template <typename Tag = impl::Types, typename... Ts>
|
template <typename Tag = impl::Types, typename... Ts>
|
||||||
consteval auto GetTypeListForTag() {
|
consteval auto GetTypeListForTag() {
|
||||||
return impl::GetTypeListForTag<Tag>(TypeList<Ts...>{});
|
return impl::GetTypeListForTag<Tag>(TypeList<Ts...>{});
|
||||||
};
|
};
|
||||||
|
|
||||||
template <
|
template <typename Tag, typename... Ts, auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1>
|
||||||
typename Tag,
|
|
||||||
typename... Ts,
|
|
||||||
auto I = utempl::loopholes::CountValue<Tag, Ts...>() - 1
|
|
||||||
>
|
|
||||||
consteval auto GetCurrentTagType() {
|
consteval auto GetCurrentTagType() {
|
||||||
return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>());
|
return Magic(utempl::loopholes::Getter<MetaInfoKey<I, Tag>{}>());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static_assert(kTypeId<int> == 0);
|
static_assert(kTypeId<int> == 0);
|
||||||
static_assert(kTypeId<void> == 1);
|
static_assert(kTypeId<void> == 1);
|
||||||
|
@ -88,5 +79,4 @@ static_assert(std::is_same_v<decltype(GetTypeListForTag()), TypeList<int, void,
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
} // namespace utempl
|
||||||
} // namespace utempl
|
|
||||||
|
|
|
@ -4,42 +4,42 @@
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Optional {
|
struct Optional { // NOLINT
|
||||||
bool flag = false;
|
bool flag = false;
|
||||||
union {
|
union {
|
||||||
char null;
|
char null;
|
||||||
T _value;
|
T _value;
|
||||||
};
|
};
|
||||||
inline constexpr Optional() = default;
|
constexpr Optional() = default;
|
||||||
inline constexpr Optional(const Optional&) = default;
|
constexpr Optional(const Optional&) = default;
|
||||||
inline constexpr Optional(Optional&&) = default;
|
constexpr Optional(Optional&&) = default;
|
||||||
inline constexpr Optional(T&& arg) : _value(std::move(arg)), flag(true) {};
|
explicit constexpr Optional(T&& arg) : _value(std::move(arg)), flag(true) {};
|
||||||
inline constexpr Optional(const T& arg) : _value(arg), flag(true) {};
|
explicit constexpr Optional(const T& arg) : _value(arg), flag(true) {};
|
||||||
inline constexpr Optional(std::nullopt_t) : flag(false), null(0) {};
|
explicit constexpr Optional(std::nullopt_t) : null(0) {};
|
||||||
inline constexpr auto has_value() const -> bool {
|
[[nodiscard]] constexpr auto has_value() const -> bool {
|
||||||
return this->flag;
|
return this->flag;
|
||||||
};
|
};
|
||||||
inline constexpr auto value() -> T& {
|
constexpr auto value() -> T& {
|
||||||
return this->_value;
|
return this->_value;
|
||||||
};
|
};
|
||||||
inline constexpr auto operator*() -> T& {
|
constexpr auto operator*() -> T& {
|
||||||
return this->value();
|
return this->value();
|
||||||
};
|
};
|
||||||
inline constexpr auto operator->() -> T* {
|
constexpr auto operator->() -> T* {
|
||||||
return &this->value();
|
return &this->value();
|
||||||
};
|
};
|
||||||
inline constexpr auto value() const -> const T& {
|
constexpr auto value() const -> const T& {
|
||||||
return this->_value;
|
return this->_value;
|
||||||
};
|
};
|
||||||
inline constexpr auto operator*() const -> const T& {
|
constexpr auto operator*() const -> const T& {
|
||||||
return this->value();
|
return this->value();
|
||||||
};
|
};
|
||||||
inline constexpr auto operator->() const -> const T* {
|
constexpr auto operator->() const -> const T* {
|
||||||
return &this->value();
|
return &this->value();
|
||||||
};
|
};
|
||||||
inline constexpr explicit operator bool() const {
|
constexpr explicit operator bool() const {
|
||||||
return this->has_value();
|
return this->has_value();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
template <typename... Fs>
|
template <typename... Fs>
|
||||||
inline constexpr auto Overloaded(Fs&&... fs) {
|
constexpr auto Overloaded(Fs&&... fs) {
|
||||||
struct Overloaded : public std::remove_cvref_t<Fs>... {
|
struct Overloaded : public std::remove_cvref_t<Fs>... {
|
||||||
using Fs::operator()...;
|
using Fs::operator()...;
|
||||||
};
|
};
|
||||||
return Overloaded{std::forward<Fs>(fs)...};
|
return Overloaded{std::forward<Fs>(fs)...};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
|
@ -6,10 +6,10 @@ struct ReferenceWrapper;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ReferenceWrapper<T&&> {
|
struct ReferenceWrapper<T&&> {
|
||||||
inline constexpr auto operator*() -> T& {
|
constexpr auto operator*() -> T& {
|
||||||
return this->value;
|
return this->value;
|
||||||
};
|
};
|
||||||
inline constexpr auto operator->() -> T* {
|
constexpr auto operator->() -> T* {
|
||||||
return &this->value;
|
return &this->value;
|
||||||
};
|
};
|
||||||
T&& value;
|
T&& value;
|
||||||
|
@ -17,10 +17,10 @@ struct ReferenceWrapper<T&&> {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ReferenceWrapper<const T&> {
|
struct ReferenceWrapper<const T&> {
|
||||||
inline constexpr auto operator*() -> const T& {
|
constexpr auto operator*() -> const T& {
|
||||||
return this->value;
|
return this->value;
|
||||||
};
|
};
|
||||||
inline constexpr auto operator->() -> const T* {
|
constexpr auto operator->() -> const T* {
|
||||||
return &this->value;
|
return &this->value;
|
||||||
};
|
};
|
||||||
const T& value;
|
const T& value;
|
||||||
|
@ -28,14 +28,13 @@ struct ReferenceWrapper<const T&> {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ReferenceWrapper<T&> {
|
struct ReferenceWrapper<T&> {
|
||||||
|
constexpr auto operator*() -> T& {
|
||||||
inline constexpr auto operator*() -> T& {
|
|
||||||
return this->value;
|
return this->value;
|
||||||
};
|
};
|
||||||
inline constexpr auto operator->() -> T* {
|
constexpr auto operator->() -> T* {
|
||||||
return &this->value;
|
return &this->value;
|
||||||
};
|
};
|
||||||
T& value;
|
T& value;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utempl/type_list.hpp>
|
|
||||||
#include <utempl/overloaded.hpp>
|
#include <utempl/overloaded.hpp>
|
||||||
|
#include <utempl/type_list.hpp>
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
template <auto>
|
template <auto>
|
||||||
|
@ -10,83 +10,86 @@ namespace impl {
|
||||||
template <auto, typename T>
|
template <auto, typename T>
|
||||||
struct TupleLeaf {
|
struct TupleLeaf {
|
||||||
T value;
|
T value;
|
||||||
inline constexpr bool operator==(const TupleLeaf&) const = default;
|
constexpr auto operator==(const TupleLeaf&) const -> bool = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename, typename...>
|
template <typename, typename...>
|
||||||
struct TupleHelper;
|
struct TupleHelper;
|
||||||
|
|
||||||
template <std::size_t... Is, typename... Ts>
|
template <std::size_t... Is, typename... Ts>
|
||||||
struct TupleHelper<std::index_sequence<Is...>, Ts...> : public impl::TupleLeaf<Is, Ts>... {
|
struct TupleHelper<std::index_sequence<Is...>, Ts...> : public impl::TupleLeaf<Is, Ts>... {
|
||||||
inline constexpr bool operator==(const TupleHelper&) const = default;
|
constexpr auto operator==(const TupleHelper&) const -> bool = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct Tuple;
|
struct Tuple;
|
||||||
|
|
||||||
template <std::size_t I, typename... Ts>
|
template <std::size_t I, typename... Ts>
|
||||||
inline constexpr auto Get(Tuple<Ts...>& tuple) -> auto& requires (I < sizeof...(Ts)) {
|
constexpr auto Get(Tuple<Ts...>& tuple) -> auto&
|
||||||
|
requires(I < sizeof...(Ts))
|
||||||
|
{
|
||||||
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
||||||
return static_cast<impl::TupleLeaf<I, Type>&>(tuple).value;
|
return static_cast<impl::TupleLeaf<I, Type>&>(tuple).value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t I, typename... Ts>
|
template <std::size_t I, typename... Ts>
|
||||||
inline constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto& requires (I < sizeof...(Ts)) {
|
constexpr auto Get(const Tuple<Ts...>& tuple) -> const auto&
|
||||||
|
requires(I < sizeof...(Ts))
|
||||||
|
{
|
||||||
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
||||||
return static_cast<const impl::TupleLeaf<I, Type>&>(tuple).value;
|
return static_cast<const impl::TupleLeaf<I, Type>&>(tuple).value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t I, typename... Ts>
|
template <std::size_t I, typename... Ts>
|
||||||
inline constexpr auto Get(Tuple<Ts...>&& tuple) -> decltype(auto) requires (I < sizeof...(Ts)) {
|
constexpr auto Get(Tuple<Ts...>&& tuple) -> decltype(auto)
|
||||||
|
requires(I < sizeof...(Ts))
|
||||||
|
{
|
||||||
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
||||||
return std::move(static_cast<impl::TupleLeaf<I, Type>&&>(tuple).value);
|
return std::move(static_cast<impl::TupleLeaf<I, Type>&&>(tuple).value);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t I, typename T>
|
template <std::size_t I, typename T>
|
||||||
inline constexpr auto Get(T&& arg) -> decltype(get<I>(std::forward<T>(arg))) {
|
constexpr auto Get(T&& arg) -> decltype(get<I>(std::forward<T>(arg))) {
|
||||||
return get<I>(std::forward<T>(arg));
|
return get<I>(std::forward<T>(arg));
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
||||||
template <typename... TTs>
|
template <typename... TTs>
|
||||||
inline constexpr Tuple(TTs&&... args) :
|
constexpr Tuple(TTs&&... args) /* NOLINT */ : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
|
||||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{std::forward<TTs>(args)}...} {};
|
|
||||||
template <std::invocable... Fs>
|
template <std::invocable... Fs>
|
||||||
inline constexpr Tuple(Fs&&... fs) requires (!std::invocable<Ts> || ...) :
|
constexpr Tuple(Fs&&... fs) // NOLINT
|
||||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{fs()}...} {};
|
requires(!std::invocable<Ts> || ...)
|
||||||
inline constexpr Tuple(Ts&&... args) :
|
: impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{fs()}...} {};
|
||||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{args}...} {};
|
constexpr Tuple(Ts&&... args) : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>{{args}...} {}; // NOLINT
|
||||||
inline constexpr Tuple(const Tuple&) = default;
|
constexpr Tuple(const Tuple&) = default;
|
||||||
inline constexpr Tuple(Tuple&&) = default;
|
constexpr Tuple(Tuple&&) = default;
|
||||||
inline constexpr Tuple(Tuple&) = default;
|
constexpr Tuple(Tuple&) = default;
|
||||||
inline constexpr Tuple& operator=(const Tuple&) = default;
|
constexpr auto operator=(const Tuple&) -> Tuple& = default;
|
||||||
inline constexpr Tuple& operator=(Tuple&&) = default;
|
constexpr auto operator=(Tuple&&) -> Tuple& = default;
|
||||||
inline constexpr Tuple& operator=(Tuple&) = default;
|
constexpr auto operator=(Tuple&) -> Tuple& = default;
|
||||||
inline constexpr Tuple() :
|
constexpr Tuple() : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>() {};
|
||||||
impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...>() {};
|
constexpr auto operator==(const Tuple<Ts...>& other) const -> bool {
|
||||||
inline constexpr bool operator==(const Tuple<Ts...>& other) const {
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
|
|
||||||
return ((Get<Is>(*this) == Get<Is>(other)) && ...);
|
return ((Get<Is>(*this) == Get<Is>(other)) && ...);
|
||||||
}(std::index_sequence_for<Ts...>());
|
}(std::index_sequence_for<Ts...>());
|
||||||
};
|
};
|
||||||
template <typename... TTs>
|
template <typename... TTs>
|
||||||
inline constexpr auto operator+(const Tuple<TTs...>& other) const -> Tuple<Ts..., TTs...> {
|
constexpr auto operator+(const Tuple<TTs...>& other) const -> Tuple<Ts..., TTs...> {
|
||||||
return [&]<std::size_t... Is, std::size_t... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) -> Tuple<Ts..., TTs...> {
|
return [&]<std::size_t... Is, std::size_t... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) -> Tuple<Ts..., TTs...> {
|
||||||
return {Get<Is>(*this)..., Get<IIs>(other)...};
|
return {Get<Is>(*this)..., Get<IIs>(other)...};
|
||||||
}(std::index_sequence_for<Ts...>(), std::index_sequence_for<TTs...>());
|
}(std::index_sequence_for<Ts...>(), std::index_sequence_for<TTs...>());
|
||||||
};
|
};
|
||||||
|
|
||||||
template <auto I>
|
template <auto I>
|
||||||
inline constexpr auto operator[](Wrapper<I>) const -> const auto& {
|
constexpr auto operator[](Wrapper<I>) const -> const auto& {
|
||||||
return Get<I>(*this);
|
return Get<I>(*this);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <auto I>
|
template <auto I>
|
||||||
inline constexpr auto operator[](Wrapper<I>) -> auto& {
|
constexpr auto operator[](Wrapper<I>) -> auto& {
|
||||||
return Get<I>(*this);
|
return Get<I>(*this);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -94,10 +97,10 @@ struct Tuple : impl::TupleHelper<std::index_sequence_for<Ts...>, Ts...> {
|
||||||
template <>
|
template <>
|
||||||
struct Tuple<> {
|
struct Tuple<> {
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
inline constexpr auto operator+(const Tuple<Ts...>& other) const -> Tuple<Ts...> {
|
constexpr auto operator+(const Tuple<Ts...>& other) const -> Tuple<Ts...> {
|
||||||
return other;
|
return other;
|
||||||
};
|
};
|
||||||
inline constexpr auto operator==(const Tuple<>&) const {
|
constexpr auto operator==(const Tuple<>&) const {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -109,4 +112,4 @@ consteval auto ListFromTuple(Tuple<Ts...>) -> TypeList<Ts...> {
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace utempl
|
} // namespace utempl
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <concepts>
|
|
||||||
#include <utility>
|
|
||||||
#include <array>
|
|
||||||
#include <utempl/overloaded.hpp>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <concepts>
|
||||||
|
#include <utempl/overloaded.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
|
@ -24,10 +23,12 @@ inline constexpr auto kTypeList = TypeList<Ts...>{};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsTypeList = Overloaded(
|
concept IsTypeList = Overloaded(
|
||||||
[]<typename... Ts>(TypeList<TypeList<Ts...>>) {return true;},
|
[]<typename... Ts>(TypeList<TypeList<Ts...>>) {
|
||||||
[](auto&&) {return false;}
|
return true;
|
||||||
)(kType<std::remove_cvref_t<T>>);
|
},
|
||||||
|
[](auto&&) {
|
||||||
|
return false;
|
||||||
|
})(kType<std::remove_cvref_t<T>>);
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
|
@ -40,9 +41,7 @@ struct Caster {};
|
||||||
template <std::size_t... Is, typename... Ts>
|
template <std::size_t... Is, typename... Ts>
|
||||||
struct Caster<std::index_sequence<Is...>, Ts...> : IndexedType<Is, Ts>... {};
|
struct Caster<std::index_sequence<Is...>, Ts...> : IndexedType<Is, Ts>... {};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
} // namespace impl
|
|
||||||
template <typename... Ts, typename... TTs>
|
template <typename... Ts, typename... TTs>
|
||||||
consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool {
|
consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool {
|
||||||
return std::same_as<decltype(first), decltype(second)>;
|
return std::same_as<decltype(first), decltype(second)>;
|
||||||
|
@ -54,8 +53,7 @@ consteval auto operator+(const TypeList<Ts...>&, const TypeList<TTs...>&) -> Typ
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t I, typename... Ts>
|
template <std::size_t I, typename... Ts>
|
||||||
consteval auto Get(TypeList<Ts...>) -> decltype(
|
consteval auto Get(TypeList<Ts...>) -> decltype([]<typename T>(impl::IndexedType<I, T>&&) -> T {
|
||||||
[]<typename T>(impl::IndexedType<I, T>&&) -> T {
|
|
||||||
}(impl::Caster<std::index_sequence_for<Ts...>, Ts...>{}));
|
}(impl::Caster<std::index_sequence_for<Ts...>, Ts...>{}));
|
||||||
|
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
|
@ -70,7 +68,6 @@ consteval auto Find(TypeList<Ts...>) -> std::size_t {
|
||||||
return std::ranges::find(arr, true) - arr.begin();
|
return std::ranges::find(arr, true) - arr.begin();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
consteval auto Reverse(TypeList<Ts...> list) {
|
consteval auto Reverse(TypeList<Ts...> list) {
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>) -> TypeList<decltype(Get<sizeof...(Ts) - Is - 1>(list))...> {
|
return [&]<auto... Is>(std::index_sequence<Is...>) -> TypeList<decltype(Get<sizeof...(Ts) - Is - 1>(list))...> {
|
||||||
|
@ -84,24 +81,20 @@ consteval auto Transform(TypeList<Ts...>, auto&& f) -> TypeList<decltype(f(TypeL
|
||||||
};
|
};
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) {
|
consteval auto FilterTypeList(TypeList<Ts...>, auto&& f) {
|
||||||
return (
|
return ((kTypeList<> +
|
||||||
(kTypeList<>
|
[](auto&& list) {
|
||||||
+ [](auto&& list) {
|
if constexpr(decltype(f(list))::kValue) {
|
||||||
if constexpr(decltype(f(list))::kValue) {
|
return list;
|
||||||
return list;
|
} else {
|
||||||
} else {
|
return kTypeList<>;
|
||||||
return kTypeList<>;
|
}
|
||||||
}
|
}(kType<Ts>)) +
|
||||||
}(kType<Ts>)
|
...);
|
||||||
)
|
|
||||||
+ ...);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
consteval auto Size(TypeList<Ts...>) -> std::size_t {
|
consteval auto Size(TypeList<Ts...>) -> std::size_t {
|
||||||
return sizeof...(Ts);
|
return sizeof...(Ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace utempl
|
||||||
} // namespace utempl
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <utempl/tuple.hpp>
|
|
||||||
#include <utempl/overloaded.hpp>
|
|
||||||
#include <utempl/constexpr_string.hpp>
|
|
||||||
#include <ranges>
|
|
||||||
#include <optional>
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <ranges>
|
||||||
|
#include <utempl/constexpr_string.hpp>
|
||||||
|
#include <utempl/overloaded.hpp>
|
||||||
|
#include <utempl/tuple.hpp>
|
||||||
|
|
||||||
namespace utempl {
|
namespace utempl {
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ struct Wrapper {
|
||||||
inline constexpr auto operator==(auto&& arg) const {
|
inline constexpr auto operator==(auto&& arg) const {
|
||||||
return arg == Value;
|
return arg == Value;
|
||||||
};
|
};
|
||||||
consteval operator decltype(Value)() const {
|
consteval operator decltype(Value)() const { // NOLINT
|
||||||
return Value;
|
return Value;
|
||||||
};
|
};
|
||||||
consteval auto operator*() const {
|
consteval auto operator*() const {
|
||||||
|
@ -32,25 +32,23 @@ template <std::size_t N>
|
||||||
struct kSeq {
|
struct kSeq {
|
||||||
template <typename F>
|
template <typename F>
|
||||||
friend constexpr auto operator|(F&& f, const kSeq<N>&) {
|
friend constexpr auto operator|(F&& f, const kSeq<N>&) {
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
return std::forward<F>(f)(kWrapper<Is>...);
|
return std::forward<F>(f)(kWrapper<Is>...);
|
||||||
}(std::make_index_sequence<N>());
|
}(std::make_index_sequence<N>());
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
inline constexpr impl::kSeq<N> kSeq;
|
inline constexpr impl::kSeq<N> kSeq;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <ConstexprString string, typename T = std::size_t>
|
template <ConstexprString string, typename T = std::size_t>
|
||||||
consteval auto ParseNumber() -> T {
|
consteval auto ParseNumber() -> T {
|
||||||
T response{};
|
T response{};
|
||||||
for(const auto& c : string) {
|
for(const auto& c : string) {
|
||||||
if (c >= '0' && c <= '9') {
|
if(c >= '0' && c <= '9') {
|
||||||
response = response * 10 + (c - '0');
|
response = response * 10 + (c - '0'); // NOLINT
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return response;
|
return response;
|
||||||
|
@ -62,10 +60,12 @@ consteval auto operator"" _c() {
|
||||||
return Wrapper<ParseNumber<ConstexprString<sizeof...(cs)>({cs...})>()>{};
|
return Wrapper<ParseNumber<ConstexprString<sizeof...(cs)>({cs...})>()>{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
|
|
||||||
template <std::size_t I, typename... Ts>
|
template <std::size_t I, typename... Ts>
|
||||||
inline constexpr auto Arg(Ts&&... args) -> decltype(auto) requires (I < sizeof...(Ts)) {
|
inline constexpr auto Arg(Ts&&... args) -> decltype(auto)
|
||||||
|
requires(I < sizeof...(Ts))
|
||||||
|
{
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>) -> decltype(auto) {
|
return [&]<auto... Is>(std::index_sequence<Is...>) -> decltype(auto) {
|
||||||
return [](decltype(Caster(Is))..., auto&& response, ...) -> decltype(auto) {
|
return [](decltype(Caster(Is))..., auto&& response, ...) -> decltype(auto) {
|
||||||
return response;
|
return response;
|
||||||
|
@ -73,10 +73,9 @@ inline constexpr auto Arg(Ts&&... args) -> decltype(auto) requires (I < sizeof..
|
||||||
}(std::make_index_sequence<I>());
|
}(std::make_index_sequence<I>());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <std::size_t Count>
|
template <std::size_t Count>
|
||||||
inline constexpr auto Times(auto&& f) {
|
inline constexpr auto Times(auto&& f) {
|
||||||
[&]<auto... Is>(std::index_sequence<Is...>){
|
[&]<auto... Is>(std::index_sequence<Is...>) {
|
||||||
(Arg<0>(f, Is)(), ...);
|
(Arg<0>(f, Is)(), ...);
|
||||||
}(std::make_index_sequence<Count>());
|
}(std::make_index_sequence<Count>());
|
||||||
};
|
};
|
||||||
|
@ -87,7 +86,6 @@ inline constexpr std::size_t kTupleSize = []() -> std::size_t {
|
||||||
return 0;
|
return 0;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr std::size_t kTupleSize<T&&> = kTupleSize<std::remove_reference_t<T>>;
|
inline constexpr std::size_t kTupleSize<T&&> = kTupleSize<std::remove_reference_t<T>>;
|
||||||
|
|
||||||
|
@ -104,8 +102,7 @@ template <template <typename, std::size_t> typename Array, typename T, std::size
|
||||||
inline constexpr std::size_t kTupleSize<Array<T, N>> = N;
|
inline constexpr std::size_t kTupleSize<Array<T, N>> = N;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct TupleMaker {
|
struct TupleMaker {};
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct TupleMaker<std::tuple<Ts...>> {
|
struct TupleMaker<std::tuple<Ts...>> {
|
||||||
|
@ -125,7 +122,8 @@ template <typename T, std::size_t N>
|
||||||
struct TupleMaker<std::array<T, N>> {
|
struct TupleMaker<std::array<T, N>> {
|
||||||
template <typename Arg, typename... Args>
|
template <typename Arg, typename... Args>
|
||||||
static inline constexpr auto Make(Arg&& arg, Args&&... args)
|
static inline constexpr auto Make(Arg&& arg, Args&&... args)
|
||||||
requires (std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...) {
|
requires(std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...)
|
||||||
|
{
|
||||||
return std::array{std::forward<Arg>(arg), std::forward<Args>(args)...};
|
return std::array{std::forward<Arg>(arg), std::forward<Args>(args)...};
|
||||||
};
|
};
|
||||||
static constexpr auto Make() -> std::array<T, 0> {
|
static constexpr auto Make() -> std::array<T, 0> {
|
||||||
|
@ -134,8 +132,7 @@ struct TupleMaker<std::array<T, N>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct TupleTieMaker {
|
struct TupleTieMaker {};
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct TupleTieMaker<std::tuple<Ts...>> {
|
struct TupleTieMaker<std::tuple<Ts...>> {
|
||||||
|
@ -157,29 +154,24 @@ template <typename T, std::size_t N>
|
||||||
struct TupleTieMaker<std::array<T, N>> {
|
struct TupleTieMaker<std::array<T, N>> {
|
||||||
template <typename Arg, typename... Args>
|
template <typename Arg, typename... Args>
|
||||||
static inline constexpr auto Make(Arg& arg, Args&... args) -> std::array<Arg&, sizeof...(Args) + 1>
|
static inline constexpr auto Make(Arg& arg, Args&... args) -> std::array<Arg&, sizeof...(Args) + 1>
|
||||||
requires (std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...) {
|
requires(std::same_as<std::remove_cvref_t<Arg>, std::remove_cvref_t<Args>> && ...)
|
||||||
|
{
|
||||||
return {arg, args...};
|
return {arg, args...};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T = Tuple<>, typename... Args>
|
template <typename T = Tuple<>, typename... Args>
|
||||||
inline constexpr auto MakeTuple(Args&&... args)
|
inline constexpr auto MakeTuple(Args&&... args) -> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) {
|
||||||
-> decltype(TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...)) {
|
|
||||||
return TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...);
|
return TupleMaker<std::remove_cvref_t<T>>::Make(std::forward<Args>(args)...);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T = Tuple<>, typename... Args>
|
template <typename T = Tuple<>, typename... Args>
|
||||||
inline constexpr auto MakeTie(Args&... args)
|
inline constexpr auto MakeTie(Args&... args) -> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
|
||||||
-> decltype(TupleTieMaker<std::remove_cvref_t<T>>::Make(args...)) {
|
|
||||||
return TupleTieMaker<std::remove_cvref_t<T>>::Make(args...);
|
return TupleTieMaker<std::remove_cvref_t<T>>::Make(args...);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept HasMakeTie = requires(int& arg) {MakeTie<T>(arg);};
|
concept HasMakeTie = requires(int& arg) { MakeTie<T>(arg); };
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
|
@ -188,7 +180,6 @@ struct Getter {
|
||||||
friend consteval auto Magic(Getter<T>);
|
friend consteval auto Magic(Getter<T>);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T, auto Insert>
|
template <typename T, auto Insert>
|
||||||
struct Inserter {
|
struct Inserter {
|
||||||
friend consteval auto Magic(Getter<T>) -> decltype(auto) {
|
friend consteval auto Magic(Getter<T>) -> decltype(auto) {
|
||||||
|
@ -196,7 +187,6 @@ struct Inserter {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct SafeTupleChecker {
|
struct SafeTupleChecker {
|
||||||
consteval SafeTupleChecker(SafeTupleChecker&&) {
|
consteval SafeTupleChecker(SafeTupleChecker&&) {
|
||||||
|
@ -218,12 +208,14 @@ struct IsSafeTuple {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsSafeTuple<T, bool(TrueF(Get<0>(std::move(Get<0>(Tuple{MakeTuple<T>(0, kSafeTupleChecker<T>)}))))
|
struct IsSafeTuple<
|
||||||
&& Magic(Getter<SafeTupleChecker<T>>{})) ? false : false> {
|
T,
|
||||||
|
bool(TrueF(Get<0>(std::move(Get<0>(Tuple{MakeTuple<T>(0, kSafeTupleChecker<T>)})))) && Magic(Getter<SafeTupleChecker<T>>{})) ? false
|
||||||
|
: false> {
|
||||||
static constexpr bool value = false;
|
static constexpr bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace impl
|
} // namespace impl
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr bool kForceEnableTuple = false;
|
inline constexpr bool kForceEnableTuple = false;
|
||||||
|
@ -231,14 +223,13 @@ inline constexpr bool kForceEnableTuple = false;
|
||||||
template <typename T, std::size_t N>
|
template <typename T, std::size_t N>
|
||||||
inline constexpr bool kForceEnableTuple<std::array<T, N>> = true;
|
inline constexpr bool kForceEnableTuple<std::array<T, N>> = true;
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept TupleLike = kForceEnableTuple<std::remove_cvref_t<T>> || (requires{Get<0>(MakeTuple<T>(42));} && impl::IsSafeTuple<std::remove_cvref_t<T>>::value);
|
concept TupleLike = kForceEnableTuple<std::remove_cvref_t<T>> ||
|
||||||
|
(requires { Get<0>(MakeTuple<T>(42)); } && impl::IsSafeTuple<std::remove_cvref_t<T>>::value); // NOLINT
|
||||||
|
|
||||||
template <typename F, typename Tuple>
|
template <typename F, typename Tuple>
|
||||||
concept TupleTransformer = requires(F f, Tuple&& tuple) {
|
concept TupleTransformer = requires(F f, Tuple&& tuple) {
|
||||||
{f(std::move(tuple))};
|
{ f(std::move(tuple)) };
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::invocable F>
|
template <std::invocable F>
|
||||||
|
@ -260,41 +251,51 @@ struct LazyTuple {
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr auto operator==(T&& other)
|
inline constexpr auto operator==(T&& other)
|
||||||
requires requires(ResultType result){result == std::forward<T>(other);} {
|
requires requires(ResultType result) { result == std::forward<T>(other); }
|
||||||
|
{
|
||||||
return (*this)() == other;
|
return (*this)() == other;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr auto operator==(T&& other) const
|
inline constexpr auto operator==(T&& other) const
|
||||||
requires requires(ResultType result){result == std::forward<T>(other);} {
|
requires requires(ResultType result) { result == std::forward<T>(other); }
|
||||||
|
{
|
||||||
return (*this)() == other;
|
return (*this)() == other;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr operator std::invoke_result_t<F>() {
|
inline constexpr operator std::invoke_result_t<F>() { // NOLINT
|
||||||
return (*this)();
|
return (*this)();
|
||||||
};
|
};
|
||||||
inline constexpr operator std::invoke_result_t<F>() const {
|
inline constexpr operator std::invoke_result_t<F>() const { // NOLINT
|
||||||
return (*this)();
|
return (*this)();
|
||||||
};
|
};
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
friend inline constexpr auto Get(LazyTuple&& tuple) -> decltype(auto) requires TupleLike<ResultType> {
|
friend inline constexpr auto Get(LazyTuple&& tuple) -> decltype(auto)
|
||||||
|
requires TupleLike<ResultType>
|
||||||
|
{
|
||||||
return Get<I>(std::move(tuple)());
|
return Get<I>(std::move(tuple)());
|
||||||
};
|
};
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
friend inline constexpr auto Get(const LazyTuple&& tuple) -> decltype(auto) requires TupleLike<ResultType> {
|
friend inline constexpr auto Get(const LazyTuple&& tuple) -> decltype(auto)
|
||||||
|
requires TupleLike<ResultType>
|
||||||
|
{
|
||||||
return Get<I>(std::move(tuple)());
|
return Get<I>(std::move(tuple)());
|
||||||
};
|
};
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
friend inline constexpr auto Get(LazyTuple& tuple) -> decltype(auto) requires TupleLike<ResultType> {
|
friend inline constexpr auto Get(LazyTuple& tuple) -> decltype(auto)
|
||||||
|
requires TupleLike<ResultType>
|
||||||
|
{
|
||||||
return Get<I>(tuple());
|
return Get<I>(tuple());
|
||||||
};
|
};
|
||||||
template <std::size_t I>
|
template <std::size_t I>
|
||||||
friend inline constexpr auto Get(const LazyTuple& tuple) -> decltype(auto) requires TupleLike<ResultType> {
|
friend inline constexpr auto Get(const LazyTuple& tuple) -> decltype(auto)
|
||||||
|
requires TupleLike<ResultType>
|
||||||
|
{
|
||||||
return Get<I>(tuple());
|
return Get<I>(tuple());
|
||||||
};
|
};
|
||||||
template <typename FF>
|
template <typename FF>
|
||||||
inline constexpr auto operator|(FF&& ff) {
|
inline constexpr auto operator|(FF&& ff) {
|
||||||
auto f = [ff = std::forward<FF>(ff), self = (*this)](){
|
auto f = [ff = std::forward<FF>(ff), self = (*this)]() {
|
||||||
return ff(self());
|
return ff(self());
|
||||||
};
|
};
|
||||||
return LazyTuple<decltype(f)>{std::move(f)};
|
return LazyTuple<decltype(f)>{std::move(f)};
|
||||||
|
@ -304,21 +305,19 @@ template <std::invocable F>
|
||||||
struct TupleMaker<LazyTuple<F>> {
|
struct TupleMaker<LazyTuple<F>> {
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
static inline constexpr auto Make(Ts&&... args)
|
static inline constexpr auto Make(Ts&&... args)
|
||||||
requires requires {TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...);} {
|
requires requires { TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...); }
|
||||||
|
{
|
||||||
return TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...);
|
return TupleMaker<typename LazyTuple<F>::ResultType>::Make(std::forward<Ts>(args)...);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple, TupleTransformer<Tuple> FF>
|
template <TupleLike Tuple, TupleTransformer<Tuple> FF>
|
||||||
inline constexpr auto operator|(Tuple&& tuple, FF&& f) {
|
inline constexpr auto operator|(Tuple&& tuple, FF&& f) {
|
||||||
return LazyTuple{
|
return LazyTuple{[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) {
|
||||||
[tuple = std::forward<Tuple>(tuple), f = std::forward<FF>(f)]() -> decltype(auto) {
|
return f(std::move(tuple));
|
||||||
return f(std::move(tuple));
|
}};
|
||||||
}};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple, typename F>
|
template <TupleLike Tuple, typename F>
|
||||||
inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
|
inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
|
||||||
return [&](auto... is) -> decltype(auto) {
|
return [&](auto... is) -> decltype(auto) {
|
||||||
|
@ -328,24 +327,21 @@ inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
inline constexpr auto Unpack(F&& f) {
|
inline constexpr auto Unpack(F&& f) {
|
||||||
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple){
|
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
return Unpack(std::forward<Tuple>(tuple), std::move(f));
|
return Unpack(std::forward<Tuple>(tuple), std::move(f));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple, typename R = Tuple, typename F>
|
template <TupleLike Tuple, typename R = Tuple, typename F>
|
||||||
inline constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) {
|
inline constexpr auto Transform(Tuple&& container, F&& f, TypeList<R> = {}) {
|
||||||
return Unpack(std::forward<Tuple>(container),
|
return Unpack(std::forward<Tuple>(container), [&]<typename... Ts>(Ts&&... args) {
|
||||||
[&]<typename... Ts>(Ts&&... args){
|
return MakeTuple<R>(f(std::forward<Ts>(args))...);
|
||||||
return MakeTuple<R>(f(std::forward<Ts>(args))...);
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename F, typename R = void>
|
template <typename F, typename R = void>
|
||||||
inline constexpr auto Transform(F&& f, TypeList<R> result = {}) {
|
inline constexpr auto Transform(F&& f, TypeList<R> result = {}) {
|
||||||
return [f = std::forward<F>(f), result]<TupleLike Tuple>(Tuple&& tuple){
|
return [f = std::forward<F>(f), result]<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
if constexpr(!std::is_same_v<R, void>) {
|
if constexpr(!std::is_same_v<R, void>) {
|
||||||
return Transform(std::forward<Tuple>(tuple), std::move(f), result);
|
return Transform(std::forward<Tuple>(tuple), std::move(f), result);
|
||||||
} else {
|
} else {
|
||||||
|
@ -354,7 +350,6 @@ inline constexpr auto Transform(F&& f, TypeList<R> result = {}) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple, typename R = Tuple, typename F>
|
template <TupleLike Tuple, typename R = Tuple, typename F>
|
||||||
inline constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> result = {}) {
|
inline constexpr auto Map(Tuple&& tuple, F&& f, TypeList<R> result = {}) {
|
||||||
return Transform(std::forward<Tuple>(tuple), std::forward<F>(f), result);
|
return Transform(std::forward<Tuple>(tuple), std::forward<F>(f), result);
|
||||||
|
@ -378,7 +373,6 @@ consteval auto PackConstexprWrapper() {
|
||||||
}(std::make_index_sequence<kTupleSize<decltype(Tuple)>>());
|
}(std::make_index_sequence<kTupleSize<decltype(Tuple)>>());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple>
|
template <TupleLike Tuple>
|
||||||
inline constexpr auto Reverse(Tuple&& tuple) {
|
inline constexpr auto Reverse(Tuple&& tuple) {
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
|
@ -413,19 +407,14 @@ struct LeftFold<T, F> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace impl
|
||||||
|
|
||||||
} // namespace impl
|
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple, typename T, typename F>
|
template <TupleLike Tuple, typename T, typename F>
|
||||||
inline constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f) {
|
inline constexpr auto LeftFold(Tuple&& tuple, T&& init, F&& f) {
|
||||||
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args){
|
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||||
return (
|
return (impl::LeftFold<std::remove_cvref_t<T>, std::remove_cvref_t<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)} | ... |
|
||||||
impl::LeftFold<std::remove_cvref_t<T>, std::remove_cvref_t<F>>{.data = std::forward<T>(init), .f = std::forward<F>(f)}
|
impl::LeftFold<std::remove_cvref_t<Ts>>{.data = std::forward<Ts>(args)})
|
||||||
| ...
|
.data;
|
||||||
| impl::LeftFold<std::remove_cvref_t<Ts>>{.data = std::forward<Ts>(args)}
|
|
||||||
).data;
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -436,27 +425,27 @@ inline constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) {
|
||||||
|
|
||||||
template <typename T, typename F>
|
template <typename T, typename F>
|
||||||
inline constexpr auto Reduce(T&& init, F&& f) {
|
inline constexpr auto Reduce(T&& init, F&& f) {
|
||||||
return [init = std::forward<T>(init), f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple){
|
return [init = std::forward<T>(init), f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
return Reduce(std::forward<Tuple>(tuple), std::move(init), std::move(f));
|
return Reduce(std::forward<Tuple>(tuple), std::move(init), std::move(f));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple, TupleLike Tuple2>
|
template <TupleLike Tuple, TupleLike Tuple2>
|
||||||
inline constexpr auto TupleCat(Tuple&& tuple, Tuple2&& tuple2) {
|
inline constexpr auto TupleCat(Tuple&& tuple, Tuple2&& tuple2) {
|
||||||
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>){
|
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) {
|
||||||
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))..., Get<IIs>(std::forward<Tuple2>(tuple2))...);
|
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))..., Get<IIs>(std::forward<Tuple2>(tuple2))...);
|
||||||
}(std::make_index_sequence<kTupleSize<Tuple>>(), std::make_index_sequence<kTupleSize<Tuple2>>());
|
}(std::make_index_sequence<kTupleSize<Tuple>>(), std::make_index_sequence<kTupleSize<Tuple2>>());
|
||||||
};
|
};
|
||||||
|
|
||||||
template <TupleLike... Tuples>
|
template <TupleLike... Tuples>
|
||||||
inline constexpr auto TupleCat(Tuples&&... tuples) requires (sizeof...(tuples) >= 1) {
|
inline constexpr auto TupleCat(Tuples&&... tuples)
|
||||||
return LeftFold(
|
requires(sizeof...(tuples) >= 1)
|
||||||
Tuple{std::forward<Tuples>(tuples)...},
|
{
|
||||||
MakeTuple<decltype(Arg<0>(std::forward<Tuples>(tuples)...))>(),
|
return LeftFold(Tuple{std::forward<Tuples>(tuples)...},
|
||||||
[]<TupleLike Tup, TupleLike Tup2>(Tup&& tup, Tup2&& tup2){
|
MakeTuple<decltype(Arg<0>(std::forward<Tuples>(tuples)...))>(),
|
||||||
return TupleCat(std::forward<Tup>(tup), std::forward<Tup2>(tup2));
|
[]<TupleLike Tup, TupleLike Tup2>(Tup&& tup, Tup2&& tup2) {
|
||||||
});
|
return TupleCat(std::forward<Tup>(tup), std::forward<Tup2>(tup2));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
template <TupleLike... Tuples, typename F>
|
template <TupleLike... Tuples, typename F>
|
||||||
|
@ -464,7 +453,6 @@ inline constexpr auto Unpack(Tuples&&... tuples, F&& f) {
|
||||||
return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f));
|
return Unpack(TupleCat(std::forward<Tuples>(tuples)...), std::forward<F>(f));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
|
inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
|
||||||
return {args...};
|
return {args...};
|
||||||
|
@ -472,8 +460,8 @@ inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
|
||||||
|
|
||||||
template <template <typename...> typename F, TupleLike Tuple>
|
template <template <typename...> typename F, TupleLike Tuple>
|
||||||
inline constexpr bool kEveryElement = [](auto... is) {
|
inline constexpr bool kEveryElement = [](auto... is) {
|
||||||
return (F<std::decay_t<decltype(Get<is>(std::declval<Tuple>()))>>::value && ...);
|
return (F<std::decay_t<decltype(Get<is>(std::declval<Tuple>()))>>::value && ...);
|
||||||
} | kSeq<kTupleSize<Tuple>>;
|
} | kSeq<kTupleSize<Tuple>>;
|
||||||
|
|
||||||
template <template <typename...> typename F, typename... Ts>
|
template <template <typename...> typename F, typename... Ts>
|
||||||
struct PartialCaller {
|
struct PartialCaller {
|
||||||
|
@ -482,25 +470,21 @@ struct PartialCaller {
|
||||||
};
|
};
|
||||||
template <template <typename...> typename F, typename... Ts>
|
template <template <typename...> typename F, typename... Ts>
|
||||||
consteval auto PartialCallerF(TypeList<Ts...>) {
|
consteval auto PartialCallerF(TypeList<Ts...>) {
|
||||||
return []<typename... TTs>(TypeList<TTs...>){
|
return []<typename... TTs>(TypeList<TTs...>) {
|
||||||
return F<Ts..., TTs...>{};
|
return F<Ts..., TTs...>{};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple, typename T>
|
template <TupleLike Tuple, typename T>
|
||||||
inline constexpr auto FirstOf(Tuple&& tuple, T&& init) requires kEveryElement<std::is_invocable, Tuple> {
|
inline constexpr auto FirstOf(Tuple&& tuple, T&& init)
|
||||||
return LeftFold(
|
requires kEveryElement<std::is_invocable, Tuple>
|
||||||
std::forward<Tuple>(tuple),
|
{
|
||||||
std::forward<T>(init),
|
return LeftFold(std::forward<Tuple>(tuple), std::forward<T>(init), []<typename TT, typename F>(TT&& value, F&& f) -> TT {
|
||||||
[]<typename TT, typename F>(TT&& value, F&& f) -> TT {
|
if(value) {
|
||||||
if(value) {
|
return value;
|
||||||
return value;
|
};
|
||||||
};
|
return f();
|
||||||
return f();
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -510,48 +494,43 @@ inline constexpr auto FirstOf(T&& init) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <TupleLike Tuple>
|
template <TupleLike Tuple>
|
||||||
inline constexpr auto Filter(Tuple&& tuple, auto&& f) {
|
inline constexpr auto Filter(Tuple&& tuple, auto&& f) {
|
||||||
return LeftFold(
|
return LeftFold(
|
||||||
std::forward<Tuple>(tuple),
|
std::forward<Tuple>(tuple), MakeTuple<Tuple>(), [&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
|
||||||
MakeTuple<Tuple>(),
|
if constexpr(decltype(f(std::forward<T>(add))){}) {
|
||||||
[&]<TupleLike Accumulator, typename T>(Accumulator&& accumulator, T&& add) {
|
return TupleCat(std::forward<Accumulator>(accumulator), std::forward<T>(add));
|
||||||
if constexpr(decltype(f(std::forward<T>(add))){}) {
|
} else {
|
||||||
return TupleCat(std::forward<Accumulator>(accumulator), std::forward<T>(add));
|
return accumulator;
|
||||||
} else {
|
};
|
||||||
return accumulator;
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
inline constexpr auto Filter(F&& f) {
|
inline constexpr auto Filter(F&& f) {
|
||||||
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple){
|
return [f = std::forward<F>(f)]<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
return Filter(std::forward<Tuple>(tuple), std::move(f));
|
return Filter(std::forward<Tuple>(tuple), std::move(f));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <TupleLike Tuple>
|
template <TupleLike Tuple>
|
||||||
inline constexpr auto ForEach(Tuple&& tuple, auto&& f) {
|
inline constexpr auto ForEach(Tuple&& tuple, auto&& f) {
|
||||||
Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args){
|
Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||||
(f(std::forward<Ts>(args)), ...);
|
(f(std::forward<Ts>(args)), ...);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename F, typename... Ts>
|
template <typename F, typename... Ts>
|
||||||
struct Curryer {
|
struct Curryer {
|
||||||
F f;
|
F f;
|
||||||
Tuple<Ts...> data;
|
Tuple<Ts...> data;
|
||||||
inline constexpr operator std::invoke_result_t<F, Ts...>() const {
|
inline constexpr operator std::invoke_result_t<F, Ts...>() const { // NOLINT
|
||||||
return [&]<auto... Is>(std::index_sequence<Is...>){
|
return [&]<auto... Is>(std::index_sequence<Is...>) {
|
||||||
return this->f(Get<Is>(this->data)...);
|
return this->f(Get<Is>(this->data)...);
|
||||||
}(std::index_sequence_for<Ts...>());
|
}(std::index_sequence_for<Ts...>());
|
||||||
};
|
};
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline constexpr auto operator()(T&& arg) const -> Curryer<F, Ts..., std::remove_cvref_t<T>>{
|
inline constexpr auto operator()(T&& arg) const -> Curryer<F, Ts..., std::remove_cvref_t<T>> {
|
||||||
return {.f = this->f, .data = this->data + Tuple{std::forward<T>(arg)}};
|
return {.f = this->f, .data = this->data + Tuple{std::forward<T>(arg)}};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -565,22 +544,21 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
|
||||||
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||||
using Type = std::remove_cvref_t<T>;
|
using Type = std::remove_cvref_t<T>;
|
||||||
std::array<bool, kTupleSize<Tuple>> bs{Overloaded(
|
std::array<bool, kTupleSize<Tuple>> bs{Overloaded(
|
||||||
[&](const Type& element) {
|
[&](const Type& element) {
|
||||||
return element == find;
|
return element == find;
|
||||||
},
|
},
|
||||||
[&](const Type&& element) {
|
[&](const Type&& element) {
|
||||||
return element == find;
|
return element == find;
|
||||||
},
|
},
|
||||||
[&](Type&& element) {
|
[&](Type&& element) {
|
||||||
return element == find;
|
return element == find;
|
||||||
},
|
},
|
||||||
[&](Type& element) {
|
[&](Type& element) {
|
||||||
return element == find;
|
return element == find;
|
||||||
},
|
},
|
||||||
[](auto&&) {
|
[](auto&&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
})(std::forward<Ts>(args))...};
|
||||||
)(std::forward<Ts>(args))...};
|
|
||||||
return std::ranges::find(bs, true) - bs.begin();
|
return std::ranges::find(bs, true) - bs.begin();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -588,11 +566,11 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
|
||||||
template <std::size_t N, TupleLike Tuple>
|
template <std::size_t N, TupleLike Tuple>
|
||||||
inline constexpr auto Take(Tuple&& tuple) {
|
inline constexpr auto Take(Tuple&& tuple) {
|
||||||
if constexpr(std::is_lvalue_reference_v<Tuple> && HasMakeTie<Tuple>) {
|
if constexpr(std::is_lvalue_reference_v<Tuple> && HasMakeTie<Tuple>) {
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
return MakeTie<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...);
|
return MakeTie<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...);
|
||||||
}(std::make_index_sequence<N>());
|
}(std::make_index_sequence<N>());
|
||||||
} else {
|
} else {
|
||||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
|
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||||
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...);
|
return MakeTuple<Tuple>(Get<Is>(std::forward<Tuple>(tuple))...);
|
||||||
}(std::make_index_sequence<N>());
|
}(std::make_index_sequence<N>());
|
||||||
};
|
};
|
||||||
|
@ -600,14 +578,14 @@ inline constexpr auto Take(Tuple&& tuple) {
|
||||||
|
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
consteval auto Take() {
|
consteval auto Take() {
|
||||||
return [&]<TupleLike Tuple>(Tuple&& tuple){
|
return [&]<TupleLike Tuple>(Tuple&& tuple) {
|
||||||
return Take<N>(std::forward<Tuple>(tuple));
|
return Take<N>(std::forward<Tuple>(tuple));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <TupleLike Tuple, typename T>
|
template <TupleLike Tuple, typename T>
|
||||||
inline constexpr auto operator<<(Tuple&& tuple, T&& t) {
|
inline constexpr auto operator<<(Tuple&& tuple, T&& t) {
|
||||||
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args){
|
return Unpack(std::forward<Tuple>(tuple), [&]<typename... Ts>(Ts&&... args) {
|
||||||
return MakeTuple<Tuple>(std::forward<Ts>(args)..., std::forward<T>(t));
|
return MakeTuple<Tuple>(std::forward<Ts>(args)..., std::forward<T>(t));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -619,5 +597,4 @@ inline constexpr auto Generate(T&& value) {
|
||||||
} | kSeq<N>;
|
} | kSeq<N>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace utempl
|
||||||
} // namespace utempl
|
|
||||||
|
|
Loading…
Reference in a new issue