diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4ca677d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.27) +project(utempl) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +find_package(fmt REQUIRED) +set(CMAKE_CXX_STANDART 23) +add_library(utempl INTERFACE) +target_link_libraries(utempl INTERFACE fmt::fmt-header-only) +target_include_directories(utempl INTERFACE include) diff --git a/README.md b/README.md new file mode 100644 index 0000000..7fc6193 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# uTempl - Modern C++ Template Library + +## Features +- ConstexprString: A template for working with compile-time strings using constexpr. +- Tuple Realization: Implementation of tuples in a modern C++ way. +- 🔥Blazing🔥 Fast Menu Builder🚀🚀🚀: Quickly build interactive menus in your terminal applications. + +## License +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/include/utempl/menu.hpp b/include/utempl/menu.hpp new file mode 100644 index 0000000..4b62cfa --- /dev/null +++ b/include/utempl/menu.hpp @@ -0,0 +1,344 @@ +#include +#include +#include +#include +#include +#include +#include + +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 operator std::string_view() const { + return {this->data.begin()}; + }; + inline constexpr operator std::string() const { + return static_cast(static_cast(*this)); + }; + 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) { + std::size_t count = 0; + do { + ++count; + num /= 10; + } 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; + } + return num % 10; +}; + +template +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'}}; + }(std::make_index_sequence()); +}; + +template +constexpr auto getMax(Range&& range) { + std::remove_cvref_t response = 0; + for(const auto& element : range) { + response = element > response ? element : response; + }; + 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 { + +namespace impl { + +template +struct CallbackMessage { + utils::ConstexprString message; + utils::Optional> 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) {}; +}; +template +CallbackMessage(const char(&)[N1], const char(&)[N2]) -> CallbackMessage; + +template +CallbackMessage(const char(&)[N1]) -> CallbackMessage; + +} // namespace impl + + + +template +struct Menu { + utils::Tuple functionStorage; + static constexpr auto kMessages = storage; + 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))...}); + }(std::make_index_sequence()); + }; + template + constexpr auto With(F&& f) const { + return Menu>{.functionStorage = this->functionStorage + utils::Tuple(std::forward(f))}; + }; +}; + +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){ + static constexpr auto message = get(messages); + constexpr std::size_t s = maxSize - (message.need ? message.need->size() : utils::countDigits(I)); + static constexpr auto str = utils::createStringWith(' '); + constexpr std::string_view str1{[&] { + static constexpr auto st = utils::toString(); + return message.need ? std::string_view(*message.need) : std::string_view(st); + }()} + ,str2{message.message} + ,str3{str}; + // + 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 + +