Sorted List (slist)
A sorted key-value list based on a doubly linked list. Each node carries a string key and a user data pointer, supporting sorting by key.
Data Structure
struct slist_t {
struct list_head_t list; /* Doubly linked list node */
char * key; /* Sort key (generated via printf formatting) */
void * priv; /* User data pointer */
};
The key and priv of the head node are unused; it serves only as a list sentinel. Actual data is stored in child nodes after the head node.
API
struct slist_t * slist_alloc(void);
Allocate an empty list. The head node's key is NULL, list is initialized as an empty linked list.
void slist_free(struct slist_t * sl);
Free the list and all child nodes (including each node's key string), but does not free the user data pointed to by priv.
Note: The caller is responsible for managing the memory pointed to by
priv.
void slist_add(struct slist_t * sl, void * priv, const char * fmt, ...);
Add a node. priv is a user data pointer, fmt is a printf-style format string used to generate the node's key. New nodes are appended to the end of the list. If key generation fails, the node is not added.
void slist_sort(struct slist_t * sl);
Sort the list by key in lexicographic order (xos_strcmp). Uses merge sort, time complexity O(n log n).
void slist_natsort(struct slist_t * sl);
Sort the list by key in natural order (xos_strnatcmp). Numeric parts are compared by value, e.g. file1 < file2 < file10 (lexicographic order would give file1 < file10 < file2). Uses merge sort, time complexity O(n log n).
void slist_sort_with(struct slist_t * sl, int (*cmp)(void *, struct list_head_t *, struct list_head_t *));
Sort the list using a custom comparison function. cmp is the comparison callback, with the same semantics as xos_strcmp (negative means a < b, 0 means equal, positive means a > b). If cmp is NULL, no sorting is performed.
int slist_isempty(struct slist_t * sl);
Returns 1 if the list is empty, 0 otherwise.
Traversal Macros
slist_for_each_entry(entry, sl)
Forward traversal of all child nodes in the list, where entry is an iteration variable of type struct slist_t *.
slist_for_each_entry_reverse(entry, sl)
Reverse traversal of all child nodes in the list.
Usage Examples
Basic Usage
struct slist_t * sl = slist_alloc();
slist_add(sl, (void *)10, "banana");
slist_add(sl, (void *)20, "apple");
slist_add(sl, (void *)30, "cherry");
slist_sort(sl);
struct slist_t * entry;
slist_for_each_entry(entry, sl)
{
printf("key=%s, priv=%d\n", entry->key, (int)(uintptr_t)entry->priv);
}
/* Output: apple, banana, cherry */
slist_free(sl);
Formatted Keys
slist_add(sl, data_ptr, "item-%04d", index);
slist_add(sl, data_ptr, "%s/%s", category, name);
Natural Sort
struct slist_t * sl = slist_alloc();
slist_add(sl, (void *)1, "file1");
slist_add(sl, (void *)2, "file10");
slist_add(sl, (void *)3, "file2");
slist_natsort(sl);
struct slist_t * entry;
slist_for_each_entry(entry, sl)
{
printf("key=%s\n", entry->key);
}
/* Output: file1, file2, file10 */
slist_free(sl);
Custom Sort
static int my_compare(void * priv, struct list_head_t * a, struct list_head_t * b)
{
char * keya = (char *)list_entry(a, struct slist_t, list)->key;
char * keyb = (char *)list_entry(b, struct slist_t, list)->key;
return xos_strnatcasecmp(keya, keyb);
}
slist_sort_with(sl, my_compare);
Traversal with Custom Data
struct my_data_t { int x; int y; };
struct slist_t * sl = slist_alloc();
struct my_data_t * d = xos_mem_malloc(sizeof(struct my_data_t));
d->x = 1; d->y = 2;
slist_add(sl, d, "key1");
struct slist_t * entry;
slist_for_each_entry(entry, sl)
{
struct my_data_t * data = (struct my_data_t *)entry->priv;
/* use data */
}
slist_free(sl); /* Note: free memory pointed to by priv before slist_free */