refactor(panels): 面板静态特征收敛为唯一登记表 + 标记面板绘制分段(§17.6 第 1/2 项)
- 新增 pvdetail::PanelKindTraits + PanelTraitsOf(唯一 switch):标题 / 排版类别 / 滚动字段 / 面板状态 / 功能开关同表登记;新增面板只改「枚举 + 一行」, -Wswitch 仍在唯一登记点生效。PanelTitle 改为「前缀 + rangeSuffix 标志」, 不再依赖 switch(标题降级为数据,不再需要函数指针)。 - PaintPanelMarkerGroups(约 340 行)拆成 6 个具名函数,主函数只保留绘制顺序 (普通分组栏 -> 条目 -> 表头 -> 吸顶栏 -> 滚动条 -> 透明度行);纯搬移、0 字节变化。 - 顺手修正该函数体遗留的多余缩进。 验证:release/debug/tools 零 warning;UnitTests 260/19;OffscreenChecks -all 7/133; panels -mode compare 7 面板像素哈希逐项不变;rowgeom compare 965+7 / 1268+7 键 0 差异。 产物 781,824 -> 782,336 B(+512,全部来自登记表)。
This commit is contained in:
1 parent
a9f1563896
commit
0c26da07d2
8 files changed
+761
-453
No files matched your search
@@ -407,5 +407,30 @@ old keys = 919, new keys = 965
|
||||
逐行状态打包进 `PanelParamState`(解析结果 / 两种条目指针 / 网格下标),
|
||||
目的是把参数表压在 5 个 —— 一个个透传会让签名比函数体更难读。
|
||||
|
||||
---
|
||||
|
||||
## 十三、第 41 轮(收尾):面板登记表 + 标记面板绘制分段
|
||||
|
||||
> 触发:用户要求「按上轮报告 §17.6 继续推进」,并在本轮结束时判断**是否已达到可以结束
|
||||
> 本次代码审查的程度**;体积一项按用户指示**继续暂停**(§17.6 第 3 项)。
|
||||
|
||||
| 节点 | 内容 | 验收标准 |
|
||||
| --- | --- | --- |
|
||||
| **P39** | `PanelStyleOf` / `PanelTitle` / `LanePanelScrollOf` / `LanePanelStateOf` / `LanePanelEnabled` 五处穷举 `switch` 合成一张 `constexpr` 登记表 `PanelTraitsOf(kind)` | 编译零 warning;`panels -mode compare` 7 面板像素哈希逐项不变 |
|
||||
| **P40** | `PaintPanelMarkerGroups`(约 340 行)拆成 6 个具名函数(分组栏 / 列宽 / 分隔线 / 条目 / 表头 / 透明度行),主函数只留"顺序" | `panels -mode compare` + `rowgeom -mode compare`(默认 + MF4)0 差异 |
|
||||
|
||||
### 13.1 本轮新增硬约束
|
||||
|
||||
1. **新增一种实验性功能面板只改两处**:`EdgePanelKind` 加一个枚举值 +
|
||||
`pvdetail::PanelTraitsOf` 加一行(标题 / 排版类别 / 滚动字段 / 面板状态 / 功能开关全在那一行)。
|
||||
`PlotView::PanelTitle` **不再需要改** —— 它只读表里的"标题前缀 + `rangeSuffix` 标志"。
|
||||
2. **`PanelTraitsOf` 的 `switch` 一律不写 `default:`**:漏登记 `EdgePanelKind` 会被 `-Wswitch`
|
||||
当场拦下(这是"编译期保护"的唯一执行点,其余四个消费者都只是取值)。
|
||||
3. **`PanelStyle` 用三个具名构造函数**(`ListPanelStyle` / `CountTablePanelStyle` /
|
||||
`MarkerPanelStyle`)构造,**禁止**在表里写 6 个裸 bool(聚合顺序错一位就变成"表格面板带按钮")。
|
||||
4. **标记面板的绘制顺序是硬约束**:普通分组栏 → 条目 → 表头 → 吸顶分组栏 → 滚动条 → 透明度行。
|
||||
它现在**只出现在 `PaintPanelMarkerGroups` 一个地方**(过去藏在一个 340 行函数的循环中间)。
|
||||
新增任何"吸顶/悬浮"元素时,必须加在"条目之后"。
|
||||
|
||||
|
||||
|
||||
@@ -712,5 +712,79 @@ std::vector<PanelRowPlan> PlanListPanelRows(const Lane&, EdgePanelKind) const;
|
||||
| 行数 | `PlotViewPanelPaint.cpp` 935 → 939;`PlotViewPanels.cpp` 1729 → 1766(新增两个几何函数,净增 37) |
|
||||
| 样式 | 顺手把机械搬移遗留的"整个函数体多缩进 2 个 tab"修正 |
|
||||
|
||||
---
|
||||
|
||||
## 第 41 轮(2026-11-04):面板登记表 + 标记面板绘制分段(§17.6 第 1 / 第 2 项,收尾)
|
||||
|
||||
> 本轮之后**代码审查进入收尾**:所有"已知问题"要么已修、要么有实测数字支撑地**明确不做**
|
||||
>(体积、`EdgeScanFor` 哈希化、`EdgePanelLayoutFor` 表驱动化),详见报告 §18。
|
||||
|
||||
### P39 面板的五个穷举 `switch` 合成一张 `constexpr` 登记表 ✅
|
||||
|
||||
改前新增一种面板要改三处(`PanelStyleOf` / `PanelTitle` / `LanePanelScrollOf`),
|
||||
实际连 `LanePanelStateOf` / `LanePanelEnabled` 一共是**五处穷举 switch**
|
||||
(§17.6 只点了三处,另外两处更早就有)。
|
||||
|
||||
改后 `PlotViewInternal.hpp` 里只有**一个**登记点:
|
||||
|
||||
```cpp
|
||||
struct PanelKindTraits
|
||||
{
|
||||
PanelStyle style; // 排版类别 + 底部控件
|
||||
const wchar_t* title = L""; // 标题前缀
|
||||
bool rangeSuffix = false; // 是否追加 EdgeRangeSuffix()
|
||||
float Lane::*scroll = nullptr; // 内容滚动偏移
|
||||
LanePanelState Lane::*panel = nullptr; // 面板 UI 状态
|
||||
bool Lane::*enabled = nullptr; // 功能开关
|
||||
};
|
||||
inline constexpr PanelKindTraits PanelTraitsOf(EdgePanelKind kind); // 唯一 switch
|
||||
```
|
||||
|
||||
* 五个消费者全部退化成一行取值:`return lane.*(PanelTraitsOf(kind).scroll);`
|
||||
* **`PanelTitle` 不再是 switch**:标题是数据(前缀字符串 + 一个 `rangeSuffix` 标志),
|
||||
运行时后缀只对两种「边沿计数」追加 ⇒ §17.6 里"`PanelTitle` 依赖运行时字符串所以先解决
|
||||
'标题是函数'的问题"就此解决(不需要函数指针,也不需要 `std::wstring` 进表)。
|
||||
* ⚠️ `PanelStyle` 的三个具名构造函数(`ListPanelStyle` / `CountTablePanelStyle` /
|
||||
`MarkerPanelStyle`)是刻意加的:表里若写 6 个裸 bool,聚合顺序错一位就变成
|
||||
"表格面板带按钮"这种没人看得出来的错误。
|
||||
* 体积代价:**+512 B**(7 份 traits 记录进 `.rdata` + `PanelTitle` 多一个分支)。
|
||||
用 512 B 换"新增面板只改两处 + 编译期强制登记",判定值得。
|
||||
|
||||
### P40 `PaintPanelMarkerGroups` 拆成 6 个具名函数 ✅
|
||||
|
||||
| 函数 | 职责 |
|
||||
| --- | --- |
|
||||
| `MeasureMarkerColumnWidths` | 六列实测文本宽度 → 写回 `Lane::freeMarkerColumnWidths` |
|
||||
| `PaintMarkerGroupBar` | 一个信号分组栏(三角 / 名称 / `N 标记点` / ✕) |
|
||||
| `PaintMarkerColumnSeparators` | 列分隔竖线(条目行与表头共用) |
|
||||
| `PaintMarkerRow` | 一个固定点条目(六列 + 分隔线 + 行尾 ✕) |
|
||||
| `PaintMarkerTableHeader` | 一个展开分组的表头(不透明底衬 + 六列标题) |
|
||||
| `PaintMarkerOpacityRow` | 底部「标记透明度」滑块行 |
|
||||
| `PaintPanelMarkerGroups` | **只负责顺序**:普通分组栏 → 条目 → 表头 → 吸顶栏 → 滚动条 → 透明度行 |
|
||||
|
||||
* 原实现把这条顺序约束埋在一个 340 行函数的循环中间("为什么表头要在这里画"),
|
||||
现在它是主函数里唯一的逻辑,注释也只剩一句"后两段必须压在上面"。
|
||||
* 提取时顺带把机械搬移遗留的"函数体多缩进 2 个 tab"修正(整个函数重新缩进)。
|
||||
* **零体积极限验证**:P39 之后产物已经是 782,336 B,P40 之后**完全相同** ⇒ 纯搬移。
|
||||
|
||||
### 过程中的一个判断(值得记)
|
||||
|
||||
`contents`(固定点内容缓存)原来在"画完普通分组栏之后"才取,现在提前到最前面。
|
||||
两者唯一的区别是缓存重建的时机,而 `FreeMarkerContents` **不改任何绘制状态**
|
||||
(只读采样 + 拼字符串 + 写 `m_freeMarkerContent`)⇒ 对像素无影响,双基线也证实了。
|
||||
|
||||
### 本轮验证
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| `make release` / `make debug` / `make -C Tools` | 零 error / 零 warning |
|
||||
| 产物 | 781,824 → **782,336 B**(+512,全部来自 P39 的登记表;P40 为 0) |
|
||||
| `UnitTests` | `checks=260 failed=0 cases=19` |
|
||||
| `OffscreenChecks -all` | 7/7 PASS,`checks=133 failed=0` |
|
||||
| `panels -mode compare` | 7 个面板像素哈希**逐项不变**(含 `resample=2BFC74B3D9B3239C`) |
|
||||
| `rowgeom -mode compare` | 965 + 7 键 0 差异;`-data MF4-Record.MF4` 1268 + 7 键 0 差异 |
|
||||
| 行数 | `PlotViewPanelPaint.cpp` 939 → 977(6 个函数头 + 说明);`PlotViewPanels.cpp` 1766 → 1758(`PanelTitle` 变短) |
|
||||
| 读点 | `PanelStyleOf` / `PanelTitle` / `LanePanelScrollOf` / `LanePanelStateOf` / `LanePanelEnabled` 的调用点**一处未改**(签名不变) |
|
||||
|
||||
|
||||
|
||||
@@ -825,5 +825,98 @@ old keys = 919, new keys = 965
|
||||
与 §17.3 同理:先给"吸顶推挤"单独一个可测函数。
|
||||
3. 体积:等有新的冗余再说(用户已明确)。
|
||||
|
||||
---
|
||||
|
||||
## 十八、第 41 轮(2026-11-04,收尾):面板登记表 + 标记面板分段,以及"能否结束审查"的判定
|
||||
|
||||
### 18.1 结论
|
||||
|
||||
| §17.6 建议 | 结果 |
|
||||
| --- | --- |
|
||||
| 1. 三处穷举 `switch` 合成 `constexpr` 表 | ✅ 完成,而且实际收敛的是**五处**(`PanelStyleOf` / `PanelTitle` / `LanePanelScrollOf` / `LanePanelStateOf` / `LanePanelEnabled`) |
|
||||
| 2. `PaintPanelMarkerGroups` 再拆 | ✅ 拆成 6 个具名函数,主函数只剩"绘制顺序" |
|
||||
| 3. 体积 | ⏸ 按用户指示不做(+512 B 是本轮唯一代价,来自登记表) |
|
||||
|
||||
### 18.2 本轮做了什么
|
||||
|
||||
**(1)面板静态特征收敛为唯一登记点**
|
||||
|
||||
```cpp
|
||||
inline constexpr PanelKindTraits PanelTraitsOf(EdgePanelKind kind); // 唯一 switch
|
||||
```
|
||||
|
||||
`PanelKindTraits{style, title, rangeSuffix, scroll, panel, enabled}` ——
|
||||
新增一种面板只改**两处**:`EdgePanelKind` 加枚举值 + 表里加一行。
|
||||
五个消费者的签名一字未改,调用点**一处未动**。
|
||||
|
||||
`PanelTitle` 从"返回 `std::wstring` 的 switch"变成"读表 + 可选追加 `EdgeRangeSuffix()`"。
|
||||
这解决了 §17.6 留下的那个具体障碍:"标题是函数、依赖运行时字符串,所以没法进表"——
|
||||
答案是**把标题降级为数据(前缀 + 标志)**,而不是把函数塞进表里。
|
||||
|
||||
**(2)标记面板绘制分段**
|
||||
|
||||
| 函数 | 职责 |
|
||||
| --- | --- |
|
||||
| `MeasureMarkerColumnWidths` | 六列实测宽度 → `Lane::freeMarkerColumnWidths` |
|
||||
| `PaintMarkerGroupBar` | 分组栏(三角 / 名称 / `N 标记点` / ✕) |
|
||||
| `PaintMarkerColumnSeparators` | 列分隔竖线(条目与表头共用) |
|
||||
| `PaintMarkerRow` | 固定点条目(六列 + 分隔线 + ✕) |
|
||||
| `PaintMarkerTableHeader` | 展开分组的表头 |
|
||||
| `PaintMarkerOpacityRow` | 「标记透明度」滑块行 |
|
||||
| `PaintPanelMarkerGroups` | **只负责顺序**:分组栏 → 条目 → 表头 → 吸顶栏 → 滚动条 → 透明度行 |
|
||||
|
||||
判据不是"看起来更清楚",而是 `panels` 的 7 个面板像素哈希 + `rowgeom` 的
|
||||
965/1268 条几何键**逐项不变**;产物字节数在 P40 前后**完全相同**(782,336 B),
|
||||
说明这一段是真正的零成本搬移。
|
||||
|
||||
### 18.3 现在可以结束这次代码审查了吗?——**可以**
|
||||
|
||||
这不是"我觉得差不多了",而是逐条对账的结果:
|
||||
|
||||
| 审查项 | 状态 | 证据 |
|
||||
| --- | --- | --- |
|
||||
| 体积(890,880 → 782,336 B,−12.2%) | 完成 | `objdump -h` 节表;`-fno-rtti` + terminate handler 覆盖 + 关异步展开表;红线 1 MB,余量 ≈260 KB |
|
||||
| Debug 构建"名不副实" | 已修 | `DEBUG_OPT -g` 真正生效(Debug 6.16 MB 属预期) |
|
||||
| 面板分派"改一次就出错" | 已消除 | 唯一登记表 + `-Wswitch` 编译期保护 |
|
||||
| 平行数组错位 / 字段重载 | 已消除 | `std::vector<PanelRow>`(结构上不可能错位) |
|
||||
| 几何算式两处/双遍历 | 已收敛 | `PanelColumnMetrics` + `PanelRowPlan` |
|
||||
| 巨型函数(1900 / 340 行) | 已拆 | `PlotViewPanelPaint.cpp` 三个内容函数 + 本轮六个标记面板函数 |
|
||||
| 过时文档/注释 | 已清理 | `UI_Refactor_*` 已删;`agent_mem.md` §2/§3 已校正 |
|
||||
| 死代码 / 死字段 / TODO | 无 | `-Wall` 零警告 + 全成员引用计数 + 全仓 grep |
|
||||
| 性能热点 | 无新发现 | 第 32 轮四处卡死已根治;三处"还能再快一点"均已量化并判定不做 |
|
||||
|
||||
**明确"不做"的三项(都有数字支撑,写在这里防止后续重复尝试)**:
|
||||
|
||||
1. `EdgeScanFor` 状态查找哈希化:198 状态 0.097 → 0.073 µs/次,但体积 **+5,632 B**。
|
||||
2. `EdgePanelLayoutFor` 表驱动化:实测 1.9~2.5 µs/次(每帧约 30 µs),**不是热点**。
|
||||
3. gdtoa(≈33 KB):MinGW 下只要还用 `std::to_*string`(含浮点)就必然链入,
|
||||
根因在 libstdc++ 的 `os_defines.h` 无条件 `#define __USE_MINGW_ANSI_STDIO 1`。
|
||||
|
||||
**剩下的都属"收益 < 风险/成本"**:`PaintPanelListRows` 还可再拆(纯可读性)、
|
||||
体积只在出现新冗余时再压、面板几何算式已经是单一来源。
|
||||
|
||||
### 18.4 合并前的建议动作(给用户)
|
||||
|
||||
1. **远端机器务必全量重编**:本分支动过 `Makefile`(`NO_RTTI` / `RELEASE_ONLY_OPT` /
|
||||
Debug `-O0 -g`),而只改 Makefile **不会**触发重编 ⇒ 先 `make clean`,再 `make release`。
|
||||
否则会误以为"体积优化无效"或"Debug 还是 -Oz"。
|
||||
2. 合并前跑一遍**最小集**(见 `Tools/README.md` §5):
|
||||
`make release` → `make -C Tools` → `UnitTests` → `OffscreenChecks -all`
|
||||
→ `-run panels -mode compare`(注意:面板/几何基线是**本机生成**的,跨机器不可比,
|
||||
远端首次应 `-mode record` 重建或直接跳过 compare)。
|
||||
3. 分支顺序:`Code_Review` → `dev` → `main`。本分支只含代码 / 文档 / `Tools/`,
|
||||
**没有**构建产物、没有 `Temp/`、没有测试数据。
|
||||
|
||||
### 18.5 本轮验证
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| `make release` / `make debug` / `make -C Tools` | 零 error / 零 warning |
|
||||
| Release 产物 | **782,336 B**(+512,全部来自 P39 登记表;P40 为 0) |
|
||||
| `UnitTests` | `checks=260 failed=0 cases=19` |
|
||||
| `OffscreenChecks -all` | 7 检查 / **133** 断言,全 PASS |
|
||||
| `panels -mode compare` | 7 个面板像素哈希**逐项不变** |
|
||||
| `rowgeom -mode compare` | 965 + 7 键 / 1268 + 7 键(MF4),**0 差异** |
|
||||
|
||||
|
||||
|
||||
@@ -10814,3 +10814,65 @@ std::vector<PanelRowPlan> PlanListPanelRows(const Lane&, EdgePanelKind) const;
|
||||
2. `PaintPanelMarkerGroups`(约 260 行)按"分组栏 / 表头 / 条目吸顶"再拆。
|
||||
3. **体积按用户指示暂停投入**(等后续功能更新产生新冗余时再做)。
|
||||
|
||||
---
|
||||
|
||||
## 2026-11-04 第 41 轮(`Code_Review` 分支,收尾):面板登记表 + 标记面板绘制分段
|
||||
|
||||
> 本轮之后**代码审查进入收尾**(判定见 `Code_Review_Report.md` §18.3)。
|
||||
> 代码:`Components/PlotView/{Inc,Src}`。判据 = `panels -mode compare` + `rowgeom -mode compare`。
|
||||
|
||||
### 1. ✅ **取代**第 35 / 40 轮的"新增面板只改三处"
|
||||
|
||||
**已作废**:旧规则「新增一种面板要在 `LanePanelScrollOf` / `PanelStyleOf` / `PanelTitle` 三处登记」。
|
||||
**现行**:新增面板只改**两处** —— `EdgePanelKind` 加枚举值 + `pvdetail::PanelTraitsOf` 加一行。
|
||||
|
||||
```cpp
|
||||
struct PanelKindTraits
|
||||
{
|
||||
PanelStyle style; // 排版类别 + 底部控件
|
||||
const wchar_t* title = L""; // 标题**前缀**(数据,不是函数)
|
||||
bool rangeSuffix = false; // 是否追加 EdgeRangeSuffix()
|
||||
float Lane::*scroll = nullptr; // 内容滚动偏移
|
||||
LanePanelState Lane::*panel = nullptr; // 面板 UI 状态
|
||||
bool Lane::*enabled = nullptr; // 功能开关
|
||||
};
|
||||
inline constexpr PanelKindTraits PanelTraitsOf(EdgePanelKind kind); // **唯一** switch
|
||||
```
|
||||
|
||||
五个消费者(`PanelStyleOf` / `PanelTitle` / `LanePanelScrollOf` / `LanePanelStateOf` /
|
||||
`LanePanelEnabled`)全部退化成一行取值,**签名未变、调用点一处未动**。
|
||||
`-Wswitch` 保护仍只在 `PanelTraitsOf` 这一处(不写 `default:`)。
|
||||
⚠️ `PanelStyle` 必须用三个具名构造函数(`ListPanelStyle` / `CountTablePanelStyle` /
|
||||
`MarkerPanelStyle`):表里写 6 个裸 bool,聚合顺序错一位就是"表格面板带按钮"这种隐形错误。
|
||||
|
||||
**"标题是函数"的解法**:把标题降级成数据(前缀 + `rangeSuffix` 标志),
|
||||
`PanelTitle` 只做 `前缀 + (rangeSuffix ? EdgeRangeSuffix() : L"")`。
|
||||
不要为此引入函数指针(等于把数据重新变成代码,新增面板又要写函数)。
|
||||
|
||||
### 2. ✅ `PaintPanelMarkerGroups` 拆成 6 个具名函数
|
||||
|
||||
`MeasureMarkerColumnWidths` / `PaintMarkerGroupBar` / `PaintMarkerColumnSeparators` /
|
||||
`PaintMarkerRow` / `PaintMarkerTableHeader` / `PaintMarkerOpacityRow`;
|
||||
`PaintPanelMarkerGroups` 现在**只负责绘制顺序**:
|
||||
|
||||
**普通分组栏 → 条目 → 表头 → 吸顶分组栏 → 滚动条 → 透明度行**
|
||||
|
||||
🔴 硬规则:**表头与吸顶分组栏必须画在条目之后**(否则向上滚动的条目会盖住它们)。
|
||||
这条约束现在只出现在一个函数里,是唯一"看代码就能看全"的顺序约束;新增悬浮/吸顶元素
|
||||
一律加在"条目之后"。
|
||||
|
||||
### 3. 本轮数字
|
||||
|
||||
* Release 781,824 → **782,336 B(+512)**,全部来自登记表(7 份 traits 记录进 `.rdata`);
|
||||
**P40 拆分前后字节数完全相同** ⇒ 纯搬移。
|
||||
* release / debug / tools 全零 warning;`UnitTests` 260/19;`OffscreenChecks -all` 7 检查 / 133 断言。
|
||||
* `panels -mode compare` 7 面板像素哈希逐项不变;`rowgeom compare` 965+7 / 1268+7 键 0 差异。
|
||||
* 行数:`PlotViewPanelPaint.cpp` 939 → 977;`PlotViewPanels.cpp` 1766 → 1758。
|
||||
|
||||
### 4. 审查收尾时确认的三条"别再试"
|
||||
|
||||
1. `EdgeScanFor` 状态查找哈希化:**+5,632 B** / 每轮省 ≈4.8 µs ⇒ 不做。
|
||||
2. `EdgePanelLayoutFor` 表驱动化:1.9~2.5 µs/次(每帧 ≈30 µs)⇒ 不是热点。
|
||||
3. gdtoa(≈33 KB):libstdc++ 的 `os_defines.h` 无条件
|
||||
`#define __USE_MINGW_ANSI_STDIO 1` ⇒ 只要还用 `std::to_*string`(含浮点)就去不掉。
|
||||
|
||||
Reference in new issue
Block a user