Linked List

#include "libstephen/ll.h"

The linked list struct (smb_ll) is a doubly-linked list. It is made up of a chain of nodes. Each node contains a DATA, as well as links to the next and previous nodes.

Operations

Like all other objects, smb_ll supports the four basic creation/deletion functions. They create new, empty lists. The deletion functions delete the struct and all nodes, but they won’t free any pointers contained in DATA, naturally.

Here are some operations supported by smb_ll

void ll_append(smb_ll *list, DATA newData);
void ll_prepend(smb_ll *list, DATA newData);
void ll_push_back(smb_ll *list, DATA newData);
DATA ll_pop_back(smb_ll *list, smb_status *status);
DATA ll_peek_back(smb_ll *list, smb_status *status);
void ll_push_front(smb_ll *list, DATA newData);
DATA ll_pop_front(smb_ll *list, smb_status *status);
DATA ll_peek_front(smb_ll *list, smb_status *status);
DATA ll_get(const smb_ll *list, int index, smb_status *status);
void ll_remove(smb_ll *list, int index, smb_status *status);
void ll_insert(smb_ll *list, int index, DATA newData);
void ll_set(smb_ll *list, int index, DATA newData, smb_status *status);
int  ll_length(const smb_ll *list);
int  ll_index_of(const smb_ll *list, DATA d, DATA_COMPARE comp);

This is directly from the header. The append and prepend functions are exactly what you’d expect. The push/pop/peek functions make the list act like a stack. The front ones act on the beginning of the list, and the back ones operate on the end of the list. So push_back is the same as append. get, remove, insert, and set provide your basic list access and modification functions. length tells you the length of the list (Don’t directly access the field, I don’t make any guarantee that the structs will remain the same. They’re implementation details!). index_of will find the first occurrence of a value, by a linear search.

You can create generic lists with the following functions:

smb_list ll_create_list();
smb_list ll_cast_to_list(smb_ll *list);

And you can get an iterator for a list with this function:

smb_iter ll_get_iter(const smb_ll *list);

Sample Usage

Using the linked list is pretty simple. Here, I create a list, add some numbers to it, and then free it.

smb_ll *list = ll_create();

ll_append(list, LLINT(0));
ll_append(list, LLINT(1));

ll_free(list);

Functional Programming!

One of the more recent additions to my linked list API is some high-level functions for lists - namely, map, filter, and fold. My implementations are all in-place for efficiency. Here they are:

void ll_filter(smb_ll *list, bool (*test_function)(DATA));
void ll_map(smb_ll *list, DATA (*map_function)(DATA));
DATA ll_foldl(smb_ll *list, DATA start_value, DATA (*reduction)(DATA,DATA));
DATA ll_foldr(smb_ll *list, DATA start_value, DATA (*reduction)(DATA,DATA));

Check the API documentation for full details.

Structure

The following items are implementation details, and not really necessary to use the linked list. Here is the structure of a node:

typedef struct smb_ll_node
{
  struct smb_ll_node *prev;
  struct smb_ll_node *next;
  DATA data;
} smb_ll_node;

And here is the actual linked list struct:

typedef struct smb_ll
{
  struct smb_ll_node *head;
  struct smb_ll_node *tail;
  int length;
} smb_ll;