nx_dlist.nx
buildroot/runtime/nx_dlist.nx
about
dlist.nx -- intrusive doubly-linked list.
Each node carries prev/next pointers; list has a sentinel node
(heap-allocated) whose prev/next thread the ring. Intrusive:
the node pointer is the handle the caller holds, not a wrapper
around T. Trade-offs vs std::list-style wrapped list:
+ O(1) remove given just a node pointer (no search)
+ one user struct can participate in multiple lists (LRU +
pending + free) with separate DNode fields
- caller allocates nodes
Design note: NishiLang v1 doesn't allow `&struct.field` for
inline fields, so DList stores the sentinel as a separately-
allocated *DNode rather than an embedded DNode. Small extra
alloc at list-construction time only.
Used by:
- LRU caches (move-to-front, evict tail)
- scheduler run queues
- free-block chains in allocators
- order-preserving map iteration (map + sibling dlist)
Invariants:
DL1 Empty list: sentinel.next == sentinel.prev == sentinel.
DL2 dlist_insert_after + dlist_remove maintain
n.next.prev == n for all n.
DL3 dlist_remove does NOT free the node -- caller owns
lifetime.
dependencies 1 imports · 1 importers
imports: nx_syscalls.nx
imported by: nx_lru.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| 38 | struct DNode |
| 44 | struct DList |
consts
| none |
functions
| 49 | func dlist_new() -> *DList |
| 62 | func dnode_new(data: *u8) -> *DNode |
| 71 | func dlist_empty(L: *DList) -> i64 |
| 78 | func dlist_insert_after(pos: *DNode, n: *DNode) -> i64 |
| 87 | func dlist_push_front(L: *DList, n: *DNode) -> i64 |
| 92 | func dlist_push_back(L: *DList, n: *DNode) -> i64 |
| 97 | func dlist_remove(n: *DNode) -> i64 |
| 104 | func dlist_move_to_front(L: *DList, n: *DNode) -> i64 |
| 111 | func dlist_pop_front(L: *DList) -> *DNode |
| 119 | func dlist_pop_back(L: *DList) -> *DNode |
| 127 | func dlist_begin(L: *DList) -> *DNode called by 1: main |
| 131 | func dlist_end(L: *DList) -> *DNode |
| 136 | func main() -> i64 |