llwfp

A C library for singly linked lists
Login

A C library for singly linked lists

⇦ previousnext ⇨

4. Add functionality for both node and data handling

Let the list of node and data handling functions grow.
This makes it easier to see how to continue from here, how to logically split up the source code in separate files into a (sort-of) organized library.

Spoiler:
Due to the added functionality, the source code example in this section has grown considerably compared to the previous examples, and many of the functions have been renamed, so the example in this section has little in common with the previous ones.

4.1. Data size

Working with generic node data, the programmer must provide the library with the data size in one way or another.
There are basically three ways:

  1. Explicitly set the data size as an argument to node_add_size(), which handles errors, allocates memory, and copies node data.
  2. Set the data size in a "size-only" user-defined callback, which should do nothing but return the data size.
    Pass the callback to node_add(), which handles errors, allocates memory, and copies data.
  3. Use a "complete" user-defined function as callback to node_add().
    The user-defined function should handle both memory allocation memory and copying data, and return 0 (or -1 in case of error). In this case, node_add() only handles errors.

1. Example using explicit size:

   int data1 = 42;
   node_add_size(&head, &data1, sizeof(data1));

2. Example using a callback to a "size-only" function, return data size:

    /* User-defined function, only returns data size */
    size_t add_int_size_only(void **node_data, void *data)
    {
        (void)node_data; (void)data; return sizeof(int);
    }

    /* Add a node, allocate and copy data in add_int() */
    int data1 = 42;
    node_add(&head, &data1, add_int_size_only);

3. Example using a callback to a "complete" function, return 0:

    /* User-defined function, takes care of both allocating memory and copying data */
    size_t add_int(void **node_data, void *data)
    {
      size_t alloc_size = sizeof(*(int *)data);
      if ((*node_data = calloc(1, alloc_size)) == NULL) return -1;
      memcpy(*node_data, data, sizeof(int));
      return 0;
    }

    /* Add a node, allocate and copy data in add_int() */
    int data1 = 42;
    node_add(&head, &data1, add_int);

Here is how node_add() internally handles cases 2 and 3:

    int rc = 0;
    /* Call the user-defined function */
    /* If the 'add_func' callback is a "complete" function, we're done */
    if ((rc = add_func(&(new_node->data), data)) == ERROR)
    {
      /* Handle errors */
      free(new_node);
      return ERROR;
    }
    else if (rc > 0)
    {
      /* If the 'add_func' callback only returns a size, handle data of that size here. */
      size_t data_size = (size_t)rc;
      new_node->data = data_init(data_size);
      memmove(new_node->data, data, data_size);
    }

4.2. Added node/list functionality

Node function list has grown, and list functions have also been added.
Generally, functions with prefix node_ handles one single node (well, node_swap() actually affects two nodes). Functions with prefix list_ deals with either an entire list, or a range of nodes.
See the API for the final list of functions.

Node functions:

    node_add()      - add new node with value
    node_add_size() - add new node with value of given data size
    node_get()      - get a pointer to a node. No need to free().
    node_copy()     - get a deep copy of a node. Has to be free():d.
    node_move()     - move a node from one position to another, or from one list to another
    node_swap()     - swap positions for two nodes, within the same list, or between two lists
    node_set()      - set node value
    node_set_size() - set node value with given data size
    node_print()    - print node data
    node_del()      - delete a node
    node_index()    - validate an index given as argument
    node_appendp()  - append an existing node to the end of a list. The node should be obtained by either get() or copy().
    node_prependp() - prepend an existing node at the beginning of a list
    node_insertp()  - insert an existing node at a given index of a list

List functions:

    list_count()         - number of nodes in a list
    list_copy()          - get a deep copy of an existing list as a new list
    list_copy_range()    - get a deep copy of a range of nodes as a new list
    list_copy_matching() - get a deep copy of nodes matching a condition as a new list
    list_set_range()     - modify a range of nodes in an existing list
    list_set_matching()  - modify matching nodes in an existing list
    list_del_range()     - delete a range of nodes in a list
    list_del_matching()  - delete matching nodes in a list
    list_del_dup()       - delete duplicated nodes in a list
    list_sort()          - sort a list using a callback for the sort algorithm
    list_rev()           - reverse a list
    list_split()         - split a list at a given index
    list_join()          - join two lists
    list_map()           - generate a result list applying a callback on each element of an existing list
    list_print()         - print data for all nodes in a list

Aliases:

    node_prepend()     -> node_add(0)
    node_append()      -> node_add(-1)
    node_get_head()    -> node_get(0)
    node_get_tail()    -> node_get(-1)
    node_set_head()    -> node_get(0)
    node_set_tail()    -> node_get(-1)
    node_del_head()    -> node_del(0)
    node_del_tail()    -> node_del(-1)

    list_set()         -> list_set_range(0, -1) modify all nodes in an existing list
    list_del()         -> list_del_range(0, -1) delete all nodes in a list
    list_del_from(pos) -> list_del_range(pos, -1)
    list_del_to(pos)   -> list_del_range(0, pos)

4.3. About this example

This example adds lots of functions for handling lists, nodes, and node data, and also test code for those functions.
This example is much more extensive than the previous one, with little code in common.

⇦ previousnext ⇨