| 295 cx_kv_list_update_destructors(kv_list); |
295 cx_kv_list_update_destructors(kv_list); |
| 296 kv_list->list_methods->clear(&kv_list->list.base); |
296 kv_list->list_methods->clear(&kv_list->list.base); |
| 297 kv_list->map_methods->clear(map); |
297 kv_list->map_methods->clear(map); |
| 298 } |
298 } |
| 299 |
299 |
| |
300 static void *cx_kvl_map_get(const CxMap *map, CxHashKey key) { |
| |
301 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
| |
302 void *node_data = kv_list->map_methods->get(map, key); |
| |
303 if (node_data == NULL) return NULL; // LCOV_EXCL_LINE |
| |
304 // return the node data |
| |
305 return kv_list->list.base.collection.store_pointer ? *(void**)node_data : node_data; |
| |
306 } |
| |
307 |
| |
308 static int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) { |
| |
309 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
| |
310 |
| |
311 void *node_data; |
| |
312 if (kv_list->map_methods->remove(map, key, &node_data)) { |
| |
313 return 1; |
| |
314 } |
| |
315 // we cannot just call a list method (because we don't have the index) |
| |
316 // and tbh. we also don't want to (because it's not performant when we |
| |
317 // can have the node ptr directly instead) |
| |
318 // therefore, we re-implement the logic ourselves |
| |
319 |
| |
320 // check if the outside caller want's us to return or to destroy the element |
| |
321 if (targetbuf == NULL) { |
| |
322 // patch the destructors and invoke them through the wrapper |
| |
323 cx_kv_list_update_destructors(kv_list); |
| |
324 cx_invoke_advanced_destructor(&kv_list->list.base, node_data); |
| |
325 } else { |
| |
326 // copy the element to the target buffer |
| |
327 memcpy(targetbuf, node_data, kv_list->list.base.collection.elem_size); |
| |
328 } |
| |
329 |
| |
330 // calculate the address of the node |
| |
331 void *node_ptr = (char*)node_data - kv_list->list.loc_data; |
| |
332 |
| |
333 // unlink the node |
| |
334 cx_linked_list_remove( |
| |
335 &kv_list->list.begin, |
| |
336 &kv_list->list.end, |
| |
337 kv_list->list.loc_prev, |
| |
338 kv_list->list.loc_next, |
| |
339 node_ptr |
| |
340 ); |
| |
341 |
| |
342 // decrement the list's size |
| |
343 kv_list->list.base.collection.size--; |
| |
344 |
| |
345 // deallocate the node |
| |
346 cxFree(kv_list->list.base.collection.allocator, node_ptr); |
| |
347 |
| |
348 return 0; |
| |
349 } |
| |
350 |
| 300 static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) { |
351 static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) { |
| 301 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
352 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
| 302 // if the hash has not yet been computed, do it now |
353 // if the hash has not yet been computed, do it now |
| 303 if (key.hash == 0) { |
354 if (key.hash == 0) { |
| 304 cx_hash_murmur(&key); |
355 cx_hash_murmur(&key); |
| 305 } |
356 } |
| 306 |
357 |
| 307 // reserve memory in the map first |
358 // remove any existing element first |
| |
359 cx_kvl_map_remove(map, key, NULL); |
| |
360 |
| |
361 // now reserve new memory in the map |
| 308 void **map_data = kv_list->map_methods->put(map, key, NULL); |
362 void **map_data = kv_list->map_methods->put(map, key, NULL); |
| 309 if (map_data == NULL) return NULL; // LCOV_EXCL_LINE |
363 if (map_data == NULL) return NULL; // LCOV_EXCL_LINE |
| 310 |
364 |
| 311 // insert the data into the list (which most likely destroys the sorted property) |
365 // insert the data into the list (which most likely destroys the sorted property) |
| 312 kv_list->list.base.collection.sorted = false; |
366 kv_list->list.base.collection.sorted = false; |
| 327 *key_ptr = key; |
381 *key_ptr = key; |
| 328 |
382 |
| 329 // we must return node_data here and not map_data, |
383 // we must return node_data here and not map_data, |
| 330 // because the node_data is the actual element of this collection |
384 // because the node_data is the actual element of this collection |
| 331 return node_data; |
385 return node_data; |
| 332 } |
|
| 333 |
|
| 334 void *cx_kvl_map_get(const CxMap *map, CxHashKey key) { |
|
| 335 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
|
| 336 void *node_data = kv_list->map_methods->get(map, key); |
|
| 337 if (node_data == NULL) return NULL; // LCOV_EXCL_LINE |
|
| 338 // return the node data |
|
| 339 return kv_list->list.base.collection.store_pointer ? *(void**)node_data : node_data; |
|
| 340 } |
|
| 341 |
|
| 342 int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) { |
|
| 343 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
|
| 344 |
|
| 345 void *node_data; |
|
| 346 if (kv_list->map_methods->remove(map, key, &node_data)) { |
|
| 347 return 1; |
|
| 348 } |
|
| 349 // we cannot just call a list method (because we don't have the index) |
|
| 350 // and tbh. we also don't want to (because it's not performant when we |
|
| 351 // can have the node ptr directly instead) |
|
| 352 // therefore, we re-implement the logic ourselves |
|
| 353 |
|
| 354 // check if the outside caller want's us to return or to destroy the element |
|
| 355 if (targetbuf == NULL) { |
|
| 356 // patch the destructors and invoke them through the wrapper |
|
| 357 cx_kv_list_update_destructors(kv_list); |
|
| 358 cx_invoke_advanced_destructor(&kv_list->list.base, node_data); |
|
| 359 } else { |
|
| 360 // copy the element to the target buffer |
|
| 361 memcpy(targetbuf, node_data, kv_list->list.base.collection.elem_size); |
|
| 362 } |
|
| 363 |
|
| 364 // calculate the address of the node |
|
| 365 void *node_ptr = (char*)node_data - kv_list->list.loc_data; |
|
| 366 |
|
| 367 // unlink the node |
|
| 368 cx_linked_list_remove( |
|
| 369 &kv_list->list.begin, |
|
| 370 &kv_list->list.end, |
|
| 371 kv_list->list.loc_prev, |
|
| 372 kv_list->list.loc_next, |
|
| 373 node_ptr |
|
| 374 ); |
|
| 375 |
|
| 376 // decrement the list's size |
|
| 377 kv_list->list.base.collection.size--; |
|
| 378 |
|
| 379 // deallocate the node |
|
| 380 cxFree(kv_list->list.base.collection.allocator, node_ptr); |
|
| 381 |
|
| 382 return 0; |
|
| 383 } |
386 } |
| 384 |
387 |
| 385 static void *cx_kvl_iter_current_entry(const void *it) { |
388 static void *cx_kvl_iter_current_entry(const void *it) { |
| 386 const CxMapIterator *iter = it; |
389 const CxMapIterator *iter = it; |
| 387 return (void*)&iter->entry; |
390 return (void*)&iter->entry; |
| 454 static bool cx_kvl_iter_valid(const void *it) { |
457 static bool cx_kvl_iter_valid(const void *it) { |
| 455 const CxMapIterator *iter = it; |
458 const CxMapIterator *iter = it; |
| 456 return iter->elem != NULL; |
459 return iter->elem != NULL; |
| 457 } |
460 } |
| 458 |
461 |
| 459 CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) { |
462 static CxMapIterator cx_kvl_map_iterator(const CxMap *map, enum cx_map_iterator_type type) { |
| 460 CxMapIterator iter = {0}; |
463 CxMapIterator iter = {0}; |
| 461 |
464 |
| 462 iter.type = type; |
465 iter.type = type; |
| 463 iter.map = (CxMap*)map; |
466 iter.map = (CxMap*)map; |
| 464 // although we iterate over the list, we only report that many elements that have a key in the map |
467 // although we iterate over the list, we only report that many elements that have a key in the map |