/src/opensc/src/common/simclist.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
18 | | /* |
19 | | * SimCList library. See http://mij.oltrelinux.com/devel/simclist |
20 | | */ |
21 | | |
22 | | /* SimCList implementation, version 1.5, with local modifications */ |
23 | | |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <errno.h> /* for setting errno */ |
27 | | #include <sys/types.h> |
28 | | #if !defined(_WIN32) |
29 | | #include <arpa/inet.h> /* for htons() */ |
30 | | #include <unistd.h> |
31 | | #ifdef HAVE_SYS_TIME_H |
32 | | #include <sys/time.h> /* for gettimeofday() */ |
33 | | #endif |
34 | | #include <stdint.h> |
35 | | #else |
36 | | #include <winsock2.h> |
37 | | #endif |
38 | | #ifdef SIMCLIST_DUMPRESTORE |
39 | | #ifndef _WIN32 |
40 | | #include <sys/uio.h> /* for READ_ERRCHECK() and write() */ |
41 | | #endif |
42 | | #include <fcntl.h> /* for open() etc */ |
43 | | #endif |
44 | | #include <time.h> /* for time() for random seed */ |
45 | | #include <sys/stat.h> /* for open()'s access modes S_IRUSR etc */ |
46 | | #include <limits.h> |
47 | | |
48 | | |
49 | | #ifdef SIMCLIST_DUMPRESTORE |
50 | | /* convert 64bit integers from host to network format */ |
51 | | #define hton64(x) (\ |
52 | | htons(1) == 1 ? \ |
53 | | (uint64_t)x /* big endian */ \ |
54 | | : /* little endian */ \ |
55 | | ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \ |
56 | | (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ |
57 | | (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ |
58 | | (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ |
59 | | (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ |
60 | | (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ |
61 | | (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ |
62 | | (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) \ |
63 | | ) |
64 | | |
65 | | /* convert 64bit integers from network to host format */ |
66 | | #define ntoh64(x) (hton64(x)) |
67 | | #endif |
68 | | |
69 | | /* some OSes don't have EPROTO (eg OpenBSD) */ |
70 | | #ifndef EPROTO |
71 | | #define EPROTO EIO |
72 | | #endif |
73 | | |
74 | | /* disable asserts */ |
75 | | #ifndef SIMCLIST_DEBUG |
76 | | #ifndef NDEBUG |
77 | | #define NDEBUG |
78 | | #endif |
79 | | #endif |
80 | | |
81 | | #include <assert.h> |
82 | | |
83 | | #ifdef SIMCLIST_WITH_THREADS |
84 | | /* limit (approx) to the number of threads running |
85 | | * for threaded operations. Only meant when |
86 | | * SIMCLIST_WITH_THREADS is defined */ |
87 | | #define SIMCLIST_MAXTHREADS 2 |
88 | | #endif |
89 | | |
90 | | /* |
91 | | * how many elems to keep as spare. During a deletion, an element |
92 | | * can be saved in a "free-list", not free()d immediately. When |
93 | | * latter insertions are performed, spare elems can be used instead |
94 | | * of malloc()ing new elems. |
95 | | * |
96 | | * about this param, some values for appending |
97 | | * 10 million elems into an empty list: |
98 | | * (#, time[sec], gain[%], gain/no[%]) |
99 | | * 0 2,164 0,00 0,00 <-- feature disabled |
100 | | * 1 1,815 34,9 34,9 |
101 | | * 2 1,446 71,8 35,9 <-- MAX gain/no |
102 | | * 3 1,347 81,7 27,23 |
103 | | * 5 1,213 95,1 19,02 |
104 | | * 8 1,064 110,0 13,75 |
105 | | * 10 1,015 114,9 11,49 <-- MAX gain w/ likely sol |
106 | | * 15 1,019 114,5 7,63 |
107 | | * 25 0,985 117,9 4,72 |
108 | | * 50 1,088 107,6 2,15 |
109 | | * 75 1,016 114,8 1,53 |
110 | | * 100 0,988 117,6 1,18 |
111 | | * 150 1,022 114,2 0,76 |
112 | | * 200 0,939 122,5 0,61 <-- MIN time |
113 | | */ |
114 | | #ifndef SIMCLIST_MAX_SPARE_ELEMS |
115 | 871k | #define SIMCLIST_MAX_SPARE_ELEMS 5 |
116 | | #endif |
117 | | |
118 | | |
119 | | #ifdef SIMCLIST_WITH_THREADS |
120 | | #include <pthread.h> |
121 | | #endif |
122 | | |
123 | | #include "simclist.h" |
124 | | |
125 | | |
126 | | /* minimum number of elements for sorting with quicksort instead of insertion */ |
127 | 0 | #define SIMCLIST_MINQUICKSORTELS 24 |
128 | | |
129 | | |
130 | | /* list dump declarations */ |
131 | | #define SIMCLIST_DUMPFORMAT_VERSION 1 /* (short integer) version of fileformat managed by _dump* and _restore* functions */ |
132 | | |
133 | | #define SIMCLIST_DUMPFORMAT_HEADERLEN 30 /* length of the header */ |
134 | | |
135 | | /* header for a list dump */ |
136 | | struct list_dump_header_s { |
137 | | uint16_t ver; /* version */ |
138 | | int64_t timestamp; /* dump timestamp */ |
139 | | int32_t rndterm; /* random value terminator -- terminates the data sequence */ |
140 | | |
141 | | uint32_t totlistlen; /* sum of every element' size, bytes */ |
142 | | uint32_t numels; /* number of elements */ |
143 | | uint32_t elemlen; /* bytes length of an element, for constant-size lists, <= 0 otherwise */ |
144 | | int32_t listhash; /* hash of the list at the time of dumping, or 0 if to be ignored */ |
145 | | }; |
146 | | |
147 | | |
148 | | |
149 | | /* deletes tmp from list, with care wrt its position (head, tail, middle) */ |
150 | | static int list_drop_elem(list_t *simclist_restrict l, struct list_entry_s *tmp, unsigned int pos); |
151 | | |
152 | | /* set default values for initialized lists */ |
153 | | static int list_attributes_setdefaults(list_t *simclist_restrict l); |
154 | | |
155 | | #ifndef NDEBUG |
156 | | /* check whether the list internal REPresentation is valid -- Costs O(n) */ |
157 | | static int list_repOk(const list_t *simclist_restrict l); |
158 | | |
159 | | /* check whether the list attribute set is valid -- Costs O(1) */ |
160 | | static int list_attrOk(const list_t *simclist_restrict l); |
161 | | #endif |
162 | | |
163 | | /* do not inline, this is recursive */ |
164 | | static void list_sort_quicksort(list_t *simclist_restrict l, int versus, |
165 | | unsigned int first, struct list_entry_s *fel, |
166 | | unsigned int last, struct list_entry_s *lel); |
167 | | |
168 | | static simclist_inline void list_sort_selectionsort(list_t *simclist_restrict l, int versus, |
169 | | unsigned int first, struct list_entry_s *fel, |
170 | | unsigned int last, struct list_entry_s *lel); |
171 | | |
172 | | static void *list_get_minmax(const list_t *simclist_restrict l, int versus); |
173 | | |
174 | | static simclist_inline struct list_entry_s *list_findpos(const list_t *simclist_restrict l, int posstart); |
175 | | |
176 | | #ifdef SIMCLIST_DUMPRESTORE |
177 | | /* write() decorated with error checking logic */ |
178 | | #define WRITE_ERRCHECK(fd, msgbuf, msglen) do { \ |
179 | | if (write(fd, msgbuf, msglen) < 0) return -1; \ |
180 | | } while (0); |
181 | | /* READ_ERRCHECK() decorated with error checking logic */ |
182 | | #define READ_ERRCHECK(fd, msgbuf, msglen) do { \ |
183 | | if (read(fd, msgbuf, msglen) != msglen) { \ |
184 | | /*errno = EPROTO;*/ \ |
185 | | free(buf); \ |
186 | | return -1; \ |
187 | | } \ |
188 | | } while (0); |
189 | | #endif |
190 | | |
191 | | /* |
192 | | * Random Number Generator |
193 | | * |
194 | | * The user is expected to seed the RNG (ie call srand()) if |
195 | | * SIMCLIST_SYSTEM_RNG is defined. |
196 | | * |
197 | | * Otherwise, a self-contained RNG based on LCG is used; see |
198 | | * http://en.wikipedia.org/wiki/Linear_congruential_generator . |
199 | | * |
200 | | * Facts pro local RNG: |
201 | | * 1. no need for the user to call srand() on his own |
202 | | * 2. very fast, possibly faster than OS |
203 | | * 3. avoid interference with user's RNG |
204 | | * |
205 | | * Facts pro system RNG: |
206 | | * 1. may be more accurate (irrelevant for SimCList random purposes) |
207 | | * 2. why reinvent the wheel |
208 | | * |
209 | | * Default to local RNG for user's ease of use. |
210 | | */ |
211 | | |
212 | | #ifdef SIMCLIST_SYSTEM_RNG |
213 | | /* keep track whether we initialized already (non-0) or not (0) */ |
214 | | static unsigned random_seed = 0; |
215 | | |
216 | | /* use local RNG */ |
217 | | static simclist_inline void seed_random() { |
218 | | if (random_seed == 0) |
219 | | random_seed = (unsigned)getpid() ^ (unsigned)time(NULL); |
220 | | } |
221 | | |
222 | | static simclist_inline long get_random() { |
223 | | random_seed = (1664525 * random_seed + 1013904223); |
224 | | return random_seed; |
225 | | } |
226 | | |
227 | | #else |
228 | | /* use OS's random generator */ |
229 | | # define seed_random() |
230 | 0 | # define get_random() (rand()) |
231 | | #endif |
232 | | |
233 | | |
234 | | /* list initialization */ |
235 | 205k | int list_init(list_t *simclist_restrict l) { |
236 | 205k | if (l == NULL) { |
237 | 0 | return -1; |
238 | 0 | } |
239 | | |
240 | 205k | memset(l, 0, sizeof *l); |
241 | | |
242 | 205k | seed_random(); |
243 | | |
244 | 205k | l->numels = 0; |
245 | | |
246 | | /* head/tail sentinels and mid pointer */ |
247 | 205k | l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); |
248 | 205k | l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); |
249 | 205k | if (l->tail_sentinel == NULL || l->head_sentinel == NULL) { |
250 | 0 | return -1; |
251 | 0 | } |
252 | 205k | l->head_sentinel->next = l->tail_sentinel; |
253 | 205k | l->tail_sentinel->prev = l->head_sentinel; |
254 | 205k | l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL; |
255 | 205k | l->head_sentinel->data = l->tail_sentinel->data = NULL; |
256 | | |
257 | | /* iteration attributes */ |
258 | 205k | l->iter_active = 0; |
259 | 205k | l->iter_pos = 0; |
260 | 205k | l->iter_curentry = NULL; |
261 | | |
262 | | /* free-list attributes */ |
263 | 205k | l->spareelsnum = 0; |
264 | 205k | l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *)); |
265 | 205k | if (l->spareels == NULL) { |
266 | 0 | return -1; |
267 | 0 | } |
268 | | |
269 | | #ifdef SIMCLIST_WITH_THREADS |
270 | | l->threadcount = 0; |
271 | | #endif |
272 | | |
273 | 205k | if (0 != list_attributes_setdefaults(l)) { |
274 | 0 | return -1; |
275 | 0 | } |
276 | | |
277 | 205k | assert(list_repOk(l)); |
278 | 205k | assert(list_attrOk(l)); |
279 | | |
280 | 205k | return 0; |
281 | 205k | } |
282 | | |
283 | 205k | void list_destroy(list_t *simclist_restrict l) { |
284 | 205k | unsigned int i; |
285 | | |
286 | 205k | list_clear(l); |
287 | 382k | for (i = 0; i < l->spareelsnum; i++) { |
288 | 177k | free(l->spareels[i]); |
289 | 177k | } |
290 | 205k | free(l->spareels); |
291 | 205k | free(l->head_sentinel); |
292 | 205k | free(l->tail_sentinel); |
293 | 205k | } |
294 | | |
295 | 205k | int list_attributes_setdefaults(list_t *simclist_restrict l) { |
296 | 205k | l->attrs.comparator = NULL; |
297 | 205k | l->attrs.seeker = NULL; |
298 | | |
299 | | /* also free() element data when removing and element from the list */ |
300 | 205k | l->attrs.meter = NULL; |
301 | 205k | l->attrs.copy_data = 0; |
302 | | |
303 | 205k | l->attrs.hasher = NULL; |
304 | | |
305 | | /* serializer/unserializer */ |
306 | 205k | l->attrs.serializer = NULL; |
307 | 205k | l->attrs.unserializer = NULL; |
308 | | |
309 | 205k | assert(list_attrOk(l)); |
310 | | |
311 | 205k | return 0; |
312 | 205k | } |
313 | | |
314 | | /* setting list properties */ |
315 | 22.9k | int list_attributes_comparator(list_t *simclist_restrict l, element_comparator comparator_fun) { |
316 | 22.9k | if (l == NULL) return -1; |
317 | | |
318 | 22.9k | l->attrs.comparator = comparator_fun; |
319 | | |
320 | 22.9k | assert(list_attrOk(l)); |
321 | | |
322 | 22.9k | return 0; |
323 | 22.9k | } |
324 | | |
325 | 162k | int list_attributes_seeker(list_t *simclist_restrict l, element_seeker seeker_fun) { |
326 | 162k | if (l == NULL) return -1; |
327 | | |
328 | 162k | l->attrs.seeker = seeker_fun; |
329 | 162k | assert(list_attrOk(l)); |
330 | | |
331 | 162k | return 0; |
332 | 162k | } |
333 | | |
334 | 32.5k | int list_attributes_copy(list_t *simclist_restrict l, element_meter metric_fun, int copy_data) { |
335 | 32.5k | if (l == NULL || (metric_fun == NULL && copy_data != 0)) return -1; |
336 | | |
337 | 32.5k | l->attrs.meter = metric_fun; |
338 | 32.5k | l->attrs.copy_data = copy_data; |
339 | | |
340 | 32.5k | assert(list_attrOk(l)); |
341 | | |
342 | 32.5k | return 0; |
343 | 32.5k | } |
344 | | |
345 | 0 | int list_attributes_hash_computer(list_t *simclist_restrict l, element_hash_computer hash_computer_fun) { |
346 | 0 | if (l == NULL) return -1; |
347 | | |
348 | 0 | l->attrs.hasher = hash_computer_fun; |
349 | 0 | assert(list_attrOk(l)); |
350 | 0 | return 0; |
351 | 0 | } |
352 | | |
353 | 0 | int list_attributes_serializer(list_t *simclist_restrict l, element_serializer serializer_fun) { |
354 | 0 | if (l == NULL) return -1; |
355 | | |
356 | 0 | l->attrs.serializer = serializer_fun; |
357 | 0 | assert(list_attrOk(l)); |
358 | 0 | return 0; |
359 | 0 | } |
360 | | |
361 | 0 | int list_attributes_unserializer(list_t *simclist_restrict l, element_unserializer unserializer_fun) { |
362 | 0 | if (l == NULL) return -1; |
363 | | |
364 | 0 | l->attrs.unserializer = unserializer_fun; |
365 | 0 | assert(list_attrOk(l)); |
366 | 0 | return 0; |
367 | 0 | } |
368 | | |
369 | 368k | int list_append(list_t *simclist_restrict l, const void *data) { |
370 | 368k | return list_insert_at(l, data, l->numels); |
371 | 368k | } |
372 | | |
373 | 0 | int list_prepend(list_t *simclist_restrict l, const void *data) { |
374 | 0 | return list_insert_at(l, data, 0); |
375 | 0 | } |
376 | | |
377 | 91.0k | void *list_fetch(list_t *simclist_restrict l) { |
378 | 91.0k | return list_extract_at(l, 0); |
379 | 91.0k | } |
380 | | |
381 | 333k | void *list_get_at(const list_t *simclist_restrict l, unsigned int pos) { |
382 | 333k | struct list_entry_s *tmp; |
383 | | |
384 | 333k | tmp = list_findpos(l, pos); |
385 | | |
386 | 333k | return (tmp != NULL ? tmp->data : NULL); |
387 | 333k | } |
388 | | |
389 | 0 | void *list_get_max(const list_t *simclist_restrict l) { |
390 | 0 | return list_get_minmax(l, +1); |
391 | 0 | } |
392 | | |
393 | 0 | void *list_get_min(const list_t *simclist_restrict l) { |
394 | 0 | return list_get_minmax(l, -1); |
395 | 0 | } |
396 | | |
397 | | /* REQUIRES {list->numels >= 1} |
398 | | * return the min (versus < 0) or max value (v > 0) in l */ |
399 | 0 | static void *list_get_minmax(const list_t *simclist_restrict l, int versus) { |
400 | 0 | void *curminmax; |
401 | 0 | struct list_entry_s *s; |
402 | |
|
403 | 0 | if (l->attrs.comparator == NULL || l->numels == 0) |
404 | 0 | return NULL; |
405 | | |
406 | 0 | curminmax = l->head_sentinel->next->data; |
407 | 0 | for (s = l->head_sentinel->next->next; s != l->tail_sentinel; s = s->next) { |
408 | 0 | if (l->attrs.comparator(curminmax, s->data) * versus > 0) |
409 | 0 | curminmax = s->data; |
410 | 0 | } |
411 | |
|
412 | 0 | return curminmax; |
413 | 0 | } |
414 | | |
415 | | /* set tmp to point to element at index posstart in l */ |
416 | 863k | static simclist_inline struct list_entry_s *list_findpos(const list_t *simclist_restrict l, int posstart) { |
417 | 863k | struct list_entry_s *ptr; |
418 | 863k | float x; |
419 | 863k | int i; |
420 | | |
421 | 863k | if (l->head_sentinel == NULL || l->tail_sentinel == NULL) return NULL; |
422 | | |
423 | | /* accept 1 slot overflow for fetching head and tail sentinels */ |
424 | 863k | if (posstart < -1 || posstart > (int)l->numels) return NULL; |
425 | | |
426 | 863k | x = l->numels ? (float)(posstart+1) / l->numels : 0; |
427 | 863k | if (x <= 0.25) { |
428 | | /* first quarter: get to posstart from head */ |
429 | 230k | for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++); |
430 | 684k | } else if (x < 0.5) { |
431 | | /* second quarter: get to posstart from mid */ |
432 | 44.3k | for (i = (l->numels-1)/2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--); |
433 | 673k | } else if (x <= 0.75) { |
434 | | /* third quarter: get to posstart from mid */ |
435 | 37.2k | for (i = (l->numels-1)/2, ptr = l->mid; i < posstart; ptr = ptr->next, i++); |
436 | 660k | } else { |
437 | | /* fourth quarter: get to posstart from tail */ |
438 | 1.34M | for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--); |
439 | 660k | } |
440 | | |
441 | 863k | return ptr; |
442 | 863k | } |
443 | | |
444 | 91.0k | void *list_extract_at(list_t *simclist_restrict l, unsigned int pos) { |
445 | 91.0k | struct list_entry_s *tmp; |
446 | 91.0k | void *data; |
447 | | |
448 | 91.0k | if (l->iter_active || pos >= l->numels) return NULL; |
449 | | |
450 | 42.8k | tmp = list_findpos(l, pos); |
451 | 42.8k | if (tmp == NULL) { |
452 | 0 | return NULL; |
453 | 0 | } |
454 | 42.8k | data = tmp->data; |
455 | | |
456 | 42.8k | tmp->data = NULL; /* save data from list_drop_elem() free() */ |
457 | 42.8k | list_drop_elem(l, tmp, pos); |
458 | 42.8k | l->numels--; |
459 | | |
460 | 42.8k | assert(list_repOk(l)); |
461 | | |
462 | 42.8k | return data; |
463 | 42.8k | } |
464 | | |
465 | 368k | int list_insert_at(list_t *simclist_restrict l, const void *data, unsigned int pos) { |
466 | 368k | struct list_entry_s *lent, *succ, *prec; |
467 | | |
468 | 368k | if (l->iter_active || pos > l->numels) return -1; |
469 | | |
470 | | /* this code optimizes malloc() with a free-list */ |
471 | 368k | if (l->spareelsnum > 0) { |
472 | 0 | lent = l->spareels[l->spareelsnum-1]; |
473 | 0 | l->spareelsnum--; |
474 | 368k | } else { |
475 | 368k | lent = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); |
476 | 368k | if (lent == NULL) { |
477 | 0 | return -1; |
478 | 0 | } |
479 | 368k | } |
480 | | |
481 | 368k | if (l->attrs.copy_data) { |
482 | | /* make room for user' data (has to be copied) */ |
483 | 207k | size_t datalen = l->attrs.meter(data); |
484 | 207k | lent->data = (struct list_entry_s *)malloc(datalen); |
485 | 207k | if (lent->data == NULL) { |
486 | 0 | if (!(l->spareelsnum > 0)) { |
487 | 0 | free(lent); |
488 | 0 | } |
489 | 0 | return -1; |
490 | 0 | } |
491 | 207k | memcpy(lent->data, data, datalen); |
492 | 207k | } else { |
493 | 161k | lent->data = (void*)data; |
494 | 161k | } |
495 | | |
496 | | /* actually append element */ |
497 | 368k | prec = list_findpos(l, pos-1); |
498 | 368k | if (prec == NULL) { |
499 | 0 | if (l->attrs.copy_data) { |
500 | 0 | free(lent->data); |
501 | 0 | } |
502 | 0 | if (!(l->spareelsnum > 0)) { |
503 | 0 | free(lent); |
504 | 0 | } |
505 | 0 | return -1; |
506 | 0 | } |
507 | 368k | succ = prec->next; |
508 | | |
509 | 368k | prec->next = lent; |
510 | 368k | lent->prev = prec; |
511 | 368k | lent->next = succ; |
512 | 368k | succ->prev = lent; |
513 | | |
514 | 368k | l->numels++; |
515 | | |
516 | | /* fix mid pointer */ |
517 | 368k | if (l->numels == 1) { /* first element, set pointer */ |
518 | 150k | l->mid = lent; |
519 | 218k | } else if (l->numels % 2) { /* now odd */ |
520 | 106k | if (pos >= (l->numels-1)/2) l->mid = l->mid->next; |
521 | 111k | } else { /* now even */ |
522 | 111k | if (pos <= (l->numels-1)/2) l->mid = l->mid->prev; |
523 | 111k | } |
524 | | |
525 | 368k | assert(list_repOk(l)); |
526 | | |
527 | 368k | return 1; |
528 | 368k | } |
529 | | |
530 | 118k | int list_delete(list_t *simclist_restrict l, const void *data) { |
531 | 118k | int pos, r; |
532 | | |
533 | 118k | pos = list_locate(l, data); |
534 | 118k | if (pos < 0) |
535 | 0 | return -1; |
536 | | |
537 | 118k | r = list_delete_at(l, pos); |
538 | 118k | if (r < 0) |
539 | 0 | return -1; |
540 | | |
541 | 118k | assert(list_repOk(l)); |
542 | | |
543 | 118k | return 0; |
544 | 118k | } |
545 | | |
546 | 118k | int list_delete_at(list_t *simclist_restrict l, unsigned int pos) { |
547 | 118k | struct list_entry_s *delendo; |
548 | | |
549 | | |
550 | 118k | if (l->iter_active || pos >= l->numels) return -1; |
551 | | |
552 | 118k | delendo = list_findpos(l, pos); |
553 | | |
554 | 118k | list_drop_elem(l, delendo, pos); |
555 | | |
556 | 118k | l->numels--; |
557 | | |
558 | | |
559 | 118k | assert(list_repOk(l)); |
560 | | |
561 | 118k | return 0; |
562 | 118k | } |
563 | | |
564 | 0 | int list_delete_range(list_t *simclist_restrict l, unsigned int posstart, unsigned int posend) { |
565 | 0 | struct list_entry_s *lastvalid, *tmp, *tmp2; |
566 | 0 | unsigned int i; |
567 | 0 | int movedx; |
568 | 0 | unsigned int numdel, midposafter; |
569 | |
|
570 | 0 | if (l->iter_active || posend < posstart || posend >= l->numels) return -1; |
571 | | |
572 | 0 | tmp = list_findpos(l, posstart); /* first el to be deleted */ |
573 | 0 | if (tmp == NULL) { |
574 | 0 | return -1; |
575 | 0 | } |
576 | 0 | lastvalid = tmp->prev; /* last valid element */ |
577 | |
|
578 | 0 | numdel = posend - posstart + 1; |
579 | 0 | midposafter = (l->numels-1-numdel)/2; |
580 | |
|
581 | 0 | midposafter = midposafter < posstart ? midposafter : midposafter+numdel; |
582 | 0 | movedx = midposafter - (l->numels-1)/2; |
583 | |
|
584 | 0 | if (movedx > 0) { /* move right */ |
585 | 0 | for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->next, i++); |
586 | 0 | } else { /* move left */ |
587 | 0 | movedx = -movedx; |
588 | 0 | for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->prev, i++); |
589 | 0 | } |
590 | |
|
591 | 0 | assert(posstart == 0 || lastvalid != l->head_sentinel); |
592 | 0 | i = posstart; |
593 | 0 | if (l->attrs.copy_data) { |
594 | | /* also free element data */ |
595 | 0 | for (; i <= posend; i++) { |
596 | 0 | tmp2 = tmp; |
597 | 0 | tmp = tmp->next; |
598 | 0 | if (tmp2->data != NULL) free(tmp2->data); |
599 | 0 | if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { |
600 | 0 | l->spareels[l->spareelsnum++] = tmp2; |
601 | 0 | } else { |
602 | 0 | free(tmp2); |
603 | 0 | } |
604 | 0 | } |
605 | 0 | } else { |
606 | | /* only free containers */ |
607 | 0 | for (; i <= posend; i++) { |
608 | 0 | tmp2 = tmp; |
609 | 0 | tmp = tmp->next; |
610 | 0 | if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { |
611 | 0 | l->spareels[l->spareelsnum++] = tmp2; |
612 | 0 | } else { |
613 | 0 | free(tmp2); |
614 | 0 | } |
615 | 0 | } |
616 | 0 | } |
617 | 0 | assert(i == posend+1 && (posend != l->numels || tmp == l->tail_sentinel)); |
618 | |
|
619 | 0 | lastvalid->next = tmp; |
620 | 0 | tmp->prev = lastvalid; |
621 | |
|
622 | 0 | l->numels -= posend - posstart + 1; |
623 | |
|
624 | 0 | assert(list_repOk(l)); |
625 | |
|
626 | 0 | return 0; |
627 | 0 | } |
628 | | |
629 | 221k | int list_clear(list_t *simclist_restrict l) { |
630 | 221k | struct list_entry_s *s; |
631 | | |
632 | 221k | if (l->iter_active) return -1; |
633 | | |
634 | 221k | if (l->head_sentinel && l->tail_sentinel) { |
635 | 221k | if (l->attrs.copy_data) { /* also free user data */ |
636 | | /* spare a loop conditional with two loops: spareing elems and freeing elems */ |
637 | 63.7k | for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { |
638 | | /* move elements as spares as long as there is room */ |
639 | 31.2k | if (s->data != NULL) free(s->data); |
640 | 31.2k | l->spareels[l->spareelsnum++] = s; |
641 | 31.2k | } |
642 | 208k | while (s != l->tail_sentinel) { |
643 | | /* free the remaining elems */ |
644 | 176k | if (s->data != NULL) free(s->data); |
645 | 176k | s = s->next; |
646 | 176k | free(s->prev); |
647 | 176k | } |
648 | 32.5k | l->head_sentinel->next = l->tail_sentinel; |
649 | 32.5k | l->tail_sentinel->prev = l->head_sentinel; |
650 | 188k | } else { /* only free element containers */ |
651 | | /* spare a loop conditional with two loops: spareing elems and freeing elems */ |
652 | 188k | for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { |
653 | | /* move elements as spares as long as there is room */ |
654 | 0 | l->spareels[l->spareelsnum++] = s; |
655 | 0 | } |
656 | 188k | while (s != l->tail_sentinel) { |
657 | | /* free the remaining elems */ |
658 | 0 | s = s->next; |
659 | 0 | free(s->prev); |
660 | 0 | } |
661 | 188k | l->head_sentinel->next = l->tail_sentinel; |
662 | 188k | l->tail_sentinel->prev = l->head_sentinel; |
663 | 188k | } |
664 | 221k | } |
665 | 221k | l->numels = 0; |
666 | 221k | l->mid = NULL; |
667 | | |
668 | 221k | assert(list_repOk(l)); |
669 | | |
670 | 221k | return 0; |
671 | 221k | } |
672 | | |
673 | 548k | unsigned int list_size(const list_t *simclist_restrict l) { |
674 | 548k | return l->numels; |
675 | 548k | } |
676 | | |
677 | 0 | int list_empty(const list_t *simclist_restrict l) { |
678 | 0 | return (l->numels == 0); |
679 | 0 | } |
680 | | |
681 | 283k | int list_locate(const list_t *simclist_restrict l, const void *data) { |
682 | 283k | struct list_entry_s *el; |
683 | 283k | int pos = 0; |
684 | | |
685 | 283k | if (l->head_sentinel == NULL || l->tail_sentinel == NULL) return -1; |
686 | | |
687 | 283k | if (l->attrs.comparator != NULL) { |
688 | | /* use comparator */ |
689 | 1.02M | for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) { |
690 | 949k | if (l->attrs.comparator(data, el->data) == 0) break; |
691 | 949k | } |
692 | 162k | } else { |
693 | | /* compare references */ |
694 | 444k | for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) { |
695 | 418k | if (el->data == data) break; |
696 | 418k | } |
697 | 162k | } |
698 | 283k | if (el == l->tail_sentinel) return -1; |
699 | | |
700 | 181k | return pos; |
701 | 283k | } |
702 | | |
703 | 73.3k | void *list_seek(list_t *simclist_restrict l, const void *indicator) { |
704 | 73.3k | const struct list_entry_s *iter; |
705 | | |
706 | 73.3k | if (l->attrs.seeker == NULL) return NULL; |
707 | | |
708 | 73.3k | if (l->head_sentinel == NULL || l->tail_sentinel == NULL) return NULL; |
709 | | |
710 | 78.2k | for (iter = l->head_sentinel->next; iter != l->tail_sentinel; iter = iter->next) { |
711 | 63.1k | if (l->attrs.seeker(iter->data, indicator) != 0) return iter->data; |
712 | 63.1k | } |
713 | | |
714 | 15.0k | return NULL; |
715 | 73.3k | } |
716 | | |
717 | 81.1k | int list_contains(const list_t *simclist_restrict l, const void *data) { |
718 | 81.1k | return (list_locate(l, data) >= 0); |
719 | 81.1k | } |
720 | | |
721 | 0 | int list_concat(const list_t *l1, const list_t *l2, list_t *simclist_restrict dest) { |
722 | 0 | struct list_entry_s *el, *srcel; |
723 | 0 | unsigned int cnt; |
724 | 0 | int err; |
725 | |
|
726 | 0 | if (l1 == NULL || l2 == NULL || dest == NULL || l1 == dest || l2 == dest) |
727 | 0 | return -1; |
728 | | |
729 | 0 | if (l1->head_sentinel == NULL || l1->tail_sentinel == NULL |
730 | 0 | || l2->head_sentinel == NULL || l2->tail_sentinel == NULL) return -1; |
731 | | |
732 | 0 | if (0 != list_init(dest)) { |
733 | 0 | return -1; |
734 | 0 | } |
735 | | |
736 | 0 | dest->numels = l1->numels + l2->numels; |
737 | 0 | if (dest->numels == 0) |
738 | 0 | return 0; |
739 | | |
740 | | /* copy list1 */ |
741 | 0 | srcel = l1->head_sentinel->next; |
742 | 0 | el = dest->head_sentinel; |
743 | 0 | while (srcel != l1->tail_sentinel) { |
744 | 0 | el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); |
745 | 0 | if (el->next == NULL) { |
746 | 0 | return -1; |
747 | 0 | } |
748 | 0 | el->next->prev = el; |
749 | 0 | el = el->next; |
750 | 0 | el->data = srcel->data; |
751 | 0 | srcel = srcel->next; |
752 | 0 | } |
753 | 0 | dest->mid = el; /* approximate position (adjust later) */ |
754 | | /* copy list 2 */ |
755 | 0 | srcel = l2->head_sentinel->next; |
756 | 0 | while (srcel != l2->tail_sentinel) { |
757 | 0 | el->next = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); |
758 | 0 | if (el->next == NULL) { |
759 | 0 | return -1; |
760 | 0 | } |
761 | 0 | el->next->prev = el; |
762 | 0 | el = el->next; |
763 | 0 | el->data = srcel->data; |
764 | 0 | srcel = srcel->next; |
765 | 0 | } |
766 | 0 | el->next = dest->tail_sentinel; |
767 | 0 | dest->tail_sentinel->prev = el; |
768 | | |
769 | | /* fix mid pointer */ |
770 | 0 | err = l2->numels - l1->numels; |
771 | 0 | if ((err+1)/2 > 0) { /* correct pos RIGHT (err-1)/2 moves */ |
772 | 0 | err = (err+1)/2; |
773 | 0 | for (cnt = 0; dest->mid && cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->next; |
774 | 0 | } else if (err/2 < 0) { /* correct pos LEFT (err/2)-1 moves */ |
775 | 0 | err = -err/2; |
776 | 0 | for (cnt = 0; dest->mid && cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->prev; |
777 | 0 | } |
778 | |
|
779 | 0 | assert(!(list_repOk(l1) && list_repOk(l2)) || list_repOk(dest)); |
780 | |
|
781 | 0 | return 0; |
782 | 0 | } |
783 | | |
784 | 0 | int list_sort(list_t *simclist_restrict l, int versus) { |
785 | 0 | if (l->iter_active || l->attrs.comparator == NULL) /* cannot modify list in the middle of an iteration */ |
786 | 0 | return -1; |
787 | | |
788 | 0 | if (l->numels <= 1) |
789 | 0 | return 0; |
790 | | |
791 | 0 | if (l->head_sentinel == NULL || l->tail_sentinel == NULL) return -1; |
792 | | |
793 | 0 | list_sort_quicksort(l, versus, 0, l->head_sentinel->next, l->numels-1, l->tail_sentinel->prev); |
794 | 0 | assert(list_repOk(l)); |
795 | 0 | return 0; |
796 | 0 | } |
797 | | |
798 | | #ifdef SIMCLIST_WITH_THREADS |
799 | | struct list_sort_wrappedparams { |
800 | | list_t *simclist_restrict l; |
801 | | int versus; |
802 | | unsigned int first, last; |
803 | | struct list_entry_s *fel, *lel; |
804 | | }; |
805 | | |
806 | | static void *list_sort_quicksort_threadwrapper(void *wrapped_params) { |
807 | | struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)wrapped_params; |
808 | | list_sort_quicksort(wp->l, wp->versus, wp->first, wp->fel, wp->last, wp->lel); |
809 | | free(wp); |
810 | | pthread_exit(NULL); |
811 | | return NULL; |
812 | | } |
813 | | #endif |
814 | | |
815 | | static simclist_inline void list_sort_selectionsort(list_t *simclist_restrict l, int versus, |
816 | | unsigned int first, struct list_entry_s *fel, |
817 | 0 | unsigned int last, struct list_entry_s *lel) { |
818 | 0 | struct list_entry_s *cursor, *toswap, *firstunsorted; |
819 | 0 | void *tmpdata; |
820 | |
|
821 | 0 | if (last <= first) /* <= 1-element lists are always sorted */ |
822 | 0 | return; |
823 | | |
824 | 0 | for (firstunsorted = fel; firstunsorted != lel; firstunsorted = firstunsorted->next) { |
825 | | /* find min or max in the remainder of the list */ |
826 | 0 | for (toswap = firstunsorted, cursor = firstunsorted->next; cursor != lel->next; cursor = cursor->next) |
827 | 0 | if (l->attrs.comparator(toswap->data, cursor->data) * -versus > 0) toswap = cursor; |
828 | 0 | if (toswap != firstunsorted) { /* swap firstunsorted with toswap */ |
829 | 0 | tmpdata = firstunsorted->data; |
830 | 0 | firstunsorted->data = toswap->data; |
831 | 0 | toswap->data = tmpdata; |
832 | 0 | } |
833 | 0 | } |
834 | 0 | } |
835 | | |
836 | | static void list_sort_quicksort(list_t *simclist_restrict l, int versus, |
837 | | unsigned int first, struct list_entry_s *fel, |
838 | 0 | unsigned int last, struct list_entry_s *lel) { |
839 | 0 | unsigned int pivotid; |
840 | 0 | unsigned int i; |
841 | 0 | register struct list_entry_s *pivot; |
842 | 0 | struct list_entry_s *left, *right; |
843 | 0 | void *tmpdata; |
844 | | #ifdef SIMCLIST_WITH_THREADS |
845 | | pthread_t tid; |
846 | | int traised; |
847 | | #endif |
848 | | |
849 | |
|
850 | 0 | if (last <= first) /* <= 1-element lists are always sorted */ |
851 | 0 | return; |
852 | | |
853 | 0 | if (last - first+1 <= SIMCLIST_MINQUICKSORTELS) { |
854 | 0 | list_sort_selectionsort(l, versus, first, fel, last, lel); |
855 | 0 | return; |
856 | 0 | } |
857 | | |
858 | | /* base of iteration: one element list */ |
859 | 0 | if (! (last > first)) return; |
860 | | |
861 | 0 | pivotid = (get_random() % (last - first + 1)); |
862 | | /* pivotid = (last - first + 1) / 2; */ |
863 | | |
864 | | /* find pivot */ |
865 | 0 | if (pivotid < (last - first + 1)/2) { |
866 | 0 | for (i = 0, pivot = fel; i < pivotid; pivot = pivot->next, i++); |
867 | 0 | } else { |
868 | 0 | for (i = last - first, pivot = lel; i > pivotid; pivot = pivot->prev, i--); |
869 | 0 | } |
870 | | |
871 | | /* smaller PIVOT bigger */ |
872 | 0 | left = fel; |
873 | 0 | right = lel; |
874 | | /* iterate --- left ---> PIV <--- right --- */ |
875 | 0 | while (left != pivot && right != pivot) { |
876 | 0 | for (; left != pivot && (l->attrs.comparator(left->data, pivot->data) * -versus <= 0); left = left->next); |
877 | | /* left points to a smaller element, or to pivot */ |
878 | 0 | for (; right != pivot && (l->attrs.comparator(right->data, pivot->data) * -versus >= 0); right = right->prev); |
879 | | /* right points to a bigger element, or to pivot */ |
880 | 0 | if (left != pivot && right != pivot) { |
881 | | /* swap, then move iterators */ |
882 | 0 | tmpdata = left->data; |
883 | 0 | left->data = right->data; |
884 | 0 | right->data = tmpdata; |
885 | |
|
886 | 0 | left = left->next; |
887 | 0 | right = right->prev; |
888 | 0 | } |
889 | 0 | } |
890 | | |
891 | | /* now either left points to pivot (end run), or right */ |
892 | 0 | if (right == pivot) { /* left part longer */ |
893 | 0 | while (left != pivot) { |
894 | 0 | if (l->attrs.comparator(left->data, pivot->data) * -versus > 0) { |
895 | 0 | tmpdata = left->data; |
896 | 0 | left->data = pivot->prev->data; |
897 | 0 | pivot->prev->data = pivot->data; |
898 | 0 | pivot->data = tmpdata; |
899 | 0 | pivot = pivot->prev; |
900 | 0 | pivotid--; |
901 | 0 | if (pivot == left) break; |
902 | 0 | } else { |
903 | 0 | left = left->next; |
904 | 0 | } |
905 | 0 | } |
906 | 0 | } else { /* right part longer */ |
907 | 0 | while (right != pivot) { |
908 | 0 | if (l->attrs.comparator(right->data, pivot->data) * -versus < 0) { |
909 | | /* move current right before pivot */ |
910 | 0 | tmpdata = right->data; |
911 | 0 | right->data = pivot->next->data; |
912 | 0 | pivot->next->data = pivot->data; |
913 | 0 | pivot->data = tmpdata; |
914 | 0 | pivot = pivot->next; |
915 | 0 | pivotid++; |
916 | 0 | if (pivot == right) break; |
917 | 0 | } else { |
918 | 0 | right = right->prev; |
919 | 0 | } |
920 | 0 | } |
921 | 0 | } |
922 | | |
923 | | /* sort sublists A and B : |---A---| pivot |---B---| */ |
924 | |
|
925 | | #ifdef SIMCLIST_WITH_THREADS |
926 | | traised = 0; |
927 | | if (pivotid > 0) { |
928 | | /* prepare wrapped args, then start thread */ |
929 | | if (l->threadcount < SIMCLIST_MAXTHREADS-1) { |
930 | | struct list_sort_wrappedparams *wp = (struct list_sort_wrappedparams *)malloc(sizeof(struct list_sort_wrappedparams)); |
931 | | if (wp == NULL) { |
932 | | return -1; |
933 | | } |
934 | | l->threadcount++; |
935 | | traised = 1; |
936 | | wp->l = l; |
937 | | wp->versus = versus; |
938 | | wp->first = first; |
939 | | wp->fel = fel; |
940 | | wp->last = first+pivotid-1; |
941 | | wp->lel = pivot->prev; |
942 | | if (pthread_create(&tid, NULL, list_sort_quicksort_threadwrapper, wp) != 0) { |
943 | | free(wp); |
944 | | traised = 0; |
945 | | list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev); |
946 | | } |
947 | | } else { |
948 | | list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev); |
949 | | } |
950 | | } |
951 | | if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel); |
952 | | if (traised) { |
953 | | pthread_join(tid, (void **)NULL); |
954 | | l->threadcount--; |
955 | | } |
956 | | #else |
957 | 0 | if (pivotid > 0) list_sort_quicksort(l, versus, first, fel, first+pivotid-1, pivot->prev); |
958 | 0 | if (first + pivotid < last) list_sort_quicksort(l, versus, first+pivotid+1, pivot->next, last, lel); |
959 | 0 | #endif |
960 | 0 | } |
961 | | |
962 | 35.7k | int list_iterator_start(list_t *simclist_restrict l) { |
963 | 35.7k | if (l->iter_active) return 0; |
964 | 35.7k | if (l->head_sentinel == NULL) return -1; |
965 | 35.7k | l->iter_pos = 0; |
966 | 35.7k | l->iter_active = 1; |
967 | 35.7k | l->iter_curentry = l->head_sentinel->next; |
968 | 35.7k | return 1; |
969 | 35.7k | } |
970 | | |
971 | 300k | void *list_iterator_next(list_t *simclist_restrict l) { |
972 | 300k | void *toret; |
973 | | |
974 | 300k | if (! l->iter_active) return NULL; |
975 | | |
976 | 300k | toret = l->iter_curentry->data; |
977 | 300k | l->iter_curentry = l->iter_curentry->next; |
978 | 300k | l->iter_pos++; |
979 | | |
980 | 300k | return toret; |
981 | 300k | } |
982 | | |
983 | 270k | int list_iterator_hasnext(const list_t *simclist_restrict l) { |
984 | 270k | if (! l->iter_active) return 0; |
985 | 270k | return (l->iter_pos < l->numels); |
986 | 270k | } |
987 | | |
988 | 35.7k | int list_iterator_stop(list_t *simclist_restrict l) { |
989 | 35.7k | if (! l->iter_active) return 0; |
990 | 35.7k | l->iter_pos = 0; |
991 | 35.7k | l->iter_active = 0; |
992 | 35.7k | return 1; |
993 | 35.7k | } |
994 | | |
995 | 0 | int list_hash(const list_t *simclist_restrict l, list_hash_t *simclist_restrict hash) { |
996 | 0 | struct list_entry_s *x; |
997 | 0 | list_hash_t tmphash; |
998 | |
|
999 | 0 | assert(hash != NULL); |
1000 | |
|
1001 | 0 | tmphash = l->numels * 2 + 100; |
1002 | 0 | if (l->attrs.hasher == NULL) { |
1003 | | #ifdef SIMCLIST_ALLOW_LOCATIONBASED_HASHES |
1004 | | /* ENABLE WITH CARE !! */ |
1005 | | #warning "Memlocation-based hash is consistent only for testing modification in the same program run." |
1006 | | int i; |
1007 | | |
1008 | | /* only use element references */ |
1009 | | for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { |
1010 | | for (i = 0; i < sizeof(x->data); i++) { |
1011 | | tmphash += (tmphash ^ (uintptr_t)x->data); |
1012 | | } |
1013 | | tmphash += tmphash % l->numels; |
1014 | | } |
1015 | | #else |
1016 | 0 | return -1; |
1017 | 0 | #endif |
1018 | 0 | } else { |
1019 | | /* hash each element with the user-given function */ |
1020 | 0 | for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { |
1021 | 0 | tmphash += tmphash ^ l->attrs.hasher(x->data); |
1022 | 0 | tmphash +=* hash % l->numels; |
1023 | 0 | } |
1024 | 0 | } |
1025 | | |
1026 | 0 | *hash = tmphash; |
1027 | |
|
1028 | 0 | return 0; |
1029 | 0 | } |
1030 | | |
1031 | | #ifdef SIMCLIST_DUMPRESTORE |
1032 | | /* Workaround for a missing gettimeofday on Windows */ |
1033 | | #if defined(_MSC_VER) || defined(__MINGW32__) |
1034 | | int gettimeofday(struct timeval* tp, void* tzp) { |
1035 | | DWORD t; |
1036 | | t = timeGetTime(); |
1037 | | tp->tv_sec = t / 1000; |
1038 | | tp->tv_usec = t % 1000; |
1039 | | return 0; |
1040 | | } |
1041 | | #endif |
1042 | | int list_dump_getinfo_filedescriptor(int fd, list_dump_info_t *simclist_restrict info) { |
1043 | | int32_t terminator_head, terminator_tail; |
1044 | | uint32_t elemlen; |
1045 | | off_t hop; |
1046 | | |
1047 | | |
1048 | | /* version */ |
1049 | | READ_ERRCHECK(fd, & info->version, sizeof(info->version)); |
1050 | | info->version = ntohs(info->version); |
1051 | | if (info->version > SIMCLIST_DUMPFORMAT_VERSION) { |
1052 | | errno = EILSEQ; |
1053 | | return -1; |
1054 | | } |
1055 | | |
1056 | | /* timestamp */ |
1057 | | READ_ERRCHECK(fd, & info->timestamp, sizeof(info->timestamp)); |
1058 | | info->timestamp = hton64(info->timestamp); |
1059 | | |
1060 | | /* list terminator (to check thereafter) */ |
1061 | | READ_ERRCHECK(fd, & terminator_head, sizeof(terminator_head)); |
1062 | | terminator_head = ntohl(terminator_head); |
1063 | | |
1064 | | /* list size */ |
1065 | | READ_ERRCHECK(fd, & info->list_size, sizeof(info->list_size)); |
1066 | | info->list_size = ntohl(info->list_size); |
1067 | | |
1068 | | /* number of elements */ |
1069 | | READ_ERRCHECK(fd, & info->list_numels, sizeof(info->list_numels)); |
1070 | | info->list_numels = ntohl(info->list_numels); |
1071 | | |
1072 | | /* length of each element (for checking for consistency) */ |
1073 | | READ_ERRCHECK(fd, & elemlen, sizeof(elemlen)); |
1074 | | elemlen = ntohl(elemlen); |
1075 | | |
1076 | | /* list hash */ |
1077 | | READ_ERRCHECK(fd, & info->list_hash, sizeof(info->list_hash)); |
1078 | | info->list_hash = ntohl(info->list_hash); |
1079 | | |
1080 | | /* check consistency */ |
1081 | | if (elemlen > 0) { |
1082 | | /* constant length, hop by size only */ |
1083 | | hop = info->list_size; |
1084 | | } else { |
1085 | | /* non-constant length, hop by size + all element length blocks */ |
1086 | | hop = info->list_size + elemlen*info->list_numels; |
1087 | | } |
1088 | | if (lseek(fd, hop, SEEK_CUR) == -1) { |
1089 | | return -1; |
1090 | | } |
1091 | | |
1092 | | /* read the trailing value and compare with terminator_head */ |
1093 | | READ_ERRCHECK(fd, & terminator_tail, sizeof(terminator_tail)); |
1094 | | terminator_tail = ntohl(terminator_tail); |
1095 | | |
1096 | | if (terminator_head == terminator_tail) |
1097 | | info->consistent = 1; |
1098 | | else |
1099 | | info->consistent = 0; |
1100 | | |
1101 | | return 0; |
1102 | | } |
1103 | | |
1104 | | int list_dump_getinfo_file(const char *simclist_restrict filename, list_dump_info_t *simclist_restrict info) { |
1105 | | int fd, ret; |
1106 | | |
1107 | | fd = open(filename, O_RDONLY, 0); |
1108 | | if (fd < 0) return -1; |
1109 | | |
1110 | | ret = list_dump_getinfo_filedescriptor(fd, info); |
1111 | | close(fd); |
1112 | | |
1113 | | return ret; |
1114 | | } |
1115 | | |
1116 | | int list_dump_filedescriptor(const list_t *simclist_restrict l, int fd, size_t *simclist_restrict len) { |
1117 | | struct list_entry_s *x; |
1118 | | void *ser_buf; |
1119 | | uint32_t bufsize; |
1120 | | struct timeval timeofday; |
1121 | | struct list_dump_header_s header; |
1122 | | |
1123 | | if (l->attrs.meter == NULL && l->attrs.serializer == NULL) { |
1124 | | errno = ENOTTY; |
1125 | | return -1; |
1126 | | } |
1127 | | |
1128 | | /**** DUMP FORMAT **** |
1129 | | |
1130 | | [ ver timestamp | totlen numels elemlen hash | DATA ] |
1131 | | |
1132 | | where DATA can be: |
1133 | | @ for constant-size list (element size is constant; elemlen > 0) |
1134 | | [ elem elem ... elem ] |
1135 | | @ for other lists (element size dictated by element_meter each time; elemlen <= 0) |
1136 | | [ size elem size elem ... size elem ] |
1137 | | |
1138 | | all integers are encoded in NETWORK BYTE FORMAT |
1139 | | *****/ |
1140 | | |
1141 | | |
1142 | | /* prepare HEADER */ |
1143 | | /* version */ |
1144 | | header.ver = htons( SIMCLIST_DUMPFORMAT_VERSION ); |
1145 | | |
1146 | | /* timestamp */ |
1147 | | gettimeofday(&timeofday, NULL); |
1148 | | header.timestamp = (int64_t)timeofday.tv_sec * 1000000 + (int64_t)timeofday.tv_usec; |
1149 | | header.timestamp = hton64(header.timestamp); |
1150 | | |
1151 | | header.rndterm = htonl((int32_t)get_random()); |
1152 | | |
1153 | | /* total list size is postprocessed afterwards */ |
1154 | | |
1155 | | /* number of elements */ |
1156 | | header.numels = htonl(l->numels); |
1157 | | |
1158 | | /* include an hash, if possible */ |
1159 | | if (l->attrs.hasher != NULL) { |
1160 | | if (htonl(list_hash(l, & header.listhash)) != 0) { |
1161 | | /* could not compute list hash! */ |
1162 | | return -1; |
1163 | | } |
1164 | | } else { |
1165 | | header.listhash = htonl(0); |
1166 | | } |
1167 | | |
1168 | | header.totlistlen = header.elemlen = 0; |
1169 | | |
1170 | | /* leave room for the header at the beginning of the file */ |
1171 | | if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) { |
1172 | | /* errno set by lseek() */ |
1173 | | return -1; |
1174 | | } |
1175 | | |
1176 | | /* write CONTENT */ |
1177 | | if (l->numels > 0) { |
1178 | | /* SPECULATE that the list has constant element size */ |
1179 | | |
1180 | | if (l->attrs.serializer != NULL) { /* user user-specified serializer */ |
1181 | | /* get preliminary length of serialized element in header.elemlen */ |
1182 | | ser_buf = l->attrs.serializer(l->head_sentinel->next->data, & header.elemlen); |
1183 | | free(ser_buf); |
1184 | | /* request custom serialization of each element */ |
1185 | | for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { |
1186 | | ser_buf = l->attrs.serializer(x->data, &bufsize); |
1187 | | header.totlistlen += bufsize; |
1188 | | if (header.elemlen != 0) { /* continue on speculation */ |
1189 | | if (header.elemlen != bufsize) { |
1190 | | free(ser_buf); |
1191 | | /* constant element length speculation broken! */ |
1192 | | header.elemlen = 0; |
1193 | | header.totlistlen = 0; |
1194 | | x = l->head_sentinel; |
1195 | | if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) { |
1196 | | /* errno set by lseek() */ |
1197 | | return -1; |
1198 | | } |
1199 | | /* restart from the beginning */ |
1200 | | continue; |
1201 | | } |
1202 | | /* speculation confirmed */ |
1203 | | WRITE_ERRCHECK(fd, ser_buf, bufsize); |
1204 | | } else { /* speculation found broken */ |
1205 | | WRITE_ERRCHECK(fd, & bufsize, sizeof(size_t)); |
1206 | | WRITE_ERRCHECK(fd, ser_buf, bufsize); |
1207 | | } |
1208 | | free(ser_buf); |
1209 | | } |
1210 | | } else if (l->attrs.meter != NULL) { |
1211 | | header.elemlen = (uint32_t)l->attrs.meter(l->head_sentinel->next->data); |
1212 | | |
1213 | | /* serialize the element straight from its data */ |
1214 | | for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { |
1215 | | bufsize = l->attrs.meter(x->data); |
1216 | | header.totlistlen += bufsize; |
1217 | | if (header.elemlen != 0) { |
1218 | | if (header.elemlen != bufsize) { |
1219 | | /* constant element length speculation broken! */ |
1220 | | header.elemlen = 0; |
1221 | | header.totlistlen = 0; |
1222 | | x = l->head_sentinel; |
1223 | | /* restart from the beginning */ |
1224 | | continue; |
1225 | | } |
1226 | | WRITE_ERRCHECK(fd, x->data, bufsize); |
1227 | | } else { |
1228 | | WRITE_ERRCHECK(fd, &bufsize, sizeof(size_t)); |
1229 | | WRITE_ERRCHECK(fd, x->data, bufsize); |
1230 | | } |
1231 | | } |
1232 | | } |
1233 | | /* adjust endianness */ |
1234 | | header.elemlen = htonl(header.elemlen); |
1235 | | header.totlistlen = htonl(header.totlistlen); |
1236 | | } |
1237 | | |
1238 | | /* write random terminator */ |
1239 | | WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* list terminator */ |
1240 | | |
1241 | | |
1242 | | /* write header */ |
1243 | | lseek(fd, 0, SEEK_SET); |
1244 | | |
1245 | | WRITE_ERRCHECK(fd, & header.ver, sizeof(header.ver)); /* version */ |
1246 | | WRITE_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp)); /* timestamp */ |
1247 | | WRITE_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); /* random terminator */ |
1248 | | |
1249 | | WRITE_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen)); /* total length of elements */ |
1250 | | WRITE_ERRCHECK(fd, & header.numels, sizeof(header.numels)); /* number of elements */ |
1251 | | WRITE_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen)); /* size of each element, or 0 for independent */ |
1252 | | WRITE_ERRCHECK(fd, & header.listhash, sizeof(header.listhash)); /* list hash, or 0 for "ignore" */ |
1253 | | |
1254 | | |
1255 | | /* possibly store total written length in "len" */ |
1256 | | if (len != NULL) { |
1257 | | *len = sizeof(header) + ntohl(header.totlistlen); |
1258 | | } |
1259 | | |
1260 | | return 0; |
1261 | | } |
1262 | | |
1263 | | int list_restore_filedescriptor(list_t *simclist_restrict l, int fd, size_t *simclist_restrict len) { |
1264 | | struct list_dump_header_s header; |
1265 | | unsigned long cnt; |
1266 | | void *buf = NULL; |
1267 | | uint32_t elsize, totreadlen, totmemorylen; |
1268 | | |
1269 | | memset(& header, 0, sizeof(header)); |
1270 | | |
1271 | | /* read header */ |
1272 | | |
1273 | | /* version */ |
1274 | | READ_ERRCHECK(fd, &header.ver, sizeof(header.ver)); |
1275 | | header.ver = ntohs(header.ver); |
1276 | | if (header.ver != SIMCLIST_DUMPFORMAT_VERSION) { |
1277 | | errno = EILSEQ; |
1278 | | return -1; |
1279 | | } |
1280 | | |
1281 | | /* timestamp */ |
1282 | | READ_ERRCHECK(fd, & header.timestamp, sizeof(header.timestamp)); |
1283 | | |
1284 | | /* list terminator */ |
1285 | | READ_ERRCHECK(fd, & header.rndterm, sizeof(header.rndterm)); |
1286 | | |
1287 | | header.rndterm = ntohl(header.rndterm); |
1288 | | |
1289 | | /* total list size */ |
1290 | | READ_ERRCHECK(fd, & header.totlistlen, sizeof(header.totlistlen)); |
1291 | | header.totlistlen = ntohl(header.totlistlen); |
1292 | | |
1293 | | /* number of elements */ |
1294 | | READ_ERRCHECK(fd, & header.numels, sizeof(header.numels)); |
1295 | | header.numels = ntohl(header.numels); |
1296 | | |
1297 | | /* length of every element, or '0' = variable */ |
1298 | | READ_ERRCHECK(fd, & header.elemlen, sizeof(header.elemlen)); |
1299 | | header.elemlen = ntohl(header.elemlen); |
1300 | | |
1301 | | /* list hash, or 0 = 'ignore' */ |
1302 | | READ_ERRCHECK(fd, & header.listhash, sizeof(header.listhash)); |
1303 | | header.listhash = ntohl(header.listhash); |
1304 | | |
1305 | | |
1306 | | /* read content */ |
1307 | | totreadlen = totmemorylen = 0; |
1308 | | if (header.elemlen > 0) { |
1309 | | /* elements have constant size = header.elemlen */ |
1310 | | if (l->attrs.unserializer != NULL) { |
1311 | | /* use unserializer */ |
1312 | | buf = malloc(header.elemlen); |
1313 | | if (buf == NULL) { |
1314 | | return -1; |
1315 | | } |
1316 | | for (cnt = 0; cnt < header.numels; cnt++) { |
1317 | | READ_ERRCHECK(fd, buf, header.elemlen); |
1318 | | list_append(l, l->attrs.unserializer(buf, & elsize)); |
1319 | | totmemorylen += elsize; |
1320 | | } |
1321 | | } else { |
1322 | | /* copy verbatim into memory */ |
1323 | | for (cnt = 0; cnt < header.numels; cnt++) { |
1324 | | buf = malloc(header.elemlen); |
1325 | | if (buf == NULL) { |
1326 | | return -1; |
1327 | | } |
1328 | | READ_ERRCHECK(fd, buf, header.elemlen); |
1329 | | list_append(l, buf); |
1330 | | } |
1331 | | totmemorylen = header.numels * header.elemlen; |
1332 | | } |
1333 | | totreadlen = header.numels * header.elemlen; |
1334 | | } else { |
1335 | | /* elements have variable size. Each element is preceded by its size */ |
1336 | | if (l->attrs.unserializer != NULL) { |
1337 | | /* use unserializer */ |
1338 | | for (cnt = 0; cnt < header.numels; cnt++) { |
1339 | | READ_ERRCHECK(fd, & elsize, sizeof(elsize)); |
1340 | | buf = malloc((size_t)elsize); |
1341 | | if (buf == NULL) { |
1342 | | return -1; |
1343 | | } |
1344 | | READ_ERRCHECK(fd, buf, elsize); |
1345 | | totreadlen += elsize; |
1346 | | list_append(l, l->attrs.unserializer(buf, & elsize)); |
1347 | | totmemorylen += elsize; |
1348 | | } |
1349 | | } else { |
1350 | | /* copy verbatim into memory */ |
1351 | | for (cnt = 0; cnt < header.numels; cnt++) { |
1352 | | READ_ERRCHECK(fd, & elsize, sizeof(elsize)); |
1353 | | buf = malloc(elsize); |
1354 | | if (buf == NULL) { |
1355 | | return -1; |
1356 | | } |
1357 | | READ_ERRCHECK(fd, buf, elsize); |
1358 | | totreadlen += elsize; |
1359 | | list_append(l, buf); |
1360 | | } |
1361 | | totmemorylen = totreadlen; |
1362 | | } |
1363 | | } |
1364 | | |
1365 | | READ_ERRCHECK(fd, &elsize, sizeof(elsize)); /* read list terminator */ |
1366 | | elsize = ntohl(elsize); |
1367 | | |
1368 | | /* possibly verify the list consistency */ |
1369 | | /* wrt hash */ |
1370 | | /* don't do that |
1371 | | if (header.listhash != 0 && header.listhash != list_hash(l)) { |
1372 | | errno = ECANCELED; |
1373 | | return -1; |
1374 | | } |
1375 | | */ |
1376 | | |
1377 | | /* wrt header */ |
1378 | | if (totreadlen != header.totlistlen && (int32_t)elsize == header.rndterm) { |
1379 | | errno = EPROTO; |
1380 | | return -1; |
1381 | | } |
1382 | | |
1383 | | /* wrt file */ |
1384 | | if (lseek(fd, 0, SEEK_CUR) != lseek(fd, 0, SEEK_END)) { |
1385 | | errno = EPROTO; |
1386 | | return -1; |
1387 | | } |
1388 | | |
1389 | | if (len != NULL) { |
1390 | | *len = totmemorylen; |
1391 | | } |
1392 | | |
1393 | | return 0; |
1394 | | } |
1395 | | |
1396 | | int list_dump_file(const list_t *simclist_restrict l, const char *simclist_restrict filename, size_t *simclist_restrict len) { |
1397 | | int fd, mode; |
1398 | | size_t sizetoret; |
1399 | | mode = O_RDWR | O_CREAT | O_TRUNC; |
1400 | | #ifndef _WIN32 |
1401 | | mode |= S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; |
1402 | | #endif |
1403 | | fd = open(filename, mode); |
1404 | | if (fd < 0) return -1; |
1405 | | |
1406 | | sizetoret = list_dump_filedescriptor(l, fd, len); |
1407 | | close(fd); |
1408 | | |
1409 | | return sizetoret; |
1410 | | } |
1411 | | |
1412 | | int list_restore_file(list_t *simclist_restrict l, const char *simclist_restrict filename, size_t *simclist_restrict len) { |
1413 | | int fd; |
1414 | | size_t totdata; |
1415 | | |
1416 | | fd = open(filename, O_RDONLY, 0); |
1417 | | if (fd < 0) return -1; |
1418 | | |
1419 | | totdata = list_restore_filedescriptor(l, fd, len); |
1420 | | close(fd); |
1421 | | |
1422 | | return totdata; |
1423 | | } |
1424 | | #endif /* ifdef SIMCLIST_DUMPRESTORE */ |
1425 | | |
1426 | | |
1427 | 161k | static int list_drop_elem(list_t *simclist_restrict l, struct list_entry_s *tmp, unsigned int pos) { |
1428 | 161k | if (tmp == NULL) return -1; |
1429 | | |
1430 | | /* fix mid pointer. This is wrt the PRE situation */ |
1431 | 161k | if (l->numels % 2) { /* now odd */ |
1432 | | /* sort out the base case by hand */ |
1433 | 149k | if (l->numels == 1) l->mid = NULL; |
1434 | 9.89k | else if (pos >= l->numels/2) l->mid = l->mid->prev; |
1435 | 149k | } else { /* now even */ |
1436 | 11.4k | if (pos < l->numels/2) l->mid = l->mid->next; |
1437 | 11.4k | } |
1438 | | |
1439 | 161k | tmp->prev->next = tmp->next; |
1440 | 161k | tmp->next->prev = tmp->prev; |
1441 | | |
1442 | | /* free what's to be freed */ |
1443 | 161k | if (l->attrs.copy_data && tmp->data != NULL) |
1444 | 0 | free(tmp->data); |
1445 | | |
1446 | 161k | if (l->spareels != NULL && l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { |
1447 | 146k | l->spareels[l->spareelsnum++] = tmp; |
1448 | 146k | } else { |
1449 | 15.1k | free(tmp); |
1450 | 15.1k | } |
1451 | | |
1452 | 161k | return 0; |
1453 | 161k | } |
1454 | | |
1455 | | /* ready-made comparators and meters */ |
1456 | 0 | #define SIMCLIST_NUMBER_COMPARATOR(type) int list_comparator_##type(const void *a, const void *b) { return( *(type *)a < *(type *)b) - (*(type *)a > *(type *)b); } Unexecuted instantiation: list_comparator_int8_t Unexecuted instantiation: list_comparator_int16_t Unexecuted instantiation: list_comparator_int32_t Unexecuted instantiation: list_comparator_int64_t Unexecuted instantiation: list_comparator_uint8_t Unexecuted instantiation: list_comparator_uint16_t Unexecuted instantiation: list_comparator_uint32_t Unexecuted instantiation: list_comparator_uint64_t Unexecuted instantiation: list_comparator_float Unexecuted instantiation: list_comparator_double |
1457 | | |
1458 | | SIMCLIST_NUMBER_COMPARATOR(int8_t) |
1459 | | SIMCLIST_NUMBER_COMPARATOR(int16_t) |
1460 | | SIMCLIST_NUMBER_COMPARATOR(int32_t) |
1461 | | SIMCLIST_NUMBER_COMPARATOR(int64_t) |
1462 | | |
1463 | | SIMCLIST_NUMBER_COMPARATOR(uint8_t) |
1464 | | SIMCLIST_NUMBER_COMPARATOR(uint16_t) |
1465 | | SIMCLIST_NUMBER_COMPARATOR(uint32_t) |
1466 | | SIMCLIST_NUMBER_COMPARATOR(uint64_t) |
1467 | | |
1468 | | SIMCLIST_NUMBER_COMPARATOR(float) |
1469 | | SIMCLIST_NUMBER_COMPARATOR(double) |
1470 | | |
1471 | 0 | int list_comparator_string(const void *a, const void *b) { return strcmp((const char *)b, (const char *)a); } |
1472 | | |
1473 | | /* ready-made metric functions */ |
1474 | 0 | #define SIMCLIST_METER(type) size_t list_meter_##type(const void *el) { if (el) { /* kill compiler whinge */ } return sizeof(type); } Unexecuted instantiation: list_meter_int8_t Unexecuted instantiation: list_meter_int16_t Unexecuted instantiation: list_meter_int32_t Unexecuted instantiation: list_meter_int64_t Unexecuted instantiation: list_meter_uint8_t Unexecuted instantiation: list_meter_uint16_t Unexecuted instantiation: list_meter_uint32_t Unexecuted instantiation: list_meter_uint64_t Unexecuted instantiation: list_meter_float Unexecuted instantiation: list_meter_double |
1475 | | |
1476 | | SIMCLIST_METER(int8_t) |
1477 | | SIMCLIST_METER(int16_t) |
1478 | | SIMCLIST_METER(int32_t) |
1479 | | SIMCLIST_METER(int64_t) |
1480 | | |
1481 | | SIMCLIST_METER(uint8_t) |
1482 | | SIMCLIST_METER(uint16_t) |
1483 | | SIMCLIST_METER(uint32_t) |
1484 | | SIMCLIST_METER(uint64_t) |
1485 | | |
1486 | | SIMCLIST_METER(float) |
1487 | | SIMCLIST_METER(double) |
1488 | | |
1489 | 0 | size_t list_meter_string(const void *el) { return strlen((const char *)el) + 1; } |
1490 | | |
1491 | | /* ready-made hashing functions */ |
1492 | 0 | #define SIMCLIST_HASHCOMPUTER(type) list_hash_t list_hashcomputer_##type(const void *el) { return (list_hash_t)(*(type *)el); } Unexecuted instantiation: list_hashcomputer_int8_t Unexecuted instantiation: list_hashcomputer_int16_t Unexecuted instantiation: list_hashcomputer_int32_t Unexecuted instantiation: list_hashcomputer_int64_t Unexecuted instantiation: list_hashcomputer_uint8_t Unexecuted instantiation: list_hashcomputer_uint16_t Unexecuted instantiation: list_hashcomputer_uint32_t Unexecuted instantiation: list_hashcomputer_uint64_t Unexecuted instantiation: list_hashcomputer_float Unexecuted instantiation: list_hashcomputer_double |
1493 | | |
1494 | | SIMCLIST_HASHCOMPUTER(int8_t) |
1495 | | SIMCLIST_HASHCOMPUTER(int16_t) |
1496 | | SIMCLIST_HASHCOMPUTER(int32_t) |
1497 | | SIMCLIST_HASHCOMPUTER(int64_t) |
1498 | | |
1499 | | SIMCLIST_HASHCOMPUTER(uint8_t) |
1500 | | SIMCLIST_HASHCOMPUTER(uint16_t) |
1501 | | SIMCLIST_HASHCOMPUTER(uint32_t) |
1502 | | SIMCLIST_HASHCOMPUTER(uint64_t) |
1503 | | |
1504 | | SIMCLIST_HASHCOMPUTER(float) |
1505 | | SIMCLIST_HASHCOMPUTER(double) |
1506 | | |
1507 | 0 | list_hash_t list_hashcomputer_string(const void *el) { |
1508 | 0 | size_t l; |
1509 | 0 | list_hash_t hash = 123; |
1510 | 0 | const char *str = (const char *)el; |
1511 | 0 | char plus; |
1512 | |
|
1513 | 0 | for (l = 0; str[l] != '\0'; l++) { |
1514 | 0 | if (l) plus = hash ^ str[l]; |
1515 | 0 | else plus = hash ^ (str[l] - str[0]); |
1516 | 0 | hash += (plus << (CHAR_BIT * (l % sizeof(list_hash_t)))); |
1517 | 0 | } |
1518 | |
|
1519 | 0 | return hash; |
1520 | 0 | } |
1521 | | |
1522 | | |
1523 | | #ifndef NDEBUG |
1524 | | static int list_repOk(const list_t *simclist_restrict l) { |
1525 | | int ok, i; |
1526 | | struct list_entry_s *s; |
1527 | | |
1528 | | ok = (l != NULL) && ( |
1529 | | /* head/tail checks */ |
1530 | | (l->head_sentinel != NULL && l->tail_sentinel != NULL) && |
1531 | | (l->head_sentinel != l->tail_sentinel) && (l->head_sentinel->prev == NULL && l->tail_sentinel->next == NULL) && |
1532 | | /* empty list */ |
1533 | | (l->numels > 0 || (l->mid == NULL && l->head_sentinel->next == l->tail_sentinel && l->tail_sentinel->prev == l->head_sentinel)) && |
1534 | | /* spare elements checks */ |
1535 | | l->spareelsnum <= SIMCLIST_MAX_SPARE_ELEMS |
1536 | | ); |
1537 | | |
1538 | | if (!ok) return 0; |
1539 | | |
1540 | | if (l->numels >= 1) { |
1541 | | /* correct referencing */ |
1542 | | for (i = -1, s = l->head_sentinel; i < (int)(l->numels-1)/2 && s->next != NULL; i++, s = s->next) { |
1543 | | if (s->next->prev != s) break; |
1544 | | } |
1545 | | ok = (i == (int)(l->numels-1)/2 && l->mid == s); |
1546 | | if (!ok) return 0; |
1547 | | for (; s->next != NULL; i++, s = s->next) { |
1548 | | if (s->next->prev != s) break; |
1549 | | } |
1550 | | ok = (i == (int)l->numels && s == l->tail_sentinel); |
1551 | | } |
1552 | | |
1553 | | return ok; |
1554 | | } |
1555 | | |
1556 | | static int list_attrOk(const list_t *simclist_restrict l) { |
1557 | | int ok; |
1558 | | |
1559 | | ok = (l->attrs.copy_data == 0 || l->attrs.meter != NULL); |
1560 | | return ok; |
1561 | | } |
1562 | | |
1563 | | #endif |
1564 | | |