Split into multiply files
This commit is contained in:
parent
5bbe94f279
commit
6e873fbc65
5 changed files with 326 additions and 284 deletions
86
include/utempl/constexpr_string.hpp
Normal file
86
include/utempl/constexpr_string.hpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
#pragma once
|
||||
#include <fmt/core.h>
|
||||
|
||||
namespace utempl {
|
||||
template <std::size_t>
|
||||
struct ConstexprString;
|
||||
};
|
||||
|
||||
template <std::size_t Size>
|
||||
struct fmt::formatter<utempl::ConstexprString<Size>> : public fmt::formatter<std::string_view> {
|
||||
constexpr auto parse(format_parse_context& ctx) const {
|
||||
return ctx.begin();
|
||||
};
|
||||
inline constexpr auto format(const utempl::ConstexprString<Size>& str, auto& ctx) const {
|
||||
return fmt::formatter<std::string_view>::format({str.begin()}, ctx);
|
||||
};
|
||||
};
|
||||
|
||||
namespace utempl {
|
||||
|
||||
template <std::size_t Size>
|
||||
struct ConstexprString {
|
||||
std::array<char, Size> data;
|
||||
inline constexpr auto begin() -> char* {
|
||||
return this->data.begin();
|
||||
};
|
||||
inline constexpr auto begin() const -> const char* {
|
||||
return this->data.begin();
|
||||
};
|
||||
inline constexpr auto end() -> char* {
|
||||
return this->data.end();
|
||||
};
|
||||
inline 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{} {
|
||||
std::ranges::copy_n(data, Size, this->data.begin());
|
||||
|
||||
};
|
||||
inline 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 {
|
||||
return Size == 0 ? 0 : Size - 1;
|
||||
};
|
||||
inline constexpr operator std::string_view() const & {
|
||||
return {this->begin()};
|
||||
};
|
||||
inline constexpr bool operator==(std::string_view other) const {
|
||||
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> {
|
||||
ConstexprString<Size + SSize - 1> response;
|
||||
std::copy_n(this->begin(), Size - 1, response.begin());
|
||||
std::copy_n(other.begin(), SSize, response.begin() + Size - 1);
|
||||
return response;
|
||||
};
|
||||
inline constexpr ConstexprString(const ConstexprString&) = default;
|
||||
inline constexpr ConstexprString(ConstexprString&&) = default;
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
inline 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 = {};
|
||||
for(std::size_t i = 0; i < Count; i++) {
|
||||
str.data[i] = c;
|
||||
};
|
||||
str.data[Count] = '\0';
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t Size>
|
||||
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>;
|
||||
} // namespace utempl
|
||||
|
|
@ -1,83 +1,19 @@
|
|||
#pragma once
|
||||
#include <utempl/optional.hpp>
|
||||
#include <utempl/constexpr_string.hpp>
|
||||
#include <utempl/tuple.hpp>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <concepts>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/compile.h>
|
||||
|
||||
|
||||
namespace utempl::utils {
|
||||
template <std::size_t>
|
||||
struct ConstexprString;
|
||||
};
|
||||
|
||||
template <std::size_t Size>
|
||||
struct fmt::formatter<utempl::utils::ConstexprString<Size>> : public fmt::formatter<std::string_view> {
|
||||
constexpr auto parse(format_parse_context& ctx) const {
|
||||
return ctx.begin();
|
||||
};
|
||||
inline constexpr auto format(const utempl::utils::ConstexprString<Size>& str, auto& ctx) const {
|
||||
return fmt::formatter<std::string_view>::format({str.data.begin()}, ctx);
|
||||
};
|
||||
};
|
||||
|
||||
namespace utempl {
|
||||
|
||||
namespace utils {
|
||||
|
||||
template <std::size_t Size>
|
||||
struct ConstexprString {
|
||||
std::array<char, Size> data;
|
||||
static constexpr auto kSize = Size == 0 ? 0 : Size - 1;
|
||||
inline constexpr ConstexprString() = default;
|
||||
inline constexpr ConstexprString(const char (&data)[Size]) : data{} {
|
||||
std::ranges::copy_n(data, Size, this->data.begin());
|
||||
|
||||
};
|
||||
inline 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 {
|
||||
return Size == 0 ? 0 : Size - 1;
|
||||
};
|
||||
inline constexpr explicit operator std::string_view() const {
|
||||
return {this->data.begin()};
|
||||
};
|
||||
inline constexpr bool operator==(std::string_view other) const {
|
||||
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> {
|
||||
ConstexprString<Size + SSize - 1> response;
|
||||
std::copy_n(this->data.begin(), Size - 1, response.data.begin());
|
||||
std::copy_n(other.data.begin(), SSize, response.data.begin() + Size - 1);
|
||||
return response;
|
||||
};
|
||||
inline constexpr ConstexprString(const ConstexprString&) = default;
|
||||
inline constexpr ConstexprString(ConstexprString&&) = default;
|
||||
};
|
||||
|
||||
template <std::size_t Count>
|
||||
consteval auto createStringWith(char c) {
|
||||
ConstexprString<Count + 1> str = {};
|
||||
for(std::size_t i = 0; i < Count; i++) {
|
||||
str.data[i] = c;
|
||||
};
|
||||
str.data[Count] = '\0';
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t Size>
|
||||
ConstexprString(const char (&data)[Size]) -> ConstexprString<Size>;
|
||||
|
||||
|
||||
template <auto>
|
||||
struct Wrapper {};
|
||||
|
||||
constexpr std::size_t countDigits(std::size_t num) {
|
||||
constexpr std::size_t CountDigits(std::size_t num) {
|
||||
std::size_t count = 0;
|
||||
do {
|
||||
++count;
|
||||
|
@ -86,7 +22,7 @@ constexpr std::size_t countDigits(std::size_t num) {
|
|||
return count;
|
||||
};
|
||||
|
||||
constexpr std::size_t getDigit(std::size_t num, std::size_t index) {
|
||||
constexpr std::size_t GetDigit(std::size_t num, std::size_t index) {
|
||||
for (std::size_t i = 0; i < index; ++i) {
|
||||
num /= 10;
|
||||
}
|
||||
|
@ -94,15 +30,15 @@ constexpr std::size_t getDigit(std::size_t num, std::size_t index) {
|
|||
};
|
||||
|
||||
template <std::size_t num>
|
||||
consteval auto toString() {
|
||||
constexpr std::size_t digits = countDigits(num);
|
||||
consteval auto ToString() {
|
||||
constexpr std::size_t digits = CountDigits(num);
|
||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
return utils::ConstexprString{std::array{static_cast<char>('0' + getDigit(num, digits - 1 - Is))..., '\0'}};
|
||||
return ConstexprString{std::array{static_cast<char>('0' + GetDigit(num, digits - 1 - Is))..., '\0'}};
|
||||
}(std::make_index_sequence<digits>());
|
||||
};
|
||||
|
||||
template <typename Range>
|
||||
constexpr auto getMax(Range&& range) {
|
||||
constexpr auto GetMax(Range&& range) {
|
||||
std::remove_cvref_t<decltype(range[0])> response = 0;
|
||||
for(const auto& element : range) {
|
||||
response = element > response ? element : response;
|
||||
|
@ -110,156 +46,6 @@ constexpr auto getMax(Range&& range) {
|
|||
return response;
|
||||
};
|
||||
|
||||
struct Caster {
|
||||
constexpr Caster(auto&&) {};
|
||||
};
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
struct TypeList {
|
||||
};
|
||||
template <typename... Ts, typename... TTs>
|
||||
consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool {
|
||||
return std::is_same_v<decltype(first), decltype(second)>;
|
||||
};
|
||||
template <std::size_t... Is, typename T>
|
||||
consteval auto get(std::index_sequence<Is...>, decltype(Caster(Is))..., T, ...) -> T;
|
||||
|
||||
|
||||
template <std::size_t I, typename... Ts>
|
||||
consteval auto get(const TypeList<Ts...>&) -> decltype(get(std::make_index_sequence<I>(), std::declval<Ts>()...)) requires (I < sizeof...(Ts));
|
||||
|
||||
|
||||
|
||||
|
||||
template <auto, typename T>
|
||||
struct TupleLeaf {
|
||||
T value;
|
||||
template <typename TT>
|
||||
inline constexpr TupleLeaf(TT&& arg) : value(std::forward<TT>(arg)) {};
|
||||
inline constexpr TupleLeaf(const TupleLeaf&) = default;
|
||||
inline constexpr TupleLeaf(TupleLeaf&&) = default;
|
||||
inline constexpr bool operator==(const TupleLeaf&) const = default;
|
||||
};
|
||||
|
||||
template <std::size_t I, typename... Ts>
|
||||
struct TupleHelper {
|
||||
consteval TupleHelper() = default;
|
||||
inline constexpr TupleHelper(const TupleHelper&) = default;
|
||||
inline constexpr TupleHelper(TupleHelper&&) = default;
|
||||
inline constexpr bool operator==(const TupleHelper&) const = default;
|
||||
};
|
||||
|
||||
template <std::size_t I, typename T, typename... Ts>
|
||||
struct TupleHelper<I, T, Ts...> : public TupleLeaf<I, T> , public TupleHelper<I + 1, Ts...> {
|
||||
template <typename TT, typename... TTs>
|
||||
inline constexpr TupleHelper(TT&& arg, TTs&&... args) :
|
||||
TupleLeaf<I, T>{std::forward<TT>(arg)},
|
||||
TupleHelper<I + 1, Ts...>{std::forward<TTs>(args)...} {};
|
||||
inline constexpr TupleHelper(const TupleHelper&) = default;
|
||||
inline constexpr TupleHelper(TupleHelper&&) = default;
|
||||
inline constexpr bool operator==(const TupleHelper&) const = default;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct Tuple;
|
||||
|
||||
template <std::size_t I, typename... Ts>
|
||||
inline constexpr auto get(Tuple<Ts...>& tuple) -> auto& requires (I < sizeof...(Ts)) {
|
||||
using Type = decltype(get<I>(TypeList<Ts...>{}));
|
||||
return static_cast<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)) {
|
||||
using Type = decltype(get<I>(TypeList<Ts...>{}));
|
||||
return static_cast<const TupleLeaf<I, Type>&>(tuple).value;
|
||||
};
|
||||
|
||||
template <std::size_t I, typename... Ts>
|
||||
inline constexpr auto get(Tuple<Ts...>&& tuple) -> auto&& requires (I < sizeof...(Ts)) {
|
||||
using Type = decltype(get<I>(TypeList<Ts...>{}));
|
||||
return std::move(static_cast<TupleLeaf<I, Type>&&>(tuple).value);
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct Tuple : public TupleHelper<0, Ts...> {
|
||||
template <typename... TTs>
|
||||
inline constexpr Tuple(TTs&&... args) :
|
||||
TupleHelper<0, Ts...>(std::forward<TTs>(args)...) {};
|
||||
inline constexpr Tuple(const Tuple&) = default;
|
||||
inline constexpr Tuple(Tuple&&) = default;
|
||||
inline constexpr bool operator==(const Tuple&) const = default;
|
||||
template <typename... TTs>
|
||||
inline constexpr auto operator+(const Tuple<TTs...>& other) const -> Tuple<Ts..., TTs...> {
|
||||
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) -> Tuple<Ts..., TTs...> {
|
||||
return {get<Is>(*this)..., get<IIs>(other)...};
|
||||
}(std::make_index_sequence<sizeof...(Ts)>(), std::make_index_sequence<sizeof...(TTs)>());
|
||||
};
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
Tuple(Ts&&...) -> Tuple<std::remove_cvref_t<Ts>...>;
|
||||
|
||||
|
||||
template <typename... Ts>
|
||||
consteval auto listFromTuple(const utils::Tuple<Ts...>&) -> utils::TypeList<Ts...> {
|
||||
return {};
|
||||
};
|
||||
template <typename>
|
||||
struct TupleSize {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct TupleSize<Tuple<Ts...>> {
|
||||
static constexpr auto value = sizeof...(Ts);
|
||||
};
|
||||
template <typename Tuple>
|
||||
inline constexpr auto kTupleSize = TupleSize<Tuple>::value;
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct Optional {
|
||||
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 {
|
||||
return this->flag;
|
||||
};
|
||||
inline constexpr auto value() -> T& {
|
||||
return this->_value;
|
||||
};
|
||||
inline constexpr auto operator*() -> T& {
|
||||
return this->value();
|
||||
};
|
||||
inline constexpr auto operator->() -> T* {
|
||||
return &this->value();
|
||||
};
|
||||
inline constexpr auto value() const -> const T& {
|
||||
return this->_value;
|
||||
};
|
||||
inline constexpr auto operator*() const -> const T& {
|
||||
return this->value();
|
||||
};
|
||||
inline constexpr auto operator->() const -> const T* {
|
||||
return &this->value();
|
||||
};
|
||||
inline constexpr explicit operator bool() const {
|
||||
return this->has_value();
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace utils
|
||||
|
||||
namespace menu {
|
||||
|
||||
|
@ -267,8 +53,8 @@ namespace impl {
|
|||
|
||||
template <std::size_t N1, std::size_t N2>
|
||||
struct CallbackMessage {
|
||||
utils::ConstexprString<N1> message;
|
||||
utils::Optional<utils::ConstexprString<N2>> need;
|
||||
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)) {};
|
||||
|
@ -286,38 +72,35 @@ CallbackMessage(const char(&)[N1]) -> CallbackMessage<N1, 0>;
|
|||
|
||||
|
||||
|
||||
template <utils::Tuple storage = utils::Tuple{}, typename... Fs>
|
||||
template <Tuple storage = Tuple{}, typename... Fs>
|
||||
struct Menu {
|
||||
utils::Tuple<Fs...> functionStorage;
|
||||
static constexpr auto kMessages = storage;
|
||||
static consteval auto getMaxSize() -> std::size_t {
|
||||
Tuple<Fs...> functionStorage;
|
||||
|
||||
static consteval auto GetMaxSize() -> std::size_t {
|
||||
return [&]<auto... Is>(std::index_sequence<Is...>){
|
||||
constexpr auto list = utils::listFromTuple(storage);
|
||||
return utils::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 : utils::countDigits(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))...});
|
||||
}(std::make_index_sequence<sizeof...(Fs)>());
|
||||
};
|
||||
template <impl::CallbackMessage message, std::invocable F>
|
||||
constexpr auto With(F&& f) const {
|
||||
return Menu<storage + utils::Tuple{message}, Fs..., std::remove_cvref_t<F>>{.functionStorage = this->functionStorage + utils::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 <utils::ConstexprString fmt, utils::ConstexprString enter = "|> ", typename Menu>
|
||||
inline auto Run(Menu&& menu) {
|
||||
using Cleared = std::remove_cvref_t<Menu>;
|
||||
constexpr auto maxSize = Cleared::getMaxSize();
|
||||
constexpr auto messagesCount = utils::kTupleSize<std::remove_cv_t<decltype(Cleared::kMessages)>>;
|
||||
[&]<auto... Is, auto messages = Cleared::kMessages>(std::index_sequence<Is...>){
|
||||
constexpr auto message = ([&]<auto I>(utils::Wrapper<I>){
|
||||
constexpr auto message = get<I>(messages);
|
||||
constexpr std::size_t s = maxSize - (message.need ? message.need->size() : utils::countDigits(I));
|
||||
constexpr auto str3 = utils::createStringWith<s>(' ');
|
||||
template <ConstexprString fmt, ConstexprString enter = "|> ">
|
||||
inline auto Run() const {
|
||||
using Cleared = std::remove_cvref_t<decltype(*this)>;
|
||||
constexpr auto maxSize = Cleared::GetMaxSize();
|
||||
[&]<auto... Is>(std::index_sequence<Is...>){
|
||||
constexpr auto message = ([&]<auto I>(Wrapper<I>){
|
||||
constexpr auto message = Get<I>(storage);
|
||||
constexpr std::size_t s = maxSize - (message.need ? message.need->size() : CountDigits(I));
|
||||
constexpr auto str3 = CreateStringWith<s>(' ');
|
||||
constexpr auto str2 = message.message;
|
||||
constexpr auto str1 = [&] {
|
||||
if constexpr(message.need) {
|
||||
return *message.need;
|
||||
} else {
|
||||
return utils::toString<I>();
|
||||
return ToString<I>();
|
||||
};
|
||||
}();
|
||||
// + 1 - NULL Terminator
|
||||
|
@ -326,32 +109,31 @@ inline auto Run(Menu&& menu) {
|
|||
,str2
|
||||
,str3) + 1;
|
||||
char data[size] = {};
|
||||
fmt::format_to(data, FMT_COMPILE(fmt.data.begin())
|
||||
fmt::format_to(data, FMT_COMPILE(fmt.begin())
|
||||
,str1
|
||||
,str2
|
||||
,str3);
|
||||
return utils::ConstexprString<size>(data);
|
||||
}(utils::Wrapper<Is>{}) + ...) + enter;
|
||||
return ConstexprString<size>(data);
|
||||
}(Wrapper<Is>{}) + ...) + enter;
|
||||
|
||||
std::fwrite(message.data.data(), 1, message.size(), stdout);
|
||||
std::fwrite(message.begin(), 1, message.size(), stdout);
|
||||
std::fflush(stdout);
|
||||
std::string input;
|
||||
std::getline(std::cin, input);
|
||||
([&]<auto I, impl::CallbackMessage message = get<I>(messages)>(utils::Wrapper<I>) {
|
||||
([&]<auto I, impl::CallbackMessage message = Get<I>(storage)>(Wrapper<I>) {
|
||||
if constexpr(message.need) {
|
||||
if(input == std::string_view(*message.need)) {
|
||||
get<I>(menu.functionStorage)();
|
||||
if(*message.need == input) {
|
||||
Get<I>(this->functionStorage)();
|
||||
};
|
||||
} else {
|
||||
if(input == std::string_view(utils::toString<I>())) {
|
||||
get<I>(menu.functionStorage)();
|
||||
if(ToString<I>() == input) {
|
||||
Get<I>(this->functionStorage)();
|
||||
};
|
||||
};
|
||||
}(utils::Wrapper<Is>{}), ...);
|
||||
}(std::make_index_sequence<messagesCount>());
|
||||
|
||||
}(Wrapper<Is>{}), ...);
|
||||
}(std::make_index_sequence<sizeof...(Fs)>());
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
} // namespace menu
|
||||
} // namespace utempl
|
||||
|
|
45
include/utempl/optional.hpp
Normal file
45
include/utempl/optional.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
|
||||
namespace utempl {
|
||||
|
||||
template <typename T>
|
||||
struct Optional {
|
||||
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 {
|
||||
return this->flag;
|
||||
};
|
||||
inline constexpr auto value() -> T& {
|
||||
return this->_value;
|
||||
};
|
||||
inline constexpr auto operator*() -> T& {
|
||||
return this->value();
|
||||
};
|
||||
inline constexpr auto operator->() -> T* {
|
||||
return &this->value();
|
||||
};
|
||||
inline constexpr auto value() const -> const T& {
|
||||
return this->_value;
|
||||
};
|
||||
inline constexpr auto operator*() const -> const T& {
|
||||
return this->value();
|
||||
};
|
||||
inline constexpr auto operator->() const -> const T* {
|
||||
return &this->value();
|
||||
};
|
||||
inline constexpr explicit operator bool() const {
|
||||
return this->has_value();
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace utempl
|
94
include/utempl/tuple.hpp
Normal file
94
include/utempl/tuple.hpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
#include <utempl/type_list.hpp>
|
||||
|
||||
namespace utempl {
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <auto, typename T>
|
||||
struct TupleLeaf {
|
||||
T value;
|
||||
template <typename TT>
|
||||
inline constexpr TupleLeaf(TT&& arg) : value(std::forward<TT>(arg)) {};
|
||||
inline constexpr TupleLeaf(const TupleLeaf&) = default;
|
||||
inline constexpr TupleLeaf(TupleLeaf&&) = default;
|
||||
inline constexpr bool operator==(const TupleLeaf&) const = default;
|
||||
};
|
||||
|
||||
template <std::size_t I, typename... Ts>
|
||||
struct TupleHelper {
|
||||
consteval TupleHelper() = default;
|
||||
inline constexpr TupleHelper(const TupleHelper&) = default;
|
||||
inline constexpr TupleHelper(TupleHelper&&) = default;
|
||||
inline constexpr bool operator==(const TupleHelper&) const = default;
|
||||
};
|
||||
|
||||
template <std::size_t I, typename T, typename... Ts>
|
||||
struct TupleHelper<I, T, Ts...> : public TupleLeaf<I, T> , public TupleHelper<I + 1, Ts...> {
|
||||
template <typename TT, typename... TTs>
|
||||
inline constexpr TupleHelper(TT&& arg, TTs&&... args) :
|
||||
TupleLeaf<I, T>{std::forward<TT>(arg)},
|
||||
TupleHelper<I + 1, Ts...>{std::forward<TTs>(args)...} {};
|
||||
inline constexpr TupleHelper(const TupleHelper&) = default;
|
||||
inline constexpr TupleHelper(TupleHelper&&) = default;
|
||||
inline constexpr bool operator==(const TupleHelper&) const = default;
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <typename... Ts>
|
||||
struct Tuple;
|
||||
|
||||
template <std::size_t I, typename... Ts>
|
||||
inline 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)) {
|
||||
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) -> auto&& requires (I < sizeof...(Ts)) {
|
||||
using Type = decltype(Get<I>(TypeList<Ts...>{}));
|
||||
return std::move(static_cast<impl::TupleLeaf<I, Type>&&>(tuple).value);
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct Tuple : public impl::TupleHelper<0, Ts...> {
|
||||
template <typename... TTs>
|
||||
inline constexpr Tuple(TTs&&... args) :
|
||||
impl::TupleHelper<0, Ts...>(std::forward<TTs>(args)...) {};
|
||||
inline constexpr Tuple(const Tuple&) = default;
|
||||
inline constexpr Tuple(Tuple&&) = default;
|
||||
inline constexpr bool operator==(const Tuple&) const = default;
|
||||
template <typename... TTs>
|
||||
inline constexpr auto operator+(const Tuple<TTs...>& other) const -> Tuple<Ts..., TTs...> {
|
||||
return [&]<auto... Is, auto... IIs>(std::index_sequence<Is...>, std::index_sequence<IIs...>) -> Tuple<Ts..., TTs...> {
|
||||
return {Get<Is>(*this)..., Get<IIs>(other)...};
|
||||
}(std::make_index_sequence<sizeof...(Ts)>(), std::make_index_sequence<sizeof...(TTs)>());
|
||||
};
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
Tuple(Ts&&...) -> Tuple<std::remove_cvref_t<Ts>...>;
|
||||
|
||||
template <typename>
|
||||
struct TupleSize {};
|
||||
|
||||
template <typename... Ts>
|
||||
struct TupleSize<Tuple<Ts...>> {
|
||||
static constexpr auto value = sizeof...(Ts);
|
||||
};
|
||||
template <typename Tuple>
|
||||
inline constexpr auto kTupleSize = TupleSize<Tuple>::value;
|
||||
|
||||
template <typename... Ts>
|
||||
consteval auto ListFromTuple(Tuple<Ts...>) -> TypeList<Ts...> {
|
||||
return {};
|
||||
};
|
||||
|
||||
|
||||
} // namespace utempl
|
35
include/utempl/type_list.hpp
Normal file
35
include/utempl/type_list.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <concepts>
|
||||
#include <utility>
|
||||
#include <array>
|
||||
#include <ranges>
|
||||
|
||||
namespace utempl {
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct Caster {
|
||||
constexpr Caster(auto&&) {};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct TypeList {
|
||||
};
|
||||
template <typename... Ts, typename... TTs>
|
||||
consteval auto operator==(const TypeList<Ts...>& first, const TypeList<TTs...>& second) -> bool {
|
||||
return std::same_as<decltype(first), decltype(second)>;
|
||||
};
|
||||
template <std::size_t... Is, typename T>
|
||||
consteval auto Get(std::index_sequence<Is...>, decltype(impl::Caster(Is))..., T, ...) -> T;
|
||||
|
||||
template <std::size_t I, typename... Ts>
|
||||
consteval auto Get(const TypeList<Ts...>&) -> decltype(Get(std::make_index_sequence<I>(), std::declval<Ts>()...)) requires (I < sizeof...(Ts));
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
consteval auto Find(TypeList<Ts...>) -> std::size_t {
|
||||
std::array arr{std::same_as<T, Ts>...};
|
||||
return std::ranges::find(arr, true) - arr.begin();
|
||||
};
|
||||
|
||||
} // namespace utempl
|
Loading…
Reference in a new issue