| 294 cx_kv_list_update_destructors(kv_list); |
295 cx_kv_list_update_destructors(kv_list); |
| 295 kv_list->list_methods->clear(&kv_list->list.base); |
296 kv_list->list_methods->clear(&kv_list->list.base); |
| 296 kv_list->map_methods->clear(map); |
297 kv_list->map_methods->clear(map); |
| 297 } |
298 } |
| 298 |
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 |
| 299 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) { |
| 300 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; |
| 301 // if the hash has not yet been computed, do it now |
353 // if the hash has not yet been computed, do it now |
| 302 if (key.hash == 0) { |
354 if (key.hash == 0) { |
| 303 cx_hash_murmur(&key); |
355 cx_hash_murmur(&key); |
| 304 } |
356 } |
| 305 |
357 |
| 306 // 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 |
| 307 void **map_data = kv_list->map_methods->put(map, key, NULL); |
362 void **map_data = kv_list->map_methods->put(map, key, NULL); |
| 308 if (map_data == NULL) return NULL; // LCOV_EXCL_LINE |
363 if (map_data == NULL) return NULL; // LCOV_EXCL_LINE |
| 309 |
364 |
| 310 // 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) |
| 311 kv_list->list.base.collection.sorted = false; |
366 kv_list->list.base.collection.sorted = false; |
| 326 *key_ptr = key; |
381 *key_ptr = key; |
| 327 |
382 |
| 328 // we must return node_data here and not map_data, |
383 // we must return node_data here and not map_data, |
| 329 // because the node_data is the actual element of this collection |
384 // because the node_data is the actual element of this collection |
| 330 return node_data; |
385 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; // LCOV_EXCL_LINE |
|
| 337 // return the node data |
|
| 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 // we cannot just call a list method (because we don't have the index) |
|
| 349 // and tbh. we also don't want to (because it's not performant when we |
|
| 350 // can have the node ptr directly instead) |
|
| 351 // therefore, we re-implement the logic ourselves |
|
| 352 |
|
| 353 // check if the outside caller want's us to return or to destroy the element |
|
| 354 if (targetbuf == NULL) { |
|
| 355 // patch the destructors and invoke them through the wrapper |
|
| 356 cx_kv_list_update_destructors(kv_list); |
|
| 357 cx_invoke_advanced_destructor(&kv_list->list.base, node_data); |
|
| 358 } else { |
|
| 359 // copy the element to the target buffer |
|
| 360 memcpy(targetbuf, node_data, kv_list->list.base.collection.elem_size); |
|
| 361 } |
|
| 362 |
|
| 363 // calculate the address of the node |
|
| 364 void *node_ptr = (char*)node_data - kv_list->list.loc_data; |
|
| 365 |
|
| 366 // unlink the node |
|
| 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 // decrement the list's size |
|
| 376 kv_list->list.base.collection.size--; |
|
| 377 |
|
| 378 // deallocate the node |
|
| 379 cxFree(kv_list->list.base.collection.allocator, node_ptr); |
|
| 380 |
|
| 381 return 0; |
|
| 382 } |
386 } |
| 383 |
387 |
| 384 static void *cx_kvl_iter_current_entry(const void *it) { |
388 static void *cx_kvl_iter_current_entry(const void *it) { |
| 385 const CxMapIterator *iter = it; |
389 const CxMapIterator *iter = it; |
| 386 return (void*)&iter->entry; |
390 return (void*)&iter->entry; |
| 453 static bool cx_kvl_iter_valid(const void *it) { |
457 static bool cx_kvl_iter_valid(const void *it) { |
| 454 const CxMapIterator *iter = it; |
458 const CxMapIterator *iter = it; |
| 455 return iter->elem != NULL; |
459 return iter->elem != NULL; |
| 456 } |
460 } |
| 457 |
461 |
| 458 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) { |
| 459 CxMapIterator iter = {0}; |
463 CxMapIterator iter = {0}; |
| 460 |
464 |
| 461 iter.type = type; |
465 iter.type = type; |
| 462 iter.map = (CxMap*)map; |
466 iter.map = (CxMap*)map; |
| 463 // 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 |