[Pcsclite-cvs-commit] r4426 - in /trunk/PCSC/src: simclist.c simclist.h

rousseau at users.alioth.debian.org rousseau at users.alioth.debian.org
Tue Oct 6 08:29:51 UTC 2009


Author: rousseau
Date: Tue Oct  6 08:29:51 2009
New Revision: 4426

URL: http://svn.debian.org/wsvn/pcsclite/?sc=1&rev=4426
Log:
Library to manage lists
Fetched from http://mij.oltrelinux.com/devel/simclist/

Added:
    trunk/PCSC/src/simclist.c   (with props)
    trunk/PCSC/src/simclist.h   (with props)

Added: trunk/PCSC/src/simclist.c
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/simclist.c?rev=4426&op=file
==============================================================================
--- trunk/PCSC/src/simclist.c (added)
+++ trunk/PCSC/src/simclist.c Tue Oct  6 08:29:51 2009
@@ -1,0 +1,1407 @@
+/*
+ * Copyright (c) 2007,2008,2009 Mij <mij at bitchx.it>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*
+ * SimCList library. See http://mij.oltrelinux.com/devel/simclist
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>      /* for setting errno */
+#include <inttypes.h>   /* (u)int*_t */
+#include <sys/types.h>
+#include <sys/uio.h>    /* for READ_ERRCHECK() and write() */
+#include <fcntl.h>      /* for open() etc */
+#include <arpa/inet.h>  /* for htons() */
+#include <unistd.h>
+#include <time.h>       /* for time() for random seed */
+#include <sys/time.h>   /* for gettimeofday() */
+#include <sys/stat.h>   /* for open()'s access modes S_IRUSR etc */
+#include <limits.h>
+#include <stdint.h>
+
+
+/* use rand() in place of srand()? */
+#ifndef _BSD_SOURCE
+#   define random       rand
+#   define srandom      srand
+#endif
+
+
+#ifndef SIMCLIST_NO_DUMPRESTORE
+/* convert 64bit integers from host to network format */
+#define hton64(x)       (\
+        htons(1) == 1 ?                                         \
+            (uint64_t)x      /* big endian */                   \
+        :       /* little endian */                             \
+        ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \
+            (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
+            (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
+            (((uint64_t)(x) & 0x000000ff00000000ULL) >>  8) | \
+            (((uint64_t)(x) & 0x00000000ff000000ULL) <<  8) | \
+            (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
+            (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
+            (((uint64_t)(x) & 0x00000000000000ffULL) << 56)))   \
+        )
+
+/* convert 64bit integers from network to host format */
+#define ntoh64(x)       (hton64(x))
+#endif
+
+/* some OSes don't have EPROTO (eg OpenBSD) */
+#ifndef EPROTO
+#define EPROTO  EIO
+#endif
+
+/* disable asserts */
+#ifndef SIMCLIST_DEBUG
+#define NDEBUG
+#endif
+
+#include <assert.h>
+
+#ifdef SIMCLIST_WITH_THREADS
+/* limit (approx) to the number of threads running
+ * for threaded operations. Only meant when
+ * SIMCLIST_WITH_THREADS is defined */
+#define SIMCLIST_MAXTHREADS   2
+#endif
+
+/*
+ * how many elems to keep as spare. During a deletion, an element
+ * can be saved in a "free-list", not free()d immediately. When
+ * latter insertions are performed, spare elems can be used instead
+ * of malloc()ing new elems.
+ *
+ * about this param, some values for appending
+ * 10 million elems into an empty list:
+ * (#, time[sec], gain[%], gain/no[%])
+ * 0    2,164   0,00    0,00    <-- feature disabled
+ * 1    1,815   34,9    34,9
+ * 2    1,446   71,8    35,9    <-- MAX gain/no
+ * 3    1,347   81,7    27,23
+ * 5    1,213   95,1    19,02
+ * 8    1,064   110,0   13,75
+ * 10   1,015   114,9   11,49   <-- MAX gain w/ likely sol
+ * 15   1,019   114,5   7,63
+ * 25   0,985   117,9   4,72
+ * 50   1,088   107,6   2,15
+ * 75   1,016   114,8   1,53
+ * 100  0,988   117,6   1,18
+ * 150  1,022   114,2   0,76
+ * 200  0,939   122,5   0,61    <-- MIN time
+ */
+#ifndef SIMCLIST_MAX_SPARE_ELEMS
+#define SIMCLIST_MAX_SPARE_ELEMS        5
+#endif
+
+
+#ifdef SIMCLIST_WITH_THREADS
+#include <pthread.h>
+#endif
+
+#include "simclist.h"
+
+
+/* minumum number of elements for sorting with quicksort instead of insertion */
+#define SIMCLIST_MINQUICKSORTELS        24
+
+
+/* list dump declarations */
+#define SIMCLIST_DUMPFORMAT_VERSION     1   /* (short integer) version of fileformat managed by _dump* and _restore* functions */
+
+#define SIMCLIST_DUMPFORMAT_HEADERLEN   30  /* length of the header */
+
+/* header for a list dump */
+struct list_dump_header_s {
+    uint16_t ver;               /* version */
+    int64_t timestamp;          /* dump timestamp */
+    int32_t rndterm;            /* random value terminator -- terminates the data sequence */
+
+    uint32_t totlistlen;        /* sum of every element' size, bytes */
+    uint32_t numels;            /* number of elements */
+    uint32_t elemlen;           /* bytes length of an element, for constant-size lists, <= 0 otherwise */
+    int32_t listhash;           /* hash of the list at the time of dumping, or 0 if to be ignored */
+};
+
+
+
+/* deletes tmp from list, with care wrt its position (head, tail, middle) */
+static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos);
+
+/* set default values for initialized lists */
+static int list_attributes_setdefaults(list_t *restrict l);
+
+#ifndef NDEBUG
+/* check whether the list internal REPresentation is valid -- Costs O(n) */
+static int list_repOk(const list_t *restrict l);
+
+/* check whether the list attribute set is valid -- Costs O(1) */
+static int list_attrOk(const list_t *restrict l);
+#endif
+
+/* do not inline, this is recursive */
+static void list_sort_quicksort(list_t *restrict l, int versus, 
+        unsigned int first, struct list_entry_s *fel,
+        unsigned int last, struct list_entry_s *lel);
+
+static inline void list_sort_selectionsort(list_t *restrict l, int versus, 
+        unsigned int first, struct list_entry_s *fel,
+        unsigned int last, struct list_entry_s *lel);
+
+static void *list_get_minmax(const list_t *restrict l, int versus);
+
+static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart);
+
+/* write() decorated with error checking logic */
+#define WRITE_ERRCHECK(fd, msgbuf, msglen)      do {                                                    \
+                                                    if (write(fd, msgbuf, msglen) < 0) return -1;       \
+                                                } while (0);
+/* READ_ERRCHECK() decorated with error checking logic */
+#define READ_ERRCHECK(fd, msgbuf, msglen)      do {                                                     \
+                                                    if (read(fd, msgbuf, msglen) != msglen) {           \
+                                                        /*errno = EPROTO;*/                             \
+                                                        return -1;                                      \
+                                                    }                                                   \
+                                                } while (0);
+
+
+/* list initialization */
+int list_init(list_t *restrict l) {
+    if (l == NULL) return -1;
+
+    srandom((unsigned long)time(NULL));
+
+    l->numels = 0;
+
+    /* head/tail sentinels and mid pointer */
+    l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+    l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+    l->head_sentinel->next = l->tail_sentinel;
+    l->tail_sentinel->prev = l->head_sentinel;
+    l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL;
+    l->head_sentinel->data = l->tail_sentinel->data = NULL;
+
+    /* iteration attributes */
+    l->iter_active = 0;
+    l->iter_pos = 0;
+    l->iter_curentry = NULL;
+
+    /* free-list attributes */
+    l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *));
+    l->spareelsnum = 0;
+
+#ifdef SIMCLIST_WITH_THREADS
+    l->threadcount = 0;
+#endif
+
+    list_attributes_setdefaults(l);
+
+    assert(list_repOk(l));
+    assert(list_attrOk(l));
+
+    return 0;
+}
+
+void list_destroy(list_t *restrict l) {
+    unsigned int i;
+
+    list_clear(l);
+    for (i = 0; i < l->spareelsnum; i++) {
+        free(l->spareels[i]);
+    }
+    free(l->spareels);
+    free(l->head_sentinel);
+    free(l->tail_sentinel);
+}
+
+int list_attributes_setdefaults(list_t *restrict l) {
+    l->attrs.comparator = NULL;
+    l->attrs.seeker = NULL;
+
+    /* also free() element data when removing and element from the list */
+    l->attrs.meter = NULL;
+    l->attrs.copy_data = 0;
+
+    l->attrs.hasher = NULL;
+
+    /* serializer/unserializer */
+    l->attrs.serializer = NULL;
+    l->attrs.unserializer = NULL;
+
+    assert(list_attrOk(l));
+    
+    return 0;
+}
+
+/* setting list properties */
+int list_attributes_comparator(list_t *restrict l, element_comparator comparator_fun) {
+    if (l == NULL) return -1;
+
+    l->attrs.comparator = comparator_fun;
+
+    assert(list_attrOk(l));
+    
+    return 0;
+}
+
+int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun) {
+    if (l == NULL) return -1;
+
+    l->attrs.seeker = seeker_fun;
+    assert(list_attrOk(l));
+
+    return 0;
+}
+
+int list_attributes_copy(list_t *restrict l, element_meter metric_fun, int copy_data) {
+    if (l == NULL || (metric_fun == NULL && copy_data != 0)) return -1;
+
+    l->attrs.meter = metric_fun;
+    l->attrs.copy_data = copy_data;
+
+    assert(list_attrOk(l));
+
+    return 0;
+}
+
+int list_attributes_hash_computer(list_t *restrict l, element_hash_computer hash_computer_fun) {
+    if (l == NULL) return -1;
+
+    l->attrs.hasher = hash_computer_fun;
+    assert(list_attrOk(l));
+    return 0;
+}
+
+int list_attributes_serializer(list_t *restrict l, element_serializer serializer_fun) {
+    if (l == NULL) return -1;
+
+    l->attrs.serializer = serializer_fun;
+    assert(list_attrOk(l));
+    return 0;
+}
+
+int list_attributes_unserializer(list_t *restrict l, element_unserializer unserializer_fun) {
+    if (l == NULL) return -1;
+
+    l->attrs.unserializer = unserializer_fun;
+    assert(list_attrOk(l));
+    return 0;
+}
+
+int list_append(list_t *restrict l, const void *data) {
+    return list_insert_at(l, data, l->numels);
+}
+
+int list_prepend(list_t *restrict l, const void *data) {
+    return list_insert_at(l, data, 0);
+}
+
+void *list_fetch(list_t *restrict l) {
+    return list_extract_at(l, 0);
+}
+
+void *list_get_at(const list_t *restrict l, unsigned int pos) {
+    struct list_entry_s *tmp;
+
+    tmp = list_findpos(l, pos);
+
+    return (tmp != NULL ? tmp->data : NULL);
+}
+
+void *list_get_max(const list_t *restrict l) {
+    return list_get_minmax(l, +1);
+}
+
+void *list_get_min(const list_t *restrict l) {
+    return list_get_minmax(l, -1);
+}
+
+/* REQUIRES {list->numels >= 1}
+ * return the min (versus < 0) or max value (v > 0) in l */
+static void *list_get_minmax(const list_t *restrict l, int versus) {
+    void *curminmax;
+    struct list_entry_s *s;
+
+    if (l->attrs.comparator == NULL || l->numels == 0)
+        return NULL;
+    
+    curminmax = l->head_sentinel->next->data;
+    for (s = l->head_sentinel->next->next; s != l->tail_sentinel; s = s->next) {
+        if (l->attrs.comparator(curminmax, s->data) * versus > 0)
+            curminmax = s->data;
+    }
+
+    return curminmax;
+}
+
+/* set tmp to point to element at index posstart in l */
+static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) {
+    struct list_entry_s *ptr;
+    float x;
+    int i;
+
+    /* accept 1 slot overflow for fetching head and tail sentinels */
+    if (posstart < -1 || posstart > (int)l->numels) return NULL;
+
+    x = (float)(posstart+1) / l->numels;
+    if (x <= 0.25) {
+        /* first quarter: get to posstart from head */
+        for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++);
+    } else if (x < 0.5) {
+        /* second quarter: get to posstart from mid */
+        for (i = (l->numels-1)/2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--);
+    } else if (x <= 0.75) {
+        /* third quarter: get to posstart from mid */
+        for (i = (l->numels-1)/2, ptr = l->mid; i < posstart; ptr = ptr->next, i++);
+    } else {
+        /* fourth quarter: get to posstart from tail */
+        for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--);
+    }
+
+    return ptr;
+}
+
+void *list_extract_at(list_t *restrict l, unsigned int pos) {
+    struct list_entry_s *tmp;
+    void *data;
+    
+    if (l->iter_active || pos >= l->numels) return NULL;
+
+    tmp = list_findpos(l, pos);
+    data = tmp->data;
+
+    tmp->data = NULL;   /* save data from list_drop_elem() free() */
+    list_drop_elem(l, tmp, pos);
+    l->numels--;
+    
+    assert(list_repOk(l));
+
+    return data;
+}
+
+int list_insert_at(list_t *restrict l, const void *data, unsigned int pos) {
+    struct list_entry_s *lent, *succ, *prec;
+    
+    if (l->iter_active || pos > l->numels) return -1;
+    
+    /* this code optimizes malloc() with a free-list */
+    if (l->spareelsnum > 0) {
+        lent = l->spareels[l->spareelsnum-1];
+        l->spareelsnum--;
+    } else {
+        lent = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+        if (lent == NULL)
+            return -1;
+    }
+
+    if (l->attrs.copy_data) {
+        /* make room for user' data (has to be copied) */
+        size_t datalen = l->attrs.meter(data);
+        lent->data = (struct list_entry_s *)malloc(datalen);
+        memcpy(lent->data, data, datalen);
+    } else {
+        lent->data = (void*)data;
+    }
+
+    /* actually append element */
+    prec = list_findpos(l, pos-1);
+    succ = prec->next;
+    
+    prec->next = lent;
+    lent->prev = prec;
+    lent->next = succ;
+    succ->prev = lent;
+
+    l->numels++;
+
+    /* fix mid pointer */
+    if (l->numels == 1) { /* first element, set pointer */
+        l->mid = lent;
+    } else if (l->numels % 2) {    /* now odd */
+        if (pos >= (l->numels-1)/2) l->mid = l->mid->next;
+    } else {                /* now even */
+        if (pos <= (l->numels-1)/2) l->mid = l->mid->prev;
+    }
+
+    assert(list_repOk(l));
+
+    return 1;
+}
+
+int list_delete_at(list_t *restrict l, unsigned int pos) {
+    struct list_entry_s *delendo;
+
+
+    if (l->iter_active || pos >= l->numels) return -1;
+
+    delendo = list_findpos(l, pos);
+
+    list_drop_elem(l, delendo, pos);
+
+    l->numels--;
+
+
+    assert(list_repOk(l));
+
+    return  0;
+}
+
+int list_delete_range(list_t *restrict l, unsigned int posstart, unsigned int posend) {
+    struct list_entry_s *lastvalid, *tmp, *tmp2;
+    unsigned int i;
+    int movedx;
+    unsigned int numdel, midposafter;
+
+    if (l->iter_active || posend < posstart || posend >= l->numels) return -1;
+
+    tmp = list_findpos(l, posstart);    /* first el to be deleted */
+    lastvalid = tmp->prev;              /* last valid element */
+
+    numdel = posend - posstart + 1;
+    midposafter = (l->numels-1-numdel)/2;
+
+    midposafter = midposafter < posstart ? midposafter : midposafter+numdel;
+    movedx = midposafter - (l->numels-1)/2;
+
+    if (movedx > 0) { /* move right */
+        for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->next, i++);
+    } else {    /* move left */
+        movedx = -movedx;
+        for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->prev, i++);
+    }
+
+    assert(posstart == 0 || lastvalid != l->head_sentinel);
+    i = posstart;
+    if (l->attrs.copy_data) {
+        /* also free element data */
+        for (; i <= posend; i++) {
+            tmp2 = tmp;
+            tmp = tmp->next;
+            if (tmp2->data != NULL) free(tmp2->data);
+            if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
+                l->spareels[l->spareelsnum++] = tmp2;
+            } else {
+                free(tmp2);
+            }
+        }
+    } else {
+        /* only free containers */
+        for (; i <= posend; i++) {
+            tmp2 = tmp;
+            tmp = tmp->next;
+            if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
+                l->spareels[l->spareelsnum++] = tmp2;
+            } else {
+                free(tmp2);
+            }
+        }
+    }
+    assert(i == posend+1 && (posend != l->numels || tmp == l->tail_sentinel));
+
+    lastvalid->next = tmp;
+    tmp->prev = lastvalid;
+
+    l->numels -= posend - posstart + 1;
+
+    assert(list_repOk(l));
+
+    return 0;
+}
+
+int list_clear(list_t *restrict l) {
+    struct list_entry_s *s;
+
+    if (l->iter_active) return -1;
+    
+    if (l->attrs.copy_data) {        /* also free user data */
+        /* spare a loop conditional with two loops: spareing elems and freeing elems */
+        for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) {
+            /* move elements as spares as long as there is room */
+            if (s->data != NULL) free(s->data);
+            l->spareels[l->spareelsnum++] = s;
+        }
+        while (s != l->tail_sentinel) {
+            /* free the remaining elems */
+            if (s->data != NULL) free(s->data);
+            s = s->next;
+            free(s->prev);
+        }
+        l->head_sentinel->next = l->tail_sentinel;
+        l->tail_sentinel->prev = l->head_sentinel;
+    } else { /* only free element containers */
+        /* spare a loop conditional with two loops: spareing elems and freeing elems */
+        for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) {
+            /* move elements as spares as long as there is room */
+            l->spareels[l->spareelsnum++] = s;
+        }
+        while (s != l->tail_sentinel) {
+            /* free the remaining elems */
+            s = s->next;
+            free(s->prev);
+        }
+        l->head_sentinel->next = l->tail_sentinel;
+        l->tail_sentinel->prev = l->head_sentinel;
+    }
+    l->numels = 0;
+    l->mid = NULL;
+
+    assert(list_repOk(l));
+
+    return 0;
+}
+
+unsigned int list_size(const list_t *restrict l) {
+    return l->numels;
+}
+
+int list_empty(const list_t *restrict l) {
+    return (l->numels == 0);
+}
+
+int list_locate(const list_t *restrict l, const void *data) {
+    struct list_entry_s *el;
+    int pos = 0;
+    
+    if (l->attrs.comparator != NULL) {
+        /* use comparator */
+        for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) {
+            if (l->attrs.comparator(data, el->data) == 0) break;
+        }
+    } else {
+        /* compare references */
+        for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) {
+            if (el->data == data) break;
+        }
+    }
+    if (el == l->tail_sentinel) return -1;
+
+    return pos;
+}
+
+void *list_seek(list_t *restrict l, const void *indicator) {
+    const struct list_entry_s *iter;
+
+    if (l->attrs.seeker == NULL) return NULL;
+
+    for (iter = l->head_sentinel->next; iter != l->tail_sentinel; iter = iter->next) {
+        if (l->attrs.seeker(iter->data, indicator) != 0) return iter->data;
+    }
+
+    return NULL;
+}
+
+int list_contains(const list_t *restrict l, const void *data) {
+    return (list_locate(l, data) >= 0);
+}
+
+int list_concat(const list_t *l1, const list_t *l2, list_t *restrict dest) {
+    struct list_entry_s *el, *srcel;
+    unsigned int cnt;
+    int err;
+
+
+    if (l1 == NULL || l2 == NULL || dest == NULL || l1 == dest || l2 == dest)
+        return -1;
+
+    list_init(dest);
+
+    dest->numels = l1->numels + l2->numels;
+    if (dest->numels == 0)
+        return 0;
+
+    /* copy list1 */
+    srcel = l1->head_sentinel->next;
+    el = dest->head_sentinel;
+    while (srcel != l1->tail_sentinel) {
+        el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+        el->next->prev = el;
+        el = el->next;
+        el->data = srcel->data;
+        srcel = srcel->next;
+    }
+    dest->mid = el;     /* approximate position (adjust later) */
+    /* copy list 2 */
+    srcel = l2->head_sentinel->next;
+    while (srcel != l2->tail_sentinel) {
+        el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
+        el->next->prev = el;
+        el = el->next;
+        el->data = srcel->data;
+        srcel = srcel->next;
+    }
+    el->next = dest->tail_sentinel;
+    dest->tail_sentinel->prev = el;
+    
+    /* fix mid pointer */
+    err = l2->numels - l1->numels;
+    if ((err+1)/2 > 0) {        /* correct pos RIGHT (err-1)/2 moves */
+        err = (err+1)/2;
+        for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->next;
+    } else if (err/2 < 0) { /* correct pos LEFT (err/2)-1 moves */
+        err = -err/2;
+        for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->prev;
+    }
+ 
+    assert(!(list_repOk(l1) && list_repOk(l2)) || list_repOk(dest));
+
+    return 0;
+}
+
+int list_sort(list_t *restrict l, int versus) {
+    if (l->iter_active || l->attrs.comparator == NULL) /* cannot modify list in the middle of an iteration */
+        return -1;
+
+    if (l->numels <= 1)
+        return 0;
+    list_sort_quicksort(l, versus, 0, l->head_sentinel->next, l->numels-1, l->tail_sentinel->prev);
+    assert(list_repOk(l));
+    return 0;
+}
+
+#ifdef SIMCLIST_WITH_THREADS
+struct list_sort_wrappedparams {
+    list_t *restrict l;
+    int versus;
+    unsigned int first, last;
+    struct list_entry_s *fel, *lel;
+};
+
+static void *list_sort_quicksort_threadwrapper(void *wrapped_params) {
+    struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)wrapped_params;
+    list_sort_quicksort(wp->l, wp->versus, wp->first, wp->fel, wp->last, wp->lel);
+    free(wp);
+    pthread_exit(NULL);
+    return NULL;
+}
+#endif
+
+static inline void list_sort_selectionsort(list_t *restrict l, int versus, 
+        unsigned int first, struct list_entry_s *fel,
+        unsigned int last, struct list_entry_s *lel) {
+    struct list_entry_s *cursor, *toswap, *firstunsorted;
+    void *tmpdata;
+
+    if (last <= first) /* <= 1-element lists are always sorted */
+        return;
+    
+    for (firstunsorted = fel; firstunsorted != lel; firstunsorted = firstunsorted->next) {
+        /* find min or max in the remainder of the list */
+        for (toswap = firstunsorted, cursor = firstunsorted->next; cursor != lel->next; cursor = cursor->next)
+            if (l->attrs.comparator(toswap->data, cursor->data) * -versus > 0) toswap = cursor;
+        if (toswap != firstunsorted) { /* swap firstunsorted with toswap */
+            tmpdata = firstunsorted->data;
+            firstunsorted->data = toswap->data;
+            toswap->data = tmpdata;
+        }
+    }
+}
+
+static void list_sort_quicksort(list_t *restrict l, int versus, 
+        unsigned int first, struct list_entry_s *fel,
+        unsigned int last, struct list_entry_s *lel) {
+    unsigned int pivotid;
+    unsigned int i;
+    register struct list_entry_s *pivot;
+    struct list_entry_s *left, *right;
+    void *tmpdata;
+#ifdef SIMCLIST_WITH_THREADS
+    pthread_t tid;
+    int traised;
+#endif
+
+
+    if (last <= first)      /* <= 1-element lists are always sorted */
+        return;
+    
+    if (last - first+1 <= SIMCLIST_MINQUICKSORTELS) {
+        list_sort_selectionsort(l, versus, first, fel, last, lel);
+        return;
+    }
+    
+    /* base of iteration: one element list */
+    if (! (last > first)) return;
+
+    pivotid = (random() % (last - first + 1));
+    /* pivotid = (last - first + 1) / 2; */
+
+    /* find pivot */
+    if (pivotid < (last - first + 1)/2) {
+        for (i = 0, pivot = fel; i < pivotid; pivot = pivot->next, i++);
+    } else {
+        for (i = last - first, pivot = lel; i > pivotid; pivot = pivot->prev, i--);
+    }
+
+    /* smaller PIVOT bigger */
+    left = fel;
+    right = lel;
+    /* iterate     --- left ---> PIV <--- right --- */
+    while (left != pivot && right != pivot) {
+        for (; left != pivot && (l->attrs.comparator(left->data, pivot->data) * -versus <= 0); left = left->next);
+        /* left points to a smaller element, or to pivot */
+        for (; right != pivot && (l->attrs.comparator(right->data, pivot->data) * -versus >= 0); right = right->prev);
+        /* right points to a bigger element, or to pivot */
+        if (left != pivot && right != pivot) {
+            /* swap, then move iterators */
+            tmpdata = left->data;
+            left->data = right->data;
+            right->data = tmpdata;
+
+            left = left->next;
+            right = right->prev;
+        }
+    }
+
+    /* now either left points to pivot (end run), or right */
+    if (right == pivot) {    /* left part longer */
+        while (left != pivot) {
+            if (l->attrs.comparator(left->data, pivot->data) * -versus > 0) {
+                tmpdata = left->data;
+                left->data = pivot->prev->data;
+                pivot->prev->data = pivot->data;
+                pivot->data = tmpdata;
+                pivot = pivot->prev;
+                pivotid--;
+                if (pivot == left) break;
+            } else {
+                left = left->next;
+            }
+        }
+    } else {                /* right part longer */
+        while (right != pivot) {
+            if (l->attrs.comparator(right->data, pivot->data) * -versus < 0) {
+                /* move current right before pivot */
+                tmpdata = right->data;
+                right->data = pivot->next->data;
+                pivot->next->data = pivot->data;
+                pivot->data = tmpdata;
+                pivot = pivot->next;
+                pivotid++;
+                if (pivot == right) break;
+            } else {
+                right = right->prev;
+            }
+        }
+    }
+
+    /* sort sublists A and B :       |---A---| pivot |---B---| */
+
+#ifdef SIMCLIST_WITH_THREADS
+    traised = 0;
+    if (pivotid > 0) {
+        /* prepare wrapped args, then start thread */
+        if (l->threadcount < SIMCLIST_MAXTHREADS-1) {
+            struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)malloc(sizeof(struct list_sort_wrappedparams));
+            l->threadcount++;
+            traised = 1;
+            wp->l = l;
+            wp->versus = versus;
+            wp->first = first;
+            wp->fel = fel;
+            wp->last = first+pivotid-1;
+            wp->lel = pivot->prev;
+            if (pthread_create(&tid, NULL, list_sort_quicksort_threadwrapper, wp) != 0) {
+                free(wp);
+                traised = 0;
+                list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
+            }
+        } else {
+            list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
+        }
+    }
+    if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel);
+    if (traised) {
+        pthread_join(tid, (void **)NULL);
+        l->threadcount--;
+    }
+#else
+    if (pivotid > 0) list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
+    if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel);
+#endif
+}
+
+int list_iterator_start(list_t *restrict l) {
+    if (l->iter_active) return 0;
+    l->iter_pos = 0;
+    l->iter_active = 1;
+    l->iter_curentry = l->head_sentinel->next;
+    return 1;
+}
+
+void *list_iterator_next(list_t *restrict l) {
+    void *toret;
+
+    if (! l->iter_active) return NULL;
+
+    toret = l->iter_curentry->data;
+    l->iter_curentry = l->iter_curentry->next;
+    l->iter_pos++;
+
+    return toret;
+}
+
+int list_iterator_hasnext(const list_t *restrict l) {
+    if (! l->iter_active) return 0;
+    return (l->iter_pos < l->numels);
+}
+
+int list_iterator_stop(list_t *restrict l) {
+    if (! l->iter_active) return 0;
+    l->iter_pos = 0;
+    l->iter_active = 0;
+    return 1;
+}
+
+int list_hash(const list_t *restrict l, list_hash_t *restrict hash) {
+    struct list_entry_s *x;
+    list_hash_t tmphash;
+    
+    assert(hash != NULL);
+
+    tmphash = l->numels * 2 + 100;
+    if (l->attrs.hasher == NULL) {
+#ifdef SIMCLIST_ALLOW_LOCATIONBASED_HASHES
+        /* ENABLE WITH CARE !! */
+#warning "Memlocation-based hash is consistent only for testing modification in the same program run."
+        int i;
+
+        /* only use element references */
+        for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+            for (i = 0; i < sizeof(x->data); i++) {
+                tmphash += (tmphash ^ (uintptr_t)x->data);
+            }
+            tmphash += tmphash % l->numels;
+        }
+#else
+        return -1;
+#endif
+    } else {
+        /* hash each element with the user-given function */
+        for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+            tmphash += tmphash ^ l->attrs.hasher(x->data);
+            tmphash +=* hash % l->numels;
+        }
+    }
+
+    *hash = tmphash;
+
+    return 0;
+}
+
+#ifndef SIMCLIST_NO_DUMPRESTORE
+int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info) {
+    int32_t terminator_head, terminator_tail;
+    uint32_t elemlen;
+    off_t hop;
+
+
+    /* version */
+    READ_ERRCHECK(fd, & info->version, sizeof(info->version));
+    info->version = ntohs(info->version);
+    if (info->version > SIMCLIST_DUMPFORMAT_VERSION) {
+        errno = EILSEQ;
+        return -1;
+    }
+
+    /* timestamp */
+    READ_ERRCHECK(fd, & info->timestamp, sizeof(info->timestamp));
+    info->timestamp = hton64(info->timestamp);
+
+    /* list terminator (to check thereafter) */
+    READ_ERRCHECK(fd, & terminator_head, sizeof(terminator_head));
+    terminator_head = ntohl(terminator_head);
+
+    /* list size */
+    READ_ERRCHECK(fd, & info->list_size, sizeof(info->list_size));
+    info->list_size = ntohl(info->list_size);
+
+    /* number of elements */
+    READ_ERRCHECK(fd, & info->list_numels, sizeof(info->list_numels));
+    info->list_numels = ntohl(info->list_numels);
+
+    /* length of each element (for checking for consistency) */
+    READ_ERRCHECK(fd, & elemlen, sizeof(elemlen));
+    elemlen = ntohl(elemlen);
+
+    /* list hash */
+    READ_ERRCHECK(fd, & info->list_hash, sizeof(info->list_hash));
+    info->list_hash = ntohl(info->list_hash);
+
+    /* check consistency */
+    if (elemlen > 0) {
+        /* constant length, hop by size only */
+        hop = info->list_size;
+    } else {
+        /* non-constant length, hop by size + all element length blocks */
+        hop = info->list_size + elemlen*info->list_numels;
+    }
+    if (lseek(fd, hop, SEEK_CUR) == -1) {
+        return -1;
+    }
+
+    /* read the trailing value and compare with terminator_head */
+    READ_ERRCHECK(fd, & terminator_tail, sizeof(terminator_tail));
+    terminator_tail = ntohl(terminator_tail);
+
+    if (terminator_head == terminator_tail)
+        info->consistent = 1;
+    else
+        info->consistent = 0;
+
+    return 0;
+}
+
+int list_dump_getinfo_file(const char *restrict filename, list_dump_info_t *restrict info) {
+    int fd, ret;
+
+    fd = open(filename, O_RDONLY, 0);
+    if (fd < 0) return -1;
+
+    ret = list_dump_getinfo_filedescriptor(fd, info);
+    close(fd);
+
+    return ret;
+}
+
+int list_dump_filedescriptor(const list_t *restrict l, int fd, size_t *restrict len) {
+    struct list_entry_s *x;
+    void *ser_buf;
+    uint32_t bufsize;
+    struct timeval timeofday;
+    struct list_dump_header_s header;
+
+    if (l->attrs.meter == NULL && l->attrs.serializer == NULL) {
+        errno = ENOTTY;
+        return -1;
+    }
+
+    /****       DUMP FORMAT      ****
+
+    [ ver   timestamp   |  totlen   numels  elemlen     hash    |   DATA ]
+    
+    where DATA can be:
+    @ for constant-size list (element size is constant; elemlen > 0)
+    [ elem    elem    ...    elem ]
+    @ for other lists (element size dictated by element_meter each time; elemlen <= 0)
+    [ size elem     size elem       ...     size elem ]
+    
+    all integers are encoded in NETWORK BYTE FORMAT
+    *****/
+
+
+    /* prepare HEADER */
+    /* version */
+    header.ver = htons( SIMCLIST_DUMPFORMAT_VERSION );
+
+    /* timestamp */
+    gettimeofday(&timeofday, NULL);
+    header.timestamp = (int64_t)timeofday.tv_sec * 1000000 + (int64_t)timeofday.tv_usec;
+    header.timestamp = hton64(header.timestamp);
+
+    header.rndterm = htonl((int32_t)random());
+
+    /* total list size is postprocessed afterwards */
+
+    /* number of elements */
+    header.numels = htonl(l->numels);
+
+    /* include an hash, if possible */
+    if (l->attrs.hasher != NULL) {
+        if (htonl(list_hash(l, & header.listhash)) != 0) {
+            /* could not compute list hash! */
+            return -1;
+        }
+    } else {
+        header.listhash = htonl(0);
+    }
+
+    header.totlistlen = header.elemlen = 0;
+
+    /* leave room for the header at the beginning of the file */
+    if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) {
+        /* errno set by lseek() */
+        return -1;
+    }
+
+    /* write CONTENT */
+    if (l->numels > 0) {
+        /* SPECULATE that the list has constant element size */
+        
+        if (l->attrs.serializer != NULL) {  /* user user-specified serializer */
+            /* get preliminary length of serialized element in header.elemlen */
+            ser_buf = l->attrs.serializer(l->head_sentinel->next->data, & header.elemlen);
+            free(ser_buf);
+            /* request custom serialization of each element */
+            for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+                ser_buf = l->attrs.serializer(x->data, &bufsize);
+                header.totlistlen += bufsize;
+                if (header.elemlen != 0) {      /* continue on speculation */
+                    if (header.elemlen != bufsize) {
+                        free(ser_buf);
+                        /* constant element length speculation broken! */
+                        header.elemlen = 0;
+                        header.totlistlen = 0;
+                        x = l->head_sentinel;
+                        /* restart from the beginning */
+                        continue;
+                    }
+                    /* speculation confirmed */
+                    WRITE_ERRCHECK(fd, ser_buf, bufsize);
+                } else {                        /* speculation found broken */
+                    WRITE_ERRCHECK(fd, & bufsize, sizeof(size_t));
+                    WRITE_ERRCHECK(fd, ser_buf, bufsize);
+                }
+                free(ser_buf);
+            }
+        } else if (l->attrs.meter != NULL) {
+            header.elemlen = (uint32_t)l->attrs.meter(l->head_sentinel->next->data);
+
+            /* serialize the element straight from its data */
+            for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
+                bufsize = l->attrs.meter(x->data);
+                header.totlistlen += bufsize;
+                if (header.elemlen != 0) {
+                    if (header.elemlen != bufsize) {
+                        /* constant element length speculation broken! */
+                        header.elemlen = 0;
+                        header.totlistlen = 0;
+                        x = l->head_sentinel;
+                        /* restart from the beginning */
+                        continue;
+                    }
+                    WRITE_ERRCHECK(fd, x->data, bufsize);
+                } else {
+                    WRITE_ERRCHECK(fd, &bufsize, sizeof(size_t));
+                    WRITE_ERRCHECK(fd, x->data, bufsize);
+                }
+            }
+        }
+        /* adjust endianness */
+        header.elemlen = htonl(header.elemlen);
+        header.totlistlen = htonl(header.totlistlen);
+    }
+
+    /* write random terminator */
+    WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm));        /* list terminator */
+
+
+    /* write header */
+    lseek(fd, 0, SEEK_SET);
+
+    WRITE_ERRCHECK(fd, & header.ver, sizeof(header.ver));                        /* version */
+    WRITE_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp));            /* timestamp */
+    WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm));                /* random terminator */
+
+    WRITE_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen));          /* total length of elements */
+    WRITE_ERRCHECK(fd, & header.numels, sizeof(header.numels));                  /* number of elements */
+    WRITE_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen));                /* size of each element, or 0 for independent */
+    WRITE_ERRCHECK(fd, & header.listhash, sizeof(header.listhash));             /* list hash, or 0 for "ignore" */
+
+
+    /* possibly store total written length in "len" */
+    if (len != NULL) {
+        *len = sizeof(header) + ntohl(header.totlistlen);
+    }
+
+    return 0;
+}
+
+int list_restore_filedescriptor(list_t *restrict l, int fd, size_t *restrict len) {
+    struct list_dump_header_s header;
+    unsigned long cnt;
+    void *buf;
+    uint32_t elsize, totreadlen, totmemorylen;
+
+    memset(& header, 0, sizeof(header));
+
+    /* read header */
+    
+    /* version */
+    READ_ERRCHECK(fd, &header.ver, sizeof(header.ver));
+    header.ver = ntohs(header.ver);
+    if (header.ver != SIMCLIST_DUMPFORMAT_VERSION) {
+        errno = EILSEQ;
+        return -1;
+    }
+
+    /* timestamp */
+    READ_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp));
+
+    /* list terminator */
+    READ_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm));
+
+    header.rndterm = ntohl(header.rndterm);
+
+    /* total list size */
+    READ_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen));
+    header.totlistlen = ntohl(header.totlistlen);
+
+    /* number of elements */
+    READ_ERRCHECK(fd, & header.numels, sizeof(header.numels));
+    header.numels = ntohl(header.numels);
+
+    /* length of every element, or '0' = variable */
+    READ_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen));
+    header.elemlen = ntohl(header.elemlen);
+
+    /* list hash, or 0 = 'ignore' */
+    READ_ERRCHECK(fd, & header.listhash, sizeof(header.listhash));
+    header.listhash = ntohl(header.listhash);
+
+
+    /* read content */
+    totreadlen = totmemorylen = 0;
+    if (header.elemlen > 0) {   
+        /* elements have constant size = header.elemlen */
+        if (l->attrs.unserializer != NULL) {
+            /* use unserializer */
+            buf = malloc(header.elemlen);
+            for (cnt = 0; cnt < header.numels; cnt++) {
+                READ_ERRCHECK(fd, buf, header.elemlen);
+                list_append(l, l->attrs.unserializer(buf, & elsize));
+                totmemorylen += elsize;
+            }
+        } else {
+            /* copy verbatim into memory */
+            for (cnt = 0; cnt < header.numels; cnt++) {
+                buf = malloc(header.elemlen);
+                READ_ERRCHECK(fd, buf, header.elemlen);
+                list_append(l, buf);
+            }
+            totmemorylen = header.numels * header.elemlen;
+        }
+        totreadlen = header.numels * header.elemlen;
+    } else {
+        /* elements have variable size. Each element is preceded by its size */
+        if (l->attrs.unserializer != NULL) {
+            /* use unserializer */
+            for (cnt = 0; cnt < header.numels; cnt++) {
+                READ_ERRCHECK(fd, & elsize, sizeof(elsize));
+                buf = malloc((size_t)elsize);
+                READ_ERRCHECK(fd, buf, elsize);
+                totreadlen += elsize;
+                list_append(l, l->attrs.unserializer(buf, & elsize));
+                totmemorylen += elsize;
+            }
+        } else {
+            /* copy verbatim into memory */
+            for (cnt = 0; cnt < header.numels; cnt++) {
+                READ_ERRCHECK(fd, & elsize, sizeof(elsize));
+                buf = malloc(elsize);
+                READ_ERRCHECK(fd, buf, elsize);
+                totreadlen += elsize;
+                list_append(l, buf);
+            }
+            totmemorylen = totreadlen;
+        }
+    }
+
+    READ_ERRCHECK(fd, &elsize, sizeof(elsize));  /* read list terminator */
+    elsize = ntohl(elsize);
+
+    /* possibly verify the list consistency */
+    /* wrt hash */
+    /* don't do that
+    if (header.listhash != 0 && header.listhash != list_hash(l)) {
+        errno = ECANCELED;
+        return -1;
+    }
+    */
+
+    /* wrt header */
+    if (totreadlen != header.totlistlen && (int32_t)elsize == header.rndterm) {
+        errno = EPROTO;
+        return -1;
+    }
+
+    /* wrt file */
+    if (lseek(fd, 0, SEEK_CUR) != lseek(fd, 0, SEEK_END)) {
+        errno = EPROTO;
+        return -1;
+    }
+
+    if (len != NULL) {
+        *len = totmemorylen;
+    }
+
+    return 0;
+}
+
+int list_dump_file(const list_t *restrict l, const char *restrict filename, size_t *restrict len) {
+    int fd;
+    size_t sizetoret;
+
+    fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    if (fd < 0) return -1;
+
+    sizetoret = list_dump_filedescriptor(l, fd, len);
+    close(fd);
+
+    return sizetoret;
+}
+
+int list_restore_file(list_t *restrict l, const char *restrict filename, size_t *restrict len) {
+    int fd;
+    size_t totdata;
+
+    fd = open(filename, O_RDONLY, 0);
+    if (fd < 0) return -1;
+
+    totdata = list_restore_filedescriptor(l, fd, len);
+    close(fd);
+
+    return totdata;
+}
+#endif /* ifndef SIMCLIST_NO_DUMPRESTORE */
+
+
+static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos) {
+    if (tmp == NULL) return -1;
+
+    /* fix mid pointer */
+    if (l->numels % 2) {    /* now odd */
+        if (pos >= l->numels/2) l->mid = l->mid->prev;
+    } else {                /* now even */
+        if (pos < l->numels/2) l->mid = l->mid->next;
+    }
+    
+    tmp->prev->next = tmp->next;
+    tmp->next->prev = tmp->prev;
+
+    /* free what's to be freed */
+    if (l->attrs.copy_data && tmp->data != NULL)
+        free(tmp->data);
+
+    if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
+        l->spareels[l->spareelsnum++] = tmp;
+    } else {
+        free(tmp);
+    }
+
+    return 0;
+}
+
+/* ready-made comparators and meters */
+#define SIMCLIST_NUMBER_COMPARATOR(type)     int list_comparator_##type(const void *a, const void *b) { return( *(type *)a < *(type *)b) - (*(type *)a > *(type *)b); } 
+
+SIMCLIST_NUMBER_COMPARATOR(int8_t);
+SIMCLIST_NUMBER_COMPARATOR(int16_t);
+SIMCLIST_NUMBER_COMPARATOR(int32_t);
+SIMCLIST_NUMBER_COMPARATOR(int64_t);
+
+SIMCLIST_NUMBER_COMPARATOR(uint8_t);
+SIMCLIST_NUMBER_COMPARATOR(uint16_t);
+SIMCLIST_NUMBER_COMPARATOR(uint32_t);
+SIMCLIST_NUMBER_COMPARATOR(uint64_t);
+
+SIMCLIST_NUMBER_COMPARATOR(float);
+SIMCLIST_NUMBER_COMPARATOR(double);
+
+int list_comparator_string(const void *a, const void *b) { return strcmp((const char *)b, (const char *)a); }
+
+/* ready-made metric functions */
+#define SIMCLIST_METER(type)        size_t list_meter_##type(const void *el) { return sizeof(type); }
+
+SIMCLIST_METER(int8_t);
+SIMCLIST_METER(int16_t);
+SIMCLIST_METER(int32_t);
+SIMCLIST_METER(int64_t);
+
+SIMCLIST_METER(uint8_t);
+SIMCLIST_METER(uint16_t);
+SIMCLIST_METER(uint32_t);
+SIMCLIST_METER(uint64_t);
+
+SIMCLIST_METER(float);
+SIMCLIST_METER(double);
+
+size_t list_meter_string(const void *el) { return strlen((const char *)el) + 1; }
+
+/* ready-made hashing functions */
+#define SIMCLIST_HASHCOMPUTER(type)    list_hash_t list_hashcomputer_##type(const void *el) { return (list_hash_t)(*(type *)el); }
+
+SIMCLIST_HASHCOMPUTER(int8_t);
+SIMCLIST_HASHCOMPUTER(int16_t);
+SIMCLIST_HASHCOMPUTER(int32_t);
+SIMCLIST_HASHCOMPUTER(int64_t);
+
+SIMCLIST_HASHCOMPUTER(uint8_t);
+SIMCLIST_HASHCOMPUTER(uint16_t);
+SIMCLIST_HASHCOMPUTER(uint32_t);
+SIMCLIST_HASHCOMPUTER(uint64_t);
+
+SIMCLIST_HASHCOMPUTER(float);
+SIMCLIST_HASHCOMPUTER(double);
+
+list_hash_t list_hashcomputer_string(const void *el) {
+    size_t l;
+    list_hash_t hash = 123;
+    const char *str = (const char *)el;
+    char plus;
+
+    for (l = 0; str[l] != '\0'; l++) {
+        if (l) plus = hash ^ str[l];
+        else plus = hash ^ (str[l] - str[0]);
+        hash += (plus << (CHAR_BIT * (l % sizeof(list_hash_t))));
+    }
+
+    return hash;
+}
+
+
+#ifndef NDEBUG
+static int list_repOk(const list_t *restrict l) {
+    int ok, i;
+    struct list_entry_s *s;
+
+    ok = (l != NULL) && (
+            /* head/tail checks */
+            (l->head_sentinel != NULL && l->tail_sentinel != NULL) &&
+                (l->head_sentinel != l->tail_sentinel) && (l->head_sentinel->prev == NULL && l->tail_sentinel->next == NULL) &&
+            /* empty list */
+            (l->numels > 0 || (l->mid == NULL && l->head_sentinel->next == l->tail_sentinel && l->tail_sentinel->prev == l->head_sentinel)) &&
+            /* spare elements checks */
+            l->spareelsnum <= SIMCLIST_MAX_SPARE_ELEMS
+         );
+    
+    if (!ok) return 0;
+
+    if (l->numels >= 1) {
+        /* correct referencing */
+        for (i = -1, s = l->head_sentinel; i < (int)(l->numels-1)/2 && s->next != NULL; i++, s = s->next) {
+            if (s->next->prev != s) break;
+        }
+        ok = (i == (int)(l->numels-1)/2 && l->mid == s);
+        if (!ok) return 0;
+        for (; s->next != NULL; i++, s = s->next) {
+            if (s->next->prev != s) break;
+        }
+        ok = (i == (int)l->numels && s == l->tail_sentinel);
+    }
+
+    return ok;
+}
+
+static int list_attrOk(const list_t *restrict l) {
+    int ok;
+
+    ok = (l->attrs.copy_data == 0 || l->attrs.meter != NULL);
+    return ok;
+}
+
+#endif
+

