feat: add utf8 format
- move utf8 stream and format patch from string to patch namespace. - add ordinay format alias and utf8 format in our format patch. - add char8_t and char inter-cast in string reinterpret namespace. - fix bug of utf8 formatter. - add test for utf8 format.
This commit is contained in:
@ -13,8 +13,8 @@ PRIVATE
|
||||
# Sources
|
||||
yycc/string/reinterpret.cpp
|
||||
yycc/string/op.cpp
|
||||
yycc/string/stream.cpp
|
||||
yycc/patch/fopen.cpp
|
||||
yycc/patch/stream.cpp
|
||||
yycc/rust/panic.cpp
|
||||
yycc/rust/env.cpp
|
||||
yycc/windows/com.cpp
|
||||
@ -31,10 +31,11 @@ PRIVATE
|
||||
yycc/carton/tabulate.cpp
|
||||
yycc/carton/ironpad.cpp
|
||||
yycc/carton/csconsole.cpp
|
||||
yycc/carton/clap/option.cpp
|
||||
yycc/carton/clap/variable.cpp
|
||||
yycc/carton/clap/summary.cpp
|
||||
yycc/carton/clap/application.cpp
|
||||
#yycc/carton/clap/option.cpp
|
||||
#yycc/carton/clap/variable.cpp
|
||||
#yycc/carton/clap/summary.cpp
|
||||
#yycc/carton/clap/application.cpp
|
||||
#yycc/carton/clap/manual.cpp
|
||||
)
|
||||
target_sources(YYCCommonplace
|
||||
PUBLIC
|
||||
@ -54,10 +55,10 @@ FILES
|
||||
yycc/flag_enum.hpp
|
||||
yycc/string/reinterpret.hpp
|
||||
yycc/string/op.hpp
|
||||
yycc/string/stream.hpp
|
||||
yycc/string/format.hpp
|
||||
yycc/patch/ptr_pad.hpp
|
||||
yycc/patch/fopen.hpp
|
||||
yycc/patch/stream.hpp
|
||||
yycc/patch/format.hpp
|
||||
yycc/num/parse.hpp
|
||||
yycc/num/stringify.hpp
|
||||
yycc/num/safe_cast.hpp
|
||||
@ -93,6 +94,7 @@ FILES
|
||||
yycc/carton/clap/variable.hpp
|
||||
yycc/carton/clap/summary.hpp
|
||||
yycc/carton/clap/application.hpp
|
||||
yycc/carton/clap/manual.hpp
|
||||
)
|
||||
# Setup header infomations
|
||||
target_include_directories(YYCCommonplace
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include "application.hpp"
|
||||
|
||||
#define NS_YYCC_CLAP ::yycc::carton::clap
|
||||
#define CLAP ::yycc::carton::clap
|
||||
|
||||
namespace yycc::carton::clap::application {
|
||||
|
||||
using Summary = NS_YYCC_CLAP::summary::Summary;
|
||||
using OptionCollection = NS_YYCC_CLAP::option::OptionCollection;
|
||||
using VariableCollection = NS_YYCC_CLAP::variable::VariableCollection;
|
||||
using Summary = CLAP::summary::Summary;
|
||||
using OptionCollection = CLAP::option::OptionCollection;
|
||||
using VariableCollection = CLAP::variable::VariableCollection;
|
||||
|
||||
Application::Application(Summary &&summary, OptionCollection &&options, VariableCollection &&variables) :
|
||||
summary(std::move(summary)), options(std::move(options)), variables(std::move(variables)) {}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "summary.hpp"
|
||||
#include "option.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "../../macro/class_copy_move.hpp"
|
||||
|
||||
#define NS_YYCC_CLAP ::yycc::carton::clap
|
||||
|
||||
|
69
src/yycc/carton/clap/manual.cpp
Normal file
69
src/yycc/carton/clap/manual.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "manual.hpp"
|
||||
#include "../termcolor.hpp"
|
||||
#include "../../patch/stream.hpp"
|
||||
#include "../../string/op.hpp"
|
||||
|
||||
#define CLAP ::yycc::carton::clap
|
||||
#define TABULATE ::yycc::carton::tabulate
|
||||
#define TERMCOLOR ::yycc::carton::termcolor
|
||||
#define OP ::yycc::carton::op
|
||||
|
||||
using namespace ::yycc::patch::stream;
|
||||
|
||||
namespace yycc::carton::clap::manual::Manual {
|
||||
|
||||
#pragma region Manual Translation
|
||||
|
||||
ManualTr::ManualTr() :
|
||||
author_and_version(u8"Invented by {0}. Version {1}."), usage_title(u8"Usage:"), usage_body(u8"{0} <options> ..."),
|
||||
avail_opt(u8"Available options:"), avail_var(u8"Available environment variables:") {}
|
||||
|
||||
ManualTr::~ManualTr() {}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Manual
|
||||
|
||||
using Application = CLAP::application::Application;
|
||||
using Tabulate = TABULATE::Tabulate;
|
||||
|
||||
Manual::Manual(const Application &app, ManualTr &&trctx) : trctx(std::move(trctx)), app(app), opt_printer(3), var_printer(2) {
|
||||
this->setup_table();
|
||||
this->fill_opt_table();
|
||||
this->fill_var_table();
|
||||
}
|
||||
|
||||
Manual::~Manual() {}
|
||||
|
||||
void Manual::setup_table() {
|
||||
this->opt_printer.show_header(false);
|
||||
this->opt_printer.show_bar(false);
|
||||
this->opt_printer.set_prefix(u8" ");
|
||||
|
||||
this->var_printer.show_header(false);
|
||||
this->var_printer.show_bar(false);
|
||||
this->var_printer.set_prefix(u8" ");
|
||||
}
|
||||
|
||||
void Manual::fill_opt_table() {
|
||||
const auto &options = app.get_options();
|
||||
for (const auto ®_opt : options.all_options()) {
|
||||
const auto &opt = reg_opt.get_option();
|
||||
}
|
||||
}
|
||||
|
||||
void Manual::fill_var_table() {}
|
||||
|
||||
void Manual::print_version(std::ostream &dst) const {
|
||||
const auto &summary = this->app.get_summary();
|
||||
|
||||
dst << std::format
|
||||
dst << summary.get_description() << std::endl;
|
||||
dst << std::endl;
|
||||
}
|
||||
|
||||
void Manual::print_help(std::ostream &dst) const {}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
} // namespace yycc::carton::clap::manual::Manual
|
49
src/yycc/carton/clap/manual.hpp
Normal file
49
src/yycc/carton/clap/manual.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "application.hpp"
|
||||
#include "../../macro/class_copy_move.hpp"
|
||||
#include "../tabulate.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#define NS_YYCC_CLAP ::yycc::carton::clap
|
||||
#define NS_YYCC_TABULATE ::yycc::carton::tabulate
|
||||
|
||||
namespace yycc::carton::clap::manual::Manual {
|
||||
|
||||
struct ManualTr {
|
||||
public:
|
||||
ManualTr();
|
||||
~ManualTr();
|
||||
YYCC_DEFAULT_COPY_MOVE(ManualTr);
|
||||
|
||||
public:
|
||||
std::u8string author_and_version;
|
||||
std::u8string usage_title, usage_body;
|
||||
std::u8string avail_opt, avail_var;
|
||||
};
|
||||
|
||||
class Manual {
|
||||
public:
|
||||
Manual(const NS_YYCC_CLAP::application::Application& app, ManualTr&& trctx = ManualTr());
|
||||
~Manual();
|
||||
YYCC_DEFAULT_COPY_MOVE(Manual);
|
||||
|
||||
private:
|
||||
void setup_table();
|
||||
void fill_opt_table();
|
||||
void fill_var_table();
|
||||
|
||||
public:
|
||||
void print_version(std::ostream& dst = std::cout) const;
|
||||
void print_help(std::ostream& dst = std::cout) const;
|
||||
|
||||
private:
|
||||
ManualTr trctx;
|
||||
const NS_YYCC_CLAP::application::Application app;
|
||||
NS_YYCC_TABULATE::Tabulate opt_printer;
|
||||
NS_YYCC_TABULATE::Tabulate var_printer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef NS_YYCC_TABULATE
|
||||
#undef NS_YYCC_CLAP
|
@ -1,6 +1,6 @@
|
||||
#include "option.hpp"
|
||||
#include "../../string/op.hpp"
|
||||
#include "../../string/format.hpp"
|
||||
#include "../../patch/format.hpp"
|
||||
#include <stdexcept>
|
||||
#include <format>
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "variable.hpp"
|
||||
#include "../../string/format.hpp"
|
||||
#include "../../patch/format.hpp"
|
||||
#include <stdexcept>
|
||||
#include <format>
|
||||
|
||||
|
@ -82,6 +82,8 @@ namespace yycc::carton::ironpad {
|
||||
m_UserCallback = callback;
|
||||
// mark registered
|
||||
m_IsRegistered = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @brief Try to unregister unhandled exception handler.
|
||||
|
@ -8,15 +8,46 @@
|
||||
* By including this file directly, you will have abilities that use UTF8 string as argument in \c std::format with \c char char type.
|
||||
*/
|
||||
#pragma once
|
||||
#include "reinterpret.hpp"
|
||||
#include "../string/reinterpret.hpp"
|
||||
#include <format>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
|
||||
|
||||
#pragma region Utf8 Format
|
||||
|
||||
namespace yycc::patch::format {
|
||||
|
||||
// TODO: order all use of std::format redirect to this function.
|
||||
|
||||
template<class... Args>
|
||||
std::string format(std::format_string<Args...> fmt, Args&&... args) {
|
||||
return std::vformat(fmt.get(), std::make_format_args(args...));
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
std::u8string format(const std::u8string_view& fmt, Args&&... args) {
|
||||
return NS_YYCC_STRING_REINTERPRET::as_utf8(
|
||||
std::vformat(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(fmt), std::make_format_args(args...)));
|
||||
}
|
||||
|
||||
} // namespace yycc::patch::format
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Utf8 Formatter
|
||||
|
||||
// Add std::formatter specialization for "char8_t"
|
||||
template<>
|
||||
struct std::formatter<char8_t, char> {
|
||||
constexpr auto parse(auto& ctx) { return underlying_formatter.parse(ctx); }
|
||||
auto format(const char8_t& str, auto& ctx) const { return underlying_formatter.format(NS_YYCC_STRING_REINTERPRET::as_ordinary(str), ctx); }
|
||||
|
||||
private:
|
||||
std::formatter<char, char> underlying_formatter{};
|
||||
};
|
||||
|
||||
// Add std::formatter specialization for "char8_t*"
|
||||
template<>
|
||||
struct std::formatter<char8_t*, char> {
|
||||
@ -43,7 +74,9 @@ private:
|
||||
template<std::size_t N>
|
||||
struct std::formatter<char8_t[N], char> {
|
||||
constexpr auto parse(auto& ctx) { return underlying_formatter.parse(ctx); }
|
||||
auto format(const char8_t (&str)[N], auto& ctx) const { return underlying_formatter.format(std::basic_string_view<char>(str, N), ctx); }
|
||||
auto format(const char8_t (&str)[N], auto& ctx) const {
|
||||
return underlying_formatter.format(std::basic_string_view<char>(NS_YYCC_STRING_REINTERPRET::as_ordinary(str), N - 1), ctx);
|
||||
}
|
||||
|
||||
private:
|
||||
std::formatter<std::basic_string_view<char>, char> underlying_formatter{};
|
@ -1,9 +1,9 @@
|
||||
#include "stream.hpp"
|
||||
#include "reinterpret.hpp"
|
||||
#include "../string/reinterpret.hpp"
|
||||
|
||||
#define REINTERPRET ::yycc::string::reinterpret
|
||||
|
||||
namespace yycc::string::stream {
|
||||
namespace yycc::patch::stream {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::u8string_view& u8str) {
|
||||
os << REINTERPRET::as_ordinary_view(u8str);
|
@ -6,9 +6,9 @@
|
||||
* @brief This namespace add UTF8 support for \c std::ostream.
|
||||
* @details
|
||||
* The operator overloads written in this namespace will give \c std::ostream ability to write UTF8 string and its char.
|
||||
* For using this feature, please directly use <TT>using namespace yycc::string:stream;</TT> to import this namespace.
|
||||
* For using this feature, please directly use <TT>using namespace yycc::patch:stream;</TT> to import this namespace.
|
||||
*/
|
||||
namespace yycc::string::stream {
|
||||
namespace yycc::patch::stream {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const std::u8string_view& u8str);
|
||||
std::ostream& operator<<(std::ostream& os, const char8_t* u8str);
|
@ -2,6 +2,9 @@
|
||||
|
||||
namespace yycc::string::reinterpret {
|
||||
|
||||
char8_t as_utf8(const char& src) {
|
||||
return static_cast<char8_t>(src);
|
||||
}
|
||||
const char8_t* as_utf8(const char* src) {
|
||||
return reinterpret_cast<const char8_t*>(src);
|
||||
}
|
||||
@ -15,6 +18,9 @@ namespace yycc::string::reinterpret {
|
||||
return std::u8string_view(reinterpret_cast<const char8_t*>(src.data()), src.size());
|
||||
}
|
||||
|
||||
char as_ordinary(char8_t src) {
|
||||
return static_cast<char>(src);
|
||||
}
|
||||
const char* as_ordinary(const char8_t* src) {
|
||||
return reinterpret_cast<const char*>(src);
|
||||
}
|
||||
|
@ -11,52 +11,64 @@
|
||||
*/
|
||||
namespace yycc::string::reinterpret {
|
||||
|
||||
/**
|
||||
* @brief Reinterpret ordinary char type to UTF-8 char type.
|
||||
* @param[in] src Source ordinary char value.
|
||||
* @return UTF8 char value.
|
||||
*/
|
||||
char8_t as_utf8(const char& src);
|
||||
/**
|
||||
* @brief Reinterpret ordinary C-string to UTF-8 string (const version).
|
||||
* @param src Source ordinary string
|
||||
* @param[in] src Source ordinary string
|
||||
* @return Pointer to UTF-8 encoded string
|
||||
*/
|
||||
const char8_t* as_utf8(const char* src);
|
||||
/**
|
||||
* @brief Reinterpret ordinary C-string as an UTF-8 string (non-const version).
|
||||
* @param src Source ordinary string
|
||||
* @param[in] src Source ordinary string
|
||||
* @return Pointer to UTF-8 encoded string
|
||||
*/
|
||||
char8_t* as_utf8(char* src);
|
||||
/**
|
||||
* @brief Reinterpret ordinary string view to copied UTF-8 string.
|
||||
* @param src Source ordinary string view
|
||||
* @param[in] src Source ordinary string view
|
||||
* @return UTF-8 encoded string
|
||||
*/
|
||||
std::u8string as_utf8(const std::string_view& src);
|
||||
/**
|
||||
* @brief Reinterpret ordinary string view to UTF-8 string view.
|
||||
* @param src Source ordinary string view
|
||||
* @param[in] src Source ordinary string view
|
||||
* @return UTF-8 encoded string view
|
||||
*/
|
||||
std::u8string_view as_utf8_view(const std::string_view& src);
|
||||
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 char type to ordinary char type.
|
||||
* @param[in] src Source UTF-8 char value.
|
||||
* @return Ordinary char value.
|
||||
*/
|
||||
char as_ordinary(char8_t src);
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 C-string to ordinary string (const version).
|
||||
* @param src Source UTF-8 string
|
||||
* @param[in] src Source UTF-8 string
|
||||
* @return Pointer to ordinary string
|
||||
*/
|
||||
const char* as_ordinary(const char8_t* src);
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 C-string to ordinary string (non-const version).
|
||||
* @param src Source UTF-8 string
|
||||
* @param[in] src Source UTF-8 string
|
||||
* @return Pointer to ordinary string
|
||||
*/
|
||||
char* as_ordinary(char8_t* src);
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 string view to ordinary string.
|
||||
* @param src Source UTF-8 string view
|
||||
* @param[in] src Source UTF-8 string view
|
||||
* @return Ordinary string
|
||||
*/
|
||||
std::string as_ordinary(const std::u8string_view& src);
|
||||
/**
|
||||
* @brief Reinterpret UTF-8 string view to ordinary string view
|
||||
* @param src Source UTF-8 string view
|
||||
* @param[in] src Source UTF-8 string view
|
||||
* @return Ordinary string view
|
||||
*/
|
||||
std::string_view as_ordinary_view(const std::u8string_view& src);
|
||||
|
@ -18,10 +18,11 @@ PRIVATE
|
||||
yycc/constraint/builder.cpp
|
||||
yycc/patch/ptr_pad.cpp
|
||||
yycc/patch/fopen.cpp
|
||||
yycc/patch/stream.cpp
|
||||
yycc/patch/format.cpp
|
||||
yycc/rust/env.cpp
|
||||
yycc/string/reinterpret.cpp
|
||||
yycc/string/op.cpp
|
||||
yycc/string/stream.cpp
|
||||
yycc/num/parse.cpp
|
||||
yycc/num/stringify.cpp
|
||||
yycc/num/op.cpp
|
||||
|
35
testbench/yycc/patch/format.cpp
Normal file
35
testbench/yycc/patch/format.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <yycc.hpp>
|
||||
#include <yycc/patch/format.hpp>
|
||||
|
||||
#define FORMAT ::yycc::patch::format
|
||||
|
||||
namespace yycctest::patch::format {
|
||||
|
||||
static constexpr char8_t PROBE[] = u8"hello";
|
||||
static std::u8string PROBE_STRING(PROBE);
|
||||
static constexpr std::u8string_view PROBE_STRING_VIEW(PROBE);
|
||||
|
||||
TEST(PatchFormat, OrdinaryFormat) {
|
||||
auto rv = FORMAT::format("{}{}{}{}{}{} world!",
|
||||
PROBE[0],
|
||||
PROBE_STRING.data(),
|
||||
PROBE_STRING.c_str(),
|
||||
PROBE,
|
||||
PROBE_STRING,
|
||||
PROBE_STRING_VIEW);
|
||||
EXPECT_EQ(rv, "104hellohellohellohellohello world!");
|
||||
}
|
||||
|
||||
TEST(PatchFormat, Utf8Format) {
|
||||
auto rv = FORMAT::format(u8"{}{}{}{}{}{} world!",
|
||||
PROBE[0],
|
||||
PROBE_STRING.data(),
|
||||
PROBE_STRING.c_str(),
|
||||
PROBE,
|
||||
PROBE_STRING,
|
||||
PROBE_STRING_VIEW);
|
||||
EXPECT_EQ(rv, u8"104hellohellohellohellohello world!");
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +1,28 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <yycc.hpp>
|
||||
#include <yycc/string/stream.hpp>
|
||||
#include <yycc/patch/stream.hpp>
|
||||
#include <yycc/string/reinterpret.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#define REINTERPRET ::yycc::string::reinterpret
|
||||
using namespace std::literals::string_view_literals;
|
||||
using namespace ::yycc::string::stream;
|
||||
using namespace ::yycc::patch::stream;
|
||||
|
||||
namespace yycctest::string::stream {
|
||||
namespace yycctest::patch::stream {
|
||||
|
||||
TEST(StringStream, StringView) {
|
||||
TEST(PatchStream, StringView) {
|
||||
std::stringstream ss;
|
||||
ss << u8"hello"sv;
|
||||
EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), u8"hello"sv);
|
||||
}
|
||||
|
||||
TEST(StringStream, CStrPtr) {
|
||||
TEST(PatchStream, CStrPtr) {
|
||||
std::stringstream ss;
|
||||
ss << u8"hello";
|
||||
EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), u8"hello");
|
||||
}
|
||||
|
||||
TEST(StringStream, Character) {
|
||||
TEST(PatchStream, Character) {
|
||||
std::stringstream ss;
|
||||
ss << u8'y';
|
||||
EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), u8"y");
|
@ -6,6 +6,7 @@
|
||||
#include <yycc/rust/prelude.hpp>
|
||||
|
||||
#define REINTERPRET ::yycc::string::reinterpret
|
||||
#define AS_UINT8(p) static_cast<u8>(p)
|
||||
#define CONST_VOID_PTR(p) reinterpret_cast<const void*>(p)
|
||||
#define VOID_PTR(p) reinterpret_cast<void*>(p)
|
||||
|
||||
@ -13,6 +14,16 @@ namespace yycctest::string::reinterpret {
|
||||
|
||||
static std::u8string PROBE(u8"Test");
|
||||
|
||||
TEST(StringReinterpret, Character) {
|
||||
const auto& src = PROBE[0];
|
||||
const auto dst = REINTERPRET::as_ordinary(src);
|
||||
const auto new_src = REINTERPRET::as_utf8(dst);
|
||||
|
||||
// Value should be the same after casting.
|
||||
EXPECT_EQ(AS_UINT8(src), AS_UINT8(dst));
|
||||
EXPECT_EQ(AS_UINT8(src), AS_UINT8(new_src));
|
||||
}
|
||||
|
||||
TEST(StringReinterpret, ConstPointer) {
|
||||
const auto* src = PROBE.data();
|
||||
const auto* dst = REINTERPRET::as_ordinary(src);
|
||||
@ -33,7 +44,7 @@ namespace yycctest::string::reinterpret {
|
||||
EXPECT_EQ(VOID_PTR(src), VOID_PTR(new_src));
|
||||
}
|
||||
|
||||
TEST(StringReinterpret, String) {
|
||||
TEST(StringReinterpret, StlString) {
|
||||
auto src = std::u8string(PROBE);
|
||||
auto dst = REINTERPRET::as_ordinary(src);
|
||||
auto new_src = REINTERPRET::as_utf8(dst);
|
||||
@ -45,7 +56,7 @@ namespace yycctest::string::reinterpret {
|
||||
EXPECT_TRUE(std::memcmp(src.data(), new_src.data(), src.length()) == 0);
|
||||
}
|
||||
|
||||
TEST(StringReinterpret, StringView) {
|
||||
TEST(StringReinterpret, StlStringView) {
|
||||
auto src = std::u8string_view(PROBE);
|
||||
auto dst = REINTERPRET::as_ordinary_view(src);
|
||||
auto new_src = REINTERPRET::as_utf8_view(dst);
|
||||
|
Reference in New Issue
Block a user