Split into multiply files

This commit is contained in:
sha512sum 2024-02-22 21:12:02 +00:00
parent 5bbe94f279
commit 6e873fbc65
5 changed files with 326 additions and 284 deletions

View 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

View file

@ -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,33 +109,32 @@ 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

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

View 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