refactor: continue refactor project from C++17 to 23

This commit is contained in:
2025-07-25 10:49:07 +08:00
parent 4f0b3d19d1
commit b79df0c65e
22 changed files with 296 additions and 498 deletions

View File

@ -26,9 +26,6 @@ FILES
# Headers
yycc.hpp
yycc/version.hpp
yycc/primitive.hpp
yycc/prelude/core.hpp
yycc/prelude/rust.hpp
yycc/macro/version_cmp.hpp
yycc/macro/os_detector.hpp
yycc/macro/endian_detector.hpp
@ -38,6 +35,8 @@ FILES
yycc/string/op.hpp
yycc/num/parse.hpp
yycc/num/stringify.hpp
yycc/rust/prelude.hpp
yycc/rust/primitive.hpp
yycc/rust/panic.hpp
yycc/rust/option.hpp
yycc/rust/result.hpp

View File

@ -1,38 +1,26 @@
#include "stlcvt.hpp"
#include <locale>
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
namespace yycc::encoding::stlcvt {
#pragma region Generic Converter
/*
* NOTE:
* YYC MARK:
* According to the documentation introduced in CppReference.
* The standard library is guaranteed to provide several specific specializations of \c std::codecvt.
* The UTF8 char type in UTF8 related specializations of \c std::codecvt is different.
* It is also independend from we defined char type.
* So it is essential define a type which can correctly trigger specific specializations of \c std::codecv in there.
* The UTF8 char type in UTF8 related specializations of \c std::codecvt is different in different C++ standard.
* But the oldest C++ version YYCC supported is C++ 23, char8_t is the only viable UTF8 char type for \c std::codecvt.
* So we can simply and safely use it to correctly trigger specific specializations of \c std::codecv in there.
*/
#if defined(YYCC_CPPFEAT_UTF8)
using CodecvtUtf8Char = char8_t;
#else
using CodecvtUtf8Char = char;
#endif
template<typename TChar>
requires(std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>)
using CodecvtFacet = std::codecvt<TChar, char8_t, std::mbstate_t>;
template<typename TChar,
std::enable_if_t<std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>, int>
= 0>
using CodecvtFacet = std::codecvt<TChar, CodecvtUtf8Char, std::mbstate_t>;
template<typename TChar,
std::enable_if_t<std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>, int>
= 0>
static ConvResult<std::basic_string<TChar>> generic_to_utf_other(
const NS_YYCC_STRING::u8string_view& src) {
template<typename TChar>
requires(std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>)
static ConvResult<std::basic_string<TChar>> generic_to_utf_other(const std::u8string_view& src) {
// Reference:
// https://en.cppreference.com/w/cpp/locale/codecvt/in
@ -52,38 +40,27 @@ namespace yycc::encoding::stlcvt {
// convertion preparation
std::mbstate_t mb{};
dst.resize(src.size());
const CodecvtUtf8Char *intern_from = reinterpret_cast<const CodecvtUtf8Char*>(src.data()),
*intern_from_end = reinterpret_cast<const CodecvtUtf8Char*>(
src.data() + src.size()),
*intern_from_next = nullptr;
TChar *extern_to = dst.data(), *extern_to_end = dst.data() + dst.size(),
*extern_to_next = nullptr;
const char8_t *intern_from = reinterpret_cast<const char8_t*>(src.data()),
*intern_from_end = reinterpret_cast<const char8_t*>(src.data() + src.size()), *intern_from_next = nullptr;
TChar *extern_to = dst.data(), *extern_to_end = dst.data() + dst.size(), *extern_to_next = nullptr;
// do convertion
auto result = this_codecvt.in(mb,
intern_from,
intern_from_end,
intern_from_next,
extern_to,
extern_to_end,
extern_to_next);
auto result = this_codecvt.in(mb, intern_from, intern_from_end, intern_from_next, extern_to, extern_to_end, extern_to_next);
// check result
if (result != CodecvtFacet<TChar>::ok) return ConvError();
if (result != CodecvtFacet<TChar>::ok) return std::unexpected(ConvError{});
// resize result and return
dst.resize(extern_to_next - dst.data());
return dst;
}
template<typename TChar,
std::enable_if_t<std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>, int>
= 0>
static ConvResult<NS_YYCC_STRING::u8string> generic_to_utf8(
const std::basic_string_view<TChar>& src) {
template<typename TChar>
requires(std::is_same_v<TChar, char16_t> || std::is_same_v<TChar, char32_t>)
static ConvResult<std::u8string> generic_to_utf8(const std::basic_string_view<TChar>& src) {
// Reference:
// https://en.cppreference.com/w/cpp/locale/codecvt/out
// prepare return value
NS_YYCC_STRING::u8string dst;
std::u8string dst;
// if src is empty, return directly
if (src.empty()) {
@ -99,102 +76,43 @@ namespace yycc::encoding::stlcvt {
// do convertion preparation
std::mbstate_t mb{};
dst.resize(src.size() * this_codecvt.max_length());
const TChar *intern_from = src.data(), *intern_from_end = src.data() + src.size(),
*intern_from_next = nullptr;
CodecvtUtf8Char *extern_to = reinterpret_cast<CodecvtUtf8Char*>(dst.data()),
*extern_to_end = reinterpret_cast<CodecvtUtf8Char*>(dst.data() + dst.size()),
*extern_to_next = nullptr;
const TChar *intern_from = src.data(), *intern_from_end = src.data() + src.size(), *intern_from_next = nullptr;
char8_t *extern_to = reinterpret_cast<char8_t*>(dst.data()), *extern_to_end = reinterpret_cast<char8_t*>(dst.data() + dst.size()),
*extern_to_next = nullptr;
// do convertion
auto result = this_codecvt.out(mb,
intern_from,
intern_from_end,
intern_from_next,
extern_to,
extern_to_end,
extern_to_next);
auto result = this_codecvt.out(mb, intern_from, intern_from_end, intern_from_next, extern_to, extern_to_end, extern_to_next);
// check result
if (result != CodecvtFacet<TChar>::ok) return ConvError();
if (result != CodecvtFacet<TChar>::ok) return std::unexpected(ConvError{});
// resize result and retuen
dst.resize(extern_to_next - reinterpret_cast<CodecvtUtf8Char*>(dst.data()));
dst.resize(extern_to_next - reinterpret_cast<char8_t*>(dst.data()));
return dst;
}
#pragma endregion
#pragma endregion Converter
#pragma region Help Macros
#pragma region
#define CONVFN_TYPE1(fct_name, src_char_type, dst_char_type) \
namespace expected = NS_YYCC_PATCH_EXPECTED; \
auto rv = priv_##fct_name(src); \
if (expected::is_value(rv)) { \
dst = std::move(expected::get_value(rv)); \
return true; \
} else { \
return false; \
}
#define CONVFN_TYPE2(fct_name, src_char_type, dst_char_type) \
std::basic_string<dst_char_type> rv; \
if (fct_name(src, rv)) return rv; \
else throw std::runtime_error("fail to convert utf string");
#pragma endregion
#pragma region UTF8 -> UTF16
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src) {
ConvResult<std::u16string> to_utf16(const std::u8string_view& src) {
// UTF8 -> UTF16
return generic_to_utf_other<char16_t>(src);
}
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst) {
CONVFN_TYPE1(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
#pragma endregion
#pragma region UTF16 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src) {
ConvResult<std::u8string> to_utf8(const std::u16string_view& src) {
// UTF16 -> UTF8
return generic_to_utf8<char16_t>(src);
}
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src) {
CONVFN_TYPE2(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
#pragma region UTF8 -> UTF32
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src) {
ConvResult<std::u32string> to_utf32(const std::u8string_view& src) {
// UTF8 -> UTF32
return generic_to_utf_other<char32_t>(src);
}
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst) {
CONVFN_TYPE1(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
#pragma endregion
#pragma region UTF32 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src) {
ConvResult<std::u8string> to_utf8(const std::u32string_view& src) {
// UTF32 -> UTF8
return generic_to_utf8<char32_t>(src);
}
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src) {
CONVFN_TYPE2(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
} // namespace yycc::encoding::utf
} // namespace yycc::encoding::stlcvt

View File

@ -1,40 +1,43 @@
#pragma once
#include "../string.hpp"
#include "../patch/expected.hpp"
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
#include <string>
#include <string_view>
#include <expected>
namespace yycc::encoding::stlcvt {
/// @private
/// @brief Possible convertion error occurs in this module.
struct ConvError {};
/// @private
/// @brief The result type of this module.
template<typename T>
using ConvResult = NS_YYCC_PATCH_EXPECTED::Expected<T, ConvError>;
using ConvResult = std::expected<T, ConvError>;
// UTF8 -> UTF16
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src);
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst);
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src);
/**
* @brief UTF8 -> UTF16
* @param src
* @return
*/
ConvResult<std::u16string> to_utf16(const std::u8string_view& src);
// UTF16 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src);
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src);
/**
* @brief UTF16 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::u16string_view& src);
// UTF8 -> UTF32
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src);
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst);
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src);
/**
* @brief UTF8 -> UTF32
* @param src
* @return
*/
ConvResult<std::u32string> to_utf32(const std::u8string_view& src);
// UTF32 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src);
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src);
/**
* @brief UTF32 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> utf8(const std::u32string_view& src);
}
#undef NS_YYCC_PATCH_EXPECTED
#undef NS_YYCC_STRING

View File

@ -11,34 +11,14 @@
#include <Windows.h>
#include "../windows/import_guard_tail.hpp"
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
namespace yycc::encoding::windows {
#pragma region Help Macros
#pragma region WideCharToMultiByte and MultiByteToWideChar stuff
#define CONVFN_TYPE1(fct_name, src_char_type, dst_char_type, ...) \
namespace expected = NS_YYCC_PATCH_EXPECTED; \
auto rv = priv_##fct_name(src, ##__VA_ARGS__); \
if (expected::is_value(rv)) { \
dst = std::move(expected::get_value(rv)); \
return true; \
} else { \
return false; \
}
#define CONVFN_TYPE2(fct_name, src_char_type, dst_char_type, ...) \
std::basic_string<dst_char_type> rv; \
if (fct_name(src, rv, ##__VA_ARGS__)) return rv; \
else throw std::runtime_error("fail to convert string in Win32 function");
#pragma endregion
#pragma region WChar -> Char
ConvResult<std::string> priv_to_char(const std::wstring_view& src, CodePage code_page) {
// WChar -> Char
ConvResult<std::string> to_char(const std::wstring_view& src, CodePage code_page) {
// prepare result
std::string dst;
@ -52,36 +32,25 @@ namespace yycc::encoding::windows {
LPCWCH lpWideCharStr = reinterpret_cast<LPCWCH>(src.data());
// check whether source string is too large.
size_t cSrcSize = src.size();
if (cSrcSize > std::numeric_limits<int>::max()) return ConvError::TooLargeLength;
if (cSrcSize > std::numeric_limits<int>::max()) return std::unexpected(ConvError::TooLargeLength);
int cchWideChar = static_cast<int>(src.size());
// do convertion
// do a dry-run first to fetch desired size.
int desired_size = WideCharToMultiByte(code_page, 0, lpWideCharStr, cchWideChar, NULL, 0, NULL, NULL);
if (desired_size <= 0) return ConvError::NoDesiredSize;
if (desired_size <= 0) return std::unexpected(ConvError::NoDesiredSize);
// resize dest for receiving result
dst.resize(static_cast<size_t>(desired_size));
// do real convertion
int write_result
= WideCharToMultiByte(code_page, 0, lpWideCharStr, cchWideChar, reinterpret_cast<LPSTR>(dst.data()), desired_size, NULL, NULL);
if (write_result <= 0) return ConvError::BadWrittenSize;
if (write_result <= 0) return std::unexpected(ConvError::BadWrittenSize);
return dst;
}
bool to_char(const std::wstring_view& src, std::string& dst, CodePage code_page) {
CONVFN_TYPE1(to_char, wchar_t, char, code_page);
}
std::string to_char(const std::wstring_view& src, CodePage code_page) {
CONVFN_TYPE2(to_char, wchar_t, char, code_page);
}
#pragma endregion
#pragma region Char -> WChar
ConvResult<std::wstring> priv_to_wchar(const std::string_view& src, CodePage code_page) {
// Char -> WChar
ConvResult<std::wstring> to_wchar(const std::string_view& src, CodePage code_page) {
// prepare result
std::wstring dst;
@ -95,134 +64,53 @@ namespace yycc::encoding::windows {
LPCCH lpMultiByteStr = reinterpret_cast<LPCCH>(src.data());
// check whether source string is too large.
size_t cSrcSize = src.size();
if (cSrcSize > std::numeric_limits<int>::max()) return ConvError::TooLargeLength;
if (cSrcSize > std::numeric_limits<int>::max()) return std::unexpected(ConvError::TooLargeLength);
int cbMultiByte = static_cast<int>(src.size());
// do convertion
// do a dry-run first to fetch desired size.
int desired_size = MultiByteToWideChar(code_page, 0, lpMultiByteStr, cbMultiByte, NULL, 0);
if (desired_size <= 0) return ConvError::NoDesiredSize;
if (desired_size <= 0) return std::unexpected(ConvError::NoDesiredSize);
// resize dest for receiving result
dst.resize(static_cast<size_t>(desired_size));
// do real convertion
int write_result = MultiByteToWideChar(code_page, 0, lpMultiByteStr, cbMultiByte, reinterpret_cast<LPWSTR>(dst.data()), desired_size);
if (write_result <= 0) return ConvError::BadWrittenSize;
if (write_result <= 0) return std::unexpected(ConvError::BadWrittenSize);
return dst;
}
bool to_wchar(const std::string_view& src, std::wstring& dst, CodePage code_page) {
CONVFN_TYPE1(to_wchar, char, wchar_t, code_page);
// Char -> Char
ConvResult<std::string> to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page) {
auto first_rv = to_wchar(src, src_code_page);
return first_rv.and_then([dst_code_page](const auto& src) { return to_char(src, dst_code_page); });
}
std::wstring to_wchar(const std::string_view& src, CodePage code_page) {
CONVFN_TYPE2(to_wchar, char, wchar_t, code_page);
// WChar -> UTF8
ConvResult<std::u8string> to_utf8(const std::wstring_view& src) {
auto rv = to_char(src, CP_UTF8);
return rv.transform([](const auto& dst) { return NS_YYCC_STRING_REINTERPRET::as_utf8(dst); });
}
// UTF8 -> WChar
ConvResult<std::wstring> to_wchar(const std::u8string_view& src) {
return to_wchar(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(src), CP_UTF8);
}
// Char -> UTF8
ConvResult<std::u8string> to_utf8(const std::string_view& src, CodePage code_page) {
auto rv = to_char(src, code_page, CP_UTF8);
return rv.transform([](const auto& dst) { return NS_YYCC_STRING_REINTERPRET::as_utf8(dst); });
}
// UTF8 -> Char
ConvResult<std::string> to_char(const std::u8string_view& src, CodePage code_page) {
return to_char(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(src), CP_UTF8, code_page);
}
#pragma endregion
#pragma region Char -> Char
ConvResult<std::string> priv_to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page) {
namespace expected = NS_YYCC_PATCH_EXPECTED;
// Perform first convertion
auto first_rv = priv_to_wchar(src, src_code_page);
if (expected::is_error(first_rv)) {
return expected::get_error(first_rv);
}
// Perform second convertion
auto second_rv = to_char(std::get<std::wstring>(first_rv), dst_code_page);
return second_rv;
}
bool to_char(const std::string_view& src, std::string& dst, CodePage src_code_page, CodePage dst_code_page) {
CONVFN_TYPE1(to_char, char, char, src_code_page, dst_code_page);
}
std::string to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page) {
CONVFN_TYPE2(to_char, char, char, src_code_page, dst_code_page);
}
#pragma endregion
#pragma region WChar -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::wstring_view& src) {
namespace expected = NS_YYCC_PATCH_EXPECTED;
auto rv = priv_to_char(src, CP_UTF8);
if (expected::is_value(rv)) {
return NS_YYCC_STRING_REINTERPRET::as_utf8(expected::get_value(rv));
} else {
return expected::get_error(rv);
}
}
bool to_utf8(const std::wstring_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, wchar_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string to_utf8(const std::wstring_view& src) {
CONVFN_TYPE2(to_utf8, wchar_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
#pragma region UTF8 -> WChar
ConvResult<std::wstring> priv_to_wchar(const NS_YYCC_STRING::u8string_view& src) {
return priv_to_wchar(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(src), CP_UTF8);
}
bool to_wchar(const NS_YYCC_STRING::u8string_view& src, std::wstring& dst) {
CONVFN_TYPE1(to_wchar, NS_YYCC_STRING::u8char, wchar_t);
}
std::wstring to_wchar(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_wchar, NS_YYCC_STRING::u8char, wchar_t);
}
#pragma endregion
#pragma region Char -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::string_view& src, CodePage code_page) {
namespace expected = NS_YYCC_PATCH_EXPECTED;
auto rv = priv_to_char(src, code_page, CP_UTF8);
if (expected::is_value(rv)) {
return NS_YYCC_STRING_REINTERPRET::as_utf8(expected::get_value(rv));
} else {
return expected::get_error(rv);
}
}
bool to_utf8(const std::string_view& src, NS_YYCC_STRING::u8string& dst, CodePage code_page) {
CONVFN_TYPE1(to_utf8, char, NS_YYCC_STRING::u8char, code_page);
}
NS_YYCC_STRING::u8string to_utf8(const std::string_view& src, CodePage code_page) {
CONVFN_TYPE2(to_utf8, char, NS_YYCC_STRING::u8char, code_page);
}
#pragma endregion
#pragma region UTF8 -> Char
ConvResult<std::string> priv_to_char(const NS_YYCC_STRING::u8string_view& src, CodePage code_page) {
return priv_to_char(NS_YYCC_STRING_REINTERPRET::as_ordinary_view(src), CP_UTF8, code_page);
}
bool to_char(const NS_YYCC_STRING::u8string_view& src, std::string& dst, CodePage code_page) {
CONVFN_TYPE1(to_char, NS_YYCC_STRING::u8char, char, code_page);
}
std::string to_char(const NS_YYCC_STRING::u8string_view& src, CodePage code_page) {
CONVFN_TYPE2(to_char, NS_YYCC_STRING::u8char, char, code_page);
}
#pragma endregion
#pragma region UTF stuff
// YYC MARK:
// The convertion between UTF is implemented by c16rtomb, c32rtomb, mbrtoc16 and mbrtoc32.
@ -239,9 +127,8 @@ namespace yycc::encoding::windows {
constexpr size_t MULTIPLE_UTF8_TO_UTF32 = 1u;
constexpr size_t MULTIPLE_UTF32_TO_UTF8 = 4u;
#pragma region UTF8 -> UTF16
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src) {
// UTF8 -> UTF16
ConvResult<std::u16string> to_utf16(const std::u8string_view& src) {
std::u16string dst;
dst.reserve(src.size() * MULTIPLE_UTF8_TO_UTF16);
@ -253,8 +140,8 @@ namespace yycc::encoding::windows {
while (ptr < end) {
size_t rc = std::mbrtoc16(&c16, ptr, end - ptr, &state);
if (rc == (size_t) -1) return ConvError::EncodeUtf8;
else if (rc == (size_t) -2) return ConvError::IncompleteUtf8;
if (rc == (size_t) -1) return std::unexpected(ConvError::EncodeUtf8);
else if (rc == (size_t) -2) return std::unexpected(ConvError::IncompleteUtf8);
else if (rc != (size_t) -3) dst.push_back(c16); // from earlier surrogate pair
else {
dst.push_back(c16);
@ -264,20 +151,9 @@ namespace yycc::encoding::windows {
return dst;
}
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst) {
CONVFN_TYPE1(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf16, NS_YYCC_STRING::u8char, char16_t);
}
#pragma endregion
#pragma region UTF16 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src) {
NS_YYCC_STRING::u8string dst;
// UTF16 -> UTF8
ConvResult<std::u8string> to_utf8(const std::u16string_view& src) {
std::u8string dst;
dst.reserve(src.size() * MULTIPLE_UTF16_TO_UTF8);
std::mbstate_t state{};
@ -285,25 +161,14 @@ namespace yycc::encoding::windows {
for (char16_t c : src) {
size_t rc = std::c16rtomb(mbout, c, &state);
if (rc != (size_t) -1) dst.append(reinterpret_cast<NS_YYCC_STRING::u8char*>(mbout), rc);
else return ConvError::InvalidUtf16;
if (rc != (size_t) -1) dst.append(reinterpret_cast<char8_t*>(mbout), rc);
else return std::unexpected(ConvError::InvalidUtf16);
}
return dst;
}
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src) {
CONVFN_TYPE2(to_utf8, char16_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
#pragma region UTF8 -> UTF32
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src) {
// UTF8 -> UTF32
ConvResult<std::u32string> to_utf32(const std::u8string_view& src) {
std::u32string dst;
dst.reserve(src.size() * MULTIPLE_UTF8_TO_UTF32);
@ -315,8 +180,8 @@ namespace yycc::encoding::windows {
while (ptr < end) {
size_t rc = std::mbrtoc32(&c32, ptr, end - ptr, &state);
if (rc == (size_t) -1) return ConvError::EncodeUtf8;
else if (rc == (size_t) -2) return ConvError::IncompleteUtf8;
if (rc == (size_t) -1) return std::unexpected(ConvError::EncodeUtf8);
else if (rc == (size_t) -2) return std::unexpected(ConvError::IncompleteUtf8);
else if (rc != (size_t) -3) throw std::runtime_error("no surrogates in UTF-32");
else dst.push_back(c32);
@ -325,20 +190,9 @@ namespace yycc::encoding::windows {
return dst;
}
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst) {
CONVFN_TYPE1(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src) {
CONVFN_TYPE2(to_utf32, NS_YYCC_STRING::u8char, char32_t);
}
#pragma endregion
#pragma region UTF32 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src) {
NS_YYCC_STRING::u8string dst;
// UTF32 -> UTF8
ConvResult<std::u8string> to_utf8(const std::u32string_view& src) {
std::u8string dst;
dst.reserve(src.size() * MULTIPLE_UTF32_TO_UTF8);
std::mbstate_t state{};
@ -346,25 +200,14 @@ namespace yycc::encoding::windows {
for (char32_t c : src) {
size_t rc = std::c32rtomb(mbout, c, &state);
if (rc != (size_t) -1) dst.append(reinterpret_cast<NS_YYCC_STRING::u8char*>(mbout), rc);
else return ConvError::InvalidUtf32;
if (rc != (size_t) -1) dst.append(reinterpret_cast<char8_t*>(mbout), rc);
else return std::unexpected(ConvError::InvalidUtf32);
}
return dst;
}
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst) {
CONVFN_TYPE1(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src) {
CONVFN_TYPE2(to_utf8, char32_t, NS_YYCC_STRING::u8char);
}
#pragma endregion
#undef CONVFN_TYPE1
#undef CONVFN_TYPE2
} // namespace yycc::encoding::windows
#endif

View File

@ -3,18 +3,17 @@
#if defined(YYCC_OS_WINDOWS)
#include "../patch/expected.hpp"
#include "../string.hpp"
#include <string>
#include <string_view>
#include <expected>
#include <cstdint>
#define NS_YYCC_STRING ::yycc::string
#define NS_YYCC_PATCH_EXPECTED ::yycc::patch::expected
namespace yycc::encoding::windows {
/// @brief The type of Windows code page.
using CodePage = uint32_t;
/// @private
/// @brief The possible error kind occurs in this module.
enum class ConvError {
TooLargeLength, ///< The length of given string is too large exceeding the maximum capacity of Win32 function.
NoDesiredSize, ///< Can not compute the desired size of result string.
@ -25,73 +24,98 @@ namespace yycc::encoding::windows {
IncompleteUtf8, ///< Given UTF8 string is incomplete.
};
/// @private
/// @brief The result type in this module.
template<typename T>
using ConvResult = NS_YYCC_PATCH_EXPECTED::Expected<T, ConvError>;
using ConvResult = std::expected<T, ConvError>;
// WChar -> Char
ConvResult<std::string> priv_to_char(const std::wstring_view& src, CodePage code_page);
bool to_char(const std::wstring_view& src, std::string& dst, CodePage code_page);
std::string to_char(const std::wstring_view& src, CodePage code_page);
/**
* @brief WChar -> Char
* @param src
* @param code_page
* @return
*/
ConvResult<std::string> to_char(const std::wstring_view& src, CodePage code_page);
// Char -> WChar
ConvResult<std::wstring> priv_to_wchar(const std::string_view& src, CodePage code_page);
bool to_wchar(const std::string_view& src, std::wstring& dst, CodePage code_page);
std::wstring to_wchar(const std::string_view& src, CodePage code_page);
/**
* @brief Char -> WChar
* @param src
* @param code_page
* @return
*/
ConvResult<std::wstring> to_wchar(const std::string_view& src, CodePage code_page);
// Char -> Char
// This is the combination of "WChar -> Char" and "Char -> WChar"
ConvResult<std::string> priv_to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page);
bool to_char(const std::string_view& src, std::string& dst, CodePage src_code_page, CodePage dst_code_page);
std::string to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page);
/**
* @brief Char -> Char
* @details This is the combination of "WChar -> Char" and "Char -> WChar"
* @param src
* @param src_code_page
* @param dst_code_page
* @return
*/
ConvResult<std::string> to_char(const std::string_view& src, CodePage src_code_page, CodePage dst_code_page);
// WChar -> UTF8
// This is the specialization of "WChar -> Char"
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::wstring_view& src);
bool to_utf8(const std::wstring_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::wstring_view& src);
/**
* @brief WChar -> UTF8
* @details This is the specialization of "WChar -> Char"
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::wstring_view& src);
// UTF8 -> WChar
// This is the specialization of "Char -> WChar"
ConvResult<std::wstring> priv_to_wchar(const NS_YYCC_STRING::u8string_view& src);
bool to_wchar(const NS_YYCC_STRING::u8string_view& src, std::wstring& dst);
std::wstring to_wchar(const NS_YYCC_STRING::u8string_view& src);
/**
* @brief UTF8 -> WChar
* @details This is the specialization of "Char -> WChar"
* @param src
* @return
*/
ConvResult<std::wstring> to_wchar(const std::u8string_view& src);
// Char -> UTF8
// This is the specialization of "Char -> Char"
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::string_view& src, CodePage code_page);
bool to_utf8(const std::string_view& src, NS_YYCC_STRING::u8string& dst, CodePage code_page);
NS_YYCC_STRING::u8string to_utf8(const std::string_view& src, CodePage code_page);
/**
* @brief Char -> UTF8
* @details This is the specialization of "Char -> Char"
* @param src
* @param code_page
* @return
*/
ConvResult<std::u8string> to_utf8(const std::string_view& src, CodePage code_page);
// UTF8 -> Char
// This is the specialization of "Char -> Char"
ConvResult<std::string> priv_to_char(const NS_YYCC_STRING::u8string_view& src, CodePage code_page);
bool to_char(const NS_YYCC_STRING::u8string_view& src, std::string& dst, CodePage code_page);
std::string to_char(const NS_YYCC_STRING::u8string_view& src, CodePage code_page);
/**
* @brief UTF8 -> Char
* @details This is the specialization of "Char -> Char"
* @param src
* @param code_page
* @return
*/
ConvResult<std::string> to_char(const std::u8string_view& src, CodePage code_page);
// UTF8 -> UTF16
ConvResult<std::u16string> priv_to_utf16(const NS_YYCC_STRING::u8string_view& src);
bool to_utf16(const NS_YYCC_STRING::u8string_view& src, std::u16string& dst);
std::u16string to_utf16(const NS_YYCC_STRING::u8string_view& src);
/**
* @brief UTF8 -> UTF16
* @param src
* @return
*/
ConvResult<std::u16string> to_utf16(const std::u8string_view& src);
// UTF16 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u16string_view& src);
bool to_utf8(const std::u16string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u16string_view& src);
/**
* @brief UTF16 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::u16string_view& src);
// UTF8 -> UTF32
ConvResult<std::u32string> priv_to_utf32(const NS_YYCC_STRING::u8string_view& src);
bool to_utf32(const NS_YYCC_STRING::u8string_view& src, std::u32string& dst);
std::u32string to_utf32(const NS_YYCC_STRING::u8string_view& src);
/**
* @brief UTF8 -> UTF32
* @param src
* @return
*/
ConvResult<std::u32string> to_utf32(const std::u8string_view& src);
// UTF32 -> UTF8
ConvResult<NS_YYCC_STRING::u8string> priv_to_utf8(const std::u32string_view& src);
bool to_utf8(const std::u32string_view& src, NS_YYCC_STRING::u8string& dst);
NS_YYCC_STRING::u8string to_utf8(const std::u32string_view& src);
/**
* @brief UTF32 -> UTF8
* @param src
* @return
*/
ConvResult<std::u8string> to_utf8(const std::u32string_view& src);
} // namespace yycc::encoding::windows
#undef NS_YYCC_PATCH_EXPECTED
#undef NS_YYCC_STRING
#endif

