NAME

libslack(link) - linked list module


SYNOPSIS

    #include <slack/std.h>
    #include <slack/link.h>
    typedef struct slink_t slink_t;
    typedef struct dlink_t dlink_t;
    struct slink_t
    {
        void *next;
    };
    struct dlink_t
    {
        void *next;
        void *prev;
    };
    int slink_has_next(void *link);
    void *slink_next(void *link);
    int dlink_has_next(void *link);
    void *dlink_next(void *link);
    int dlink_has_prev(void *link);
    void *dlink_prev(void *link);
    void *slink_insert(void *link, void *item);
    void *dlink_insert(void *link, void *item);
    void *slink_remove(void *link);
    void *dlink_remove(void *link);
    void *slink_freelist_init(void *freelist, size_t nelem, size_t size);
    void *dlink_freelist_init(void *freelist, size_t nelem, size_t size);
    void *slink_freelist_attach(void *freelist1, void *freelist2);
    void *dlink_freelist_attach(void *freelist1, void *freelist2);
    void *slink_alloc(void **freelist);
    void *dlink_alloc(void **freelist);
    void *slink_free(void **freelist, void *item);
    void *dlink_free(void **freelist, void *item);


DESCRIPTION

This module provides functions for manipulating singly and doubly linked lists. Two abstract types are defined: slink_t, containing a pointer to the next item, and dlink_t, containing pointers to the next and previous items. These functions work with any struct whose first element is an slink_t or a dlink_t struct. There is support for optional growable free lists so items may be dynamically allocated individually or allocated from a free list. Free lists can be arrays of structs or dynamically allocated. When a free list is exhausted, further memory may be attached to the free list to extend it.

int slink_has_next(void *link)
Returns 1 if link's next pointer is not null. Otherwise, returns 0. On error, returns -1 with errno set appropriately.

void *slink_next(void *link)
Returns link's next pointer. On error, returns null with errno set appropriately.

int dlink_has_next(void *link)
Returns 1 if link's next pointer is not null. Otherwise, returns 0. On error, returns -1 with errno set appropriately.

void *dlink_next(void *link)
Returns link's next pointer. On error, returns null with errno set appropriately.

int dlink_has_prev(void *link)
Returns 1 if link's prev pointer is not null. Otherwise, returns 0. On error, returns -1 with errno set appropriately.

void *dlink_prev(void *link)
Returns link's prev pointer. On error, returns null with errno set appropriately.

void *slink_insert(void *link, void *item)
Inserts item before link. Returns item. On error, returns null with errno set appropriately. Items may only be inserted at the beginning of a singly linked list.

void *dlink_insert(void *link, void *item)
Inserts item before link. Returns item. On error, returns null with errno set appropriately. Items may be inserted anywhere in a doubly linked list.

void *slink_remove(void *link)
Removes the first item from the list beginning with link. On success, returns link's next pointer. On error, returns null with errno set appropriately.

void *dlink_remove(void *link)
Removes link from the list of which it is part. On success, returns link's next pointer. On error, returns null with errno set appropriately.

void *slink_freelist_init(void *freelist, size_t nelem, size_t size)
Initialises an array of nelem elements each size bytes for use as a singly linked free list. On success, returns freelist. On error, returns null with errno set appropriately.

void *dlink_freelist_init(void *freelist, size_t nelem, size_t size)
Initialises an array of nelem elements each size bytes for use as a doubly linked free list. On success, returns freelist. On error, returns null with errno set appropriately.

void *slink_freelist_attach(void *freelist1, void *freelist2)
Attaches freelist2 to the end of freelist1. Both free lists must have already been initialised with slink_freelist_init(3). Note that it will not be possible to separate these free lists. On success, returns a pointer to the beginning of the combined freelist. On error, returns null with errno set appropriately.

void *dlink_freelist_attach(void *freelist1, void *freelist2)
Attaches freelist2 to the end of freelist1. Both free lists must have already been initialised with dlink_freelist_init(3). Note that it will not be possible to separate these free lists. On success, returns a pointer to the beginning of the combined freelist. On error, returns null with errno set appropriately.

void *slink_alloc(void **freelist)
Allocates an item from *freelist and updates *freelist to point to the next free item. *freelist must be a singly linked freelist initialised with slink_freelist_init(3). On success, returns the allocated item. On error, returns null with errno set appropriately.

void *dlink_alloc(void **freelist)
Allocates an item from *freelist and updates *freelist to point to the next free item. *freelist must be a doubly linked freelist initialised with dlink_freelist_init(3). On success, returns the allocated item. On error, returns null with errno set appropriately.

void *slink_free(void **freelist, void *item)
Inserts item into *freelist and updates *freelist to point to item. *freelist must be a singly linked freelist initialised with slink_freelist_init(3). On success, returns the resulting free list. On error, returns null with errno set appropriately.

void *dlink_free(void **freelist, void *item)
Inserts item into *freelist and updates *freelist to point to item. *freelist must be a doubly linked freelist initialised with dlink_freelist_init(3). On success, returns the resulting free list. On error, returns null with errno set appropriately.


ERRORS

The following errors are returned by these functions.

EINVAL
When null pointers are incorrectly passed as arguments to most functions.

ENOSPC
When slink_alloc(3) or dlink_alloc(3) is called and the free list is exhausted.


MT-Level

Unsafe

This module declares abstract types. They must be used as part of larger data structures. It is assumed that the surrounding data structure and its functions will provide any locking that is required.


BUGS

These functions only work on structs where the next and prev pointers at the first elements. To fix this would require adding an offset parameter to each function to tell it where the next and prev pointers where within the item. It's probably not worth it.

Attached free lists can't be detached. To fix this would require more code and more metadata. Again, it's probably not worth it.


SEE ALSO

libslack(3), list(3), map(3), mem(3), locker(3)


AUTHOR

20020916 raf <raf@raf.org>