| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482 |
- /*
- * Copyright (c) 2007,2008,2009,2010 Mij <mij@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
- */
- /* SimCList implementation, version 1.5 */
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h> /* for setting errno */
- #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>
- /* work around lack of inttypes.h support in broken Microsoft Visual Studio compilers */
- #if !defined(WIN32) || !defined(_MSC_VER)
- # include <inttypes.h> /* (u)int*_t */
- #else
- # include <basetsd.h>
- typedef UINT8 uint8_t;
- typedef UINT16 uint16_t;
- typedef ULONG32 uint32_t;
- typedef UINT64 uint64_t;
- typedef INT8 int8_t;
- typedef INT16 int16_t;
- typedef LONG32 int32_t;
- typedef INT64 int64_t;
- #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);
- /*
- * Random Number Generator
- *
- * The user is expected to seed the RNG (ie call srand()) if
- * SIMCLIST_SYSTEM_RNG is defined.
- *
- * Otherwise, a self-contained RNG based on LCG is used; see
- * http://en.wikipedia.org/wiki/Linear_congruential_generator .
- *
- * Facts pro local RNG:
- * 1. no need for the user to call srand() on his own
- * 2. very fast, possibly faster than OS
- * 3. avoid interference with user's RNG
- *
- * Facts pro system RNG:
- * 1. may be more accurate (irrelevant for SimCList randno purposes)
- * 2. why reinvent the wheel
- *
- * Default to local RNG for user's ease of use.
- */
- #ifdef SIMCLIST_SYSTEM_RNG
- /* keep track whether we initialized already (non-0) or not (0) */
- static unsigned random_seed = 0;
- /* use local RNG */
- static inline void seed_random() {
- if (random_seed == 0)
- random_seed = (unsigned)getpid() ^ (unsigned)time(NULL);
- }
- static inline long get_random() {
- random_seed = (1664525 * random_seed + 1013904223);
- return random_seed;
- }
- #else
- /* use OS's random generator */
- # define seed_random()
- # define get_random() (rand())
- #endif
- /* list initialization */
- int list_init(list_t *restrict l) {
- if (l == NULL) return -1;
- seed_random();
- 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(list_t *restrict l, const void *data) {
- int pos, r;
- pos = list_locate(l, data);
- if (pos < 0)
- return -1;
- r = list_delete_at(l, pos);
- if (r < 0)
- return -1;
- assert(list_repOk(l));
- return 0;
- }
- 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 = (get_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)get_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;
- if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) {
- /* errno set by lseek() */
- return -1;
- }
- /* 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. This is wrt the PRE situation */
- if (l->numels % 2) { /* now odd */
- /* sort out the base case by hand */
- if (l->numels == 1) l->mid = NULL;
- else 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) { if (el) { /* kill compiler whinge */ } 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
|