View File

@ -3,3 +3,28 @@
#if (defined(YYCC_CC_MSVC) + defined(YYCC_CC_GCC) + defined(YYCC_CC_CLANG)) != 1
#error "Current compiler is not supported!"
#endif
namespace yycc::macro::compiler {
/// @brief The kind of compiler.
enum class CompilerKind {
Msvc, ///< MSVC
Gcc, ///< GCC
Clang, ///< Clang
};
/**
* @brief Fetch the compiler type.
* @return The kind of compiler.
*/
inline constexpr CompilerKind get_compiler() {
#if defined(YYCC_CC_MSVC)
return CompilerKind::Msvc;
#elif defined(YYCC_CC_GCC)
return CompilerKind::Gcc;
#else
return CompilerKind::Clang;
#endif
}
} // namespace yycc::macro::compiler

View File

@ -5,3 +5,24 @@
#error "Current system endian (byte order) is not supported!"
#endif
namespace yycc::macro::endian {
/// @brief The endian kind of OS.
enum class EndianKind {
Little, ///< Little endian.
Big, ///< Big endian.
};
/**
* @brief Fetch the endian of OS.
* @return The endian of OS.
*/
inline constexpr EndianKind get_endian() {
#if defined(YYCC_ENDIAN_LITTLE)
return EndianKind::Little;
#else
return EndianKind::Big;
#endif
}
} // namespace yycc::macro::endian

