mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
feat: 支持格鲁吉亚语和构建 ImGui 字体的性能优化
This commit is contained in:
parent
4068872634
commit
1e4df90075
14 changed files with 98 additions and 67 deletions
|
|
@ -10,14 +10,14 @@
|
|||
namespace yas::detail {
|
||||
|
||||
// winrt::com_ptr<ID3DBlob>
|
||||
template<std::size_t F>
|
||||
template <std::size_t F>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
winrt::com_ptr<ID3DBlob>
|
||||
> {
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const winrt::com_ptr<ID3DBlob>& blob) {
|
||||
uint32_t size = (uint32_t)blob->GetBufferSize();
|
||||
ar& size;
|
||||
|
|
@ -27,7 +27,7 @@ struct serializer<
|
|||
return ar;
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, winrt::com_ptr<ID3DBlob>& blob) {
|
||||
uint32_t size = 0;
|
||||
ar& size;
|
||||
|
|
@ -47,27 +47,27 @@ struct serializer<
|
|||
|
||||
namespace Magpie {
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, EffectParameterDesc& o) {
|
||||
ar& o.name& o.label& o.constant;
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, EffectIntermediateTextureDesc& o) {
|
||||
ar& o.format& o.name& o.source& o.sizeExpr;
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, EffectSamplerDesc& o) {
|
||||
ar& o.filterType& o.addressType& o.name;
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, EffectPassDesc& o) {
|
||||
ar& o.cso& o.inputs& o.outputs& o.numThreads[0] & o.numThreads[1] & o.numThreads[2] & o.blockSize& o.desc& o.flags;
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, EffectDesc& o) {
|
||||
ar& o.name& o.params& o.textures& o.samplers& o.passes& o.flags;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ static uint32_t RemoveComments(std::string& source) noexcept {
|
|||
return 0;
|
||||
}
|
||||
|
||||
template<bool IncludeNewLine>
|
||||
template <bool IncludeNewLine>
|
||||
static void RemoveLeadingBlanks(std::string_view& source) noexcept {
|
||||
size_t i = 0;
|
||||
for (; i < source.size(); ++i) {
|
||||
|
|
@ -137,7 +137,7 @@ static void RemoveLeadingBlanks(std::string_view& source) noexcept {
|
|||
source.remove_prefix(i);
|
||||
}
|
||||
|
||||
template<bool AllowNewLine>
|
||||
template <bool AllowNewLine>
|
||||
static bool CheckNextToken(std::string_view& source, std::string_view token) noexcept {
|
||||
RemoveLeadingBlanks<AllowNewLine>(source);
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ static bool CheckNextToken(std::string_view& source, std::string_view token) noe
|
|||
return true;
|
||||
}
|
||||
|
||||
template<bool AllowNewLine>
|
||||
template <bool AllowNewLine>
|
||||
static uint32_t GetNextToken(std::string_view& source, std::string_view& value) noexcept {
|
||||
RemoveLeadingBlanks<AllowNewLine>(source);
|
||||
|
||||
|
|
@ -224,7 +224,7 @@ static uint32_t GetNextString(std::string_view& source, std::string_view& value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static uint32_t GetNextNumber(std::string_view& source, T& value) noexcept {
|
||||
RemoveLeadingBlanks<false>(source);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ void EffectsProfiler::OnEndEffects(ID3D11DeviceContext* d3dDC) {
|
|||
d3dDC->End(_disjointQuery.get());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static T GetQueryData(ID3D11DeviceContext* d3dDC, ID3D11Query* query) noexcept {
|
||||
T data{};
|
||||
while (d3dDC->GetData(query, &data, sizeof(data), 0) != S_OK) {
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@
|
|||
namespace yas::detail {
|
||||
|
||||
// ImVector
|
||||
template<std::size_t F, typename T>
|
||||
template <std::size_t F, typename T>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
ImVector<T>
|
||||
> {
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const ImVector<T>& vector) noexcept {
|
||||
uint32_t size = (uint32_t)vector.size();
|
||||
ar& size;
|
||||
|
|
@ -33,7 +33,7 @@ struct serializer<
|
|||
return ar;
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, ImVector<T>& vector) noexcept {
|
||||
uint32_t size = 0;
|
||||
ar& size;
|
||||
|
|
@ -52,14 +52,14 @@ struct serializer<
|
|||
};
|
||||
|
||||
// 对 ImFontAtlas 的序列化与反序列化来自 https://github.com/ocornut/imgui/issues/6169
|
||||
template<std::size_t F>
|
||||
template <std::size_t F>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
ImFontAtlas
|
||||
> {
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const ImFontAtlas& fontAltas) noexcept {
|
||||
ar& fontAltas.Flags & fontAltas.TexUvWhitePixel& fontAltas.TexUvLines;
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ struct serializer<
|
|||
return ar;
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, ImFontAtlas& fontAltas) noexcept {
|
||||
fontAltas.ClearTexData();
|
||||
ar& fontAltas.Flags& fontAltas.TexUvWhitePixel& fontAltas.TexUvLines;
|
||||
|
|
|
|||
|
|
@ -10,13 +10,18 @@ struct ImGuiHelper {
|
|||
static constexpr ImWchar NUMBER_RANGES[] = { L'0', L'9', 0 };
|
||||
static constexpr ImWchar NOT_NUMBER_RANGES[] = { 0x20, L'0' - 1, L'9' + 1, 0x7E, 0 };
|
||||
// Basic Latin
|
||||
static constexpr ImWchar ENGLISH_RANGES[] = { 0x20, 0x7E, 0 };
|
||||
static constexpr ImWchar BASIC_LATIN_RANGES[] = { 0x20, 0x7E, 0 };
|
||||
// Basic Latin + Latin-1 Supplement + Latin Extended-A,用于土耳其语、匈牙利语等。
|
||||
// 参见 https://en.wikipedia.org/wiki/Latin_Extended-A
|
||||
static constexpr ImWchar Latin_1_Extended_A_RANGES[] = { 0x20, 0x17F, 0 };
|
||||
static constexpr ImWchar EXTENDED_LATIN_RANGES[] = { 0x20, 0x17F, 0 };
|
||||
// Basic Latin + Georgian + Georgian Supplement + Georgian Extended,用于格鲁吉亚语。
|
||||
// https://en.wikipedia.org/wiki/Georgian_scripts
|
||||
static constexpr ImWchar GEORGIAN_RANGES[] = { 0x20, 0x7E, 0x10A0, 0x10FF, 0x2D00, 0x2D2F, 0x1C90, 0x1CBF, 0 };
|
||||
// 不包含 Basic Latin,用于 Win11
|
||||
static constexpr ImWchar GEORGIAN_EXTRA_RANGES[] = { 0x10A0, 0x10FF, 0x2D00, 0x2D2F, 0x1C90, 0x1CBF, 0 };
|
||||
// Tamil,用于泰米尔语。Tamil Supplement 超出了 ImWchar16 的存储范围,因此暂不支持。
|
||||
// 参见 https://en.wikipedia.org/wiki/Tamil_script
|
||||
static constexpr ImWchar TAMIL_RANGES[] = { 0xB80, 0xBFF, 0 };
|
||||
static constexpr ImWchar TAMIL_EXTRA_RANGES[] = { 0xB80, 0xBFF, 0 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ bool OverlayDrawer::_BuildFonts() noexcept {
|
|||
|
||||
{
|
||||
// 构建 ImFontAtlas 前 uiRanges 不能析构,因为 ImGui 只保存了指针
|
||||
ImVector<ImWchar> uiRanges;
|
||||
std::vector<ImWchar> uiRanges;
|
||||
_BuildFontUI(language, fontData, uiRanges);
|
||||
_BuildFontFPS(fontData);
|
||||
|
||||
|
|
@ -393,31 +393,45 @@ bool OverlayDrawer::_BuildFonts() noexcept {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <size_t SIZE>
|
||||
static void SetGlyphRanges(std::vector<ImWchar>& uiRanges, const ImWchar (&ranges)[SIZE]) noexcept {
|
||||
uiRanges.assign(std::begin(ranges), std::end(ranges));
|
||||
}
|
||||
|
||||
// 指针重载,但不能直接使用指针
|
||||
template <typename T, typename = std::enable_if_t<std::is_same_v<T, const ImWchar*>>>
|
||||
static void SetGlyphRanges(std::vector<ImWchar>& uiRanges, T ranges) noexcept {
|
||||
for (const ImWchar* range = ranges; *range; ++range) {
|
||||
uiRanges.push_back(*range);
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayDrawer::_BuildFontUI(
|
||||
std::wstring_view language,
|
||||
const std::vector<uint8_t>& fontData,
|
||||
ImVector<ImWchar>& uiRanges
|
||||
std::vector<ImWchar>& uiRanges
|
||||
) noexcept {
|
||||
ImFontAtlas& fontAtlas = *ImGui::GetIO().Fonts;
|
||||
|
||||
std::string extraFontPath;
|
||||
const ImWchar* extraRanges = nullptr;
|
||||
int extraFontNo = 0;
|
||||
|
||||
ImFontGlyphRangesBuilder builder;
|
||||
|
||||
assert(uiRanges.empty());
|
||||
if (language == L"en-us") {
|
||||
builder.AddRanges(ImGuiHelper::ENGLISH_RANGES);
|
||||
SetGlyphRanges(uiRanges, ImGuiHelper::BASIC_LATIN_RANGES);
|
||||
} else if (language == L"ru" || language == L"uk") {
|
||||
builder.AddRanges(fontAtlas.GetGlyphRangesCyrillic());
|
||||
SetGlyphRanges(uiRanges, fontAtlas.GetGlyphRangesCyrillic());
|
||||
} else if (language == L"tr" || language == L"hu" || language == L"pl") {
|
||||
builder.AddRanges(ImGuiHelper::Latin_1_Extended_A_RANGES);
|
||||
SetGlyphRanges(uiRanges, ImGuiHelper::EXTENDED_LATIN_RANGES);
|
||||
} else if (language == L"vi") {
|
||||
builder.AddRanges(fontAtlas.GetGlyphRangesVietnamese());
|
||||
SetGlyphRanges(uiRanges, fontAtlas.GetGlyphRangesVietnamese());
|
||||
} else if (language == L"ka" && !Win32Helper::GetOSVersion().IsWin11()) {
|
||||
// Win10 中格鲁吉亚语无需加载额外字体
|
||||
SetGlyphRanges(uiRanges, ImGuiHelper::GEORGIAN_RANGES);
|
||||
} else {
|
||||
// 默认 Basic Latin + Latin-1 Supplement
|
||||
// 参见 https://en.wikipedia.org/wiki/Latin-1_Supplement
|
||||
builder.AddRanges(fontAtlas.GetGlyphRangesDefault());
|
||||
// Basic Latin 使用默认字体
|
||||
SetGlyphRanges(uiRanges, ImGuiHelper::BASIC_LATIN_RANGES);
|
||||
|
||||
// 一些语言需要加载额外的字体:
|
||||
// 简体中文 -> Microsoft YaHei UI
|
||||
|
|
@ -425,6 +439,7 @@ void OverlayDrawer::_BuildFontUI(
|
|||
// 日语 -> Yu Gothic UI
|
||||
// 韩语/朝鲜语 -> Malgun Gothic
|
||||
// 泰米尔语 -> Nirmala UI
|
||||
// 格鲁吉亚语 -> Segoe UI (仅限 Win11)
|
||||
// 参见 https://learn.microsoft.com/en-us/windows/apps/design/style/typography#fonts-for-non-latin-languages
|
||||
if (language == L"zh-hans") {
|
||||
// msyh.ttc: 0 是微软雅黑,1 是 Microsoft YaHei UI
|
||||
|
|
@ -441,16 +456,22 @@ void OverlayDrawer::_BuildFontUI(
|
|||
extraFontPath = StrHelper::Concat(StrHelper::UTF16ToUTF8(GetSystemFontsFolder()), "\\YuGothM.ttc");
|
||||
extraFontNo = 1;
|
||||
extraRanges = fontAtlas.GetGlyphRangesJapanese();
|
||||
} else if (language == L"ka") {
|
||||
// Win11 中的 Segoe UI Variable 不包含格鲁吉亚字母,需额外加载 Segoe UI
|
||||
extraFontPath = StrHelper::Concat(StrHelper::UTF16ToUTF8(GetSystemFontsFolder()), "\\segoeui.ttf");
|
||||
extraRanges = ImGuiHelper::GEORGIAN_EXTRA_RANGES;
|
||||
} else if (language == L"ko") {
|
||||
extraFontPath = StrHelper::Concat(StrHelper::UTF16ToUTF8(GetSystemFontsFolder()), "\\malgun.ttf");
|
||||
extraRanges = fontAtlas.GetGlyphRangesKorean();
|
||||
} else if (language == L"ta") {
|
||||
extraFontPath = StrHelper::Concat(StrHelper::UTF16ToUTF8(GetSystemFontsFolder()), "\\Nirmala.ttf");
|
||||
extraRanges = ImGuiHelper::TAMIL_RANGES;
|
||||
extraRanges = ImGuiHelper::TAMIL_EXTRA_RANGES;
|
||||
}
|
||||
}
|
||||
builder.SetBit(COLOR_INDICATOR_W);
|
||||
builder.BuildRanges(&uiRanges);
|
||||
|
||||
uiRanges.push_back(COLOR_INDICATOR_W);
|
||||
uiRanges.push_back(COLOR_INDICATOR_W);
|
||||
uiRanges.push_back(0);
|
||||
|
||||
ImFontConfig config;
|
||||
config.FontDataOwnedByAtlas = false;
|
||||
|
|
@ -469,7 +490,7 @@ void OverlayDrawer::_BuildFontUI(
|
|||
#endif
|
||||
|
||||
_fontUI = fontAtlas.AddFontFromMemoryTTF(
|
||||
(void*)fontData.data(), (int)fontData.size(), fontSize, &config, uiRanges.Data);
|
||||
(void*)fontData.data(), (int)fontData.size(), fontSize, &config, uiRanges.data());
|
||||
|
||||
if (extraRanges) {
|
||||
assert(Win32Helper::FileExists(StrHelper::UTF8ToUTF16(extraFontPath).c_str()));
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public:
|
|||
|
||||
private:
|
||||
bool _BuildFonts() noexcept;
|
||||
void _BuildFontUI(std::wstring_view language, const std::vector<uint8_t>& fontData, ImVector<ImWchar>& uiRanges) noexcept;
|
||||
void _BuildFontUI(std::wstring_view language, const std::vector<uint8_t>& fontData, std::vector<ImWchar>& uiRanges) noexcept;
|
||||
void _BuildFontFPS(const std::vector<uint8_t>& fontData) noexcept;
|
||||
|
||||
struct _EffectDrawInfo {
|
||||
|
|
|
|||
|
|
@ -431,7 +431,7 @@ bool Renderer::_InitFrameSource() noexcept {
|
|||
}
|
||||
|
||||
// 单位为微秒
|
||||
template<typename Fn>
|
||||
template <typename Fn>
|
||||
static int Measure(const Fn& func) noexcept {
|
||||
using namespace std::chrono;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,20 +24,20 @@ namespace yas::detail {
|
|||
|
||||
// 可平凡复制类型
|
||||
// 注意不检查指针成员
|
||||
template<size_t F, typename T>
|
||||
template <size_t F, typename T>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
T
|
||||
> {
|
||||
template<typename Archive, typename = std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T>>
|
||||
template <typename Archive, typename = std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T>>
|
||||
static Archive& save(Archive& ar, const T& o) noexcept {
|
||||
ar.write(&o, sizeof(T));
|
||||
return ar;
|
||||
}
|
||||
|
||||
template<typename Archive, typename = std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T>>
|
||||
template <typename Archive, typename = std::enable_if_t<std::is_trivially_copyable_v<T> && !std::is_pointer_v<T>, T>>
|
||||
static Archive& load(Archive& ar, T& o) noexcept {
|
||||
ar.read(&o, sizeof(T));
|
||||
return ar;
|
||||
|
|
@ -45,19 +45,19 @@ struct serializer<
|
|||
};
|
||||
|
||||
// SmallVector
|
||||
template<size_t F, typename T, unsigned N>
|
||||
template <size_t F, typename T, unsigned N>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
Magpie::SmallVector<T, N>
|
||||
> {
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const Magpie::SmallVector<T, N>& vector) noexcept {
|
||||
return concepts::array::save<F>(ar, vector);
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, Magpie::SmallVector<T, N>& vector) noexcept {
|
||||
return concepts::array::load<F>(ar, vector);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,14 +359,14 @@ protected:
|
|||
|
||||
/// Move the range [I, E) into the uninitialized memory starting with "Dest",
|
||||
/// constructing elements as needed.
|
||||
template<typename It1, typename It2>
|
||||
template <typename It1, typename It2>
|
||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||
std::uninitialized_move(I, E, Dest);
|
||||
}
|
||||
|
||||
/// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
|
||||
/// constructing elements as needed.
|
||||
template<typename It1, typename It2>
|
||||
template <typename It1, typename It2>
|
||||
static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
|
||||
std::uninitialized_copy(I, E, Dest);
|
||||
}
|
||||
|
|
@ -506,7 +506,7 @@ protected:
|
|||
|
||||
/// Move the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template<typename It1, typename It2>
|
||||
template <typename It1, typename It2>
|
||||
static void uninitialized_move(It1 I, It1 E, It2 Dest) {
|
||||
// Just do a copy.
|
||||
uninitialized_copy(I, E, Dest);
|
||||
|
|
@ -514,7 +514,7 @@ protected:
|
|||
|
||||
/// Copy the range [I, E) onto the uninitialized memory
|
||||
/// starting with "Dest", constructing elements into it as needed.
|
||||
template<typename It1, typename It2>
|
||||
template <typename It1, typename It2>
|
||||
static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
|
||||
// Arbitrary iterator types; just use the basic implementation.
|
||||
std::uninitialized_copy(I, E, Dest);
|
||||
|
|
@ -1324,13 +1324,13 @@ template <typename Out, typename R> SmallVector<Out> to_vector_of(R&& Range) {
|
|||
namespace std {
|
||||
|
||||
/// Implement std::swap in terms of SmallVector swap.
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
inline void swap(Magpie::SmallVectorImpl<T>& LHS, Magpie::SmallVectorImpl<T>& RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
|
||||
/// Implement std::swap in terms of SmallVector swap.
|
||||
template<typename T, unsigned N>
|
||||
template <typename T, unsigned N>
|
||||
inline void swap(Magpie::SmallVector<T, N>& LHS, Magpie::SmallVector<T, N>& RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ struct StrHelper {
|
|||
|
||||
static std::string UTF16ToANSI(std::wstring_view str) noexcept;
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static void Trim(std::basic_string_view<CHAR_T>& str) noexcept {
|
||||
for (int i = 0; i < str.size(); ++i) {
|
||||
if (!isspace(str[i])) {
|
||||
|
|
@ -42,7 +42,7 @@ struct StrHelper {
|
|||
Trim<wchar_t>(str);
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static void Trim(std::basic_string<CHAR_T>& str) noexcept {
|
||||
std::basic_string_view<CHAR_T> sv(str);
|
||||
Trim(sv);
|
||||
|
|
@ -53,7 +53,7 @@ struct StrHelper {
|
|||
Trim<char>(str);
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> Trim(const std::basic_string<CHAR_T>& str) noexcept {
|
||||
std::basic_string<CHAR_T> result = str;
|
||||
Trim(result);
|
||||
|
|
@ -64,7 +64,7 @@ struct StrHelper {
|
|||
return Trim<char>(str);
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static SmallVector<std::basic_string_view<CHAR_T>> Split(std::basic_string_view<CHAR_T> str, CHAR_T delimiter) noexcept {
|
||||
SmallVector<std::basic_string_view<CHAR_T>> result;
|
||||
while (!str.empty()) {
|
||||
|
|
@ -136,49 +136,49 @@ struct StrHelper {
|
|||
return (wchar_t)std::towlower(c);
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> ToUpperCase(std::basic_string_view<CHAR_T> str) noexcept {
|
||||
std::basic_string<CHAR_T> result(str);
|
||||
ToUpperCase(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static void ToUpperCase(std::basic_string<CHAR_T>& str) noexcept {
|
||||
for (CHAR_T& c : str) {
|
||||
c = toupper(c);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> ToLowerCase(std::basic_string_view<CHAR_T> str) noexcept {
|
||||
std::basic_string<CHAR_T> result(str);
|
||||
ToLowerCase(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static void ToLowerCase(std::basic_string<CHAR_T>& str) noexcept {
|
||||
for (CHAR_T& c : str) {
|
||||
c = tolower(c);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static constexpr size_t StrLen(const CHAR_T* str) noexcept {
|
||||
// std::char_traits 相比 std::strlen 支持更多字符类型
|
||||
// 目前 MSVC 使用 __builtin_strlen,可以在编译时计算字符串常量的长度
|
||||
return std::char_traits<CHAR_T>::length(str);
|
||||
}
|
||||
|
||||
template<typename T1, typename T2, typename... AV,
|
||||
template <typename T1, typename T2, typename... AV,
|
||||
typename CHAR_T = std::conditional_t<std::is_constructible_v<std::basic_string_view<char>, T1>, char, wchar_t>>
|
||||
static std::basic_string<CHAR_T> Concat(T1&& s1, T2&& s2, AV&&... args) noexcept {
|
||||
return _Concat<CHAR_T>(std::forward<T1>(s1), std::forward<T2>(s2), std::forward<AV>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> _Concat(
|
||||
const std::basic_string_view<CHAR_T>& s1,
|
||||
const std::basic_string_view<CHAR_T>& s2
|
||||
|
|
@ -189,7 +189,7 @@ private:
|
|||
return result;
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> _Concat(
|
||||
const std::basic_string_view<CHAR_T>& s1,
|
||||
const std::basic_string_view<CHAR_T>& s2,
|
||||
|
|
@ -201,7 +201,7 @@ private:
|
|||
return result;
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> _Concat(
|
||||
const std::basic_string_view<CHAR_T>& s1,
|
||||
const std::basic_string_view<CHAR_T>& s2,
|
||||
|
|
@ -214,7 +214,7 @@ private:
|
|||
return result;
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> _Concat(
|
||||
const std::basic_string_view<CHAR_T>& s1,
|
||||
const std::basic_string_view<CHAR_T>& s2,
|
||||
|
|
@ -228,7 +228,7 @@ private:
|
|||
return result;
|
||||
}
|
||||
|
||||
template<typename CHAR_T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename... AV>
|
||||
template <typename CHAR_T, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename... AV>
|
||||
static std::basic_string<CHAR_T> _Concat(
|
||||
T1&& s1,
|
||||
T2&& s2,
|
||||
|
|
@ -249,7 +249,7 @@ private:
|
|||
});
|
||||
}
|
||||
|
||||
template<typename CHAR_T>
|
||||
template <typename CHAR_T>
|
||||
static std::basic_string<CHAR_T> _ConcatHelper(std::initializer_list<std::basic_string_view<CHAR_T>> args) noexcept {
|
||||
std::basic_string<CHAR_T> result;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ static std::array SUPPORTED_LANGUAGES{
|
|||
L"id",
|
||||
L"it",
|
||||
L"ja",
|
||||
L"ka",
|
||||
L"ko",
|
||||
L"pl",
|
||||
L"pt-br",
|
||||
|
|
|
|||
|
|
@ -631,6 +631,7 @@
|
|||
<PRIResource Include="Resources.language-id.resw" />
|
||||
<PRIResource Include="Resources.language-it.resw" />
|
||||
<PRIResource Include="Resources.language-ja.resw" />
|
||||
<PRIResource Include="Resources.language-ka.resw" />
|
||||
<PRIResource Include="Resources.language-ko.resw" />
|
||||
<PRIResource Include="Resources.language-pl.resw" />
|
||||
<PRIResource Include="Resources.language-pt-BR.resw" />
|
||||
|
|
|
|||
|
|
@ -385,6 +385,9 @@
|
|||
<PRIResource Include="Resources.language-ta.resw">
|
||||
<Filter>Strings</Filter>
|
||||
</PRIResource>
|
||||
<PRIResource Include="Resources.language-ka.resw">
|
||||
<Filter>Strings</Filter>
|
||||
</PRIResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="conanfile.txt" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue