diff --git a/include/utempl/constexpr_string.hpp b/include/utempl/constexpr_string.hpp new file mode 100644 index 0000000..206695d --- /dev/null +++ b/include/utempl/constexpr_string.hpp @@ -0,0 +1,86 @@ +#pragma once +#include + +namespace utempl { + template + struct ConstexprString; +}; + +template +struct fmt::formatter> : public fmt::formatter { + constexpr auto parse(format_parse_context& ctx) const { + return ctx.begin(); + }; + inline constexpr auto format(const utempl::ConstexprString& str, auto& ctx) const { + return fmt::formatter::format({str.begin()}, ctx); + }; +}; + +namespace utempl { + +template +struct ConstexprString { + std::array 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 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(*this) == other; + }; + template + inline constexpr auto operator+(const ConstexprString& other) -> ConstexprString { + ConstexprString 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 +inline constexpr auto operator<<(std::ostream& stream, const ConstexprString& str) -> std::ostream& { + stream << static_cast(str); + return stream; +}; + +template +inline constexpr auto CreateStringWith(char c) { + ConstexprString str = {}; + for(std::size_t i = 0; i < Count; i++) { + str.data[i] = c; + }; + str.data[Count] = '\0'; + return str; +}; + + +template +ConstexprString(const char (&data)[Size]) -> ConstexprString; +} // namespace utempl + diff --git a/include/utempl/menu.hpp b/include/utempl/menu.hpp index 76f35e9..8e707da 100644 --- a/include/utempl/menu.hpp +++ b/include/utempl/menu.hpp @@ -1,83 +1,19 @@ +#pragma once +#include +#include +#include #include #include -#include -#include -#include #include #include -namespace utempl::utils { - template - struct ConstexprString; -}; - -template -struct fmt::formatter> : public fmt::formatter { - constexpr auto parse(format_parse_context& ctx) const { - return ctx.begin(); - }; - inline constexpr auto format(const utempl::utils::ConstexprString& str, auto& ctx) const { - return fmt::formatter::format({str.data.begin()}, ctx); - }; -}; - namespace utempl { -namespace utils { - -template -struct ConstexprString { - std::array 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 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(*this) == other; - }; - template - inline constexpr auto operator+(const ConstexprString& other) -> ConstexprString { - ConstexprString 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 -consteval auto createStringWith(char c) { - ConstexprString str = {}; - for(std::size_t i = 0; i < Count; i++) { - str.data[i] = c; - }; - str.data[Count] = '\0'; - return str; -}; - - -template -ConstexprString(const char (&data)[Size]) -> ConstexprString; - - template 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 -consteval auto toString() { - constexpr std::size_t digits = countDigits(num); +consteval auto ToString() { + constexpr std::size_t digits = CountDigits(num); return [&](std::index_sequence) { - return utils::ConstexprString{std::array{static_cast('0' + getDigit(num, digits - 1 - Is))..., '\0'}}; + return ConstexprString{std::array{static_cast('0' + GetDigit(num, digits - 1 - Is))..., '\0'}}; }(std::make_index_sequence()); }; template -constexpr auto getMax(Range&& range) { +constexpr auto GetMax(Range&& range) { std::remove_cvref_t 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 -struct TypeList { -}; -template -consteval auto operator==(const TypeList& first, const TypeList& second) -> bool { - return std::is_same_v; -}; -template -consteval auto get(std::index_sequence, decltype(Caster(Is))..., T, ...) -> T; - - -template -consteval auto get(const TypeList&) -> decltype(get(std::make_index_sequence(), std::declval()...)) requires (I < sizeof...(Ts)); - - - - -template -struct TupleLeaf { - T value; - template - inline constexpr TupleLeaf(TT&& arg) : value(std::forward(arg)) {}; - inline constexpr TupleLeaf(const TupleLeaf&) = default; - inline constexpr TupleLeaf(TupleLeaf&&) = default; - inline constexpr bool operator==(const TupleLeaf&) const = default; -}; - -template -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 -struct TupleHelper : public TupleLeaf , public TupleHelper { - template - inline constexpr TupleHelper(TT&& arg, TTs&&... args) : - TupleLeaf{std::forward(arg)}, - TupleHelper{std::forward(args)...} {}; - inline constexpr TupleHelper(const TupleHelper&) = default; - inline constexpr TupleHelper(TupleHelper&&) = default; - inline constexpr bool operator==(const TupleHelper&) const = default; -}; - -template -struct Tuple; - -template -inline constexpr auto get(Tuple& tuple) -> auto& requires (I < sizeof...(Ts)) { - using Type = decltype(get(TypeList{})); - return static_cast&>(tuple).value; -}; - -template -inline constexpr auto get(const Tuple& tuple) -> const auto& requires (I < sizeof...(Ts)) { - using Type = decltype(get(TypeList{})); - return static_cast&>(tuple).value; -}; - -template -inline constexpr auto get(Tuple&& tuple) -> auto&& requires (I < sizeof...(Ts)) { - using Type = decltype(get(TypeList{})); - return std::move(static_cast&&>(tuple).value); -}; - -template -struct Tuple : public TupleHelper<0, Ts...> { - template - inline constexpr Tuple(TTs&&... args) : - TupleHelper<0, Ts...>(std::forward(args)...) {}; - inline constexpr Tuple(const Tuple&) = default; - inline constexpr Tuple(Tuple&&) = default; - inline constexpr bool operator==(const Tuple&) const = default; - template - inline constexpr auto operator+(const Tuple& other) const -> Tuple { - return [&](std::index_sequence, std::index_sequence) -> Tuple { - return {get(*this)..., get(other)...}; - }(std::make_index_sequence(), std::make_index_sequence()); - }; -}; - -template -Tuple(Ts&&...) -> Tuple...>; - - -template -consteval auto listFromTuple(const utils::Tuple&) -> utils::TypeList { - return {}; -}; -template -struct TupleSize {}; - -template -struct TupleSize> { - static constexpr auto value = sizeof...(Ts); -}; -template -inline constexpr auto kTupleSize = TupleSize::value; - - - -template -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 struct CallbackMessage { - utils::ConstexprString message; - utils::Optional> need; + ConstexprString message; + Optional> need; consteval CallbackMessage(const char (&need)[N2], const char (&message)[N1]) : message(std::move(message)) ,need(std::move(need)) {}; @@ -286,73 +72,69 @@ CallbackMessage(const char(&)[N1]) -> CallbackMessage; -template +template struct Menu { - utils::Tuple functionStorage; - static constexpr auto kMessages = storage; - static consteval auto getMaxSize() -> std::size_t { + Tuple functionStorage; + + static consteval auto GetMaxSize() -> std::size_t { return [&](std::index_sequence){ - constexpr auto list = utils::listFromTuple(storage); - return utils::getMax(std::array{(std::remove_cvref_t(list))>().need)>::kSize != 0 ? std::remove_cvref_t(list))>().need)>::kSize : utils::countDigits(Is))...}); + constexpr auto list = ListFromTuple(storage); + return GetMax(std::array{(std::remove_cvref_t(list))>().need)>::kSize != 0 ? std::remove_cvref_t(list))>().need)>::kSize : CountDigits(Is))...}); }(std::make_index_sequence()); }; template constexpr auto With(F&& f) const { - return Menu>{.functionStorage = this->functionStorage + utils::Tuple(std::forward(f))}; + return Menu>{.functionStorage = this->functionStorage + Tuple(std::forward(f))}; + }; + template + inline auto Run() const { + using Cleared = std::remove_cvref_t; + constexpr auto maxSize = Cleared::GetMaxSize(); + [&](std::index_sequence){ + constexpr auto message = ([&](Wrapper){ + constexpr auto message = Get(storage); + constexpr std::size_t s = maxSize - (message.need ? message.need->size() : CountDigits(I)); + constexpr auto str3 = CreateStringWith(' '); + constexpr auto str2 = message.message; + constexpr auto str1 = [&] { + if constexpr(message.need) { + return *message.need; + } else { + return ToString(); + }; + }(); + // + 1 - NULL Terminator + constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin()) + ,str1 + ,str2 + ,str3) + 1; + char data[size] = {}; + fmt::format_to(data, FMT_COMPILE(fmt.begin()) + ,str1 + ,str2 + ,str3); + return ConstexprString(data); + }(Wrapper{}) + ...) + enter; + + std::fwrite(message.begin(), 1, message.size(), stdout); + std::fflush(stdout); + std::string input; + std::getline(std::cin, input); + ([&](storage)>(Wrapper) { + if constexpr(message.need) { + if(*message.need == input) { + Get(this->functionStorage)(); + }; + } else { + if(ToString() == input) { + Get(this->functionStorage)(); + }; + }; + }(Wrapper{}), ...); + }(std::make_index_sequence()); }; }; -template -inline auto Run(Menu&& menu) { - using Cleared = std::remove_cvref_t; - constexpr auto maxSize = Cleared::getMaxSize(); - constexpr auto messagesCount = utils::kTupleSize>; - [&](std::index_sequence){ - constexpr auto message = ([&](utils::Wrapper){ - constexpr auto message = get(messages); - constexpr std::size_t s = maxSize - (message.need ? message.need->size() : utils::countDigits(I)); - constexpr auto str3 = utils::createStringWith(' '); - constexpr auto str2 = message.message; - constexpr auto str1 = [&] { - if constexpr(message.need) { - return *message.need; - } else { - return utils::toString(); - }; - }(); - // + 1 - NULL Terminator - constexpr auto size = fmt::formatted_size(FMT_COMPILE(fmt.data.begin()) - ,str1 - ,str2 - ,str3) + 1; - char data[size] = {}; - fmt::format_to(data, FMT_COMPILE(fmt.data.begin()) - ,str1 - ,str2 - ,str3); - return utils::ConstexprString(data); - }(utils::Wrapper{}) + ...) + enter; - - std::fwrite(message.data.data(), 1, message.size(), stdout); - std::fflush(stdout); - std::string input; - std::getline(std::cin, input); - ([&](messages)>(utils::Wrapper) { - if constexpr(message.need) { - if(input == std::string_view(*message.need)) { - get(menu.functionStorage)(); - }; - } else { - if(input == std::string_view(utils::toString())) { - get(menu.functionStorage)(); - }; - }; - }(utils::Wrapper{}), ...); - }(std::make_index_sequence()); - -}; - - } // namespace menu } // namespace utempl diff --git a/include/utempl/optional.hpp b/include/utempl/optional.hpp new file mode 100644 index 0000000..7b8c7ad --- /dev/null +++ b/include/utempl/optional.hpp @@ -0,0 +1,45 @@ +#pragma once +#include + +namespace utempl { + +template +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 diff --git a/include/utempl/tuple.hpp b/include/utempl/tuple.hpp new file mode 100644 index 0000000..c601396 --- /dev/null +++ b/include/utempl/tuple.hpp @@ -0,0 +1,94 @@ +#include + +namespace utempl { + +namespace impl { + +template +struct TupleLeaf { + T value; + template + inline constexpr TupleLeaf(TT&& arg) : value(std::forward(arg)) {}; + inline constexpr TupleLeaf(const TupleLeaf&) = default; + inline constexpr TupleLeaf(TupleLeaf&&) = default; + inline constexpr bool operator==(const TupleLeaf&) const = default; +}; + +template +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 +struct TupleHelper : public TupleLeaf , public TupleHelper { + template + inline constexpr TupleHelper(TT&& arg, TTs&&... args) : + TupleLeaf{std::forward(arg)}, + TupleHelper{std::forward(args)...} {}; + inline constexpr TupleHelper(const TupleHelper&) = default; + inline constexpr TupleHelper(TupleHelper&&) = default; + inline constexpr bool operator==(const TupleHelper&) const = default; +}; + +} // namespace impl + +template +struct Tuple; + +template +inline constexpr auto Get(Tuple& tuple) -> auto& requires (I < sizeof...(Ts)) { + using Type = decltype(Get(TypeList{})); + return static_cast&>(tuple).value; +}; + +template +inline constexpr auto Get(const Tuple& tuple) -> const auto& requires (I < sizeof...(Ts)) { + using Type = decltype(Get(TypeList{})); + return static_cast&>(tuple).value; +}; + +template +inline constexpr auto Get(Tuple&& tuple) -> auto&& requires (I < sizeof...(Ts)) { + using Type = decltype(Get(TypeList{})); + return std::move(static_cast&&>(tuple).value); +}; + +template +struct Tuple : public impl::TupleHelper<0, Ts...> { + template + inline constexpr Tuple(TTs&&... args) : + impl::TupleHelper<0, Ts...>(std::forward(args)...) {}; + inline constexpr Tuple(const Tuple&) = default; + inline constexpr Tuple(Tuple&&) = default; + inline constexpr bool operator==(const Tuple&) const = default; + template + inline constexpr auto operator+(const Tuple& other) const -> Tuple { + return [&](std::index_sequence, std::index_sequence) -> Tuple { + return {Get(*this)..., Get(other)...}; + }(std::make_index_sequence(), std::make_index_sequence()); + }; +}; + +template +Tuple(Ts&&...) -> Tuple...>; + +template +struct TupleSize {}; + +template +struct TupleSize> { + static constexpr auto value = sizeof...(Ts); +}; +template +inline constexpr auto kTupleSize = TupleSize::value; + +template +consteval auto ListFromTuple(Tuple) -> TypeList { + return {}; +}; + + +} // namespace utempl diff --git a/include/utempl/type_list.hpp b/include/utempl/type_list.hpp new file mode 100644 index 0000000..aaee0fa --- /dev/null +++ b/include/utempl/type_list.hpp @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +namespace utempl { + +namespace impl { + +struct Caster { + constexpr Caster(auto&&) {}; +}; + +}; + +template +struct TypeList { +}; +template +consteval auto operator==(const TypeList& first, const TypeList& second) -> bool { + return std::same_as; +}; +template +consteval auto Get(std::index_sequence, decltype(impl::Caster(Is))..., T, ...) -> T; + +template +consteval auto Get(const TypeList&) -> decltype(Get(std::make_index_sequence(), std::declval()...)) requires (I < sizeof...(Ts)); + +template +consteval auto Find(TypeList) -> std::size_t { + std::array arr{std::same_as...}; + return std::ranges::find(arr, true) - arr.begin(); +}; + +} // namespace utempl