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.base.collection.elem_size);
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 cx_list_class cx_kv_list_class = {
513 cx_kvl_deallocate,
514 cx_kvl_insert_element,
515 cx_kvl_insert_array,
516 cx_kvl_insert_sorted,
517 cx_kvl_insert_unique,
518 cx_kvl_insert_iter,
519 cx_kvl_remove,
520 cx_kvl_clear,
521 cx_kvl_swap,
522 cx_kvl_at,
523 cx_kvl_find_remove,
524 cx_kvl_sort,
525 NULL,
526 cx_kvl_reverse,
527 cx_kvl_iterator,
528 };
529
530 static cx_map_class cx_kv_map_class = {
531 cx_kvl_map_deallocate,
532 cx_kvl_map_clear,
533 cx_kvl_map_put,
534 cx_kvl_map_get,
535 cx_kvl_map_remove,
536 cx_kvl_map_iterator,
537 };
538
539 CxList *cxKvListCreate(
540 const CxAllocator *allocator,
541 cx_compare_func comparator,
542 size_t elem_size
543 ) {
544 if (allocator ==
NULL) {
545 allocator = cxDefaultAllocator;
546 }
547
548
549 CxList *list = cxLinkedListCreate(allocator, comparator, elem_size);
550 if (list ==
NULL)
return NULL;
551 cx_linked_list *ll = (cx_linked_list*)list;
552 ll->extra_data_len =
sizeof(CxHashKey);
553 CxMap *map = cxHashMapCreate(allocator,
CX_STORE_POINTERS,
0);
554 if (map ==
NULL) {
555 cxListFree(list);
556 return NULL;
557 }
558
559
560
561 cx_kv_list_class.compare = list->cl->compare;
562
563
564 struct cx_kv_list_map_s *kv_map = cxRealloc(allocator, map,
sizeof(
struct cx_kv_list_map_s));
565
566
567 cx_kv_list *kv_list = cxRealloc(allocator, list,
sizeof(
struct cx_kv_list_s));
568
569
570 if (kv_map !=
NULL && kv_list !=
NULL) {
571 map = (CxMap*) kv_map;
572 list = (CxList*) kv_list;
573 }
else {
574 cxListFree(list);
575 cxMapFree(map);
576 return NULL;
577 }
578
579
580 memset((
char*)kv_list + offsetof(cx_kv_list, list_destr),
0,
sizeof(
void*)*
6);
581
582
583 kv_list->map = kv_map;
584 kv_map->list = kv_list;
585
586
587 kv_list->map_methods = map->cl;
588 map->cl = &cx_kv_map_class;
589 if (list->climpl ==
NULL) {
590 kv_list->list_methods = list->cl;
591 list->cl = &cx_kv_list_class;
592 }
else {
593 kv_list->list_methods = list->climpl;
594 list->climpl = &cx_kv_list_class;
595 }
596
597 return list;
598 }
599
600 CxMap *cxKvListCreateAsMap(
601 const CxAllocator *allocator,
602 cx_compare_func comparator,
603 size_t elem_size
604 ) {
605 CxList *list = cxKvListCreate(allocator, comparator, elem_size);
606 return list ==
NULL ?
NULL : cxKvListAsMap(list);
607 }
608
609 CxList *cxKvListAsList(CxMap *map) {
610 return &((
struct cx_kv_list_map_s*)map)->list->list.base;
611 }
612
613 CxMap *cxKvListAsMap(CxList *list) {
614 return &((cx_kv_list*)list)->map->map_base.base;
615 }
616
617 int cx_kv_list_set_key(CxList *list,
size_t index, CxHashKey key) {
618 cx_kv_list *kv_list = (cx_kv_list*)list;
619 void *node_data = kv_list->list_methods->at(list, index);
620 if (node_data ==
NULL) {
621 return 1;
622 }
623
624 if (key.hash ==
0) {
625 cx_hash_murmur(&key);
626 }
627
628
629 void *existing = kv_list->map_methods->get(&kv_list->map->map_base.base, key);
630 if (existing == node_data) {
631 return 0;
632 }
633 if (existing !=
NULL) {
634
635 return 1;
636 }
637
638
639 if (
NULL == kv_list->map_methods->put(&kv_list->map->map_base.base, key, node_data)) {
640 return 1;
641 }
642
643
644 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
645 *loc_key = key;
646
647 return 0;
648 }
649
650 int cxKvListRemoveKey(CxList *list,
size_t index) {
651 cx_kv_list *kv_list = (cx_kv_list*)list;
652 void *node_data = kv_list->list_methods->at(list, index);
653 if (node_data ==
NULL) {
654 return 1;
655 }
656 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
657 if (loc_key->hash ==
0) {
658 return 0;
659 }
660 kv_list->map_methods->remove(&kv_list->map->map_base.base, *loc_key,
NULL);
661
662
663 memset(loc_key,
0,
sizeof(CxHashKey));
664 return 0;
665 }
666
667 const CxHashKey *cxKvListGetKey(CxList *list,
size_t index) {
668 cx_kv_list *kv_list = (cx_kv_list*)list;
669 void *node_data = kv_list->list_methods->at(list, index);
670 if (node_data ==
NULL) {
671 return NULL;
672 }
673 CxHashKey *key = cx_kv_list_loc_key(kv_list, node_data);
674 if (key->hash ==
0) {
675 return NULL;
676 }
677 return key;
678 }
679
680 int cx_kv_list_insert(CxList *list,
size_t index, CxHashKey key,
void *value) {
681
682 list->collection.sorted = false;
683
684 cx_kv_list *kv_list = (cx_kv_list*)list;
685
686
687 void **map_data = kv_list->map_methods->put(&kv_list->map->map_base.base, key,
NULL);
688 if (map_data ==
NULL)
return 1;
689
690
691 void *node_data = kv_list->list_methods->insert_element(&kv_list->list.base, index,
692 kv_list->list.base.collection.store_pointer ? &value : value);
693 if (node_data ==
NULL) {
694
695 kv_list->map_methods->remove(&kv_list->map->map_base.base, key, &map_data);
696 return 1;
697 }
698 *map_data = node_data;
699
700
701 CxHashKey *loc_key = cx_kv_list_loc_key(kv_list, node_data);
702 *loc_key = key;
703
704 return 0;
705 }
706