1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "cx/kv_list.h"
30 #include "cx/hash_map.h"
31 #include "cx/linked_list.h"
32
33 #include <string.h>
34 #include <assert.h>
35
36 typedef struct cx_kv_list_s cx_kv_list;
37
38 struct cx_kv_list_map_s {
39 struct cx_hash_map_s map_base;
40
41 cx_kv_list *list;
42 };
43
44 struct cx_kv_list_s {
45 struct cx_linked_list_s list;
46
47 struct cx_kv_list_map_s *map;
48 const cx_list_class *list_methods;
49 const cx_map_class *map_methods;
50 cx_destructor_func list_destr;
51 cx_destructor_func2 list_destr2;
52 void *list_destr_data;
53 cx_destructor_func map_destr;
54 cx_destructor_func2 map_destr2;
55 void *map_destr_data;
56 };
57
58 static void cx_kv_list_destructor_wrapper(
void *list_ptr,
void *elem) {
59 const cx_kv_list *kv_list = list_ptr;
60
61 if (kv_list->list_destr) {
62 kv_list->list_destr(elem);
63 }
64 if (kv_list->list_destr2) {
65 kv_list->list_destr2(kv_list->list_destr_data, elem);
66 }
67 if (kv_list->map_destr) {
68 kv_list->map_destr(elem);
69 }
70 if (kv_list->map_destr2) {
71 kv_list->map_destr2(kv_list->map_destr_data, elem);
72 }
73 }
74
75 static void cx_kv_list_update_destructors(cx_kv_list *list) {
76
77
78 if (list->list.base.collection.simple_destructor !=
NULL) {
79 list->list_destr = list->list.base.collection.simple_destructor;
80 list->list.base.collection.simple_destructor =
NULL;
81 }
82 if (list->list.base.collection.advanced_destructor != cx_kv_list_destructor_wrapper) {
83 list->list_destr2 = list->list.base.collection.advanced_destructor;
84 list->list_destr_data = list->list.base.collection.destructor_data;
85 list->list.base.collection.advanced_destructor = cx_kv_list_destructor_wrapper;
86 list->list.base.collection.destructor_data = list;
87 }
88 if (list->map->map_base.base.collection.simple_destructor !=
NULL) {
89 list->map_destr = list->map->map_base.base.collection.simple_destructor;
90 list->map->map_base.base.collection.simple_destructor =
NULL;
91 }
92 if (list->map->map_base.base.collection.advanced_destructor !=
NULL) {
93 list->map_destr2 = list->map->map_base.base.collection.advanced_destructor;
94 list->map_destr_data = list->map->map_base.base.collection.destructor_data;
95 list->map->map_base.base.collection.advanced_destructor =
NULL;
96 list->map->map_base.base.collection.destructor_data =
NULL;
97 }
98 }
99
100 static CxHashKey *cx_kv_list_loc_key(cx_kv_list *list,
void *node_data) {
101 return (CxHashKey*)((
char*)node_data - list->list.loc_data + list->list.loc_extra);
102 }
103
104 static void cx_kvl_deallocate(
struct cx_list_s *list) {
105 cx_kv_list *kv_list = (cx_kv_list*)list;
106
107 cx_kv_list_update_destructors(kv_list);
108 kv_list->map_methods->deallocate(&kv_list->map->map_base.base);
109
110 kv_list->list_methods->deallocate(list);
111 }
112
113 static void *cx_kvl_insert_element(
114 struct cx_list_s *list,
115 size_t index,
116 const void *data
117 ) {
118 cx_kv_list *kv_list = (cx_kv_list*)list;
119 return kv_list->list_methods->insert_element(list, index, data);
120 }
121
122 static size_t cx_kvl_insert_array(
123 struct cx_list_s *list,
124 size_t index,
125 const void *data,
126 size_t n
127 ) {
128 cx_kv_list *kv_list = (cx_kv_list*)list;
129 return kv_list->list_methods->insert_array(list, index, data, n);
130 }
131
132 static size_t cx_kvl_insert_sorted(
133 struct cx_list_s *list,
134 const void *sorted_data,
135 size_t n
136 ) {
137 cx_kv_list *kv_list = (cx_kv_list*)list;
138 return kv_list->list_methods->insert_sorted(list, sorted_data, n);
139 }
140
141 static size_t cx_kvl_insert_unique(
142 struct cx_list_s *list,
143 const void *sorted_data,
144 size_t n
145 ) {
146 cx_kv_list *kv_list = (cx_kv_list*)list;
147 return kv_list->list_methods->insert_unique(list, sorted_data, n);
148 }
149
150 static int cx_kvl_insert_iter(
151 struct cx_iterator_s *iter,
152 const void *elem,
153 int prepend
154 ) {
155 cx_kv_list *kv_list = iter->src_handle;
156 return kv_list->list_methods->insert_iter(iter, elem, prepend);
157 }
158
159 static size_t cx_kvl_remove(
160 struct cx_list_s *list,
161 size_t index,
162 size_t num,
163 void *targetbuf
164 ) {
165 cx_kv_list *kv_list = (cx_kv_list*)list;
166
167
168
169 cx_kv_list_update_destructors(kv_list);
170
171 CxIterator iter = kv_list->list_methods->iterator(list, index, false);
172 for (
size_t i =
0; i < num && cxIteratorValid(iter); i++) {
173 void *node_data = cxIteratorCurrent(iter);
174 CxHashKey *key = cx_kv_list_loc_key(kv_list, node_data);
175
176 if (key->hash !=
0) {
177 kv_list->map_methods->remove(&kv_list->map->map_base.base, *key,
NULL);
178 }
179 cxIteratorNext(iter);
180 }
181 return kv_list->list_methods->remove(list, index, num, targetbuf);
182 }
183
184 static void cx_kvl_clear(
struct cx_list_s *list) {
185 cx_kv_list *kv_list = (cx_kv_list*)list;
186
187 cx_kv_list_update_destructors(kv_list);
188
189 kv_list->list_methods->clear(list);
190
191 kv_list->map_methods->clear(&kv_list->map->map_base.base);
192 }
193
194 static int cx_kvl_swap(
195 struct cx_list_s *list,
196 size_t i,
197 size_t j
198 ) {
199 cx_kv_list *kv_list = (cx_kv_list*)list;
200 return kv_list->list_methods->swap(list, i, j);
201 }
202
203 static void *cx_kvl_at(
204 const struct cx_list_s *list,
205 size_t index
206 ) {
207 const cx_kv_list *kv_list = (
const cx_kv_list*)list;
208 return kv_list->list_methods->at(list, index);
209 }
210
211 static size_t cx_kvl_find_remove(
212 struct cx_list_s *list,
213 const void *elem,
214 bool remove
215 ) {
216 cx_kv_list *kv_list = (cx_kv_list*)list;
217
218
219
220 if (list->collection.size ==
0)
return 0;
221
222 size_t index;
223 cx_linked_list *ll = &kv_list->list;
224 char *node = cx_linked_list_find(
225 ll->begin,
226 ll->loc_next, ll->loc_data,
227 list->collection.cmpfunc, elem,
228 &index
229 );
230 if (node ==
NULL) {
231 return list->collection.size;
232 }
233 if (remove) {
234 cx_kv_list_update_destructors(kv_list);
235 cx_invoke_advanced_destructor(list, node + ll->loc_data);
236 cx_linked_list_remove(&ll->begin, &ll->end,
237 ll->loc_prev, ll->loc_next, node);
238 CxHashKey *key = cx_kv_list_loc_key(kv_list, node + ll->loc_data);
239 if (key->hash !=
0) {
240 kv_list->map_methods->remove(&kv_list->map->map_base.base, *key,
NULL);
241 }
242 list->collection.size--;
243 cxFree(list->collection.allocator, node);
244 }
245 return index;
246 }
247
248 static void cx_kvl_sort(
struct cx_list_s *list) {
249 cx_kv_list *kv_list = (cx_kv_list*)list;
250 kv_list->list_methods->sort(list);
251 }
252
253 static void cx_kvl_reverse(
struct cx_list_s *list) {
254 cx_kv_list *kv_list = (cx_kv_list*)list;
255 kv_list->list_methods->reverse(list);
256 }
257
258 static void cx_kvl_list_iter_next(
void *it) {
259 struct cx_iterator_s *iter = it;
260 if (iter->base.remove) {
261
262 cx_kv_list *kv_list = iter->src_handle;
263 cx_kv_list_update_destructors(kv_list);
264 char *node = iter->elem_handle;
265 CxHashKey *key = cx_kv_list_loc_key(kv_list, node + kv_list->list.loc_data);
266 if (key->hash !=
0) {
267 kv_list->map_methods->remove(&kv_list->map->map_base.base, *key,
NULL);
268 }
269 }
270
271 iter->base.next_impl(it);
272 }
273
274 static struct cx_iterator_s cx_kvl_iterator(
275 const struct cx_list_s *list,
276 size_t index,
277 bool backward
278 ) {
279 const cx_kv_list *kv_list = (
const cx_kv_list*)list;
280 struct cx_iterator_s iter = kv_list->list_methods->iterator(list, index, backward);
281 iter.base.next_impl = iter.base.next;
282 iter.base.next = cx_kvl_list_iter_next;
283 return iter;
284 }
285
286 static void cx_kvl_map_deallocate(
struct cx_map_s *map) {
287 cx_kv_list *kv_list = ((
struct cx_kv_list_map_s*)map)->list;
288 kv_list->map_methods->deallocate(map);
289 kv_list->list_methods->deallocate(&kv_list->list.base);
290 }
291
292 static void cx_kvl_map_clear(
struct cx_map_s *map) {
293 cx_kv_list *kv_list = ((
struct cx_kv_list_map_s*)map)->list;
294 cx_kv_list_update_destructors(kv_list);
295 kv_list->list_methods->clear(&kv_list->list.base);
296 kv_list->map_methods->clear(map);
297 }
298
299 static void *cx_kvl_map_put(CxMap *map, CxHashKey key,
void *value) {
300 cx_kv_list *kv_list = ((
struct cx_kv_list_map_s*)map)->list;
301
302 if (key.hash ==
0) {
303 cx_hash_murmur(&key);
304 }
305
306
307 void **map_data = kv_list->map_methods->put(map, key,
NULL);
308 if (map_data ==
NULL)
return NULL;
309
310
311 kv_list->list.base.collection.sorted = false;
312 void *node_data = kv_list->list_methods->insert_element(
313 &kv_list->list.base, kv_list->list.base.collection.size,
314 kv_list->list.base.collection.store_pointer ? &value : value);
315 if (node_data ==
NULL) {
316
317 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data);
318 return NULL;
319 }
320
321
322 *map_data = node_data;
323
324
325 CxHashKey *key_ptr = cx_kv_list_loc_key(kv_list, node_data);
326 *key_ptr = key;
327
328
329
330 return node_data;
331 }
332
333 void *cx_kvl_map_get(
const CxMap *map, CxHashKey key) {
334 cx_kv_list *kv_list = ((
struct cx_kv_list_map_s*)map)->list;
335 void *node_data = kv_list->map_methods->get(map, key);
336 if (node_data ==
NULL)
return NULL;
337
338 return kv_list->list.base.collection.store_pointer ? *(
void**)node_data : node_data;
339 }
340
341 int cx_kvl_map_remove(CxMap *map, CxHashKey key,
void *targetbuf) {
342 cx_kv_list *kv_list = ((
struct cx_kv_list_map_s*)map)->list;
343
344 void *node_data;
345 if (kv_list->map_methods->remove(map, key, &node_data)) {
346 return 1;
347 }
348
349
350
351
352
353
354 if (targetbuf ==
NULL) {
355
356 cx_kv_list_update_destructors(kv_list);
357 cx_invoke_advanced_destructor(&kv_list->list.base, node_data);
358 }
else {
359
360 memcpy(targetbuf, node_data, kv_list->list.base.collection.elem_size);
361 }
362
363
364 void *node_ptr = (
char*)node_data - kv_list->list.loc_data;
365
366
367 cx_linked_list_remove(
368 &kv_list->list.begin,
369 &kv_list->list.end,
370 kv_list->list.loc_prev,
371 kv_list->list.loc_next,
372 node_ptr
373 );
374
375
376 kv_list->list.base.collection.size--;
377
378
379 cxFree(kv_list->list.base.collection.allocator, node_ptr);
380
381 return 0;
382 }
383
384 static void *cx_kvl_iter_current_entry(
const void *it) {
385 const CxMapIterator *iter = it;
386 return (
void*)&iter->entry;
387 }
388
389 static void *cx_kvl_iter_current_key(
const void *it) {
390 const CxMapEntry *entry = cx_kvl_iter_current_entry(it);
391 return (
void*)entry->key;
392 }
393
394 static void *cx_kvl_iter_current_value(
const void *it) {
395 const CxMapEntry *entry = cx_kvl_iter_current_entry(it);
396 return entry->value;
397 }
398
399 static void cx_kvl_iter_next(
void *it) {
400 CxMapIterator *iter = it;
401 cx_kv_list *kv_list = ((
struct cx_kv_list_map_s*)iter->map)->list;
402
403
404 CxHashKey *key =
NULL;
405 char *next = iter->elem;
406 while (true) {
407 next = *(
char**)(next + kv_list->list.loc_next);
408 if (next ==
NULL)
break;
409 key = cx_kv_list_loc_key(kv_list, next + kv_list->list.loc_data);
410 if (key->hash !=
0)
break;
411 }
412
413
414 if (iter->base.remove) {
415 iter->base.remove = false;
416 cx_kv_list_update_destructors(kv_list);
417 char *elem = iter->elem;
418 char *elem_data = elem + kv_list->list.loc_data;
419 CxHashKey *elem_key = cx_kv_list_loc_key(kv_list, elem_data);
420
421 kv_list->map_methods->remove(&kv_list->map->map_base.base, *elem_key,
NULL);
422 cx_invoke_advanced_destructor(&kv_list->list.base, elem_data);
423 cx_linked_list_remove(
424 &kv_list->list.begin,
425 &kv_list->list.end,
426 kv_list->list.loc_prev,
427 kv_list->list.loc_next,
428 elem
429 );
430 cxFree(kv_list->list.base.collection.allocator, elem);
431 kv_list->list.base.collection.size--;
432 iter->index--;
433 iter->elem_count--;
434 }
435
436
437 if (next ==
NULL) {
438 iter->index = kv_list->list.base.collection.size;
439 iter->elem =
NULL;
440 iter->entry = (CxMapEntry){
NULL,
NULL};
441 return;
442 }
443 iter->index++;
444 iter->elem = next;
445 iter->entry.key = key;
446 if (kv_list->list.base.collection.store_pointer) {
447 iter->entry.value = *(
void**)(next + kv_list->list.loc_data);
448 }
else {
449 iter->entry.value = (
void*)(next + kv_list->list.loc_data);
450 }
451 }
452
453 static bool cx_kvl_iter_valid(
const void *it) {
454 const CxMapIterator *iter = it;
455 return iter->elem !=
NULL;
456 }
457
458 CxMapIterator cx_kvl_map_iterator(
const CxMap *map,
enum cx_map_iterator_type type) {
459 CxMapIterator iter = {
0};
460
461 iter.type = type;
462 iter.map = (CxMap*)map;
463
464 iter.elem_count = map->collection.size;
465
466 switch (type) {
467 case CX_MAP_ITERATOR_PAIRS:
468 iter.elem_size =
sizeof(CxMapEntry);
469 iter.base.current = cx_kvl_iter_current_entry;
470 break;
471 case CX_MAP_ITERATOR_KEYS:
472 iter.elem_size =
sizeof(CxHashKey);
473 iter.base.current = cx_kvl_iter_current_key;
474 break;
475 case CX_MAP_ITERATOR_VALUES:
476 iter.elem_size = map->collection.elem_size;
477 iter.base.current = cx_kvl_iter_current_value;
478 break;
479 default:
480 assert(false);
481 }
482
483 iter.base.allow_remove = true;
484 iter.base.next = cx_kvl_iter_next;
485 iter.base.valid = cx_kvl_iter_valid;
486
487
488 cx_kv_list *kv_list = ((
struct cx_kv_list_map_s*)map)->list;
489 CxHashKey *key =
NULL;
490 char *next = kv_list->list.begin;
491 while (next !=
NULL) {
492 key = cx_kv_list_loc_key(kv_list, next + kv_list->list.loc_data);
493 if (key->hash !=
0)
break;
494 next = *(
char**)(next + kv_list->list.loc_next);
495 }
496 if (next ==
NULL) {
497 iter.elem =
NULL;
498 iter.entry = (CxMapEntry){
NULL,
NULL};
499 }
else {
500 iter.elem = next;
501 iter.entry.key = key;
502 if (kv_list->list.base.collection.store_pointer) {
503 iter.entry.value = *(
void**)(next + kv_list->list.loc_data);
504 }
else {
505 iter.entry.value = (
void*)(next + kv_list->list.loc_data);
506 }
507 }
508
509 return iter;
510 }
511
512 static int cx_kvl_change_capacity(
struct cx_list_s *list,
513 cx_attr_unused
size_t cap) {
514
515
516 cx_kv_list *kv_list = (cx_kv_list*)list;
517 cxMapRehash(&kv_list->map->map_base.base);
518 return 0;
519 }
520
521 static cx_list_class cx_kv_list_class = {
522 cx_kvl_deallocate,
523 cx_kvl_insert_element,
524 cx_kvl_insert_array,
525 cx_kvl_insert_sorted,
526 cx_kvl_insert_unique,
527 cx_kvl_insert_iter,
528 cx_kvl_remove,
529 cx_kvl_clear,
530 cx_kvl_swap,
531 cx_kvl_at,
532 cx_kvl_find_remove,
533 cx_kvl_sort,
534 NULL,
535 cx_kvl_reverse,
536 cx_kvl_change_capacity,
537 cx_kvl_iterator,
538 };
539
540 static cx_map_class cx_kv_map_class = {
541 cx_kvl_map_deallocate,
542 cx_kvl_map_clear,
543 cx_kvl_map_put,
544 cx_kvl_map_get,
545 cx_kvl_map_remove,
546 cx_kvl_map_iterator,
547 };
548
549 CxList *cxKvListCreate(
550 const CxAllocator *allocator,
551 cx_compare_func comparator,
552 size_t elem_size
553 ) {
554 if (allocator ==
NULL) {
555 allocator = cxDefaultAllocator;
556 }
557
558
559 CxList *list = cxLinkedListCreate(allocator, comparator, elem_size);
560 if (list ==
NULL)
return NULL;
561 cx_linked_list *ll = (cx_linked_list*)list;
562 cx_linked_list_extra_data(ll,
sizeof(CxHashKey));
563 CxMap *map = cxHashMapCreate(allocator,
CX_STORE_POINTERS,
0);
564 if (map ==
NULL) {
565 cxListFree(list);
566 return NULL;
567 }
568
569
570
571 cx_kv_list_class.compare = list->cl->compare;
572
573
574 struct cx_kv_list_map_s *kv_map = cxRealloc(allocator, map,
sizeof(
struct cx_kv_list_map_s));
575
576
577 cx_kv_list *kv_list = cxRealloc(allocator, list,
sizeof(
struct cx_kv_list_s));
578
579
580 if (kv_map !=
NULL && kv_list !=
NULL) {
581 map = (CxMap*) kv_map;
582 list = (CxList*) kv_list;
583 }
else {
584 cxListFree(list);
585 cxMapFree(map);
586 return NULL;
587 }
588
589
590 memset((
char*)kv_list + offsetof(cx_kv_list, list_destr),
0,
sizeof(
void*)*
6);
591
592
593 kv_list->map = kv_map;
594 kv_map->list = kv_list;
595
596
597 kv_list->map_methods = map->cl;
598 map->cl = &cx_kv_map_class;
599 if (list->climpl ==
NULL) {
600 kv_list->list_methods = list->cl;
601 list->cl = &cx_kv_list_class;
602 }
else {
603 kv_list->list_methods = list->climpl;
604 list->climpl = &cx_kv_list_class;
605 }
606
607 return list;
608 }
609
610 CxMap *cxKvListCreateAsMap(
611 const CxAllocator *allocator,
612 cx_compare_func comparator,
613 size_t elem_size
614 ) {
615 CxList *list = cxKvListCreate(allocator, comparator, elem_size);
616 return list ==
NULL ?
NULL : cxKvListAsMap(list);
617 }
618
619 CxList *cxKvListAsList(CxMap *map) {
620 return &((
struct cx_kv_list_map_s*)map)->list->list.base;
621 }
622
623 CxMap *cxKvListAsMap(CxList *list) {
624 return &((cx_kv_list*)list)->map->map_base.base;
625 }
626
627 int cx_kv_list_set_key(CxList *list,
size_t index, CxHashKey key) {
628 cx_kv_list *kv_list = (cx_kv_list*)list;
629 void *node_data = kv_list->list_methods->at(list, index);
630 if (node_data ==
NULL) {
631 return 1;
632 }
633
634 if (key.hash ==
0) {
635 cx_hash_murmur(&key);
636 }
637
638
639 void *existing = kv_list->map_methods->get(&kv_list->map->map_base.base, key);
640 if (existing == node_data) {
641 return 0;
642 }
643 if (existing !=
NULL) {
644
645 return 1;
646 }
647
648
649 if (
NULL == kv_list->map_methods->put(&kv_list->map->map_base.base, key, node_data)) {
650 return 1;
651 }
652
653
654 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
655 *loc_key = key;
656
657 return 0;
658 }
659
660 int cxKvListRemoveKey(CxList *list,
size_t index) {
661 cx_kv_list *kv_list = (cx_kv_list*)list;
662 void *node_data = kv_list->list_methods->at(list, index);
663 if (node_data ==
NULL) {
664 return 1;
665 }
666 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
667 if (loc_key->hash ==
0) {
668 return 0;
669 }
670 kv_list->map_methods->remove(&kv_list->map->map_base.base, *loc_key,
NULL);
671
672
673 memset(loc_key,
0,
sizeof(CxHashKey));
674 return 0;
675 }
676
677 const CxHashKey *cxKvListGetKey(CxList *list,
size_t index) {
678 cx_kv_list *kv_list = (cx_kv_list*)list;
679 void *node_data = kv_list->list_methods->at(list, index);
680 if (node_data ==
NULL) {
681 return NULL;
682 }
683 CxHashKey *key = cx_kv_list_loc_key(kv_list, node_data);
684 if (key->hash ==
0) {
685 return NULL;
686 }
687 return key;
688 }
689
690 int cx_kv_list_insert(CxList *list,
size_t index, CxHashKey key,
void *value) {
691
692 list->collection.sorted = false;
693
694 cx_kv_list *kv_list = (cx_kv_list*)list;
695
696
697 void **map_data = kv_list->map_methods->put(&kv_list->map->map_base.base, key,
NULL);
698 if (map_data ==
NULL)
return 1;
699
700
701 void *node_data = kv_list->list_methods->insert_element(&kv_list->list.base, index,
702 kv_list->list.base.collection.store_pointer ? &value : value);
703 if (node_data ==
NULL) {
704
705 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data);
706 return 1;
707 }
708 *map_data = node_data;
709
710
711 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
712 *loc_key = key;
713
714 return 0;
715 }
716