From: Pavel Charvat Date: Thu, 6 Nov 2008 13:36:36 +0000 (+0100) Subject: Doc: Partially documented linked lists. X-Git-Tag: holmes-import~191 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=5da5de23d38aac0a6a04043879f97ae92feef1c5;p=libucw.git Doc: Partially documented linked lists. --- diff --git a/ucw/clists.h b/ucw/clists.h index 921b7dc5..bc8779d9 100644 --- a/ucw/clists.h +++ b/ucw/clists.h @@ -10,34 +10,64 @@ #ifndef _UCW_CLISTS_H #define _UCW_CLISTS_H +/** + * Common header for list nodes. + **/ typedef struct cnode { struct cnode *next, *prev; } cnode; +/** + * Circilar linked list. + **/ typedef struct clist { struct cnode head; } clist; +/** + * Initialize a new circular linked list. Must be called before any other function. + **/ +static inline void clist_init(clist *l) +{ + cnode *head = &l->head; + head->next = head->prev = head; +} + +/** + * Return the first node on @l or NULL if @l is empty. + **/ static inline void *clist_head(clist *l) { return (l->head.next != &l->head) ? l->head.next : NULL; } +/** + * Return the last node on @l or NULL if @l is empty. + **/ static inline void *clist_tail(clist *l) { return (l->head.prev != &l->head) ? l->head.prev : NULL; } +/** + * Find the next node to @n or NULL if @n is the last one. + **/ static inline void *clist_next(clist *l, cnode *n) { return (n->next != &l->head) ? (void *) n->next : NULL; } +/** + * Find the previous node to @n or NULL if @n is the first one. + **/ static inline void *clist_prev(clist *l, cnode *n) { return (n->prev != &l->head) ? (void *) n->prev : NULL; } +/** + * Return a non-zero value iff @l is empty. + **/ static inline int clist_empty(clist *l) { return (l->head.next == &l->head); @@ -50,6 +80,9 @@ static inline int clist_empty(clist *l) #define CLIST_FOR_EACH_BACKWARDS(type,n,list) for(type n=(void*)(list).head.prev; (cnode*)(n) != &(list).head; n=(void*)((cnode*)(n))->prev) +/** + * Insert a new node just after the node @after. To insert a new head, use @clist_add_head() instead. + **/ static inline void clist_insert_after(cnode *what, cnode *after) { cnode *before = after->next; @@ -59,6 +92,9 @@ static inline void clist_insert_after(cnode *what, cnode *after) after->next = what; } +/** + * Insert a new node just before the node @before. To insert a new tail, use @clist_add_tail() instead. + **/ static inline void clist_insert_before(cnode *what, cnode *before) { cnode *after = before->prev; @@ -68,16 +104,25 @@ static inline void clist_insert_before(cnode *what, cnode *before) after->next = what; } -static inline void clist_add_tail(clist *l, cnode *n) +/** + * Insert a new node in front of all other nodes. + **/ +static inline void clist_add_head(clist *l, cnode *n) { - clist_insert_before(n, &l->head); + clist_insert_after(n, &l->head); } -static inline void clist_add_head(clist *l, cnode *n) +/** + * Insert a new node after all other nodes. + **/ +static inline void clist_add_tail(clist *l, cnode *n) { - clist_insert_after(n, &l->head); + clist_insert_before(n, &l->head); } +/** + * Remove node @n. + **/ static inline void clist_remove(cnode *n) { cnode *before = n->prev; @@ -86,6 +131,9 @@ static inline void clist_remove(cnode *n) after->prev = before; } +/** + * Remove the first node in @l. The list can be empty. + **/ static inline void *clist_remove_head(clist *l) { cnode *n = clist_head(l); @@ -94,6 +142,9 @@ static inline void *clist_remove_head(clist *l) return n; } +/** + * Remove the last node in @l. The list can be empty. + **/ static inline void *clist_remove_tail(clist *l) { cnode *n = clist_tail(l); @@ -102,12 +153,10 @@ static inline void *clist_remove_tail(clist *l) return n; } -static inline void clist_init(clist *l) -{ - cnode *head = &l->head; - head->next = head->prev = head; -} - +/** + * Merge two lists by inserting the list @what just after the node @after in a different list. + * The first list is then cleared. + **/ static inline void clist_insert_list_after(clist *what, cnode *after) { if (!clist_empty(what)) @@ -121,6 +170,9 @@ static inline void clist_insert_list_after(clist *what, cnode *after) } } +/** + * Compute the number of nodes in @l. Beware linear time complexity. + **/ static inline uns clist_size(clist *l) { uns i = 0; diff --git a/ucw/doc/Makefile b/ucw/doc/Makefile index 6949eb53..e805f79f 100644 --- a/ucw/doc/Makefile +++ b/ucw/doc/Makefile @@ -2,7 +2,7 @@ DIRS+=ucw/doc -UCW_DOCS=fastbuf index config configure install basecode hash docsys conf mempool mainloop generic growbuf unaligned +UCW_DOCS=fastbuf index config configure install basecode hash docsys conf mempool mainloop generic growbuf unaligned lists UCW_INDEX=$(o)/ucw/doc/def_index.html UCW_DOCS_HTML=$(addprefix $(o)/ucw/doc/,$(addsuffix .html,$(UCW_DOCS))) diff --git a/ucw/doc/index.txt b/ucw/doc/index.txt index 9bc47004..e96211d0 100644 --- a/ucw/doc/index.txt +++ b/ucw/doc/index.txt @@ -21,6 +21,7 @@ Modules - <> - <> - <> +- <> Other features -------------- @@ -43,10 +44,6 @@ Yet undocumented modules * `binheap.h` * `binheap-node.h` * `heap.h` -- Link lists - * `clists.h` - * `simple-lists.h` - * `slists.h` - Hash tables * `hashtable.h` - Trie diff --git a/ucw/doc/lists.txt b/ucw/doc/lists.txt new file mode 100644 index 00000000..eb9f1188 --- /dev/null +++ b/ucw/doc/lists.txt @@ -0,0 +1,26 @@ +Linked lists +============ + +Ucwlib defines two basic linked list structures: single-linked lists and circular linked lists. +Both of them support insertion of any number of nodes, removal of nodes and various searches. +Single-linked lists are a bit simplier (they especially requires smaller nodes) +but some operations need assymptoticaly more time. + +Linked lists can be used very simply. We define a structure as list's handle and +a common header in all inserted nodes. All routines then accept and return pointers +to this handle and node headers. + +Single-linked lists +------------------- + +!!ucw/slists.h + +Circular linked lists +--------------------- + +!!ucw/clists.h + +Circular linked lists of simple items +------------------------------------- + +!!ucw/simple-lists.h diff --git a/ucw/slists.c b/ucw/slists.c index 35b26850..d1501d74 100644 --- a/ucw/slists.c +++ b/ucw/slists.c @@ -40,8 +40,11 @@ slist_insert_before(slist *l, snode *what, snode *before) void slist_remove(slist *l, snode *n) { - snode *p = slist_raw_prev(l, n); - slist_remove_after(l, p); + if (n) + { + snode *p = slist_raw_prev(l, n); + slist_remove_after(l, p); + } } #ifdef TEST diff --git a/ucw/slists.h b/ucw/slists.h index b0e9f4e2..bdab355d 100644 --- a/ucw/slists.h +++ b/ucw/slists.h @@ -10,46 +10,63 @@ #ifndef _UCW_SLISTS_H #define _UCW_SLISTS_H +/** + * Common header for list nodes. + **/ typedef struct snode { struct snode *next; } snode; +/** + * Single-linked list. + **/ typedef struct slist { struct snode head, *last; } slist; +/** + * Initialize a new single-linked list. Must be called before any other function. + **/ +static inline void slist_init(slist *l) +{ + l->head.next = l->last = NULL; +} + +/** + * Return the first node of @l or NULL if @l is empty. + **/ static inline void *slist_head(slist *l) { return l->head.next; } +/** + * Return the last node of @l or NULL if @l is empty. + **/ static inline void *slist_tail(slist *l) { return l->last; } +/** + * Find the next node to @n or NULL if @n is the last one. + **/ static inline void *slist_next(snode *n) { return n->next; } +/** + * Return a non-zero value iff @l is empty. + **/ static inline int slist_empty(slist *l) { return !l->head.next; } -#define SLIST_WALK(n,list) for(n=(void*)(list).head.next; (n); (n)=(void*)((snode*)(n))->next) -#define SLIST_WALK_DELSAFE(n,list,prev) for((prev)=(void*)&(list).head; (n)=(void*)((snode*)prev)->next; (prev)=(((snode*)(prev))->next==(snode*)(n) ? (void*)(n) : (void*)(prev))) -#define SLIST_FOR_EACH(type,n,list) for(type n=(void*)(list).head.next; n; n=(void*)((snode*)(n))->next) - -static inline void slist_insert_after(slist *l, snode *what, snode *after) -{ - what->next = after->next; - after->next = what; - if (!what->next) - l->last = what; -} - +/** + * Insert a new node in front of all other nodes. + **/ static inline void slist_add_head(slist *l, snode *n) { n->next = l->head.next; @@ -58,6 +75,9 @@ static inline void slist_add_head(slist *l, snode *n) l->last = n; } +/** + * Insert a new node after all other nodes. + **/ static inline void slist_add_tail(slist *l, snode *n) { if (l->last) @@ -68,23 +88,79 @@ static inline void slist_add_tail(slist *l, snode *n) l->last = n; } -static inline void slist_init(slist *l) +/** + * Insert a new node just after the node @after. To insert a new head, use @slist_add_head() instead. + **/ +static inline void slist_insert_after(slist *l, snode *what, snode *after) { - l->head.next = l->last = NULL; + what->next = after->next; + after->next = what; + if (!what->next) + l->last = what; } +/** + * Quickly remove the node next to @after. The node may not exist. + **/ static inline void slist_remove_after(slist *l, snode *after) { snode *n = after->next; - after->next = n->next; - if (l->last == n) - l->last = (after == &l->head) ? NULL : after; + if (n) + { + after->next = n->next; + if (l->last == n) + l->last = (after == &l->head) ? NULL : after; + } +} + +/** + * Remove the first node in @l. The list can be empty. + **/ +static inline void slist_remove_head(slist *l) +{ + slist_remove_after(l, &l->head); } +/* Loops */ + +#define SLIST_WALK(n,list) for(n=(void*)(list).head.next; (n); (n)=(void*)((snode*)(n))->next) +#define SLIST_WALK_DELSAFE(n,list,prev) for((prev)=(void*)&(list).head; (n)=(void*)((snode*)prev)->next; (prev)=(((snode*)(prev))->next==(snode*)(n) ? (void*)(n) : (void*)(prev))) +#define SLIST_FOR_EACH(type,n,list) for(type n=(void*)(list).head.next; n; n=(void*)((snode*)(n))->next) + /* Non-trivial functions */ +/** + * Find the previous node to @n or NULL if @n is the first one. Beware linear time complexity. + **/ void *slist_prev(slist *l, snode *n); + +/** + * Insert a new node just before the node @before. To insert a new tail, use @slist_add_tail(). Beware linear time complexity. + **/ void slist_insert_before(slist *l, snode *what, snode *before); + +/** + * Remove node @n. Beware linear time complexity. + **/ void slist_remove(slist *l, snode *n); +/** + * Remove the last node in @l. The list can be empty. + **/ +static inline void slist_remove_tail(slist *l) +{ + slist_remove(l, l->last); +} + +/** + * Compute the number of nodes in @l. Beware linear time complexity. + **/ +static inline uns slist_size(slist *l) +{ + uns i = 0; + SLIST_FOR_EACH(snode *, n, *l) + i++; + return i; +} + #endif