模块契约侵入式链表 API
错误
错误域为 xrt.list:
| 代码 | 常量 | 含义 |
|---|
| 1 | XLIST_ERROR_ARGUMENT | 空链表、节点或迭代器参数。 |
| 2 | XLIST_ERROR_STATE | 未初始化、节点归属错误或链接不一致。 |
| 3 | XLIST_ERROR_RANGE | 节点计数将溢出。 |
| 4 | XLIST_ERROR_MODIFIED | 迭代期间发生外部结构修改。 |
查询未命中、空链表弹出和迭代自然结束是正常结果,不制造错误。成功操作不会隐式清除 调用方先前保存的错误。
定位
链表不拥有节点,也不决定对象类型和分配方式。用户把 xlistnode 嵌入自己的对象, 对象可以来自栈、全局存储、XRT 堆或任意内存池。一个对象需要同时进入多个链表时, 嵌入多个独立节点即可。
每个节点保存 Prev、Next 和只读的 Owner。额外的所属链表指针让插入、删除、 移动和归属检查保持 O(1),同时能够确定性拒绝重复插入和跨链表删除。链表不内建 同步;多个线程读写同一链表时由调用方加锁。
连续数据使用 array,FIFO/LIFO 工作负载使用 queue / stack,拥有运行时类型值的 稀疏有序容器使用 typed_list。本模块不重复这些高层容器的分配和类型生命周期逻辑。
类型与初始化
XRT_LIST_INIT 和 XRT_LIST_NODE_INIT 用于静态或聚合初始化;动态对象使用 xrtListInit 和 xrtListNodeInit。初始化函数只用于新的存储,不能覆盖仍然持有节点 的链表或仍然已连接的节点。xrtListReady 判断链表是否初始化,xrtListValidate 以 O(n) 完整检查端点、所有权、双向链接和计数。
链表字段公开是为了零成本检查和调试,但调用方只能读取。直接改写 First、Last、 Count、Version、State 或活动节点的链接字段会破坏契约。
XRT_CONTAINER_OF(node, type, member) 从任意位置嵌入的节点恢复对象,不要求节点是 结构的第一个成员:
查询
xrtListEmpty / xrtListCount 返回空状态和节点数。xrtListFirst / xrtListLast 返回借用端点,空链表返回 NULL。xrtListPrev / xrtListNext 返回借用相邻节点。xrtListOwner 返回节点所属链表,未连接节点返回 NULL。xrtListContains 判断节点是否属于指定链表。xrtListLinked 判断节点是否属于任意链表。
借用节点在被移除、弹出或清空后仍由用户拥有,但其 Prev、Next 和 Owner 会全部 恢复为 NULL,可以安全插入其他链表。
结构操作
xrtListPushFront / xrtListPushBack 在首尾插入未连接节点。 xrtListInsertBefore / xrtListInsertAfter 要求参考节点属于目标链表;参考位置不能用 NULL 表示,首尾便利路径由 Push 函数明确表达。
xrtListRemove 只分离节点,不释放对象。xrtListPopFront / xrtListPopBack 分离并 返回端点,空链表返回 NULL 且不设置错误。xrtListMoveFront / xrtListMoveBack 把已有节点移动到首尾,不改变计数。xrtListClear 先完整验证链表,再分离所有节点; 验证失败时不会部分清空。
所有成功的结构变化都会更新 Version。节点数使用 size_t,达到 SIZE_MAX 后新增 节点以 XERR_RANGE 拒绝,不发生回绕。
安全迭代
xlistiter 是调用方持有的外置状态,不分配内存:
xrtListIterBegin 正向迭代,xrtListIterRBegin 反向迭代。自然结束不设置错误。 xrtListIterRemove 只能删除最近一次 Next 返回的当前节点,并同步迭代版本;连续删除 两次会失败。通过其他 API 修改链表会使现有迭代器失效,下一次 Next/Remove 以 XLIST_ERROR_MODIFIED 拒绝。xrtListIterEnd 用于提前结束,允许传入 NULL。
API 索引
完整示例位于 examples/containers/list/main.c。
旧版资产决策
新版保留旧 LList Base 的侵入节点、双向遍历、首尾操作、任意内存来源和多链接对象 能力,并补齐节点所有权、size_t 计数、结构验证、安全迭代和结构化错误。旧宏缺少 do/while 边界,重复插入、外来参考和跨链表删除会静默损坏结构,因此不保留原名称和 布局。
旧自动分配 LList 把节点头与未对齐的匿名字节负载拼接,并重复承担固定池、队列、栈和 类型容器职责。该层不再恢复:低层链接使用本模块,分配复用使用 Pool,高层数据结构使用 Array/Queue/Stack/Typed List,避免第二套节点分配与类型生命周期实现。
类型与初始化
xlistnode类型
侵入式链表节点(不透明):由宿主对象嵌入,一个对象可嵌入多个独立节点分别挂入不同链表。
| 字段 | 类型 | 语义 |
|---|
Prev | struct xlistnode* | 前驱 |
Next | struct xlistnode* | 后继 |
Owner | xlist* | Owner |
typedef struct xlistnode { struct xlistnode* Prev; struct xlistnode* Next; xlist* Owner; } xlistnode;
xlistiter类型
外置迭代器不分配内存,并允许通过专用操作删除当前节点。
| 字段 | 类型 | 语义 |
|---|
List | xlist* | List |
Next | xlistnode* | 后继 |
Current | xlistnode* | Current |
Version | uint64 | 结构版本 |
Reverse | bool | Reverse |
typedef struct xlistiter { xlist* List; xlistnode* Next; xlistnode* Current; uint64 Version; bool Reverse; } xlistiter;
xlisterror类型
链表模块稳定错误代码。
| 值 | 语义 |
|---|
XLIST_ERROR_ARGUMENT | 参数非法 |
XLIST_ERROR_STATE | 状态非法 |
XLIST_ERROR_RANGE | 范围越界 |
XLIST_ERROR_MODIFIED | 迭代期间被修改 |
typedef enum xlisterror { XLIST_ERROR_ARGUMENT = 1, XLIST_ERROR_STATE, XLIST_ERROR_RANGE, XLIST_ERROR_MODIFIED } xlisterror;
xlist类型
侵入式链表不拥有节点内存;一个对象可嵌入多个独立节点。 不透明句柄或别名;生命周期与所有权见各使用方 API 节。
typedef struct xlist xlist;
xrtListInit函数
初始化新的链表存储;不能用于仍然持有节点的活动链表。
void xrtListInit(xlist* pList)
xrtListNodeInit函数
初始化新的节点存储;不能用于仍然属于链表的节点。
void xrtListNodeInit(xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pNode | 输出 | 非空 | 接收独立状态节点 |
xrtListReady函数
判断链表是否已经初始化。
bool xrtListReady(const xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已初始化 | — |
false | 未初始化 | 纯查询 |
范例已编译验证
containers/list_tour · 查询 · 观察
if ( !xrtListReady(&List) ||
!xrtListEmpty(&List) ||
(xrtListCount(&List) != 0u) ||
!xrtListValidate(&List) ||
(xrtListFirst(&List) != NULL) ||
(xrtListLast(&List) != NULL) ||
(xrtListPopFront(&List) != NULL) ||
(xrtListPopBack(&List) != NULL) ) {
xrtListValidate函数
完整验证节点所有权、双向链接、端点和计数(调试/断言用)。
bool xrtListValidate(const xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 全部不变量成立 | — |
false | 结构被破坏 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 公开结构损坏
xrtListEmpty函数
返回链表是否为空。
bool xrtListEmpty(const xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 无节点 | — |
false | 非空 | 纯查询 |
xrtListCount函数
返回当前节点数量。
size_t xrtListCount(const xlist* pList)
xrtListFirst函数
返回首节点;空链表返回空指针。
xlistnode* xrtListFirst(const xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 首节点(借用) | — |
NULL | 空链表(正常结果) | 不设错 |
范例已编译验证
containers/list · 导航 · 观察
for ( xlistnode* pNode = xrtListFirst(pCache);
pNode != NULL;
pNode = xrtListNext(pNode) ) {
xrtListLast函数
返回尾节点;空链表返回空指针。
xlistnode* xrtListLast(const xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 尾节点(借用) | — |
NULL | 空链表 | 不设错 |
xrtListPrev函数
返回节点的前驱。
xlistnode* xrtListPrev(const xlistnode* pNode)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 前驱 | — |
NULL | 首节点或未连接 | 不设错 |
xrtListNext函数
返回节点的后继。
xlistnode* xrtListNext(const xlistnode* pNode)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 后继 | — |
NULL | 尾节点或未连接 | 不设错 |
xrtListOwner函数
返回节点所属链表。
xlist* xrtListOwner(const xlistnode* pNode)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 所属链表 | — |
NULL | 未连接 | 不设错 |
xrtListContains函数
判断节点是否属于指定链表。
bool xrtListContains(const xlist* pList, const xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入 | 非空 | 链表 |
pNode | 输入 | 非空 | 节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 属于 | — |
false | 不属于或未连接 | 不设错 |
范例已编译验证
containers/list_tour · 查询 · 观察
if ( !xrtListContains(&List, &Entries[2].Node) ||
xrtListContains(&List, NULL) ||
!xrtListLinked(&Entries[2].Node) ||
xrtListLinked(&Detached.Node) ||
(xrtListOwner(&Entries[2].Node) != &List) ||
(xrtListOwner(NULL) != NULL) ||
(xrtListPrev(&Entries[0].Node) != NULL) ||
(xrtListPrev(&Entries[1].Node) != &Entries[0].Node) ||
(xrtListNext(&Entries[4].Node) != NULL) ) {
xrtListLinked函数
判断节点是否已连接到任意链表。
bool xrtListLinked(const xlistnode* pNode)
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已连接 | — |
false | 独立 | 不设错 |
xrtListPushFront函数
在链表首插入一个已初始化且未连接的节点。
bool xrtListPushFront(xlist* pList, xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入/输出 | 非空、已初始化 | 链表 |
pNode | 输入 | 已 NodeInit、未连接 | 节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已插入;Count +1 | — |
false | 参数或状态错误 | 链表不变 |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
xrtListPushBack函数
在链表尾插入一个已初始化且未连接的节点。
bool xrtListPushBack(xlist* pList, xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入/输出 | 非空 | 链表 |
pNode | 输入 | 未连接 | 节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已插入;Count +1 | — |
false | 参数或状态错误 | 链表不变 |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
范例已编译验证
containers/list_tour · 编辑 · 观察
if ( !xrtListPushBack(&List, &Entries[1].Node) ||
!xrtListInsertBefore(&List, &Entries[1].Node,
&Entries[0].Node) ||
!xrtListInsertAfter(&List, &Entries[1].Node,
&Entries[2].Node) ||
!xrtListPushBack(&List, &Entries[3].Node) ||
!xrtListInsertAfter(&List, &Entries[3].Node,
&Entries[4].Node) ||
(xrtListCount(&List) != 5u) ||
!exampleForwardText(&List, Text, sizeof(Text)) ||
(strcmp(Text, "12345") != 0) ) {
xrtListInsertBefore函数
在参考节点之前插入未连接节点。
bool xrtListInsertBefore(xlist* pList, xlistnode* pPosition, xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入/输出 | 非空 | 链表 |
pPosition | 输入 | 属于 pList | 参考节点 |
pNode | 输入 | 未连接 | 新节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已插入 | — |
false | 参数或所有权错误 | 链表不变 |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
xrtListInsertAfter函数
在参考节点之后插入未连接节点。
bool xrtListInsertAfter(xlist* pList, xlistnode* pPosition, xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入/输出 | 非空 | 链表 |
pPosition | 输入 | 属于 pList | 参考节点 |
pNode | 输入 | 未连接 | 新节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已插入 | — |
false | 参数或所有权错误 | 链表不变 |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
xrtListRemove函数
从指定链表移除节点,但不释放节点内存;节点恢复独立状态可再插入。
bool xrtListRemove(xlist* pList, xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入/输出 | 非空 | 链表 |
pNode | 输入 | 属于 pList | 节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已移除;Count -1 | — |
false | 参数或所有权错误 | 链表不变 |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
范例已编译验证
containers/list_tour · 编辑 · 观察
if ( !xrtListRemove(&List, &Entries[3].Node) ||
!xrtListPushBack(&List, &Entries[3].Node) ||
!exampleForwardText(&List, Text, sizeof(Text)) ||
(strcmp(Text, "354") != 0) ) {
xrtListPopFront函数
移除并返回首节点;空链表是正常结果。
xlistnode* xrtListPopFront(xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 已脱离的首节点(独立状态) | — |
NULL | 空链表(正常结果) | 不设错 |
xrtListPopBack函数
移除并返回尾节点;空链表是正常结果。
xlistnode* xrtListPopBack(xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 已脱离的尾节点 | — |
NULL | 空链表 | 不设错 |
xrtListMoveFront函数
把已有节点移动到链表首,不改变节点数量。
bool xrtListMoveFront(xlist* pList, xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入/输出 | 非空 | 链表 |
pNode | 输入 | 属于 pList | 节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已移动 | — |
false | 参数或所有权错误 | 链表不变 |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
xrtListMoveBack函数
把已有节点移动到链表尾,不改变节点数量。
bool xrtListMoveBack(xlist* pList, xlistnode* pNode)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入/输出 | 非空 | 链表 |
pNode | 输入 | 属于 pList | 节点 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已移动 | — |
false | 参数或所有权错误 | 链表不变 |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
范例已编译验证
containers/list_tour · 编辑 · 观察
if ( !xrtListMoveBack(&List, &Entries[0].Node) ||
!exampleForwardText(&List, Text, sizeof(Text)) ||
(strcmp(Text, "23451") != 0) ) {
xrtListClear函数
分离全部节点并保留可继续使用的空链表;各节点恢复独立状态。
bool xrtListClear(xlist* pList)
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已清空;Count 归零 | — |
false | 参数或状态错误 | — |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 节点未初始化、已属于链表或不属于指定链表
xrtListIterBegin函数
启动正向迭代(升序)。
bool xrtListIterBegin(xlist* pList, xlistiter* pIterator)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入 | 非空 | 链表 |
pIterator | 输出 | 非空 | 迭代器 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 迭代器已就绪(空链表也可启动) | — |
false | 参数错误 | XERR_ARGUMENT |
xrtListIterRBegin函数
启动反向迭代(降序)。
bool xrtListIterRBegin(xlist* pList, xlistiter* pIterator)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pList | 输入 | 非空 | 链表 |
pIterator | 输出 | 非空 | 迭代器 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 迭代器已就绪 | — |
false | 参数错误 | XERR_ARGUMENT |
xrtListIterNext函数
返回下一节点;自然结束不设置错误,外部结构修改会被拒绝。
xlistnode* xrtListIterNext(xlistiter* pIterator)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pIterator | 输入/输出 | 非空、活动 | 迭代器 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
| 非空 | 下一节点 | — |
NULL | 自然耗尽(不设错)或结构被修改 | 结构被修改时 XERR_STATE |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 迭代期间链表结构被外部修改
xrtListIterRemove函数
移除最近一次返回的节点,并让迭代器继续保持有效。
bool xrtListIterRemove(xlistiter* pIterator)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pIterator | 输入/输出 | 非空、活动 | 迭代器 |
返回值| 返回 | 含义 | 失败时状态 |
|---|
true | 已移除(Count -1,迭代继续) | — |
false | 尚未取节点或已结束 | XERR_STATE |
错误XERR_ARGUMENT — 指针为空XERR_STATE — 当前轮尚未发布节点
xrtListIterEnd函数
提前结束迭代;允许传入空指针。
void xrtListIterEnd(xlistiter* pIterator)
参数
| 参数 | 方向 | 约束 | 说明 |
|---|
pIterator | 输入 | 允许空 | 空 = 空操作 |
常量索引常量
以下常量在本页所属头文件中定义,语义见公共头注释。
| 常量 | 说明 |
| XLIST_ERROR_ARGUMENT | 见头文件注释 |
| XLIST_ERROR_MODIFIED | 见头文件注释 |
| XLIST_ERROR_RANGE | 见头文件注释 |
| XLIST_ERROR_STATE | 见头文件注释 |
| XRT_CONTAINER_OF | 见头文件注释 |
| XRT_LIST_INIT | 见头文件注释 |
| XRT_LIST_NODE_INIT | 见头文件注释 |