SimCList: a sneak peak into the API

l.u. 04/01/2006

There are some snippets of code using lists with SimCList. They are meant to introduce to the API with trivial solutions, not to express how the library is powerful.

Basic data type usage

This is the typical code for importing the library, specifying and preparing a list object for use, do something and dismiss it:

#include <simclist.h>
...
    list_t mylist;

    list_init(&mylist);
    ...
    list_destroy(&mylist);
...
            

Basic insertion and extraction

All library functions are list_something() and take a reference to the list to operate as first argument. This introduces some more functions:

#include <stdio.h>

#include <simclist.h>   /* use the SimCList library */


int main() {
    list_t mylist;      /* declare a list */
    int userval;


    list_init(& mylist);    /* initialize the list */

    printf("Insert your number: ");
    scanf("%d", & userval);

    list_append(& mylist, & userval);       /* add an element to the list */

    printf("The list now holds %u elements.\n", \
            list_size(& mylist));           /* get the size of the list */

    printf("Your number was: %d\n", \
            * (int*)list_get_at(& mylist, 0));  /* extract the first element of the list */

    list_destroy(&mylist);

    return 0;
}
           

Using element autocopy

The list stores elements as references by default. In the above example, you cannot list_append() twice &userval for two different user values, as the former element will also update. SimCList is able to insert photocopies of elements for you, and not the elements passed themselves. For the list to do so, you must provide a metric function to it, that tells how long each element is. Some ready-made metric functions are available for the most popular data types: integers, decimal types and strings.

#include <stdio.h>

#include <simclist.h>

int main() {
    int val;
    list_t l;

    list_init(&l);

    /* request to store copies, and provide the metric function */
    list_attributes_copy(&l, list_meter_int32_t, 1);

    printf("Give numbers. Terminate with one negative.\n");
    scanf("%d", &val);
    while (val > 0) {
        list_append(&l, &val);
        scanf("%d", &val);
    }

    /* setting the comparator, so the list can sort, find the min, max etc */
    list_attributes_comparator(&l, list_comparator_int32_t);
    list_sort(&l, -1);      /* sorting the list in descending (-1) order */

    /* printing out the result */
    printf("Sorted values:\n");

    list_iterator_start(&l);        /* starting an iteration "session" */
    while (list_iterator_hasnext(&l)) { /* tell whether more values available */
        printf("%d\n", *(int *)list_iterator_next(&l));     /* get the next value */
    }
    list_iterator_stop(&l);         /* ending the iteration "session" */

    list_destroy(&l);

    return 0;
}

When the elements of the list have a custom type, custom functions must be specified for comparing, spanning, and hashing them. The following code gives an example of this, for a list of rectangle items:

#include <stdio.h>

#include <simclist.h>

typedef struct {
    int x, y;
} point2D;

typedef struct {
    point2D a, b, c, d;
} rectangle;    /* custom data type to store in list */

/* this function returns the size of elements */
size_t mymeter(const void *el) {
    /* every element has the constant size of a rectangle structure */
    return sizeof(rectangle);
}

/*
 * compare rectangles by area
 * 
 * this function compares two elements:
 * <0: a greater than b
 * 0: a equivalent to b
 * >0: b greater than a
 */
int mycomparator(const void *a, const void *b) {
    /* compare areas */
    const rectangle *A = (rectangle *) a;
    const rectangle *B = (rectangle *) b;
    unsigned int    areaA, areaB;
    areaA = ((A->c.y - A->b.y) * (A->b.x - A->a.x));
    areaB = ((B->c.y - B->b.y) * (B->b.x - B->a.x));
    return (areaA < areaB) - (areaA > areaB);
}

int main() {
    rectangle rect;
    list_t l;

    list_init(&l);

    /* setting the custom spanning function */
    list_attributes_copy(&l, mymeter, 1);

    /* acquire rectangles and insert in list ... */

    /* setting the custom area comparator */
    list_attributes_comparator(&l, mycomparator);
    list_sort(&l, -1);  /* sorting by area (descending) */

    /* [display list ...] */

    list_destroy(&l);

    return 0;
}

List dump and restore

It is sometimes useful to preserve the content of the list across diffent runs of a program. SimCList supports this natively with a bunch of list_dump_*() and list_restore_*() functions. The output format of SimCList is portable across different hosts (with different byte orders or data type lengths).

Because the data type to store is unknown to the list, for storing elements it is necessary to provide the element meter for the list to span correctly the length of each element. This is not necessary for restoring the list into memory because simclist can extract autonomously this information from its dump.

#include <simclist.h>

int main() {
    list_t mylist;      /* list to be used for storing strings */

    list_init(&mylist);
    /* provide the function to span the extent of elements */
    list_attributes_copy(& mylist, list_meter_string, 0);

    /* operate the list, insert elements ... */

    /* dump the list content to a file */
    list_dump_file(&mylist, "mylist.simc");

    list_destroy(&mylist);

    return 0;
}
#include <simclist.h>

int main() {
    list_t mylist;

    list_init(&mylist);

    /* restore the list content from the persistent storage into memory */
    list_restore_file(&mylist, "mylist.simc");

    /* operate the list ... */

    list_destroy(&mylist);
    return 0;
}

Element seeking

When the list is used to store structures, it comes frequently useful to extract elements by one specific field. While this is possible using an opportune comparator as seen previously, this is uncomfortable because a fake seeker structure has to be built for every search. SimCList provides a convienient way for performing element seeking with a specific seeker function that points when an element matches a search key of any kind.

#include <stdio.h>
#include <simclist.h>

/* data structure to use as element of the list */
struct contact_s {
    unsigned int ID;
    char name[20], surname[20];
    char phone[20];
    int dept;
};

/* return "match" when the contact ID matches the key */
int seeker(const void *el, const void *key) {
    /* let's assume el and key being always != NULL */
    const struct contact_s *cont = (struct contact_s *)el;

    if (cont->ID == *(unsigned int *)key)
        return 1;
    return 0;
}

#define MAX_ID      100

int main() {
    list_t employees;
    struct contact_s *empl;
    unsigned int i;


    list_init(& employees);
    /* set the custom seeker function */
    list_attributes_seeker(& employees, seeker);

    /* make some insertions ... */

    for (i = 0; i < MAX_ID; i++) {
        /* "seek" the element, by ID */
        empl = (struct contact_s *)list_seek(& employees, & i);
        if (empl != NULL)
            printf("Employee %u is '%s, %s'.\n", i, empl->surname, empl->name);
        else
            printf("%u has been apparently fired.\n", i);
    }

    list_destroy(& employees);
    return 0;
}

For more advanced topics, have a look at the simclist documentation: