stage1 更多的语义以及类型构造器
This commit is contained in:
@@ -130,6 +130,56 @@ static inline usize map_hash_str(const char *s) {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* 插入(仅当键不存在时),若键已存在则静默跳过,不更新值
|
||||
* 与 map_put 的差异仅在"键已存在时":map_put 更新值,map_put_new 放弃
|
||||
*/
|
||||
#define map_put_new(map, _key, _val) \
|
||||
do { \
|
||||
/* 扩容 */ \
|
||||
if ((map).cap == 0 || (map).size * 128 / (map).cap >= MAP_DEFAULT_LOAD_FACTOR) { \
|
||||
usize new_cap = (map).cap == 0 ? 8 : (map).cap * 2; \
|
||||
MAP_SLOT(MAP_TYPEOF((map).data->key), MAP_TYPEOF((map).data->val)) *new_data = \
|
||||
calloc(new_cap, sizeof(*new_data)); \
|
||||
if (!new_data) \
|
||||
abort(); \
|
||||
/* 重新插入旧元素 */ \
|
||||
for (usize _i = 0; _i < (map).cap; ++_i) { \
|
||||
if ((map).data[_i].state == __MAP_SLOT_OCCUPIED) { \
|
||||
usize _h = (map).hash((map).data[_i].key) & (new_cap - 1); \
|
||||
while (new_data[_h].state == __MAP_SLOT_OCCUPIED) \
|
||||
_h = (_h + 1) & (new_cap - 1); \
|
||||
new_data[_h].key = (map).data[_i].key; \
|
||||
new_data[_h].val = (map).data[_i].val; \
|
||||
new_data[_h].state = __MAP_SLOT_OCCUPIED; \
|
||||
} \
|
||||
} \
|
||||
free((map).data); \
|
||||
(map).data = (void *)new_data; \
|
||||
(map).cap = new_cap; \
|
||||
} \
|
||||
/* 查找 */ \
|
||||
usize _mask = (map).cap - 1; \
|
||||
usize _idx = (map).hash(_key) & _mask; \
|
||||
usize _first_del = (usize) - 1; \
|
||||
while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \
|
||||
if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \
|
||||
(map).cmp((map).data[_idx].key, _key) == 0) { \
|
||||
break; /* 已存在,不更新 */ \
|
||||
} \
|
||||
if ((map).data[_idx].state == __MAP_SLOT_DELETED && _first_del == (usize) - 1) \
|
||||
_first_del = _idx; \
|
||||
_idx = (_idx + 1) & _mask; \
|
||||
} \
|
||||
if ((map).data[_idx].state == __MAP_SLOT_EMPTY) { \
|
||||
usize _target = (_first_del != (usize) - 1) ? _first_del : _idx; \
|
||||
(map).data[_target].key = _key; \
|
||||
(map).data[_target].val = _val; \
|
||||
(map).data[_target].state = __MAP_SLOT_OCCUPIED; \
|
||||
++(map).size; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* 查询:若找到,*out_val 被赋值为对应值并返回 1;否则返回 0
|
||||
*/
|
||||
@@ -152,6 +202,33 @@ static inline usize map_hash_str(const char *s) {
|
||||
_found; \
|
||||
}))
|
||||
|
||||
/**
|
||||
* 查询(续探):首次调用前将 *in_out_idx 置为 (usize)-1,
|
||||
* 则从键自身的 hash 桶开始查找;命中后 *out_val 被赋值、返回 1,
|
||||
* 且 *in_out_idx 更新为命中槽位,下次调用从该槽的下一个继续探测(碰撞续探)。
|
||||
* 扫描到空槽返回 0。用于 key 碰撞后需要回表二次比较的场景。
|
||||
*/
|
||||
#define map_get_continue(map, _key, out_val, in_out_idx) \
|
||||
(({ \
|
||||
int _found = 0; \
|
||||
if ((map).cap > 0) { \
|
||||
usize _mask = (map).cap - 1; \
|
||||
usize _idx = (*(in_out_idx) == (usize) - 1) ? (map).hash(_key) & _mask \
|
||||
: (*(in_out_idx) + 1) & _mask; \
|
||||
while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \
|
||||
if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \
|
||||
(map).cmp((map).data[_idx].key, _key) == 0) { \
|
||||
*out_val = (map).data[_idx].val; \
|
||||
*(in_out_idx) = _idx; \
|
||||
_found = 1; \
|
||||
break; \
|
||||
} \
|
||||
_idx = (_idx + 1) & _mask; \
|
||||
} \
|
||||
} \
|
||||
_found; \
|
||||
}))
|
||||
|
||||
/**
|
||||
* 删除指定键
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user