Propchange: trunk/PCSC/src/simclist.c
------------------------------------------------------------------------------
    svn:executable = *

Added: trunk/PCSC/src/simclist.h
URL: http://svn.debian.org/wsvn/pcsclite/trunk/PCSC/src/simclist.h?rev=4426&op=file
==============================================================================
--- trunk/PCSC/src/simclist.h (added)
+++ trunk/PCSC/src/simclist.h Tue Oct  6 08:29:51 2009
@@ -1,0 +1,954 @@
+/*
+ * Copyright (c) 2007,2008 Mij <mij at bitchx.it>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+/*
+ * SimCList library. See http://mij.oltrelinux.com/devel/simclist
+ */
+
+
+#ifndef SIMCLIST_H
+#define SIMCLIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/types.h>
+
+/* Be friend of both C90 and C99 compilers */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+    /* "inline" and "restrict" are keywords */
+#else
+#   define inline           /* inline */
+#   define restrict         /* restrict */
+#endif
+
+
+/**
+ * Type representing list hashes.
+ *
+ * This is a signed integer value.
+ */
+typedef int32_t list_hash_t;
+
+#ifndef SIMCLIST_NO_DUMPRESTORE
+typedef struct {
+    uint16_t version;       /* dump version */
+    int64_t timestamp;      /* when the list has been dumped, microseconds from UNIX epoch */
+    uint32_t list_size;
+    uint32_t list_numels;
+    list_hash_t list_hash;       /* hash of the list when dumped, or 0 if invalid */
+    uint32_t dumpsize;
+    int consistent;         /* 1 if the dump is verified complete/consistent; 0 otherwise */
+} list_dump_info_t;
+#endif
+
+/**
+ * a comparator of elements.
+ *
+ * A comparator of elements is a function that:
+ *      -# receives two references to elements a and b
+ *      -# returns {<0, 0, >0} if (a > b), (a == b), (a < b) respectively
+ *
+ * It is responsability of the function to handle possible NULL values.
+ */
+typedef int (*element_comparator)(const void *a, const void *b);
+
+/**
+ * a seeker of elements.
+ *
+ * An element seeker is a function that:
+ *      -# receives a reference to an element el
+ *      -# receives a reference to some indicator data
+ *      -# returns non-0 if the element matches the indicator, 0 otherwise
+ *
+ * It is responsability of the function to handle possible NULL values in any
+ * argument.
+ */
+typedef int (*element_seeker)(const void *el, const void *indicator);
+
+/**
+ * an element lenght meter.
+ *
+ * An element meter is a function that:
+ *      -# receives the reference to an element el
+ *      -# returns its size in bytes
+ *
+ * It is responsability of the function to handle possible NULL values.
+ */
+typedef size_t (*element_meter)(const void *el);
+
+/**
+ * a function computing the hash of elements.
+ *
+ * An hash computing function is a function that:
+ *      -# receives the reference to an element el
+ *      -# returns a hash value for el
+ *
+ * It is responsability of the function to handle possible NULL values.
+ */
+typedef list_hash_t (*element_hash_computer)(const void *el);
+
+/**
+ * a function for serializing an element.
+ *
+ * A serializer function is one that gets a reference to an element,
+ * and returns a reference to a buffer that contains its serialization
+ * along with the length of this buffer.
+ * It is responsability of the function to handle possible NULL values,
+ * returning a NULL buffer and a 0 buffer length.
+ *
+ * These functions have 3 goals:
+ *  -# "freeze" and "flatten" the memory representation of the element
+ *  -# provide a portable (wrt byte order, or type size) representation of the element, if the dump can be used on different sw/hw combinations
+ *  -# possibly extract a compressed representation of the element
+ *
+ * @param el                reference to the element data
+ * @param serialize_buffer  reference to fill with the length of the buffer
+ * @return                  reference to the buffer with the serialized data
+ */
+typedef void *(*element_serializer)(const void *restrict el, uint32_t *restrict serializ_len);
+
+/**
+ * a function for un-serializing an element.
+ *
+ * An unserializer function accomplishes the inverse operation of the
+ * serializer function.  An unserializer function is one that gets a
+ * serialized representation of an element and turns it backe to the original
+ * element. The serialized representation is passed as a reference to a buffer
+ * with its data, and the function allocates and returns the buffer containing
+ * the original element, and it sets the length of this buffer into the
+ * integer passed by reference.
+ *
+ * @param data              reference to the buffer with the serialized representation of the element
+ * @param data_len          reference to the location where to store the length of the data in the buffer returned
+ * @return                  reference to a buffer with the original, unserialized representation of the element
+ */
+typedef void *(*element_unserializer)(const void *restrict data, uint32_t *restrict data_len);
+
+/* [private-use] list entry -- olds actual user datum */
+struct list_entry_s {
+    void *data;
+
+    /* doubly-linked list service references */
+    struct list_entry_s *next;
+    struct list_entry_s *prev;
+};
+
+/* [private-use] list attributes */
+struct list_attributes_s {
+    /* user-set routine for comparing list elements */
+    element_comparator comparator;
+    /* user-set routing for seeking elements */
+    element_seeker seeker;
+    /* user-set routine for determining the length of an element */
+    element_meter meter;
+    int copy_data;
+    /* user-set routine for computing the hash of an element */
+    element_hash_computer hasher;
+    /* user-set routine for serializing an element */
+    element_serializer serializer;
+    /* user-set routine for unserializing an element */
+    element_unserializer unserializer;
+};
+
+/** list object */
+typedef struct {
+    struct list_entry_s *head_sentinel;
+    struct list_entry_s *tail_sentinel;
+    struct list_entry_s *mid;
+
+    unsigned int numels;
+
+    /* array of spare elements */
+    struct list_entry_s **spareels;
+    unsigned int spareelsnum;
+
+#ifdef SIMCLIST_WITH_THREADS
+    /* how many threads are currently running */
+    unsigned int threadcount;
+#endif
+
+    /* service variables for list iteration */
+    int iter_active;
+    unsigned int iter_pos;
+    struct list_entry_s *iter_curentry;
+
+    /* list attributes */
+    struct list_attributes_s attrs;
+} list_t;
+
+/**
+ * initialize a list object for use.
+ *
+ * @param l     must point to a user-provided memory location
+ * @return      0 for success. -1 for failure
+ */
+int list_init(list_t *restrict l);
+
+/**
+ * completely remove the list from memory.
+ *
+ * This function is the inverse of list_init(). It is meant to be called when
+ * the list is no longer going to be used. Elements and possible memory taken
+ * for internal use are freed.
+ *
+ * @param l     list to destroy
+ */
+void list_destroy(list_t *restrict l);
+
+/**
+ * set the comparator function for list elements.
+ *
+ * Comparator functions are used for searching and sorting. If NULL is passed
+ * as reference to the function, the comparator is disabled.
+ *
+ * @param l     list to operate
+ * @param comparator_fun    pointer to the actual comparator function
+ * @return      0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_comparator()
+ */
+int list_attributes_comparator(list_t *restrict l, element_comparator comparator_fun);
+
+/**
+ * set a seeker function for list elements.
+ *
+ * Seeker functions are used for finding elements. If NULL is passed as reference
+ * to the function, the seeker is disabled.
+ *
+ * @param l     list to operate
+ * @param seeker_fun    pointer to the actual seeker function
+ * @return      0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_seeker()
+ */
+int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun);
+
+/**
+ * require to free element data when list entry is removed (default: don't free).
+ *
+ * [ advanced preference ]
+ *
+ * By default, when an element is removed from the list, it disappears from
+ * the list by its actual data is not free()d. With this option, every
+ * deletion causes element data to be freed.
+ *
+ * It is responsability of this function to correctly handle NULL values, if
+ * NULL elements are inserted into the list.
+ *
+ * @param l             list to operate
+ * @param metric_fun    pointer to the actual metric function
+ * @param copy_data     0: do not free element data (default); non-0: do free
+ * @return          0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_meter()
+ * @see list_meter_int8_t()
+ * @see list_meter_int16_t()
+ * @see list_meter_int32_t()
+ * @see list_meter_int64_t()
+ * @see list_meter_uint8_t()
+ * @see list_meter_uint16_t()
+ * @see list_meter_uint32_t()
+ * @see list_meter_uint64_t()
+ * @see list_meter_float()
+ * @see list_meter_double()
+ * @see list_meter_string()
+ */
+int list_attributes_copy(list_t *restrict l, element_meter metric_fun, int copy_data);
+
+/**
+ * set the element hash computing function for the list elements.
+ *
+ * [ advanced preference ]
+ *
+ * An hash can be requested depicting the list status at a given time. An hash
+ * only depends on the elements and their order. By default, the hash of an
+ * element is only computed on its reference. With this function, the user can
+ * set a custom function computing the hash of an element. If such function is
+ * provided, the list_hash() function automatically computes the list hash using
+ * the custom function instead of simply referring to element references.
+ *
+ * @param l             list to operate
+ * @param hash_computer_fun pointer to the actual hash computing function
+ * @return              0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see element_hash_computer()
+ */
+int list_attributes_hash_computer(list_t *restrict l, element_hash_computer hash_computer_fun);
+
+/**
+ * set the element serializer function for the list elements.
+ *
+ * [ advanced preference ]
+ *
+ * Serialize functions are used for dumping the list to some persistent
+ * storage.  The serializer function is called for each element; it is passed
+ * a reference to the element and a reference to a size_t object. It will
+ * provide (and return) the buffer with the serialization of the element and
+ * fill the size_t object with the length of this serialization data.
+ *
+ * @param   l   list to operate
+ * @param   serializer_fun  pointer to the actual serializer function
+ * @return      0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see     element_serializer()
+ * @see     list_dump_filedescriptor()
+ * @see     list_restore_filedescriptor()
+ */
+int list_attributes_serializer(list_t *restrict l, element_serializer serializer_fun);
+
+/**
+ * set the element unserializer function for the list elements.
+ *
+ * [ advanced preference ]
+ *
+ * Unserialize functions are used for restoring the list from some persistent
+ * storage. The unserializer function is called for each element segment read
+ * from the storage; it is passed the segment and a reference to an integer.
+ * It shall allocate and return a buffer compiled with the resumed memory
+ * representation of the element, and set the integer value to the length of
+ * this buffer.
+ *
+ * @param   l       list to operate
+ * @param   unserializer_fun    pointer to the actual unserializer function
+ * @return      0 if the attribute was successfully set; -1 otherwise
+ *
+ * @see     element_unserializer()
+ * @see     list_dump_filedescriptor()
+ * @see     list_restore_filedescriptor()
+ */
+int list_attributes_unserializer(list_t *restrict l, element_unserializer unserializer_fun);
+
+/**
+ * append data at the end of the list.
+ *
+ * This function is useful for adding elements with a FIFO/queue policy.
+ *
+ * @param l     list to operate
+ * @param data  pointer to user data to append
+ *
+ * @return      1 for success. < 0 for failure
+ */
+int list_append(list_t *restrict l, const void *data);
+
+/**
+ * insert data in the head of the list.
+ *
+ * This function is useful for adding elements with a LIFO/Stack policy.
+ *
+ * @param l     list to operate
+ * @param data  pointer to user data to append
+ *
+ * @return      1 for success. < 0 for failure
+ */
+int list_prepend(list_t *restrict l, const void *restrict data);
+
+/**
+ * extract the element in the top of the list.
+ *
+ * This function is for using a list with a FIFO/queue policy.
+ *
+ * @param l     list to operate
+ * @return      reference to user datum, or NULL on errors
+ */
+void *list_fetch(list_t *restrict l);
+
+/**
+ * retrieve an element at a given position.
+ *
+ * @param l     list to operate
+ * @param pos   [0,size-1] position index of the element wanted
+ * @return      reference to user datum, or NULL on errors
+ */
+void *list_get_at(const list_t *restrict l, unsigned int pos);
+
+/**
+ * return the maximum element of the list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Returns the maximum element with respect to the comparator function output.
+ * 
+ * @see list_attributes_comparator()
+ *
+ * @param l     list to operate
+ * @return      the reference to the element, or NULL
+ */
+void *list_get_max(const list_t *restrict l);
+
+/**
+ * return the minimum element of the list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Returns the minimum element with respect to the comparator function output.
+ *
+ * @see list_attributes_comparator()
+ *
+ * @param l     list to operate
+ * @return      the reference to the element, or NULL
+ */
+void *list_get_min(const list_t *restrict l);
+
+/**
+ * retrieve and remove from list an element at a given position.
+ *
+ * @param l     list to operate
+ * @param pos   [0,size-1] position index of the element wanted
+ * @return      reference to user datum, or NULL on errors
+ */
+void *list_extract_at(list_t *restrict l, unsigned int pos);
+
+/**
+ * insert an element at a given position.
+ *
+ * @param l     list to operate
+ * @param data  reference to data to be inserted
+ * @param pos   [0,size-1] position index to insert the element at
+ * @return      positive value on success. Negative on failure
+ */
+int list_insert_at(list_t *restrict l, const void *data, unsigned int pos);
+
+/**
+ * expunge an element at a given position from the list.
+ *
+ * @param l     list to operate
+ * @param pos   [0,size-1] position index of the element to be deleted
+ * @return      0 on success. Negative value on failure
+ */
+int list_delete_at(list_t *restrict l, unsigned int pos);
+
+/**
+ * expunge an array of elements from the list, given their position range.
+ *
+ * @param l     list to operate
+ * @param posstart  [0,size-1] position index of the first element to be deleted
+ * @param posend    [posstart,size-1] position of the last element to be deleted
+ * @return      the number of elements successfully removed
+ */
+int list_delete_range(list_t *restrict l, unsigned int posstart, unsigned int posend);
+
+/**
+ * clear all the elements off of the list.
+ *
+ * The element datums will not be freed.
+ *
+ * @see list_delete_range()
+ * @see list_size()
+ *
+ * @param l     list to operate
+ * @return      the number of elements in the list before cleaning
+ */
+int list_clear(list_t *restrict l);
+
+/**
+ * inspect the number of elements in the list.
+ *
+ * @param l     list to operate
+ * @return      number of elements currently held by the list
+ */
+unsigned int list_size(const list_t *restrict l);
+
+/**
+ * inspect whether the list is empty.
+ *
+ * @param l     list to operate
+ * @return      0 iff the list is not empty
+ * 
+ * @see list_size()
+ */
+int list_empty(const list_t *restrict l);
+
+/**
+ * find the position of an element in a list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Inspects the given list looking for the given element; if the element
+ * is found, its position into the list is returned.
+ * Elements are inspected comparing references if a comparator has not been
+ * set. Otherwise, the comparator is used to find the element.
+ *
+ * @param l     list to operate
+ * @param data  reference of the element to search for
+ * @return      position of element in the list, or <0 if not found
+ * 
+ * @see list_attributes_comparator()
+ * @see list_get_at()
+ */
+int list_locate(const list_t *restrict l, const void *data);
+
+/**
+ * returns an element given an indicator.
+ *
+ * @warning Requires a seeker function to be set for the list.
+ *
+ * Inspect the given list looking with the seeker if an element matches
+ * an indicator. If such element is found, the reference to the element
+ * is returned.
+ *
+ * @param l     list to operate
+ * @param indicator indicator data to pass to the seeker along with elements
+ * @return      reference to the element accepted by the seeker, or NULL if none found
+ */
+void *list_seek(list_t *restrict l, const void *indicator);
+
+/**
+ * inspect whether some data is member of the list.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * By default, a per-reference comparison is accomplished. That is,
+ * the data is in list if any element of the list points to the same
+ * location of data.
+ * A "semantic" comparison is accomplished, otherwise, if a comparator
+ * function has been set previously, with list_attributes_comparator();
+ * in which case, the given data reference is believed to be in list iff
+ * comparator_fun(elementdata, userdata) == 0 for any element in the list.
+ * 
+ * @param l     list to operate
+ * @param data  reference to the data to search
+ * @return      0 iff the list does not contain data as an element
+ *
+ * @see list_attributes_comparator()
+ */
+int list_contains(const list_t *restrict l, const void *data);
+
+/**
+ * concatenate two lists
+ *
+ * Concatenates one list with another, and stores the result into a
+ * user-provided list object, which must be different from both the
+ * lists to concatenate. Attributes from the original lists are not
+ * cloned.
+ * The destination list referred is threated as virgin room: if it
+ * is an existing list containing elements, memory leaks will happen.
+ * It is OK to specify the same list twice as source, for "doubling"
+ * it in the destination.
+ *
+ * @param l1    base list
+ * @param l2    list to append to the base
+ * @param dest  reference to the destination list
+ * @return      0 for success, -1 for errors
+ */
+int list_concat(const list_t *l1, const list_t *l2, list_t *restrict dest);
+
+/**
+ * sort list elements.
+ *
+ * @warning Requires a comparator function to be set for the list.
+ *
+ * Sorts the list in ascending or descending order as specified by the versus
+ * flag. The algorithm chooses autonomously what algorithm is best suited for
+ * sorting the list wrt its current status.
+ *
+ * @param l     list to operate
+ * @param versus positive: order small to big; negative: order big to small
+ * @return      0: sorting went OK      non-0: errors happened
+ *
+ * @see list_attributes_comparator()
+ */
+int list_sort(list_t *restrict l, int versus);
+
+/**
+ * start an iteration session.
+ *
+ * This function prepares the list to be iterated.
+ *
+ * @param l     list to operate
+ * @return 		0 if the list cannot be currently iterated. >0 otherwise
+ * 
+ * @see list_iterator_stop()
+ */
+int list_iterator_start(list_t *restrict l);
+
+/**
+ * return the next element in the iteration session.
+ *
+ * @param l     list to operate
+ * @return		element datum, or NULL on errors
+ */
+void *list_iterator_next(list_t *restrict l);
+
+/**
+ * inspect whether more elements are available in the iteration session.
+ *
+ * @param l     list to operate
+ * @return      0 iff no more elements are available.
+ */
+int list_iterator_hasnext(const list_t *restrict l);
+
+/**
+ * end an iteration session.
+ *
+ * @param l     list to operate
+ * @return      0 iff the iteration session cannot be stopped
+ */
+int list_iterator_stop(list_t *restrict l);
+
+/**
+ * return the hash of the current status of the list.
+ *
+ * @param l     list to operate
+ * @param hash  where the resulting hash is put
+ *
+ * @return      0 for success; <0 for failure
+ */
+int list_hash(const list_t *restrict l, list_hash_t *restrict hash);
+
+#ifndef SIMCLIST_NO_DUMPRESTORE
+/**
+ * get meta informations on a list dump on filedescriptor.
+ *
+ * [ advanced function ]
+ *
+ * Extracts the meta information from a SimCList dump located in a file
+ * descriptor. The file descriptor must be open and positioned at the
+ * beginning of the SimCList dump block.
+ *
+ * @param fd        file descriptor to get metadata from
+ * @param info      reference to a dump metainformation structure to fill
+ * @return          0 for success; <0 for failure
+ *
+ * @see list_dump_filedescriptor()
+ */
+int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info);
+
+/**
+ * get meta informations on a list dump on file.
+ *
+ * [ advanced function ]
+ *
+ * Extracts the meta information from a SimCList dump located in a file.
+ *
+ * @param filename  filename of the file to fetch from
+ * @param info      reference to a dump metainformation structure to fill
+ * @return          0 for success; <0 for failure
+ *
+ * @see list_dump_filedescriptor()
+ */
+int list_dump_getinfo_file(const char *restrict filename, list_dump_info_t *restrict info);
+
+/**
+ * dump the list into an open, writable file descriptor.
+ *
+ * This function "dumps" the list to a persistent storage so it can be
+ * preserved across process terminations.
+ * When called, the file descriptor must be open for writing and positioned
+ * where the serialized data must begin. It writes its serialization of the
+ * list in a form which is portable across different architectures. Dump can
+ * be safely performed on stream-only (non seekable) descriptors. The file
+ * descriptor is not closed at the end of the operations.
+ *
+ * To use dump functions, either of these conditions must be satisfied:
+ *      -# a metric function has been specified with list_attributes_copy()
+ *      -# a serializer function has been specified with list_attributes_serializer()
+ *
+ * If a metric function has been specified, each element of the list is dumped
+ * as-is from memory, copying it from its pointer for its length down to the
+ * file descriptor. This might have impacts on portability of the dump to
+ * different architectures.
+ *
+ * If a serializer function has been specified, its result for each element is
+ * dumped to the file descriptor.
+ *
+ *
+ * @param l     list to operate
+ * @param fd    file descriptor to write to
+ * @param len   location to store the resulting length of the dump (bytes), or NULL
+ *
+ * @return      0 if successful; -1 otherwise
+ *
+ * @see element_serializer()
+ * @see list_attributes_copy()
+ * @see list_attributes_serializer()
+ */
+int list_dump_filedescriptor(const list_t *restrict l, int fd, size_t *restrict len);
+
+/**
+ * dump the list to a file name.
+ *
+ * This function creates a filename and dumps the current content of the list
+ * to it. If the file exists it is overwritten. The number of bytes written to
+ * the file can be returned in a specified argument.
+ *
+ * @param l     list to operate
+ * @param filename    filename to write to
+ * @param len   location to store the resulting length of the dump (bytes), or NULL
+ *
+ * @return      0 if successful; -1 otherwise
+ *
+ * @see list_attributes_copy()
+ * @see element_serializer()
+ * @see list_attributes_serializer()
+ * @see list_dump_filedescriptor()
+ * @see list_restore_file()
+ *
+ * This function stores a representation of the list 
+ */
+int list_dump_file(const list_t *restrict l, const char *restrict filename, size_t *restrict len);
+
+/**
+ * restore the list from an open, readable file descriptor to memory.
+ *
+ * This function is the "inverse" of list_dump_filedescriptor(). It restores
+ * the list content from a (open, read-ready) file descriptor to memory. An
+ * unserializer might be needed to restore elements from the persistent
+ * representation back into memory-consistent format. List attributes can not
+ * be restored and must be set manually.
+ *
+ * @see list_dump_filedescriptor()
+ * @see list_attributes_serializer()
+ * @see list_attributes_unserializer()
+ *
+ * @param l     list to restore to
+ * @param fd    file descriptor to read from.
+ * @param len   location to store the length of the dump read (bytes), or NULL
+ * @return      0 if successful; -1 otherwise
+ */
+int list_restore_filedescriptor(list_t *restrict l, int fd, size_t *restrict len);
+
+/**
+ * restore the list from a file name.
+ *
+ * This function restores the content of a list from a file into memory. It is
+ * the inverse of list_dump_file().
+ *
+ * @see element_unserializer()
+ * @see list_attributes_unserializer()
+ * @see list_dump_file()
+ * @see list_restore_filedescriptor()
+ *
+ * @param l         list to restore to
+ * @param filename  filename to read data from
+ * @param len       location to store the length of the dump read (bytes), or NULL
+ * @return          0 if successful; -1 otherwise
+ */
+int list_restore_file(list_t *restrict l, const char *restrict filename, size_t *len);
+#endif
+
+/* ready-made comparators, meters and hash computers */
+                                /* comparator functions */
+/**
+ * ready-made comparator for int8_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int8_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for int16_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int16_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for int32_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int32_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for int64_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_int64_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint8_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint8_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint16_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint16_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint32_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint32_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for uint64_t elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_uint64_t(const void *a, const void *b);
+
+/**
+ * ready-made comparator for float elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_float(const void *a, const void *b);
+
+/**
+ * ready-made comparator for double elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_double(const void *a, const void *b);
+
+/**
+ * ready-made comparator for string elements.
+ * @see list_attributes_comparator()
+ */
+int list_comparator_string(const void *a, const void *b);
+
+                                /*          metric functions        */
+/**
+ * ready-made metric function for int8_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int8_t(const void *el);
+
+/**
+ * ready-made metric function for int16_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int16_t(const void *el);
+
+/**
+ * ready-made metric function for int32_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int32_t(const void *el);
+
+/**
+ * ready-made metric function for int64_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_int64_t(const void *el);
+
+/**
+ * ready-made metric function for uint8_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint8_t(const void *el);
+
+/**
+ * ready-made metric function for uint16_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint16_t(const void *el);
+
+/**
+ * ready-made metric function for uint32_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint32_t(const void *el);
+
+/**
+ * ready-made metric function for uint64_t elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_uint64_t(const void *el);
+
+/**
+ * ready-made metric function for float elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_float(const void *el);
+
+/**
+ * ready-made metric function for double elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_double(const void *el);
+
+/**
+ * ready-made metric function for string elements.
+ * @see list_attributes_copy()
+ */
+size_t list_meter_string(const void *el);
+
+                                /*          hash functions          */
+/**
+ * ready-made hash function for int8_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int8_t(const void *el);
+
+/**
+ * ready-made hash function for int16_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int16_t(const void *el);
+
+/**
+ * ready-made hash function for int32_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int32_t(const void *el);
+
+/**
+ * ready-made hash function for int64_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_int64_t(const void *el);
+
+/**
+ * ready-made hash function for uint8_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint8_t(const void *el);
+
+/**
+ * ready-made hash function for uint16_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint16_t(const void *el);
+
+/**
+ * ready-made hash function for uint32_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint32_t(const void *el);
+
+/**
+ * ready-made hash function for uint64_t elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_uint64_t(const void *el);
+
+/**
+ * ready-made hash function for float elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_float(const void *el);
+
+/**
+ * ready-made hash function for double elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_double(const void *el);
+
+/**
+ * ready-made hash function for string elements.
+ * @see list_attributes_hash_computer()
+ */
+list_hash_t list_hashcomputer_string(const void *el);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+

Propchange: trunk/PCSC/src/simclist.h
------------------------------------------------------------------------------
    svn:executable = *




More information about the Pcsclite-cvs-commit mailing list