Fixes for fmt
This commit is contained in:
parent
b440c81474
commit
5b402e48dd
6 changed files with 0 additions and 209 deletions
|
@ -48,7 +48,6 @@ CPMAddPackage(
|
|||
URL
|
||||
"https://github.com/linuxnyasha/fmt_import/archive/refs/heads/linuxnyasha-patch-1.zip"
|
||||
# Fixes for fmt module and constexpr fmt::formatted_size
|
||||
OPTIONS "CMAKE_CXX_FLAGS -DFMT_ATTACH_TO_GLOBAL_MODULE"
|
||||
)
|
||||
|
||||
set(CPM_USE_LOCAL_PACKAGES ${TMP})
|
||||
|
@ -98,7 +97,6 @@ endif()
|
|||
if(BUILD_STATIC_LIBS)
|
||||
add_library(utempl_static)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
add_library(utempl ALIAS utempl_static)
|
||||
add_library(utempl::utempl ALIAS utempl_static)
|
||||
endif()
|
||||
configure(utempl_static)
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import utempl;
|
||||
import std;
|
||||
|
||||
auto main() -> int {
|
||||
utempl::menu::Menu{}
|
||||
.With<{"This is 0"}>([] {
|
||||
std::cout << "You entered 0" << std::endl;
|
||||
})
|
||||
.With<{"Some Long", "S"}>([] {
|
||||
std::cout << "It aligns the output to the longest element" << std::endl;
|
||||
})
|
||||
.Run<"[{0}]{2} - |{1}|\n">();
|
||||
};
|
|
@ -1,25 +1,7 @@
|
|||
module;
|
||||
#include <fmt/compile.h>
|
||||
export module utempl.string;
|
||||
import std;
|
||||
// import fmt;
|
||||
|
||||
namespace utempl {
|
||||
export template <std::size_t>
|
||||
struct ConstexprString;
|
||||
} // namespace utempl
|
||||
|
||||
export {
|
||||
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();
|
||||
};
|
||||
constexpr auto format(const utempl::ConstexprString<Size>& str, auto& ctx) const {
|
||||
return fmt::formatter<std::string_view>::format({str.begin()}, ctx);
|
||||
};
|
||||
};
|
||||
};
|
||||
export namespace utempl {
|
||||
|
||||
template <std::size_t Size>
|
||||
|
@ -77,11 +59,6 @@ struct ConstexprString {
|
|||
constexpr ConstexprString(ConstexprString&&) = default;
|
||||
};
|
||||
|
||||
template <ConstexprString Str>
|
||||
consteval auto GetFmtCompiledString() {
|
||||
return FMT_COMPILE(Str.data.begin());
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
constexpr auto operator<<(std::ostream& stream, const ConstexprString<N>& str) -> std::ostream& {
|
||||
stream << static_cast<std::string_view>(str);
|
||||
|
|
147
src/menu.cpp
147
src/menu.cpp
|
@ -1,147 +0,0 @@
|
|||
module;
|
||||
#include <cstdio>
|
||||
export module utempl.menu;
|
||||
|
||||
import fmt;
|
||||
import std;
|
||||
import utempl.string;
|
||||
import utempl.optional;
|
||||
import utempl.tuple;
|
||||
import utempl.utils;
|
||||
import utempl.type_list;
|
||||
|
||||
namespace utempl {
|
||||
|
||||
constexpr auto CountDigits(std::size_t num) -> std::size_t {
|
||||
std::size_t count = 0;
|
||||
do { // NOLINT
|
||||
++count;
|
||||
num /= 10; // NOLINT
|
||||
} while(num != 0);
|
||||
return count;
|
||||
};
|
||||
|
||||
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; // NOLINT
|
||||
};
|
||||
|
||||
template <std::size_t num>
|
||||
consteval auto ToString() {
|
||||
constexpr std::size_t digits = CountDigits(num);
|
||||
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
|
||||
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) {
|
||||
std::remove_cvref_t<decltype(range[0])> response = 0;
|
||||
for(const auto& element : range) {
|
||||
response = element > response ? element : response;
|
||||
};
|
||||
return response;
|
||||
};
|
||||
|
||||
namespace menu {
|
||||
|
||||
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]) : // 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>; // NOLINT
|
||||
|
||||
template <std::size_t N1>
|
||||
CallbackMessage(const char (&)[N1]) -> CallbackMessage<N1, 0>; // NOLINT
|
||||
|
||||
export template <Tuple storage = Tuple{}, typename... Fs>
|
||||
struct Menu {
|
||||
private:
|
||||
template <ConstexprString fmt, ConstexprString message, ConstexprString alignment, ConstexprString neededInput>
|
||||
static consteval auto FormatMessage() {
|
||||
constexpr auto fmtlib = GetFmtCompiledString<fmt>();
|
||||
// + 1 - NULL Terminator
|
||||
constexpr auto size = fmt::formatted_size(fmtlib,
|
||||
static_cast<std::string_view>(neededInput),
|
||||
static_cast<std::string_view>(message),
|
||||
static_cast<std::string_view>(alignment)) +
|
||||
1;
|
||||
std::array<char, size> data{};
|
||||
fmt::format_to(data.begin(),
|
||||
fmtlib,
|
||||
static_cast<std::string_view>(neededInput),
|
||||
static_cast<std::string_view>(message),
|
||||
static_cast<std::string_view>(alignment));
|
||||
return ConstexprString<size>(data);
|
||||
};
|
||||
template <ConstexprString fmt, std::size_t I>
|
||||
static consteval auto FormatMessageFor() {
|
||||
constexpr ConstexprString message = Get<I>(storage).message;
|
||||
constexpr ConstexprString neededInput = [&] {
|
||||
if constexpr(Get<I>(storage).need) {
|
||||
return *Get<I>(storage).need;
|
||||
} else {
|
||||
return ToString<I>();
|
||||
};
|
||||
}();
|
||||
constexpr ConstexprString alignment =
|
||||
CreateStringWith<GetMaxSize() - (Get<I>(storage).need ? Get<I>(storage).need->size() : CountDigits(I))>(' ');
|
||||
return FormatMessage<fmt, message, alignment, neededInput>();
|
||||
};
|
||||
|
||||
public:
|
||||
Tuple<Fs...> functionStorage;
|
||||
|
||||
static consteval auto GetMaxSize() -> std::size_t {
|
||||
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))...});
|
||||
}(std::index_sequence_for<Fs...>());
|
||||
};
|
||||
template <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))};
|
||||
};
|
||||
template <ConstexprString fmt, ConstexprString enter = "|> ">
|
||||
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);
|
||||
if(result < message.size()) {
|
||||
return EOF;
|
||||
};
|
||||
if(std::fflush(out) != 0) {
|
||||
return EOF;
|
||||
};
|
||||
std::string input;
|
||||
std::getline(in, input);
|
||||
(
|
||||
[&]<auto I, CallbackMessage message = Get<I>(storage)>(Wrapper<I>) {
|
||||
if constexpr(message.need) {
|
||||
if(*message.need == input) {
|
||||
Get<I>(this->functionStorage)();
|
||||
};
|
||||
} else {
|
||||
if(ToString<I>() == input) {
|
||||
Get<I>(this->functionStorage)();
|
||||
};
|
||||
};
|
||||
}(Wrapper<Is>{}),
|
||||
...);
|
||||
return 0;
|
||||
}(std::index_sequence_for<Fs...>());
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace menu
|
||||
} // namespace utempl
|
|
@ -2,7 +2,6 @@ export module utempl;
|
|||
export import utempl.type_list;
|
||||
export import utempl.tuple;
|
||||
export import utempl.string;
|
||||
export import utempl.menu;
|
||||
export import utempl.loopholes;
|
||||
export import utempl.attributes;
|
||||
export import utempl.meta_info;
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
module;
|
||||
#include <gtest/gtest.h>
|
||||
export module tests.menu;
|
||||
import utempl;
|
||||
|
||||
namespace utempl {
|
||||
|
||||
TEST(Menu, Basic) {
|
||||
testing::internal::CaptureStdout();
|
||||
std::istringstream stream("t\n");
|
||||
int value = 0;
|
||||
menu::Menu{}
|
||||
.With<{"t", "This is t"}>([&] {
|
||||
std::cout << "Success!" << std::endl;
|
||||
value = 1;
|
||||
})
|
||||
.Run<"[{0}]{2} - ({1})\n">(stream);
|
||||
auto captured = testing::internal::GetCapturedStdout();
|
||||
EXPECT_EQ(captured, "[t] - (This is t)\n|> Success!\n");
|
||||
EXPECT_EQ(value, 1);
|
||||
};
|
||||
|
||||
} // namespace utempl
|
Loading…
Reference in a new issue