Files
TransPyC/includes/_dict.py

284 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
import mbuddy
import string
import json
import mpool
from stdint import *
# Variant 类型标签 (与 _variant.py 保持一致)
VARIANT_NONE: t.CDefine = 0 # 无类型/空值
VARIANT_INT: t.CDefine = 1 # int (i64)
VARIANT_FLOAT: t.CDefine = 2 # float (f32)
VARIANT_DOUBLE: t.CDefine = 3 # double (f64)
VARIANT_STR: t.CDefine = 4 # str (i8*)
VARIANT_DICT: t.CDefine = 5 # dict*
VARIANT_LIST: t.CDefine = 6 # list*
VARIANT_BOOL: t.CDefine = 7 # bool (i1/i32)
VARIANT_PTR: t.CDefine = 8 # 自定义指针类型
# Variant 结构体大小: vtype(i32, 4 bytes) + padding(4 bytes) + ptr(i8*, 8 bytes) = 16 bytes
_VARIANT_SIZE: t.CDefine = 16
class dict:
"""堆上动态字典容器,基于 mbuddy 分配器。
键类型固定为 str (i8*),值使用 Variant 存储 (类型标签 + 无类型指针)。
支持嵌套 dict/list 和 JSON 序列化。
用法:
mb: mbuddy.MBuddy = mbuddy.MBuddy(arena, arena_size)
d: dict = dict(mb)
d.set_int("x", 42)
p: t.CPtr = d["x"]
v: int = c.Deref(p)
# 嵌套 dict
inner: dict = dict(mb)
inner.set_int("a", 1)
d.set_dict("sub", inner)
sub: dict = c.Deref(d["sub"])
av: int = c.Deref(sub["a"])
"""
__keys__: t.CVoid | t.CPtr
__values__: t.CVoid | t.CPtr
__count__: t.CSizeT
__capacity__: t.CSizeT
__mbuddy__: mbuddy.MBuddy | t.CPtr
__iter_index__: t.CSizeT
def __new__(self, mb: mbuddy.MBuddy | t.CPtr) -> t.CPtr:
# 堆分配 dict 对象 (6 字段 × 8 字节 = 48 字节)
buf: t.CVoid | t.CPtr = mb.alloc(48)
return buf
def __init__(self, mb: mbuddy.MBuddy | t.CPtr):
self.__mbuddy__ = mb
self.__count__ = 0
self.__capacity__ = 8
self.__keys__ = mb.alloc(self.__capacity__ * 8)
self.__values__ = mb.alloc(self.__capacity__ * _VARIANT_SIZE)
self.__iter_index__ = 0
def __len__(self) -> t.CSizeT:
return self.__count__
def _find(self, key: str) -> t.CSizeT:
"""查找 key 的索引,找不到返回 __count__"""
i: t.CSizeT = 0
while i < self.__count__:
key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + i * 8, t.CPtr)
if string.strcmp(key_ptr[0], key) == 0:
return i
i += 1
return self.__count__
def __getitem__(self, key: str) -> t.CPtr:
"""返回值的无类型指针。用户用 c.Deref 解引用获取实际值。
例: p: t.CPtr = d["x"]; v: int = c.Deref(p)"""
idx: t.CSizeT = self._find(key)
if idx >= self.__count__:
return None
# Variant.ptr 在 Variant 结构体偏移 8 处
val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8, t.CPtr)
return val_ptr[0]
def __setitem__(self, key: str, val: t.CNeedPtr):
"""存储值为 VARIANT_PTR。val 自动取地址 (t.CNeedPtr)。
注意: val 指向的值生命周期由调用者管理。
如需持久存储,请使用 set_int / set_str 等类型化方法。"""
self._set_variant_raw(key, VARIANT_PTR, val)
def _set_variant_raw(self, key: str, vtype: t.CInt, ptr: t.CPtr):
"""内部方法: 存储 Variant (vtype + ptr)。不自动取地址。"""
idx: t.CSizeT = self._find(key)
if idx < self.__count__:
# 更新已有键
vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE, t.CPtr)
vtype_ptr[0] = vtype
val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8, t.CPtr)
val_ptr[0] = ptr
return
if self.__count__ >= self.__capacity__:
new_cap: t.CSizeT = self.__capacity__ * 2
new_keys: t.CVoid | t.CPtr = self.__mbuddy__.alloc(new_cap * 8)
new_values: t.CVoid | t.CPtr = self.__mbuddy__.alloc(new_cap * _VARIANT_SIZE)
if new_keys == None:
return
if new_values == None:
return
string.memcpy(new_keys, self.__keys__, self.__count__ * 8)
string.memcpy(new_values, self.__values__, self.__count__ * _VARIANT_SIZE)
self.__keys__ = new_keys
self.__values__ = new_values
self.__capacity__ = new_cap
key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + self.__count__ * 8, t.CPtr)
key_ptr[0] = key
vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE, t.CPtr)
vtype_ptr[0] = vtype
val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + self.__count__ * _VARIANT_SIZE + 8, t.CPtr)
val_ptr[0] = ptr
self.__count__ += 1
# ============================================================
# 类型化 setter — 在 __mbuddy__ 中分配持久存储
# ============================================================
def set_int(self, key: str, val: int):
"""存储 int 值 (VARIANT_INT)。值复制到 __mbuddy__ 持久存储。"""
storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8)
int_ptr: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
int_ptr[0] = val
self._set_variant_raw(key, VARIANT_INT, storage)
def set_str(self, key: str, val: str):
"""存储 str 值 (VARIANT_STR)。直接存储字符串指针。"""
self._set_variant_raw(key, VARIANT_STR, val)
def set_float(self, key: str, val: float):
"""存储 float 值 (VARIANT_FLOAT)。值复制到 __mbuddy__ 持久存储。"""
storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8)
float_ptr: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
float_ptr[0] = val
self._set_variant_raw(key, VARIANT_FLOAT, storage)
def set_double(self, key: str, val: t.CDouble):
"""存储 double 值 (VARIANT_DOUBLE)。值复制到 __mbuddy__ 持久存储。"""
storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8)
dbl_ptr: t.CDouble | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
dbl_ptr[0] = val
self._set_variant_raw(key, VARIANT_DOUBLE, storage)
def set_dict(self, key: str, val: dict | t.CPtr):
"""存储嵌套 dict 指针 (VARIANT_DICT)。"""
self._set_variant_raw(key, VARIANT_DICT, val)
def set_list(self, key: str, val: t.CPtr):
"""存储嵌套 list 指针 (VARIANT_LIST)。"""
self._set_variant_raw(key, VARIANT_LIST, val)
def set_bool(self, key: str, val: t.CInt):
"""存储 bool 值 (VARIANT_BOOL)。值复制到 __mbuddy__ 持久存储。"""
storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8)
bool_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
bool_ptr[0] = val
self._set_variant_raw(key, VARIANT_BOOL, storage)
# ============================================================
# 查询方法
# ============================================================
def get_vtype(self, key: str) -> t.CInt:
"""返回 key 对应值的 Variant 类型标签。"""
idx: t.CSizeT = self._find(key)
if idx >= self.__count__:
return VARIANT_NONE
vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE, t.CPtr)
return vtype_ptr[0]
def get(self, key: str, default: t.CPtr) -> t.CPtr:
"""返回值指针,不存在则返回 default。"""
idx: t.CSizeT = self._find(key)
if idx >= self.__count__:
return default
val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + idx * _VARIANT_SIZE + 8, t.CPtr)
return val_ptr[0]
def contains(self, key: str) -> t.CInt:
"""检查 key 是否存在。"""
idx: t.CSizeT = self._find(key)
if idx < self.__count__:
return 1
return 0
def __iter__(self) -> dict | t.CPtr:
self.__iter_index__ = 0
return self
def __next__(self) -> str:
if self.__iter_index__ >= self.__count__:
raise StopIteration
idx: t.CSizeT = self.__iter_index__
self.__iter_index__ = idx + 1
key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + idx * 8, t.CPtr)
return key_ptr[0]
# ============================================================
# JSON 处理:利用 includes/json 库实现序列化/反序列化
# ============================================================
def to_json(self, pool: mpool.MPool | t.CPtr) -> json.JsonValue | t.CPtr:
"""将 dict 转换为 JsonValue 对象 (JSON_OBJECT)。
根据 Variant 类型标签自动选择合适的 JSON 值类型。"""
obj: json.JsonValue | t.CPtr = json.object(pool)
i: t.CSizeT = 0
while i < self.__count__:
key_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__keys__) + i * 8, t.CPtr)
vtype_ptr: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE, t.CPtr)
val_ptr: str | t.CPtr = t.CVoid(t.CUInt64T(self.__values__) + i * _VARIANT_SIZE + 8, t.CPtr)
vt: t.CInt = vtype_ptr[0]
vp: t.CPtr = val_ptr[0]
jv: json.JsonValue | t.CPtr = json.null(pool)
if jv != None:
if vt == VARIANT_INT:
jv.vtype = 2 # JSON_INT
ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.int_val = ip[0]
elif vt == VARIANT_STR:
jv.vtype = 4 # JSON_STRING
jv.str_val = vp
elif vt == VARIANT_BOOL:
jv.vtype = 1 # JSON_BOOL
bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.bool_val = bp[0]
elif vt == VARIANT_FLOAT:
jv.vtype = 3 # JSON_FLOAT
fp: float | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.float_val = fp[0]
elif vt == VARIANT_PTR:
# 默认: 将 PTR 作为整数处理
jv.vtype = 2 # JSON_INT
ip: int | t.CPtr = t.CVoid(t.CUInt64T(vp), t.CPtr)
jv.int_val = ip[0]
json.object_set(pool, obj, key_ptr[0], jv)
i += 1
return obj
def from_json(self, pool: mpool.MPool | t.CPtr, root: json.JsonValue | t.CPtr):
"""从 JsonValue 对象填充 dict。
根据 JSON 值类型自动提取并存储为对应 Variant 类型。"""
if root == None:
return
if root.vtype != 6: # JSON_OBJECT
return
cur: json.JsonValue | t.CPtr = root.child
while cur != None:
if cur.key != None:
if cur.vtype == 2: # JSON_INT
storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8)
ip: int | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
ip[0] = cur.int_val
self._set_variant_raw(cur.key, VARIANT_INT, storage)
elif cur.vtype == 4: # JSON_STRING
self._set_variant_raw(cur.key, VARIANT_STR, cur.str_val)
elif cur.vtype == 1: # JSON_BOOL
storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8)
bp: t.CInt | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
bp[0] = cur.bool_val
self._set_variant_raw(cur.key, VARIANT_BOOL, storage)
elif cur.vtype == 3: # JSON_FLOAT
storage: t.CVoid | t.CPtr = self.__mbuddy__.alloc(8)
fp: float | t.CPtr = t.CVoid(t.CUInt64T(storage), t.CPtr)
fp[0] = cur.float_val
self._set_variant_raw(cur.key, VARIANT_FLOAT, storage)
cur = cur.next
def dumps(self, pool: mpool.MPool | t.CPtr) -> str:
"""将 dict 序列化为 JSON 字符串。"""
obj: json.JsonValue | t.CPtr = self.to_json(pool)
return json.write(pool, obj, False)
def loads(self, pool: mpool.MPool | t.CPtr, json_str: str):
"""从 JSON 字符串解析并填充 dict。"""
root: json.JsonValue | t.CPtr = json.parse(pool, json_str)
self.from_json(pool, root)