View File

@ -4,3 +4,25 @@
#if (defined(YYCC_OS_WINDOWS) + defined(YYCC_OS_LINUX)) != 1
#error "Current operating system is not supported!"
#endif
namespace yycc::macro::os {
/// @brief The operating system kind.
enum class OsKind {
Windows, ///< Microsoft Windows
Linux, ///< GNU/Linux
};
/**
* @brief Fetch the operating system
* @return The kind of operating system.
*/
inline constexpr OsKind get_os() {
#if defined(YYCC_OS_WINDOWS)
return OsKind::Windows;
#else
return OsKind::Linux;
#endif
}
} // namespace yycc::macro::os

View File

@ -1,21 +0,0 @@
#pragma once
// Suppress unsafe warning on Windows
#include "../windows/unsafe_suppressor.hpp"
// Prelude section
#include "../string.hpp"
namespace yycc::prelude {
#define NS_YYCC_STRING ::yycc::string
using u8char = NS_YYCC_STRING::u8char;
using u8string = NS_YYCC_STRING::u8string;
using u8string_view = NS_YYCC_STRING::u8string_view;
#undef NS_YYCC_STRING
} // namespace yycc::prelude
// Expose all members
using namespace yycc::prelude;

View File

@ -1,10 +1,12 @@
#pragma once
#include <optional>
/// @brief The reproduction of Rust Option type.
/// @details
/// This namespace reproduce Rust Option type, and its members Some and None in C++.
/// However Option is not important than Result, so its implementation is very casual.
/**
* @brief The reproduction of Rust Option type.
* @details
* This namespace reproduce Rust Option type, and its members Some and None in C++.
* However Option is not important than Result, so its implementation is very casual.
*/
namespace yycc::rust::option {
template<typename T>

View File

@ -1,12 +1,9 @@
#include "panic.hpp"
#include "../macro/feature_probe.hpp"
#include <cstdlib>
#include <iomanip>
#include <iostream>
#if defined(YYCC_CPPFEAT_STACKTRACE)
#include <stacktrace>
#endif
namespace yycc::rust::panic {
@ -24,12 +21,8 @@ namespace yycc::rust::panic {
// User custom message
dst << "note: " << msg << std::endl;
// Stacktrace message if we support it.
#if defined(YYCC_CPPFEAT_STACKTRACE)
dst << "stacktrace: " << std::endl;
dst << std::stacktrace::current() << std::endl;
#else
dst << "there is no stacktrace because your C++ runtime do not support it." << std::endl;
#endif
// // Restore color
// dst << RESET;

View File

@ -1,10 +1,6 @@
#pragma once
#include "../macro/feature_probe.hpp"
#include <string_view>
#if defined(YYCC_CPPFEAT_FORMAT)
#include <format>
#endif
/**
* @brief Provides Rust-style panic functionality for immediate program termination on unrecoverable errors.
@ -38,13 +34,7 @@ namespace yycc::rust::panic {
* The macro parameters are the message to format and its arguments, following \c std::format syntax.
* This macro essentially calls \c std::format internally.
*/
#if defined(YYCC_CPPFEAT_FORMAT)
#if defined(YYCC_CPPFEAT_VA_OPT)
#define RS_PANICF(msg, ...) RS_PANIC(std::format(msg __VA_OPT__(, ) __VA_ARGS__))
#else
#define RS_PANICF(msg, ...) RS_PANIC(std::format(msg, ##__VA_ARGS__))
#endif
#endif
/**
* @brief Immediately crashes the entire program like Rust's \c panic! macro.

View File

@ -1,16 +1,13 @@
#pragma once
// Include YYCC prelude first
#include "core.hpp"
// Rust prelude section
#include "../rust/primitive.hpp"
#include "../rust/result.hpp"
#include "../rust/option.hpp"
#include "../rust/panic.hpp"
#include "primitive.hpp"
#include "result.hpp"
#include "option.hpp"
#include "panic.hpp"
#include <vector>
namespace yycc::prelude::rust {
namespace yycc::rust::prelude {
// Include primitive types
#define NS_RUST_PRIMITIVE ::yycc::rust::primitive
@ -35,7 +32,7 @@ namespace yycc::prelude::rust {
#undef NS_RUST_PRIMITIVE
// Other types
using String = ::yycc::string::u8string;
using String = std::u8string;
template<typename T>
using Vec = std::vector<T>;
@ -49,4 +46,4 @@ namespace yycc::prelude::rust {
} // namespace yycc::prelude::rust
// Expose all members
using namespace yycc::prelude::rust;
using namespace ::yycc::rust::prelude;

View File

@ -3,7 +3,7 @@
#include <cstddef>
#include <string_view>
namespace yycc::primitive {
namespace yycc::rust::primitive {
// `bool` is keyword so should not declare it anymore.
// `char` is keyword so should not declare it anymore.

View File

@ -1,9 +1,5 @@
#pragma once
#include "../macro/feature_probe.hpp"
#if defined(YYCC_CPPFEAT_EXPECTED)
#include <expected>
#endif
/**
* @brief The reproduction of Rust Option type.
@ -42,8 +38,6 @@
*/
namespace yycc::rust::result {
#if defined(YYCC_CPPFEAT_EXPECTED)
/**
* @brief Equivalent Rust \c Result in C++
* @tparam T The type of the expected value.
@ -80,6 +74,4 @@ namespace yycc::rust::result {
return ResultType(std::unexpect, std::forward<Args>(args)...);
}
#endif
} // namespace yycc::rust::result

View File

@ -27,7 +27,7 @@ namespace yycc::string::op {
// Check expected size.
if (count < 0) {
// Invalid length returned by vsnprintf.
return std::unexpected(FormatError::NoExpSize);
return std::unexpected(FormatError::NoDesiredSize);
}
va_end(args1);

View File

@ -9,8 +9,8 @@
namespace yycc::string::op {
enum class FormatError {
NullFormat, ///< Given format string is nullptr.
NoExpSize, ///< Fail to fetch the expected size of result.
NullFormat, ///< Given format string is nullptr.
NoDesiredSize, ///< Fail to fetch the expected size of result.
BadWrittenSize, ///< The written size is different with expected size.
};

View File

@ -2,18 +2,8 @@
// Because this header is the part of wrapper, not a real header.
// #pragma once
#include "../macro/os_detector.hpp"
#if defined(YYCC_OS_WINDOWS)
// Define 2 macros to disallow Windows generate MIN and MAX macros
// which cause std::min and std::max can not function as normal.
#if !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN
#endif
#if !defined(NOMINMAX)
#define NOMINMAX
#endif
#endif
// YYC MARK:
// Since YYCC 2.0 version, we use CMake to handle Windows shitty macros,
// so we do not need declare WIN32_LEAN_AND_MEAN or NOMINMAX in there.
// But for keep the pair of this guard, we still keep this header file,
// although it do nothing.