#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);
#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;
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;
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;
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);
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);
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))
}
}
+/**
+ * Compute the number of nodes in @l. Beware linear time complexity.
+ **/
static inline uns clist_size(clist *l)
{
uns i = 0;
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)))
- <<mempool:,Memory pools>>
- <<mainloop:,Mainloop>>
- <<unaligned:,Unaligned data>>
+- <<lists:,Link lists>>
Other features
--------------
* `binheap.h`
* `binheap-node.h`
* `heap.h`
-- Link lists
- * `clists.h`
- * `simple-lists.h`
- * `slists.h`
- Hash tables
* `hashtable.h`
- Trie
--- /dev/null
+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
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
#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;
l->last = n;
}
+/**
+ * Insert a new node after all other nodes.
+ **/
static inline void slist_add_tail(slist *l, snode *n)
{
if (l->last)
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