perf(size): 用自写整数格式化替换全部 std::to_wstring / std::to_string
背景:Code Review 报告 §10.3 / §11.5 建议「替换 std::to_wstring / std::to_string,
可去掉 gdtoa 链(≈33 KB)」。本轮把它做完,并给出这条建议的**真实边界**。
一、新增 `Utf8Util::FormatInteger*`(手写十进制展开,不经 printf)
* `FormatInteger(long long)` / `FormatIntegerUnsigned(unsigned long long)` /
`FormatIntegerNarrow(long long)`(后者供 MatLoader 拼 HDF5 成员路径)。
* 语义与 `std::to_wstring` / `std::to_string` 完全一致:`0` → `"0"`、负数带 `-`、
`LLONG_MIN` 用模 2^64 语义取绝对值(不会溢出)。
* 这样做的直接理由:预编译 libstdc++ 的 `to_string` 内部转调 `__mingw_swprintf`,
工程里只要留一处,MinGW 的 printf 引擎(`mingw_wpformat.o`)+ gdtoa 就必然被链入。
二、全仓替换(76 处 `to_wstring` + 2 处 `to_string`,20 个文件)
* `MatLoader.cpp` 的 `TrimNumber` 整数分支也改为 `FormatInteger`(它曾是产物里
**最后一个**引用 MinGW printf 的调用点)。
* 需要的地方补 `#include "Utf8Util.hpp"`(仅 `MatLoader.cpp` 一个新 include,其余由
`PlotViewInternal` / `SignalPanelInternal` / `ApplicationInternal` / `DataModelInternal`
已经包含)。
三、⚠️ 实测结论:gdtoa **去不掉**(把这件事彻底查清并写进 Makefile 注释)
* 只替换 `to_wstring`/`to_string`:**−1,024 B**(787,968 → 786,944)。
* 再叠加 `-D__USE_MINGW_ANSI_STDIO=0`(把 `swprintf` 让给系统 UCRT):**0 字节**。
* 根因(定位到文件与行):libstdc++ 的
`lib/gcc/.../include/c++/x86_64-w64-mingw32/bits/os_defines.h:48-51` **无条件**执行
`#undef __USE_MINGW_ANSI_STDIO` + `#define __USE_MINGW_ANSI_STDIO 1`
(注释:libstdc++ depends on POSIX-definitions of those functions)。
`g++ -E -dM` 实测最终值恒为 1 ⇒ **任何 C++ TU 的 `swprintf` / `strtod` 都是 MinGW 版本**,
命令行无法覆盖。
* 要真省这 33 KB 只能自己实现「浮点 → 十进制(正确舍入)」与「浮点解析的
十六进制/inf/nan 分支」,等价于重写 gdtoa。**判定:不做**(风险 >> 收益)。
* 该开关已回退,Makefile 里保留一段说明,避免后续接手者重复这两次实验。
四、验证
* 新增单元测试 `integer_replacement_matches_std`:12 个有符号样本(含 LLONG_MIN/MAX)
+ 5 个无符号样本(含 ULLONG_MAX),与 `std::to_wstring` **逐字符对照**,
并校验窄/宽版本内容一致。
* `UnitTests`:`checks=260 failed=0 cases=19`(新增 41 条断言)。
* `OffscreenChecks -all`:6 个检查全 PASS,`checks=87 failed=0`。
* `panels -mode compare`:7 个面板像素哈希与几何**逐项不变**
(整数文本从 `to_wstring` 换到手写实现后,渲染结果零差异 —— 这是最强的语义证据)。
* release 全量零 error / 零 warning;产物 787,968 → **786,944 B**。
This commit is contained in:
1 parent
abcf3e6c44
commit
34365b3c1c
23 files changed
+256
-94
No files matched your search
@@ -1398,7 +1398,7 @@ namespace jdi
|
||||
|
||||
std::wstring SignalPanel::GroupLabelText(int groupIndex)
|
||||
{
|
||||
return L"组" + std::to_wstring(groupIndex + 1);
|
||||
return L"组" + FormatInteger(groupIndex + 1);
|
||||
}
|
||||
|
||||
std::wstring SignalPanel::GroupStatsText(int row) const
|
||||
@@ -1409,7 +1409,7 @@ namespace jdi
|
||||
}
|
||||
// 项数:普通模式 = 信号总数;筛选模式 = 该组内**符合筛选条件**的信号个数
|
||||
//(用户 2026-10-16 要求)。两者都在 `BuildRows` 里写入 `displayCount`。
|
||||
return std::to_wstring(m_rows[static_cast<std::size_t>(row)].displayCount) + L" 项";
|
||||
return FormatInteger(m_rows[static_cast<std::size_t>(row)].displayCount) + L" 项";
|
||||
}
|
||||
|
||||
gd::RectF SignalPanel::FilterFieldRect() const
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace jdi
|
||||
{
|
||||
return false;
|
||||
}
|
||||
initial = std::to_wstring(static_cast<int>(style->opacity * 100.0f + 0.5f));
|
||||
initial = FormatInteger(static_cast<int>(style->opacity * 100.0f + 0.5f));
|
||||
break;
|
||||
}
|
||||
case StyleEditField::SIGNAL_NAME:
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace jdi
|
||||
MenuItem entry;
|
||||
// ⚠️ 显示形式为「组号 + 竖线 + 组名」(用户 2026-11-03 明确要求),
|
||||
// **不要**用括号把组名括起来(旧实现 `分组 1(名称)` 已被要求改掉)。
|
||||
entry.label = std::to_wstring(index + 1) + L" | " + group->name;
|
||||
entry.label = FormatInteger(index + 1) + L" | " + group->name;
|
||||
entry.id = CMD_GROUP_MOVE_BASE + static_cast<int>(index);
|
||||
entry.checked = (static_cast<int>(index) == ref.groupIndex);
|
||||
moveMenu.submenu.push_back(entry);
|
||||
@@ -350,8 +350,8 @@ namespace jdi
|
||||
for (std::size_t index = 0; index < lanes.size(); ++index)
|
||||
{
|
||||
MenuItem lane;
|
||||
lane.label = L"网格 " + std::to_wstring(index + 1) + L"(" +
|
||||
std::to_wstring(lanes[index].signals.size()) + L" 条信号)";
|
||||
lane.label = L"网格 " + FormatInteger(index + 1) + L"(" +
|
||||
FormatInteger(lanes[index].signals.size()) + L" 条信号)";
|
||||
lane.id = CMD_LANE_BASE + static_cast<int>(index);
|
||||
lane.checked = (currentLane == static_cast<int>(index));
|
||||
items.push_back(lane);
|
||||
|
||||
@@ -81,8 +81,8 @@ namespace jdi
|
||||
std::wstring title = L"信号";
|
||||
if (m_dataSet != nullptr && m_tab != nullptr)
|
||||
{
|
||||
title += L" · " + std::to_wstring(m_tab->VisibleCount()) + L"/" +
|
||||
std::to_wstring(TotalSignalCount()) + L" 已选";
|
||||
title += L" · " + FormatInteger(m_tab->VisibleCount()) + L"/" +
|
||||
FormatInteger(TotalSignalCount()) + L" 已选";
|
||||
}
|
||||
|
||||
gd::RectF titleRect(m_headerRect.X + kPadding * m_scale, m_headerRect.Y,
|
||||
@@ -751,7 +751,7 @@ namespace jdi
|
||||
badgeHot ? m_theme->accentSoft : m_theme->cardBg);
|
||||
UiDrawRoundRect(g, badgeRect, kBadgeHeight * m_scale * 0.5f,
|
||||
badgeHot ? m_theme->accent : m_theme->border, 1.0f);
|
||||
PaintRowText(g, L"G" + std::to_wstring(m_tab->LaneOfSignal(ref) + 1), m_fonts->monoSmall,
|
||||
PaintRowText(g, L"G" + FormatInteger(m_tab->LaneOfSignal(ref) + 1), m_fonts->monoSmall,
|
||||
badgeRect, badgeHot ? m_theme->textStrong : m_theme->text, TextAlign::CENTER);
|
||||
}
|
||||
|
||||
@@ -992,7 +992,7 @@ namespace jdi
|
||||
else
|
||||
{
|
||||
const int percent = static_cast<int>(style->opacity * 100.0f + 0.5f);
|
||||
UiText(g, std::to_wstring(percent) + L"%", m_fonts->monoSmall, m_opacityValueRect,
|
||||
UiText(g, FormatInteger(percent) + L"%", m_fonts->monoSmall, m_opacityValueRect,
|
||||
m_theme->textStrong, TextAlign::RIGHT);
|
||||
}
|
||||
paintStyleReset(m_opacityResetRect, StyleHit::OPACITY_RESET,
|
||||
@@ -1059,7 +1059,7 @@ namespace jdi
|
||||
badgeHot ? m_theme->accentSoft : m_theme->cardBg);
|
||||
UiDrawRoundRect(g, m_targetBadgeRect, kBadgeHeight * m_scale * 0.5f,
|
||||
badgeHot ? m_theme->accent : m_theme->border, 1.0f);
|
||||
UiText(g, L"G" + std::to_wstring(m_targetGeomLane + 1), m_fonts->monoSmall,
|
||||
UiText(g, L"G" + FormatInteger(m_targetGeomLane + 1), m_fonts->monoSmall,
|
||||
m_targetBadgeRect, badgeHot ? m_theme->textStrong : m_theme->text, TextAlign::CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user