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

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

13
.clang-format Normal file
View file

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

1
.clang-tidy Normal file
View file

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

View file

@ -2,11 +2,8 @@
#include <utempl/meta_info.hpp>
#include <utempl/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...,
auto f = []{},
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 = []{},
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,44 +56,36 @@ consteval auto FieldAttribute() -> T;
template <typename... Ts>
using FieldAttribute = decltype(impl::FieldAttribute<Ts...>());
#define ATTRIBUTE_STRUCT(name, ...) struct name { \
static_assert(::utempl::OpenStruct<name>()); \
template <std::size_t N> \
static consteval auto GetAttribute(); \
#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());\
}
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>();};
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

View file

@ -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

View file

@ -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) {
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))...};
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))...};
}(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 {
return [&]<auto... Is>(std::index_sequence<Is...>){
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

View file

@ -9,10 +9,11 @@ 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 {
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>
concept Injected = InjectedImpl<I, void, Ts...>::value;
} // namespace utempl::loopholes

View file

@ -1,7 +1,7 @@
#pragma once
#include <utempl/loopholes/core.hpp>
#include <cstddef>
#include <tuple>
#include <utempl/loopholes/core.hpp>
namespace utempl::loopholes {
@ -12,7 +12,7 @@ struct TagWithValue {};
template <bool Add, typename Tag, std::size_t I, typename... Ts>
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...>();
};
if constexpr(Add) {
@ -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);

View file

@ -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;
} while (num != 0);
num /= 10; // NOLINT
} while(num != 0);
return count;
};
constexpr std::size_t GetDigit(std::size_t num, std::size_t index) {
for (std::size_t i = 0; i < index; ++i) {
num /= 10;
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; // 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:
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:
public:
Tuple<Fs...> functionStorage;
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);
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

View file

@ -9,35 +9,31 @@ 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:
private:
static constexpr auto _ = loopholes::Injector<MetaInfoKey<kTypeId, Tag>{}, TypeList<T>{}>{};
};
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,12 +43,13 @@ 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>{}>{});}) {
if constexpr(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 {
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>{}>{});
return GetTypeListForTag<Tag, I + 1, Ts..., typename decltype(type)::Type>(g);
} 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

View file

@ -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();
};
};

View file

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

View file

@ -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;

View file

@ -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 {
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
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;
};
};

View file

@ -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

View file

@ -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 {
@ -32,7 +32,7 @@ template <std::size_t N>
struct kSeq {
template <typename F>
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>...);
}(std::make_index_sequence<N>());
};
@ -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');
if(c >= '0' && c <= '9') {
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,10 +73,9 @@ 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...>){
[&]<auto... Is>(std::index_sequence<Is...>) {
(Arg<0>(f, Is)(), ...);
}(std::make_index_sequence<Count>());
};
@ -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,29 +154,24 @@ 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);};
concept HasMakeTie = requires(int& arg) { MakeTie<T>(arg); };
namespace impl {
@ -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,14 +223,13 @@ 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) {
{f(std::move(tuple))};
{ f(std::move(tuple)) };
};
template <std::invocable F>
@ -260,41 +251,51 @@ 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>
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 LazyTuple<decltype(f)>{std::move(f)};
@ -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) {
@ -328,24 +327,21 @@ inline constexpr auto Unpack(Tuple&& tuple, F&& f) -> decltype(auto) {
template <typename 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));
};
};
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))...);
});
};
template <typename F, typename R = void>
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>) {
return Transform(std::forward<Tuple>(tuple), std::move(f), result);
} else {
@ -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 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;
});
};
@ -436,25 +425,25 @@ inline constexpr auto Reduce(Tuple&& tuple, T&& init, F&& f) {
template <typename T, typename 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));
};
};
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...>){
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))...);
}(std::make_index_sequence<kTupleSize<Tuple>>(), std::make_index_sequence<kTupleSize<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){
[]<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...};
@ -473,7 +461,7 @@ inline constexpr auto Tie(Ts&... args) -> Tuple<Ts&...> {
template <template <typename...> typename F, TupleLike Tuple>
inline constexpr bool kEveryElement = [](auto... is) {
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>
struct PartialCaller {
@ -482,25 +470,21 @@ struct PartialCaller {
};
template <template <typename...> typename F, typename... Ts>
consteval auto PartialCallerF(TypeList<Ts...>) {
return []<typename... TTs>(TypeList<TTs...>){
return []<typename... TTs>(TypeList<TTs...>) {
return F<Ts..., TTs...>{};
};
};
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,48 +494,43 @@ 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>
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));
};
};
template <TupleLike Tuple>
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)), ...);
});
};
template <typename F, typename... Ts>
struct Curryer {
F f;
Tuple<Ts...> data;
inline constexpr operator std::invoke_result_t<F, Ts...>() const {
return [&]<auto... Is>(std::index_sequence<Is...>){
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...>());
};
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)}};
};
};
@ -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();
});
};
@ -588,11 +566,11 @@ inline constexpr auto Find(Tuple&& tuple, T&& find) -> std::size_t {
template <std::size_t N, TupleLike Tuple>
inline constexpr auto Take(Tuple&& 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))...);
}(std::make_index_sequence<N>());
} 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))...);
}(std::make_index_sequence<N>());
};
@ -600,14 +578,14 @@ inline constexpr auto Take(Tuple&& tuple) {
template <std::size_t N>
consteval auto Take() {
return [&]<TupleLike Tuple>(Tuple&& tuple){
return [&]<TupleLike Tuple>(Tuple&& tuple) {
return Take<N>(std::forward<Tuple>(tuple));
};
};
template <TupleLike Tuple, typename 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));
});
};
@ -619,5 +597,4 @@ inline constexpr auto Generate(T&& value) {
} | kSeq<N>;
};
} // namespace utempl