Skip to main content

cure_tree/
name.rs

1//! 名字 intern 表 + 每节点名字键。
2
3use std::collections::HashMap;
4
5/// 无名节点的键(哨兵:intern id 从 0 只增,实际不可达)。
6pub const KEY_NONE: u32 = u32::MAX;
7
8/// 名字表:单元级「名字 ↔ u32」intern(只增、永不回收)+ 每节点的
9/// 名字键(槽位 = arena 下标,`KEY_NONE` = 无名)。
10///
11/// 语言的 `Lang::NameKey` 采用 intern u32 时(推荐——区域扫描的名字
12/// 比较退化为整数等值)直接复用本表。
13#[derive(Default, Debug)]
14pub struct NameTable {
15    /// 名字 → 键(intern)。
16    name_to_key: HashMap<String, u32>,
17    /// 键 → 名字原文(intern 顺序稠密)。
18    names: Vec<String>,
19    /// 节点名字键(槽位 = arena 下标;`KEY_NONE` = 无名)。
20    /// prepare 增量扩展(新节点 intern;既有节点键与名字恒同)。
21    node_key: Vec<u32>,
22}
23
24impl NameTable {
25    pub fn new() -> Self {
26        Self::default()
27    }
28
29    /// 名字 → 键(intern:同名字同键)。
30    pub fn intern(&mut self, name: &str) -> u32 {
31        if let Some(&k) = self.name_to_key.get(name) {
32            return k;
33        }
34        let k = self.names.len() as u32;
35        self.name_to_key.insert(name.to_string(), k);
36        self.names.push(name.to_string());
37        k
38    }
39
40    /// 键 → 名字原文(未知键返回空串,与调用方 `sn` 惯例一致)。
41    pub fn name(&self, key: u32) -> &str {
42        self.names.get(key as usize).map(|s| s.as_str()).unwrap_or("")
43    }
44
45    /// 节点名字键(`KEY_NONE` → None;供 `Lang::var_key`)。
46    pub fn var_key(&self, idx: usize) -> Option<u32> {
47        match self.node_key.get(idx) {
48            Some(&k) if k != KEY_NONE => Some(k),
49            _ => None,
50        }
51    }
52
53    /// 原始键(含 `KEY_NONE`;供兼容旧路径)。
54    pub fn raw_key(&self, idx: usize) -> u32 {
55        self.node_key.get(idx).copied().unwrap_or(KEY_NONE)
56    }
57
58    /// 已填充的节点键槽数(与 arena 下标对齐检查用)。
59    pub fn key_slots(&self) -> usize {
60        self.node_key.len()
61    }
62
63    /// 增量扩展节点键表:为下标 `[base, base + names.len())` 的**新**
64    /// 节点填键(名字已由语言侧先收集——`Lang::var_name` 的借用安全
65    /// 形态)。既有节点的键与其名字恒同,无需重填。
66    pub fn extend_owned(&mut self, base: usize, names: &[Option<String>]) {
67        if self.node_key.len() < base + names.len() {
68            self.node_key.resize(base + names.len(), KEY_NONE);
69        }
70        for (i, name) in names.iter().enumerate() {
71            if let Some(n) = name {
72                self.node_key[base + i] = self.intern(n);
73            }
74        }
75    }
76}