simclist.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482
  1. /*
  2. * Copyright (c) 2007,2008,2009,2010 Mij <mij@bitchx.it>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. /*
  17. * SimCList library. See http://mij.oltrelinux.com/devel/simclist
  18. */
  19. /* SimCList implementation, version 1.5 */
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <errno.h> /* for setting errno */
  23. #include <sys/types.h>
  24. #include <sys/uio.h> /* for READ_ERRCHECK() and write() */
  25. #include <fcntl.h> /* for open() etc */
  26. #include <arpa/inet.h> /* for htons() */
  27. #include <unistd.h>
  28. #include <time.h> /* for time() for random seed */
  29. #include <sys/time.h> /* for gettimeofday() */
  30. #include <sys/stat.h> /* for open()'s access modes S_IRUSR etc */
  31. #include <limits.h>
  32. #include <stdint.h>
  33. /* work around lack of inttypes.h support in broken Microsoft Visual Studio compilers */
  34. #if !defined(WIN32) || !defined(_MSC_VER)
  35. # include <inttypes.h> /* (u)int*_t */
  36. #else
  37. # include <basetsd.h>
  38. typedef UINT8 uint8_t;
  39. typedef UINT16 uint16_t;
  40. typedef ULONG32 uint32_t;
  41. typedef UINT64 uint64_t;
  42. typedef INT8 int8_t;
  43. typedef INT16 int16_t;
  44. typedef LONG32 int32_t;
  45. typedef INT64 int64_t;
  46. #endif
  47. #ifndef SIMCLIST_NO_DUMPRESTORE
  48. /* convert 64bit integers from host to network format */
  49. #define hton64(x) (\
  50. htons(1) == 1 ? \
  51. (uint64_t)x /* big endian */ \
  52. : /* little endian */ \
  53. ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \
  54. (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \
  55. (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \
  56. (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \
  57. (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \
  58. (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \
  59. (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \
  60. (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) \
  61. )
  62. /* convert 64bit integers from network to host format */
  63. #define ntoh64(x) (hton64(x))
  64. #endif
  65. /* some OSes don't have EPROTO (eg OpenBSD) */
  66. #ifndef EPROTO
  67. #define EPROTO EIO
  68. #endif
  69. /* disable asserts */
  70. #ifndef SIMCLIST_DEBUG
  71. #define NDEBUG
  72. #endif
  73. #include <assert.h>
  74. #ifdef SIMCLIST_WITH_THREADS
  75. /* limit (approx) to the number of threads running
  76. * for threaded operations. Only meant when
  77. * SIMCLIST_WITH_THREADS is defined */
  78. #define SIMCLIST_MAXTHREADS 2
  79. #endif
  80. /*
  81. * how many elems to keep as spare. During a deletion, an element
  82. * can be saved in a "free-list", not free()d immediately. When
  83. * latter insertions are performed, spare elems can be used instead
  84. * of malloc()ing new elems.
  85. *
  86. * about this param, some values for appending
  87. * 10 million elems into an empty list:
  88. * (#, time[sec], gain[%], gain/no[%])
  89. * 0 2,164 0,00 0,00 <-- feature disabled
  90. * 1 1,815 34,9 34,9
  91. * 2 1,446 71,8 35,9 <-- MAX gain/no
  92. * 3 1,347 81,7 27,23
  93. * 5 1,213 95,1 19,02
  94. * 8 1,064 110,0 13,75
  95. * 10 1,015 114,9 11,49 <-- MAX gain w/ likely sol
  96. * 15 1,019 114,5 7,63
  97. * 25 0,985 117,9 4,72
  98. * 50 1,088 107,6 2,15
  99. * 75 1,016 114,8 1,53
  100. * 100 0,988 117,6 1,18
  101. * 150 1,022 114,2 0,76
  102. * 200 0,939 122,5 0,61 <-- MIN time
  103. */
  104. #ifndef SIMCLIST_MAX_SPARE_ELEMS
  105. #define SIMCLIST_MAX_SPARE_ELEMS 5
  106. #endif
  107. #ifdef SIMCLIST_WITH_THREADS
  108. #include <pthread.h>
  109. #endif
  110. #include "simclist.h"
  111. /* minumum number of elements for sorting with quicksort instead of insertion */
  112. #define SIMCLIST_MINQUICKSORTELS 24
  113. /* list dump declarations */
  114. #define SIMCLIST_DUMPFORMAT_VERSION 1 /* (short integer) version of fileformat managed by _dump* and _restore* functions */
  115. #define SIMCLIST_DUMPFORMAT_HEADERLEN 30 /* length of the header */
  116. /* header for a list dump */
  117. struct list_dump_header_s {
  118. uint16_t ver; /* version */
  119. int64_t timestamp; /* dump timestamp */
  120. int32_t rndterm; /* random value terminator -- terminates the data sequence */
  121. uint32_t totlistlen; /* sum of every element' size, bytes */
  122. uint32_t numels; /* number of elements */
  123. uint32_t elemlen; /* bytes length of an element, for constant-size lists, <= 0 otherwise */
  124. int32_t listhash; /* hash of the list at the time of dumping, or 0 if to be ignored */
  125. };
  126. /* deletes tmp from list, with care wrt its position (head, tail, middle) */
  127. static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos);
  128. /* set default values for initialized lists */
  129. static int list_attributes_setdefaults(list_t *restrict l);
  130. #ifndef NDEBUG
  131. /* check whether the list internal REPresentation is valid -- Costs O(n) */
  132. static int list_repOk(const list_t *restrict l);
  133. /* check whether the list attribute set is valid -- Costs O(1) */
  134. static int list_attrOk(const list_t *restrict l);
  135. #endif
  136. /* do not inline, this is recursive */
  137. static void list_sort_quicksort(list_t *restrict l, int versus,
  138. unsigned int first, struct list_entry_s *fel,
  139. unsigned int last, struct list_entry_s *lel);
  140. static inline void list_sort_selectionsort(list_t *restrict l, int versus,
  141. unsigned int first, struct list_entry_s *fel,
  142. unsigned int last, struct list_entry_s *lel);
  143. static void *list_get_minmax(const list_t *restrict l, int versus);
  144. static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart);
  145. /* write() decorated with error checking logic */
  146. #define WRITE_ERRCHECK(fd, msgbuf, msglen) do { \
  147. if (write(fd, msgbuf, msglen) < 0) return -1; \
  148. } while (0);
  149. /* READ_ERRCHECK() decorated with error checking logic */
  150. #define READ_ERRCHECK(fd, msgbuf, msglen) do { \
  151. if (read(fd, msgbuf, msglen) != msglen) { \
  152. /*errno = EPROTO;*/ \
  153. return -1; \
  154. } \
  155. } while (0);
  156. /*
  157. * Random Number Generator
  158. *
  159. * The user is expected to seed the RNG (ie call srand()) if
  160. * SIMCLIST_SYSTEM_RNG is defined.
  161. *
  162. * Otherwise, a self-contained RNG based on LCG is used; see
  163. * http://en.wikipedia.org/wiki/Linear_congruential_generator .
  164. *
  165. * Facts pro local RNG:
  166. * 1. no need for the user to call srand() on his own
  167. * 2. very fast, possibly faster than OS
  168. * 3. avoid interference with user's RNG
  169. *
  170. * Facts pro system RNG:
  171. * 1. may be more accurate (irrelevant for SimCList randno purposes)
  172. * 2. why reinvent the wheel
  173. *
  174. * Default to local RNG for user's ease of use.
  175. */
  176. #ifdef SIMCLIST_SYSTEM_RNG
  177. /* keep track whether we initialized already (non-0) or not (0) */
  178. static unsigned random_seed = 0;
  179. /* use local RNG */
  180. static inline void seed_random() {
  181. if (random_seed == 0)
  182. random_seed = (unsigned)getpid() ^ (unsigned)time(NULL);
  183. }
  184. static inline long get_random() {
  185. random_seed = (1664525 * random_seed + 1013904223);
  186. return random_seed;
  187. }
  188. #else
  189. /* use OS's random generator */
  190. # define seed_random()
  191. # define get_random() (rand())
  192. #endif
  193. /* list initialization */
  194. int list_init(list_t *restrict l) {
  195. if (l == NULL) return -1;
  196. seed_random();
  197. l->numels = 0;
  198. /* head/tail sentinels and mid pointer */
  199. l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
  200. l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
  201. l->head_sentinel->next = l->tail_sentinel;
  202. l->tail_sentinel->prev = l->head_sentinel;
  203. l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL;
  204. l->head_sentinel->data = l->tail_sentinel->data = NULL;
  205. /* iteration attributes */
  206. l->iter_active = 0;
  207. l->iter_pos = 0;
  208. l->iter_curentry = NULL;
  209. /* free-list attributes */
  210. l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *));
  211. l->spareelsnum = 0;
  212. #ifdef SIMCLIST_WITH_THREADS
  213. l->threadcount = 0;
  214. #endif
  215. list_attributes_setdefaults(l);
  216. assert(list_repOk(l));
  217. assert(list_attrOk(l));
  218. return 0;
  219. }
  220. void list_destroy(list_t *restrict l) {
  221. unsigned int i;
  222. list_clear(l);
  223. for (i = 0; i < l->spareelsnum; i++) {
  224. free(l->spareels[i]);
  225. }
  226. free(l->spareels);
  227. free(l->head_sentinel);
  228. free(l->tail_sentinel);
  229. }
  230. int list_attributes_setdefaults(list_t *restrict l) {
  231. l->attrs.comparator = NULL;
  232. l->attrs.seeker = NULL;
  233. /* also free() element data when removing and element from the list */
  234. l->attrs.meter = NULL;
  235. l->attrs.copy_data = 0;
  236. l->attrs.hasher = NULL;
  237. /* serializer/unserializer */
  238. l->attrs.serializer = NULL;
  239. l->attrs.unserializer = NULL;
  240. assert(list_attrOk(l));
  241. return 0;
  242. }
  243. /* setting list properties */
  244. int list_attributes_comparator(list_t *restrict l, element_comparator comparator_fun) {
  245. if (l == NULL) return -1;
  246. l->attrs.comparator = comparator_fun;
  247. assert(list_attrOk(l));
  248. return 0;
  249. }
  250. int list_attributes_seeker(list_t *restrict l, element_seeker seeker_fun) {
  251. if (l == NULL) return -1;
  252. l->attrs.seeker = seeker_fun;
  253. assert(list_attrOk(l));
  254. return 0;
  255. }
  256. int list_attributes_copy(list_t *restrict l, element_meter metric_fun, int copy_data) {
  257. if (l == NULL || (metric_fun == NULL && copy_data != 0)) return -1;
  258. l->attrs.meter = metric_fun;
  259. l->attrs.copy_data = copy_data;
  260. assert(list_attrOk(l));
  261. return 0;
  262. }
  263. int list_attributes_hash_computer(list_t *restrict l, element_hash_computer hash_computer_fun) {
  264. if (l == NULL) return -1;
  265. l->attrs.hasher = hash_computer_fun;
  266. assert(list_attrOk(l));
  267. return 0;
  268. }
  269. int list_attributes_serializer(list_t *restrict l, element_serializer serializer_fun) {
  270. if (l == NULL) return -1;
  271. l->attrs.serializer = serializer_fun;
  272. assert(list_attrOk(l));
  273. return 0;
  274. }
  275. int list_attributes_unserializer(list_t *restrict l, element_unserializer unserializer_fun) {
  276. if (l == NULL) return -1;
  277. l->attrs.unserializer = unserializer_fun;
  278. assert(list_attrOk(l));
  279. return 0;
  280. }
  281. int list_append(list_t *restrict l, const void *data) {
  282. return list_insert_at(l, data, l->numels);
  283. }
  284. int list_prepend(list_t *restrict l, const void *data) {
  285. return list_insert_at(l, data, 0);
  286. }
  287. void *list_fetch(list_t *restrict l) {
  288. return list_extract_at(l, 0);
  289. }
  290. void *list_get_at(const list_t *restrict l, unsigned int pos) {
  291. struct list_entry_s *tmp;
  292. tmp = list_findpos(l, pos);
  293. return (tmp != NULL ? tmp->data : NULL);
  294. }
  295. void *list_get_max(const list_t *restrict l) {
  296. return list_get_minmax(l, +1);
  297. }
  298. void *list_get_min(const list_t *restrict l) {
  299. return list_get_minmax(l, -1);
  300. }
  301. /* REQUIRES {list->numels >= 1}
  302. * return the min (versus < 0) or max value (v > 0) in l */
  303. static void *list_get_minmax(const list_t *restrict l, int versus) {
  304. void *curminmax;
  305. struct list_entry_s *s;
  306. if (l->attrs.comparator == NULL || l->numels == 0)
  307. return NULL;
  308. curminmax = l->head_sentinel->next->data;
  309. for (s = l->head_sentinel->next->next; s != l->tail_sentinel; s = s->next) {
  310. if (l->attrs.comparator(curminmax, s->data) * versus > 0)
  311. curminmax = s->data;
  312. }
  313. return curminmax;
  314. }
  315. /* set tmp to point to element at index posstart in l */
  316. static inline struct list_entry_s *list_findpos(const list_t *restrict l, int posstart) {
  317. struct list_entry_s *ptr;
  318. float x;
  319. int i;
  320. /* accept 1 slot overflow for fetching head and tail sentinels */
  321. if (posstart < -1 || posstart > (int)l->numels) return NULL;
  322. x = (float)(posstart+1) / l->numels;
  323. if (x <= 0.25) {
  324. /* first quarter: get to posstart from head */
  325. for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++);
  326. } else if (x < 0.5) {
  327. /* second quarter: get to posstart from mid */
  328. for (i = (l->numels-1)/2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--);
  329. } else if (x <= 0.75) {
  330. /* third quarter: get to posstart from mid */
  331. for (i = (l->numels-1)/2, ptr = l->mid; i < posstart; ptr = ptr->next, i++);
  332. } else {
  333. /* fourth quarter: get to posstart from tail */
  334. for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--);
  335. }
  336. return ptr;
  337. }
  338. void *list_extract_at(list_t *restrict l, unsigned int pos) {
  339. struct list_entry_s *tmp;
  340. void *data;
  341. if (l->iter_active || pos >= l->numels) return NULL;
  342. tmp = list_findpos(l, pos);
  343. data = tmp->data;
  344. tmp->data = NULL; /* save data from list_drop_elem() free() */
  345. list_drop_elem(l, tmp, pos);
  346. l->numels--;
  347. assert(list_repOk(l));
  348. return data;
  349. }
  350. int list_insert_at(list_t *restrict l, const void *data, unsigned int pos) {
  351. struct list_entry_s *lent, *succ, *prec;
  352. if (l->iter_active || pos > l->numels) return -1;
  353. /* this code optimizes malloc() with a free-list */
  354. if (l->spareelsnum > 0) {
  355. lent = l->spareels[l->spareelsnum-1];
  356. l->spareelsnum--;
  357. } else {
  358. lent = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
  359. if (lent == NULL)
  360. return -1;
  361. }
  362. if (l->attrs.copy_data) {
  363. /* make room for user' data (has to be copied) */
  364. size_t datalen = l->attrs.meter(data);
  365. lent->data = (struct list_entry_s *)malloc(datalen);
  366. memcpy(lent->data, data, datalen);
  367. } else {
  368. lent->data = (void*)data;
  369. }
  370. /* actually append element */
  371. prec = list_findpos(l, pos-1);
  372. succ = prec->next;
  373. prec->next = lent;
  374. lent->prev = prec;
  375. lent->next = succ;
  376. succ->prev = lent;
  377. l->numels++;
  378. /* fix mid pointer */
  379. if (l->numels == 1) { /* first element, set pointer */
  380. l->mid = lent;
  381. } else if (l->numels % 2) { /* now odd */
  382. if (pos >= (l->numels-1)/2) l->mid = l->mid->next;
  383. } else { /* now even */
  384. if (pos <= (l->numels-1)/2) l->mid = l->mid->prev;
  385. }
  386. assert(list_repOk(l));
  387. return 1;
  388. }
  389. int list_delete(list_t *restrict l, const void *data) {
  390. int pos, r;
  391. pos = list_locate(l, data);
  392. if (pos < 0)
  393. return -1;
  394. r = list_delete_at(l, pos);
  395. if (r < 0)
  396. return -1;
  397. assert(list_repOk(l));
  398. return 0;
  399. }
  400. int list_delete_at(list_t *restrict l, unsigned int pos) {
  401. struct list_entry_s *delendo;
  402. if (l->iter_active || pos >= l->numels) return -1;
  403. delendo = list_findpos(l, pos);
  404. list_drop_elem(l, delendo, pos);
  405. l->numels--;
  406. assert(list_repOk(l));
  407. return 0;
  408. }
  409. int list_delete_range(list_t *restrict l, unsigned int posstart, unsigned int posend) {
  410. struct list_entry_s *lastvalid, *tmp, *tmp2;
  411. unsigned int i;
  412. int movedx;
  413. unsigned int numdel, midposafter;
  414. if (l->iter_active || posend < posstart || posend >= l->numels) return -1;
  415. tmp = list_findpos(l, posstart); /* first el to be deleted */
  416. lastvalid = tmp->prev; /* last valid element */
  417. numdel = posend - posstart + 1;
  418. midposafter = (l->numels-1-numdel)/2;
  419. midposafter = midposafter < posstart ? midposafter : midposafter+numdel;
  420. movedx = midposafter - (l->numels-1)/2;
  421. if (movedx > 0) { /* move right */
  422. for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->next, i++);
  423. } else { /* move left */
  424. movedx = -movedx;
  425. for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->prev, i++);
  426. }
  427. assert(posstart == 0 || lastvalid != l->head_sentinel);
  428. i = posstart;
  429. if (l->attrs.copy_data) {
  430. /* also free element data */
  431. for (; i <= posend; i++) {
  432. tmp2 = tmp;
  433. tmp = tmp->next;
  434. if (tmp2->data != NULL) free(tmp2->data);
  435. if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
  436. l->spareels[l->spareelsnum++] = tmp2;
  437. } else {
  438. free(tmp2);
  439. }
  440. }
  441. } else {
  442. /* only free containers */
  443. for (; i <= posend; i++) {
  444. tmp2 = tmp;
  445. tmp = tmp->next;
  446. if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
  447. l->spareels[l->spareelsnum++] = tmp2;
  448. } else {
  449. free(tmp2);
  450. }
  451. }
  452. }
  453. assert(i == posend+1 && (posend != l->numels || tmp == l->tail_sentinel));
  454. lastvalid->next = tmp;
  455. tmp->prev = lastvalid;
  456. l->numels -= posend - posstart + 1;
  457. assert(list_repOk(l));
  458. return 0;
  459. }
  460. int list_clear(list_t *restrict l) {
  461. struct list_entry_s *s;
  462. if (l->iter_active) return -1;
  463. if (l->attrs.copy_data) { /* also free user data */
  464. /* spare a loop conditional with two loops: spareing elems and freeing elems */
  465. for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) {
  466. /* move elements as spares as long as there is room */
  467. if (s->data != NULL) free(s->data);
  468. l->spareels[l->spareelsnum++] = s;
  469. }
  470. while (s != l->tail_sentinel) {
  471. /* free the remaining elems */
  472. if (s->data != NULL) free(s->data);
  473. s = s->next;
  474. free(s->prev);
  475. }
  476. l->head_sentinel->next = l->tail_sentinel;
  477. l->tail_sentinel->prev = l->head_sentinel;
  478. } else { /* only free element containers */
  479. /* spare a loop conditional with two loops: spareing elems and freeing elems */
  480. for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) {
  481. /* move elements as spares as long as there is room */
  482. l->spareels[l->spareelsnum++] = s;
  483. }
  484. while (s != l->tail_sentinel) {
  485. /* free the remaining elems */
  486. s = s->next;
  487. free(s->prev);
  488. }
  489. l->head_sentinel->next = l->tail_sentinel;
  490. l->tail_sentinel->prev = l->head_sentinel;
  491. }
  492. l->numels = 0;
  493. l->mid = NULL;
  494. assert(list_repOk(l));
  495. return 0;
  496. }
  497. unsigned int list_size(const list_t *restrict l) {
  498. return l->numels;
  499. }
  500. int list_empty(const list_t *restrict l) {
  501. return (l->numels == 0);
  502. }
  503. int list_locate(const list_t *restrict l, const void *data) {
  504. struct list_entry_s *el;
  505. int pos = 0;
  506. if (l->attrs.comparator != NULL) {
  507. /* use comparator */
  508. for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) {
  509. if (l->attrs.comparator(data, el->data) == 0) break;
  510. }
  511. } else {
  512. /* compare references */
  513. for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) {
  514. if (el->data == data) break;
  515. }
  516. }
  517. if (el == l->tail_sentinel) return -1;
  518. return pos;
  519. }
  520. void *list_seek(list_t *restrict l, const void *indicator) {
  521. const struct list_entry_s *iter;
  522. if (l->attrs.seeker == NULL) return NULL;
  523. for (iter = l->head_sentinel->next; iter != l->tail_sentinel; iter = iter->next) {
  524. if (l->attrs.seeker(iter->data, indicator) != 0) return iter->data;
  525. }
  526. return NULL;
  527. }
  528. int list_contains(const list_t *restrict l, const void *data) {
  529. return (list_locate(l, data) >= 0);
  530. }
  531. int list_concat(const list_t *l1, const list_t *l2, list_t *restrict dest) {
  532. struct list_entry_s *el, *srcel;
  533. unsigned int cnt;
  534. int err;
  535. if (l1 == NULL || l2 == NULL || dest == NULL || l1 == dest || l2 == dest)
  536. return -1;
  537. list_init(dest);
  538. dest->numels = l1->numels + l2->numels;
  539. if (dest->numels == 0)
  540. return 0;
  541. /* copy list1 */
  542. srcel = l1->head_sentinel->next;
  543. el = dest->head_sentinel;
  544. while (srcel != l1->tail_sentinel) {
  545. el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
  546. el->next->prev = el;
  547. el = el->next;
  548. el->data = srcel->data;
  549. srcel = srcel->next;
  550. }
  551. dest->mid = el; /* approximate position (adjust later) */
  552. /* copy list 2 */
  553. srcel = l2->head_sentinel->next;
  554. while (srcel != l2->tail_sentinel) {
  555. el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s));
  556. el->next->prev = el;
  557. el = el->next;
  558. el->data = srcel->data;
  559. srcel = srcel->next;
  560. }
  561. el->next = dest->tail_sentinel;
  562. dest->tail_sentinel->prev = el;
  563. /* fix mid pointer */
  564. err = l2->numels - l1->numels;
  565. if ((err+1)/2 > 0) { /* correct pos RIGHT (err-1)/2 moves */
  566. err = (err+1)/2;
  567. for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->next;
  568. } else if (err/2 < 0) { /* correct pos LEFT (err/2)-1 moves */
  569. err = -err/2;
  570. for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->prev;
  571. }
  572. assert(!(list_repOk(l1) && list_repOk(l2)) || list_repOk(dest));
  573. return 0;
  574. }
  575. int list_sort(list_t *restrict l, int versus) {
  576. if (l->iter_active || l->attrs.comparator == NULL) /* cannot modify list in the middle of an iteration */
  577. return -1;
  578. if (l->numels <= 1)
  579. return 0;
  580. list_sort_quicksort(l, versus, 0, l->head_sentinel->next, l->numels-1, l->tail_sentinel->prev);
  581. assert(list_repOk(l));
  582. return 0;
  583. }
  584. #ifdef SIMCLIST_WITH_THREADS
  585. struct list_sort_wrappedparams {
  586. list_t *restrict l;
  587. int versus;
  588. unsigned int first, last;
  589. struct list_entry_s *fel, *lel;
  590. };
  591. static void *list_sort_quicksort_threadwrapper(void *wrapped_params) {
  592. struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)wrapped_params;
  593. list_sort_quicksort(wp->l, wp->versus, wp->first, wp->fel, wp->last, wp->lel);
  594. free(wp);
  595. pthread_exit(NULL);
  596. return NULL;
  597. }
  598. #endif
  599. static inline void list_sort_selectionsort(list_t *restrict l, int versus,
  600. unsigned int first, struct list_entry_s *fel,
  601. unsigned int last, struct list_entry_s *lel) {
  602. struct list_entry_s *cursor, *toswap, *firstunsorted;
  603. void *tmpdata;
  604. if (last <= first) /* <= 1-element lists are always sorted */
  605. return;
  606. for (firstunsorted = fel; firstunsorted != lel; firstunsorted = firstunsorted->next) {
  607. /* find min or max in the remainder of the list */
  608. for (toswap = firstunsorted, cursor = firstunsorted->next; cursor != lel->next; cursor = cursor->next)
  609. if (l->attrs.comparator(toswap->data, cursor->data) * -versus > 0) toswap = cursor;
  610. if (toswap != firstunsorted) { /* swap firstunsorted with toswap */
  611. tmpdata = firstunsorted->data;
  612. firstunsorted->data = toswap->data;
  613. toswap->data = tmpdata;
  614. }
  615. }
  616. }
  617. static void list_sort_quicksort(list_t *restrict l, int versus,
  618. unsigned int first, struct list_entry_s *fel,
  619. unsigned int last, struct list_entry_s *lel) {
  620. unsigned int pivotid;
  621. unsigned int i;
  622. register struct list_entry_s *pivot;
  623. struct list_entry_s *left, *right;
  624. void *tmpdata;
  625. #ifdef SIMCLIST_WITH_THREADS
  626. pthread_t tid;
  627. int traised;
  628. #endif
  629. if (last <= first) /* <= 1-element lists are always sorted */
  630. return;
  631. if (last - first+1 <= SIMCLIST_MINQUICKSORTELS) {
  632. list_sort_selectionsort(l, versus, first, fel, last, lel);
  633. return;
  634. }
  635. /* base of iteration: one element list */
  636. if (! (last > first)) return;
  637. pivotid = (get_random() % (last - first + 1));
  638. /* pivotid = (last - first + 1) / 2; */
  639. /* find pivot */
  640. if (pivotid < (last - first + 1)/2) {
  641. for (i = 0, pivot = fel; i < pivotid; pivot = pivot->next, i++);
  642. } else {
  643. for (i = last - first, pivot = lel; i > pivotid; pivot = pivot->prev, i--);
  644. }
  645. /* smaller PIVOT bigger */
  646. left = fel;
  647. right = lel;
  648. /* iterate --- left ---> PIV <--- right --- */
  649. while (left != pivot && right != pivot) {
  650. for (; left != pivot && (l->attrs.comparator(left->data, pivot->data) * -versus <= 0); left = left->next);
  651. /* left points to a smaller element, or to pivot */
  652. for (; right != pivot && (l->attrs.comparator(right->data, pivot->data) * -versus >= 0); right = right->prev);
  653. /* right points to a bigger element, or to pivot */
  654. if (left != pivot && right != pivot) {
  655. /* swap, then move iterators */
  656. tmpdata = left->data;
  657. left->data = right->data;
  658. right->data = tmpdata;
  659. left = left->next;
  660. right = right->prev;
  661. }
  662. }
  663. /* now either left points to pivot (end run), or right */
  664. if (right == pivot) { /* left part longer */
  665. while (left != pivot) {
  666. if (l->attrs.comparator(left->data, pivot->data) * -versus > 0) {
  667. tmpdata = left->data;
  668. left->data = pivot->prev->data;
  669. pivot->prev->data = pivot->data;
  670. pivot->data = tmpdata;
  671. pivot = pivot->prev;
  672. pivotid--;
  673. if (pivot == left) break;
  674. } else {
  675. left = left->next;
  676. }
  677. }
  678. } else { /* right part longer */
  679. while (right != pivot) {
  680. if (l->attrs.comparator(right->data, pivot->data) * -versus < 0) {
  681. /* move current right before pivot */
  682. tmpdata = right->data;
  683. right->data = pivot->next->data;
  684. pivot->next->data = pivot->data;
  685. pivot->data = tmpdata;
  686. pivot = pivot->next;
  687. pivotid++;
  688. if (pivot == right) break;
  689. } else {
  690. right = right->prev;
  691. }
  692. }
  693. }
  694. /* sort sublists A and B : |---A---| pivot |---B---| */
  695. #ifdef SIMCLIST_WITH_THREADS
  696. traised = 0;
  697. if (pivotid > 0) {
  698. /* prepare wrapped args, then start thread */
  699. if (l->threadcount < SIMCLIST_MAXTHREADS-1) {
  700. struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)malloc(sizeof(struct list_sort_wrappedparams));
  701. l->threadcount++;
  702. traised = 1;
  703. wp->l = l;
  704. wp->versus = versus;
  705. wp->first = first;
  706. wp->fel = fel;
  707. wp->last = first+pivotid-1;
  708. wp->lel = pivot->prev;
  709. if (pthread_create(&tid, NULL, list_sort_quicksort_threadwrapper, wp) != 0) {
  710. free(wp);
  711. traised = 0;
  712. list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
  713. }
  714. } else {
  715. list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
  716. }
  717. }
  718. if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel);
  719. if (traised) {
  720. pthread_join(tid, (void **)NULL);
  721. l->threadcount--;
  722. }
  723. #else
  724. if (pivotid > 0) list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev);
  725. if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel);
  726. #endif
  727. }
  728. int list_iterator_start(list_t *restrict l) {
  729. if (l->iter_active) return 0;
  730. l->iter_pos = 0;
  731. l->iter_active = 1;
  732. l->iter_curentry = l->head_sentinel->next;
  733. return 1;
  734. }
  735. void *list_iterator_next(list_t *restrict l) {
  736. void *toret;
  737. if (! l->iter_active) return NULL;
  738. toret = l->iter_curentry->data;
  739. l->iter_curentry = l->iter_curentry->next;
  740. l->iter_pos++;
  741. return toret;
  742. }
  743. int list_iterator_hasnext(const list_t *restrict l) {
  744. if (! l->iter_active) return 0;
  745. return (l->iter_pos < l->numels);
  746. }
  747. int list_iterator_stop(list_t *restrict l) {
  748. if (! l->iter_active) return 0;
  749. l->iter_pos = 0;
  750. l->iter_active = 0;
  751. return 1;
  752. }
  753. int list_hash(const list_t *restrict l, list_hash_t *restrict hash) {
  754. struct list_entry_s *x;
  755. list_hash_t tmphash;
  756. assert(hash != NULL);
  757. tmphash = l->numels * 2 + 100;
  758. if (l->attrs.hasher == NULL) {
  759. #ifdef SIMCLIST_ALLOW_LOCATIONBASED_HASHES
  760. /* ENABLE WITH CARE !! */
  761. #warning "Memlocation-based hash is consistent only for testing modification in the same program run."
  762. int i;
  763. /* only use element references */
  764. for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
  765. for (i = 0; i < sizeof(x->data); i++) {
  766. tmphash += (tmphash ^ (uintptr_t)x->data);
  767. }
  768. tmphash += tmphash % l->numels;
  769. }
  770. #else
  771. return -1;
  772. #endif
  773. } else {
  774. /* hash each element with the user-given function */
  775. for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
  776. tmphash += tmphash ^ l->attrs.hasher(x->data);
  777. tmphash +=* hash % l->numels;
  778. }
  779. }
  780. *hash = tmphash;
  781. return 0;
  782. }
  783. #ifndef SIMCLIST_NO_DUMPRESTORE
  784. int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *restrict info) {
  785. int32_t terminator_head, terminator_tail;
  786. uint32_t elemlen;
  787. off_t hop;
  788. /* version */
  789. READ_ERRCHECK(fd, & info->version, sizeof(info->version));
  790. info->version = ntohs(info->version);
  791. if (info->version > SIMCLIST_DUMPFORMAT_VERSION) {
  792. errno = EILSEQ;
  793. return -1;
  794. }
  795. /* timestamp */
  796. READ_ERRCHECK(fd, & info->timestamp, sizeof(info->timestamp));
  797. info->timestamp = hton64(info->timestamp);
  798. /* list terminator (to check thereafter) */
  799. READ_ERRCHECK(fd, & terminator_head, sizeof(terminator_head));
  800. terminator_head = ntohl(terminator_head);
  801. /* list size */
  802. READ_ERRCHECK(fd, & info->list_size, sizeof(info->list_size));
  803. info->list_size = ntohl(info->list_size);
  804. /* number of elements */
  805. READ_ERRCHECK(fd, & info->list_numels, sizeof(info->list_numels));
  806. info->list_numels = ntohl(info->list_numels);
  807. /* length of each element (for checking for consistency) */
  808. READ_ERRCHECK(fd, & elemlen, sizeof(elemlen));
  809. elemlen = ntohl(elemlen);
  810. /* list hash */
  811. READ_ERRCHECK(fd, & info->list_hash, sizeof(info->list_hash));
  812. info->list_hash = ntohl(info->list_hash);
  813. /* check consistency */
  814. if (elemlen > 0) {
  815. /* constant length, hop by size only */
  816. hop = info->list_size;
  817. } else {
  818. /* non-constant length, hop by size + all element length blocks */
  819. hop = info->list_size + elemlen*info->list_numels;
  820. }
  821. if (lseek(fd, hop, SEEK_CUR) == -1) {
  822. return -1;
  823. }
  824. /* read the trailing value and compare with terminator_head */
  825. READ_ERRCHECK(fd, & terminator_tail, sizeof(terminator_tail));
  826. terminator_tail = ntohl(terminator_tail);
  827. if (terminator_head == terminator_tail)
  828. info->consistent = 1;
  829. else
  830. info->consistent = 0;
  831. return 0;
  832. }
  833. int list_dump_getinfo_file(const char *restrict filename, list_dump_info_t *restrict info) {
  834. int fd, ret;
  835. fd = open(filename, O_RDONLY, 0);
  836. if (fd < 0) return -1;
  837. ret = list_dump_getinfo_filedescriptor(fd, info);
  838. close(fd);
  839. return ret;
  840. }
  841. int list_dump_filedescriptor(const list_t *restrict l, int fd, size_t *restrict len) {
  842. struct list_entry_s *x;
  843. void *ser_buf;
  844. uint32_t bufsize;
  845. struct timeval timeofday;
  846. struct list_dump_header_s header;
  847. if (l->attrs.meter == NULL && l->attrs.serializer == NULL) {
  848. errno = ENOTTY;
  849. return -1;
  850. }
  851. /**** DUMP FORMAT ****
  852. [ ver timestamp | totlen numels elemlen hash | DATA ]
  853. where DATA can be:
  854. @ for constant-size list (element size is constant; elemlen > 0)
  855. [ elem elem ... elem ]
  856. @ for other lists (element size dictated by element_meter each time; elemlen <= 0)
  857. [ size elem size elem ... size elem ]
  858. all integers are encoded in NETWORK BYTE FORMAT
  859. *****/
  860. /* prepare HEADER */
  861. /* version */
  862. header.ver = htons( SIMCLIST_DUMPFORMAT_VERSION );
  863. /* timestamp */
  864. gettimeofday(&timeofday, NULL);
  865. header.timestamp = (int64_t)timeofday.tv_sec * 1000000 + (int64_t)timeofday.tv_usec;
  866. header.timestamp = hton64(header.timestamp);
  867. header.rndterm = htonl((int32_t)get_random());
  868. /* total list size is postprocessed afterwards */
  869. /* number of elements */
  870. header.numels = htonl(l->numels);
  871. /* include an hash, if possible */
  872. if (l->attrs.hasher != NULL) {
  873. if (htonl(list_hash(l, & header.listhash)) != 0) {
  874. /* could not compute list hash! */
  875. return -1;
  876. }
  877. } else {
  878. header.listhash = htonl(0);
  879. }
  880. header.totlistlen = header.elemlen = 0;
  881. /* leave room for the header at the beginning of the file */
  882. if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) {
  883. /* errno set by lseek() */
  884. return -1;
  885. }
  886. /* write CONTENT */
  887. if (l->numels > 0) {
  888. /* SPECULATE that the list has constant element size */
  889. if (l->attrs.serializer != NULL) { /* user user-specified serializer */
  890. /* get preliminary length of serialized element in header.elemlen */
  891. ser_buf = l->attrs.serializer(l->head_sentinel->next->data, & header.elemlen);
  892. free(ser_buf);
  893. /* request custom serialization of each element */
  894. for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
  895. ser_buf = l->attrs.serializer(x->data, &bufsize);
  896. header.totlistlen += bufsize;
  897. if (header.elemlen != 0) { /* continue on speculation */
  898. if (header.elemlen != bufsize) {
  899. free(ser_buf);
  900. /* constant element length speculation broken! */
  901. header.elemlen = 0;
  902. header.totlistlen = 0;
  903. x = l->head_sentinel;
  904. if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) {
  905. /* errno set by lseek() */
  906. return -1;
  907. }
  908. /* restart from the beginning */
  909. continue;
  910. }
  911. /* speculation confirmed */
  912. WRITE_ERRCHECK(fd, ser_buf, bufsize);
  913. } else { /* speculation found broken */
  914. WRITE_ERRCHECK(fd, & bufsize, sizeof(size_t));
  915. WRITE_ERRCHECK(fd, ser_buf, bufsize);
  916. }
  917. free(ser_buf);
  918. }
  919. } else if (l->attrs.meter != NULL) {
  920. header.elemlen = (uint32_t)l->attrs.meter(l->head_sentinel->next->data);
  921. /* serialize the element straight from its data */
  922. for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) {
  923. bufsize = l->attrs.meter(x->data);
  924. header.totlistlen += bufsize;
  925. if (header.elemlen != 0) {
  926. if (header.elemlen != bufsize) {
  927. /* constant element length speculation broken! */
  928. header.elemlen = 0;
  929. header.totlistlen = 0;
  930. x = l->head_sentinel;
  931. /* restart from the beginning */
  932. continue;
  933. }
  934. WRITE_ERRCHECK(fd, x->data, bufsize);
  935. } else {
  936. WRITE_ERRCHECK(fd, &bufsize, sizeof(size_t));
  937. WRITE_ERRCHECK(fd, x->data, bufsize);
  938. }
  939. }
  940. }
  941. /* adjust endianness */
  942. header.elemlen = htonl(header.elemlen);
  943. header.totlistlen = htonl(header.totlistlen);
  944. }
  945. /* write random terminator */
  946. WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* list terminator */
  947. /* write header */
  948. lseek(fd, 0, SEEK_SET);
  949. WRITE_ERRCHECK(fd, & header.ver, sizeof(header.ver)); /* version */
  950. WRITE_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp)); /* timestamp */
  951. WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* random terminator */
  952. WRITE_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen)); /* total length of elements */
  953. WRITE_ERRCHECK(fd, & header.numels, sizeof(header.numels)); /* number of elements */
  954. WRITE_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen)); /* size of each element, or 0 for independent */
  955. WRITE_ERRCHECK(fd, & header.listhash, sizeof(header.listhash)); /* list hash, or 0 for "ignore" */
  956. /* possibly store total written length in "len" */
  957. if (len != NULL) {
  958. *len = sizeof(header) + ntohl(header.totlistlen);
  959. }
  960. return 0;
  961. }
  962. int list_restore_filedescriptor(list_t *restrict l, int fd, size_t *restrict len) {
  963. struct list_dump_header_s header;
  964. unsigned long cnt;
  965. void *buf;
  966. uint32_t elsize, totreadlen, totmemorylen;
  967. memset(& header, 0, sizeof(header));
  968. /* read header */
  969. /* version */
  970. READ_ERRCHECK(fd, &header.ver, sizeof(header.ver));
  971. header.ver = ntohs(header.ver);
  972. if (header.ver != SIMCLIST_DUMPFORMAT_VERSION) {
  973. errno = EILSEQ;
  974. return -1;
  975. }
  976. /* timestamp */
  977. READ_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp));
  978. /* list terminator */
  979. READ_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm));
  980. header.rndterm = ntohl(header.rndterm);
  981. /* total list size */
  982. READ_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen));
  983. header.totlistlen = ntohl(header.totlistlen);
  984. /* number of elements */
  985. READ_ERRCHECK(fd, & header.numels, sizeof(header.numels));
  986. header.numels = ntohl(header.numels);
  987. /* length of every element, or '0' = variable */
  988. READ_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen));
  989. header.elemlen = ntohl(header.elemlen);
  990. /* list hash, or 0 = 'ignore' */
  991. READ_ERRCHECK(fd, & header.listhash, sizeof(header.listhash));
  992. header.listhash = ntohl(header.listhash);
  993. /* read content */
  994. totreadlen = totmemorylen = 0;
  995. if (header.elemlen > 0) {
  996. /* elements have constant size = header.elemlen */
  997. if (l->attrs.unserializer != NULL) {
  998. /* use unserializer */
  999. buf = malloc(header.elemlen);
  1000. for (cnt = 0; cnt < header.numels; cnt++) {
  1001. READ_ERRCHECK(fd, buf, header.elemlen);
  1002. list_append(l, l->attrs.unserializer(buf, & elsize));
  1003. totmemorylen += elsize;
  1004. }
  1005. } else {
  1006. /* copy verbatim into memory */
  1007. for (cnt = 0; cnt < header.numels; cnt++) {
  1008. buf = malloc(header.elemlen);
  1009. READ_ERRCHECK(fd, buf, header.elemlen);
  1010. list_append(l, buf);
  1011. }
  1012. totmemorylen = header.numels * header.elemlen;
  1013. }
  1014. totreadlen = header.numels * header.elemlen;
  1015. } else {
  1016. /* elements have variable size. Each element is preceded by its size */
  1017. if (l->attrs.unserializer != NULL) {
  1018. /* use unserializer */
  1019. for (cnt = 0; cnt < header.numels; cnt++) {
  1020. READ_ERRCHECK(fd, & elsize, sizeof(elsize));
  1021. buf = malloc((size_t)elsize);
  1022. READ_ERRCHECK(fd, buf, elsize);
  1023. totreadlen += elsize;
  1024. list_append(l, l->attrs.unserializer(buf, & elsize));
  1025. totmemorylen += elsize;
  1026. }
  1027. } else {
  1028. /* copy verbatim into memory */
  1029. for (cnt = 0; cnt < header.numels; cnt++) {
  1030. READ_ERRCHECK(fd, & elsize, sizeof(elsize));
  1031. buf = malloc(elsize);
  1032. READ_ERRCHECK(fd, buf, elsize);
  1033. totreadlen += elsize;
  1034. list_append(l, buf);
  1035. }
  1036. totmemorylen = totreadlen;
  1037. }
  1038. }
  1039. READ_ERRCHECK(fd, &elsize, sizeof(elsize)); /* read list terminator */
  1040. elsize = ntohl(elsize);
  1041. /* possibly verify the list consistency */
  1042. /* wrt hash */
  1043. /* don't do that
  1044. if (header.listhash != 0 && header.listhash != list_hash(l)) {
  1045. errno = ECANCELED;
  1046. return -1;
  1047. }
  1048. */
  1049. /* wrt header */
  1050. if (totreadlen != header.totlistlen && (int32_t)elsize == header.rndterm) {
  1051. errno = EPROTO;
  1052. return -1;
  1053. }
  1054. /* wrt file */
  1055. if (lseek(fd, 0, SEEK_CUR) != lseek(fd, 0, SEEK_END)) {
  1056. errno = EPROTO;
  1057. return -1;
  1058. }
  1059. if (len != NULL) {
  1060. *len = totmemorylen;
  1061. }
  1062. return 0;
  1063. }
  1064. int list_dump_file(const list_t *restrict l, const char *restrict filename, size_t *restrict len) {
  1065. int fd;
  1066. size_t sizetoret;
  1067. fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  1068. if (fd < 0) return -1;
  1069. sizetoret = list_dump_filedescriptor(l, fd, len);
  1070. close(fd);
  1071. return sizetoret;
  1072. }
  1073. int list_restore_file(list_t *restrict l, const char *restrict filename, size_t *restrict len) {
  1074. int fd;
  1075. size_t totdata;
  1076. fd = open(filename, O_RDONLY, 0);
  1077. if (fd < 0) return -1;
  1078. totdata = list_restore_filedescriptor(l, fd, len);
  1079. close(fd);
  1080. return totdata;
  1081. }
  1082. #endif /* ifndef SIMCLIST_NO_DUMPRESTORE */
  1083. static int list_drop_elem(list_t *restrict l, struct list_entry_s *tmp, unsigned int pos) {
  1084. if (tmp == NULL) return -1;
  1085. /* fix mid pointer. This is wrt the PRE situation */
  1086. if (l->numels % 2) { /* now odd */
  1087. /* sort out the base case by hand */
  1088. if (l->numels == 1) l->mid = NULL;
  1089. else if (pos >= l->numels/2) l->mid = l->mid->prev;
  1090. } else { /* now even */
  1091. if (pos < l->numels/2) l->mid = l->mid->next;
  1092. }
  1093. tmp->prev->next = tmp->next;
  1094. tmp->next->prev = tmp->prev;
  1095. /* free what's to be freed */
  1096. if (l->attrs.copy_data && tmp->data != NULL)
  1097. free(tmp->data);
  1098. if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) {
  1099. l->spareels[l->spareelsnum++] = tmp;
  1100. } else {
  1101. free(tmp);
  1102. }
  1103. return 0;
  1104. }
  1105. /* ready-made comparators and meters */
  1106. #define SIMCLIST_NUMBER_COMPARATOR(type) int list_comparator_##type(const void *a, const void *b) { return( *(type *)a < *(type *)b) - (*(type *)a > *(type *)b); }
  1107. SIMCLIST_NUMBER_COMPARATOR(int8_t)
  1108. SIMCLIST_NUMBER_COMPARATOR(int16_t)
  1109. SIMCLIST_NUMBER_COMPARATOR(int32_t)
  1110. SIMCLIST_NUMBER_COMPARATOR(int64_t)
  1111. SIMCLIST_NUMBER_COMPARATOR(uint8_t)
  1112. SIMCLIST_NUMBER_COMPARATOR(uint16_t)
  1113. SIMCLIST_NUMBER_COMPARATOR(uint32_t)
  1114. SIMCLIST_NUMBER_COMPARATOR(uint64_t)
  1115. SIMCLIST_NUMBER_COMPARATOR(float)
  1116. SIMCLIST_NUMBER_COMPARATOR(double)
  1117. int list_comparator_string(const void *a, const void *b) { return strcmp((const char *)b, (const char *)a); }
  1118. /* ready-made metric functions */
  1119. #define SIMCLIST_METER(type) size_t list_meter_##type(const void *el) { if (el) { /* kill compiler whinge */ } return sizeof(type); }
  1120. SIMCLIST_METER(int8_t)
  1121. SIMCLIST_METER(int16_t)
  1122. SIMCLIST_METER(int32_t)
  1123. SIMCLIST_METER(int64_t)
  1124. SIMCLIST_METER(uint8_t)
  1125. SIMCLIST_METER(uint16_t)
  1126. SIMCLIST_METER(uint32_t)
  1127. SIMCLIST_METER(uint64_t)
  1128. SIMCLIST_METER(float)
  1129. SIMCLIST_METER(double)
  1130. size_t list_meter_string(const void *el) { return strlen((const char *)el) + 1; }
  1131. /* ready-made hashing functions */
  1132. #define SIMCLIST_HASHCOMPUTER(type) list_hash_t list_hashcomputer_##type(const void *el) { return (list_hash_t)(*(type *)el); }
  1133. SIMCLIST_HASHCOMPUTER(int8_t)
  1134. SIMCLIST_HASHCOMPUTER(int16_t)
  1135. SIMCLIST_HASHCOMPUTER(int32_t)
  1136. SIMCLIST_HASHCOMPUTER(int64_t)
  1137. SIMCLIST_HASHCOMPUTER(uint8_t)
  1138. SIMCLIST_HASHCOMPUTER(uint16_t)
  1139. SIMCLIST_HASHCOMPUTER(uint32_t)
  1140. SIMCLIST_HASHCOMPUTER(uint64_t)
  1141. SIMCLIST_HASHCOMPUTER(float)
  1142. SIMCLIST_HASHCOMPUTER(double)
  1143. list_hash_t list_hashcomputer_string(const void *el) {
  1144. size_t l;
  1145. list_hash_t hash = 123;
  1146. const char *str = (const char *)el;
  1147. char plus;
  1148. for (l = 0; str[l] != '\0'; l++) {
  1149. if (l) plus = hash ^ str[l];
  1150. else plus = hash ^ (str[l] - str[0]);
  1151. hash += (plus << (CHAR_BIT * (l % sizeof(list_hash_t))));
  1152. }
  1153. return hash;
  1154. }
  1155. #ifndef NDEBUG
  1156. static int list_repOk(const list_t *restrict l) {
  1157. int ok, i;
  1158. struct list_entry_s *s;
  1159. ok = (l != NULL) && (
  1160. /* head/tail checks */
  1161. (l->head_sentinel != NULL && l->tail_sentinel != NULL) &&
  1162. (l->head_sentinel != l->tail_sentinel) && (l->head_sentinel->prev == NULL && l->tail_sentinel->next == NULL) &&
  1163. /* empty list */
  1164. (l->numels > 0 || (l->mid == NULL && l->head_sentinel->next == l->tail_sentinel && l->tail_sentinel->prev == l->head_sentinel)) &&
  1165. /* spare elements checks */
  1166. l->spareelsnum <= SIMCLIST_MAX_SPARE_ELEMS
  1167. );
  1168. if (!ok) return 0;
  1169. if (l->numels >= 1) {
  1170. /* correct referencing */
  1171. for (i = -1, s = l->head_sentinel; i < (int)(l->numels-1)/2 && s->next != NULL; i++, s = s->next) {
  1172. if (s->next->prev != s) break;
  1173. }
  1174. ok = (i == (int)(l->numels-1)/2 && l->mid == s);
  1175. if (!ok) return 0;
  1176. for (; s->next != NULL; i++, s = s->next) {
  1177. if (s->next->prev != s) break;
  1178. }
  1179. ok = (i == (int)l->numels && s == l->tail_sentinel);
  1180. }
  1181. return ok;
  1182. }
  1183. static int list_attrOk(const list_t *restrict l) {
  1184. int ok;
  1185. ok = (l->attrs.copy_data == 0 || l->attrs.meter != NULL);
  1186. return ok;
  1187. }
  1188. #endif