| 99 while (elm != NULL && elm->key.hash < hash) { |
99 while (elm != NULL && elm->key.hash < hash) { |
| 100 prev = elm; |
100 prev = elm; |
| 101 elm = elm->next; |
101 elm = elm->next; |
| 102 } |
102 } |
| 103 |
103 |
| 104 if (elm != NULL && elm->key.hash == hash && elm->key.len == key.len && |
104 if (elm != NULL && cx_hash_key_cmp(&elm->key, &key) == 0) { |
| 105 memcmp(elm->key.data, key.data, key.len) == 0) { |
|
| 106 // overwrite existing element, but call destructors first |
105 // overwrite existing element, but call destructors first |
| 107 cx_invoke_destructor(map, elm->data); |
106 cx_invoke_destructor(map, elm->data); |
| 108 if (value == NULL) { |
107 if (value == NULL) { |
| 109 memset(elm->data, 0, map->collection.elem_size); |
108 memset(elm->data, 0, map->collection.elem_size); |
| 110 } else if (map->collection.store_pointer) { |
109 } else if (map->collection.store_pointer) { |
| 202 void *targetbuf, |
201 void *targetbuf, |
| 203 bool remove |
202 bool remove |
| 204 ) { |
203 ) { |
| 205 struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; |
204 struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; |
| 206 |
205 |
| 207 unsigned hash = key.hash; |
206 uint64_t hash = key.hash; |
| 208 if (hash == 0) { |
207 if (hash == 0) { |
| 209 cx_hash_murmur(&key); |
208 cx_hash_murmur(&key); |
| 210 hash = key.hash; |
209 hash = key.hash; |
| 211 } |
210 } |
| 212 |
211 |
| 213 size_t slot = hash % hash_map->bucket_count; |
212 size_t slot = hash % hash_map->bucket_count; |
| 214 struct cx_hash_map_element_s *elm = hash_map->buckets[slot]; |
213 struct cx_hash_map_element_s *elm = hash_map->buckets[slot]; |
| 215 struct cx_hash_map_element_s *prev = NULL; |
214 struct cx_hash_map_element_s *prev = NULL; |
| 216 while (elm && elm->key.hash <= hash) { |
215 while (elm && elm->key.hash <= hash) { |
| 217 if (elm->key.hash == hash && elm->key.len == key.len) { |
216 if (cx_hash_key_cmp(&elm->key, &key) == 0) { |
| 218 if (memcmp(elm->key.data, key.data, key.len) == 0) { |
217 if (remove) { |
| 219 if (remove) { |
218 if (targetbuf == NULL) { |
| 220 if (targetbuf == NULL) { |
219 cx_invoke_destructor(map, elm->data); |
| 221 cx_invoke_destructor(map, elm->data); |
|
| 222 } else { |
|
| 223 memcpy(targetbuf, elm->data, map->collection.elem_size); |
|
| 224 } |
|
| 225 cx_hash_map_unlink(hash_map, slot, prev, elm); |
|
| 226 } else { |
220 } else { |
| 227 assert(targetbuf != NULL); |
221 memcpy(targetbuf, elm->data, map->collection.elem_size); |
| 228 void *data = NULL; |
|
| 229 if (map->collection.store_pointer) { |
|
| 230 data = *(void **) elm->data; |
|
| 231 } else { |
|
| 232 data = elm->data; |
|
| 233 } |
|
| 234 memcpy(targetbuf, &data, sizeof(void *)); |
|
| 235 } |
222 } |
| 236 return 0; |
223 cx_hash_map_unlink(hash_map, slot, prev, elm); |
| |
224 } else { |
| |
225 assert(targetbuf != NULL); |
| |
226 void *data = NULL; |
| |
227 if (map->collection.store_pointer) { |
| |
228 data = *(void **) elm->data; |
| |
229 } else { |
| |
230 data = elm->data; |
| |
231 } |
| |
232 memcpy(targetbuf, &data, sizeof(void *)); |
| 237 } |
233 } |
| |
234 return 0; |
| 238 } |
235 } |
| 239 prev = elm; |
236 prev = elm; |
| 240 elm = prev->next; |
237 elm = prev->next; |
| 241 } |
238 } |
| 242 |
239 |
| 267 return (void*) &iter->entry; |
264 return (void*) &iter->entry; |
| 268 } |
265 } |
| 269 |
266 |
| 270 static void *cx_hash_map_iter_current_key(const void *it) { |
267 static void *cx_hash_map_iter_current_key(const void *it) { |
| 271 const CxMapIterator *iter = it; |
268 const CxMapIterator *iter = it; |
| 272 struct cx_hash_map_element_s *elm = iter->elem; |
269 return (void*) iter->entry.key; |
| 273 return &elm->key; |
|
| 274 } |
270 } |
| 275 |
271 |
| 276 static void *cx_hash_map_iter_current_value(const void *it) { |
272 static void *cx_hash_map_iter_current_value(const void *it) { |
| 277 const CxMapIterator *iter = it; |
273 const CxMapIterator *iter = it; |
| 278 const CxMap *map = iter->map.c; |
274 return iter->entry.value; |
| 279 struct cx_hash_map_element_s *elm = iter->elem; |
|
| 280 if (map->collection.store_pointer) { |
|
| 281 return *(void **) elm->data; |
|
| 282 } else { |
|
| 283 return elm->data; |
|
| 284 } |
|
| 285 } |
275 } |
| 286 |
276 |
| 287 static bool cx_hash_map_iter_valid(const void *it) { |
277 static bool cx_hash_map_iter_valid(const void *it) { |
| 288 const CxMapIterator *iter = it; |
278 const CxMapIterator *iter = it; |
| 289 return iter->elem != NULL; |
279 return iter->elem != NULL; |
| 290 } |
280 } |
| 291 |
281 |
| 292 static void cx_hash_map_iter_next(void *it) { |
282 static void cx_hash_map_iter_next(void *it) { |
| 293 CxMapIterator *iter = it; |
283 CxMapIterator *iter = it; |
| 294 CxMap *map = iter->map.m; |
284 CxMap *map = iter->map; |
| 295 struct cx_hash_map_s *hmap = (struct cx_hash_map_s *) map; |
285 struct cx_hash_map_s *hmap = (struct cx_hash_map_s *) map; |
| 296 struct cx_hash_map_element_s *elm = iter->elem; |
286 struct cx_hash_map_element_s *elm = iter->elem; |
| 297 |
287 |
| 298 // remove current element, if asked |
288 // remove current element, if asked |
| 299 if (iter->base.remove) { |
289 if (iter->base.remove) { |
| 336 // copy data to a location where the iterator can point to |
327 // copy data to a location where the iterator can point to |
| 337 // we need to do it here, because the iterator function call |
328 // we need to do it here, because the iterator function call |
| 338 // must not modify the iterator (the parameter is const) |
329 // must not modify the iterator (the parameter is const) |
| 339 if (elm != NULL) { |
330 if (elm != NULL) { |
| 340 iter->entry.key = &elm->key; |
331 iter->entry.key = &elm->key; |
| 341 if (iter->map.c->collection.store_pointer) { |
332 if (map->collection.store_pointer) { |
| 342 iter->entry.value = *(void **) elm->data; |
333 iter->entry.value = *(void **) elm->data; |
| 343 } else { |
334 } else { |
| 344 iter->entry.value = elm->data; |
335 iter->entry.value = elm->data; |
| 345 } |
336 } |
| 346 } |
337 } |
| 373 } |
364 } |
| 374 |
365 |
| 375 iter.base.valid = cx_hash_map_iter_valid; |
366 iter.base.valid = cx_hash_map_iter_valid; |
| 376 iter.base.next = cx_hash_map_iter_next; |
367 iter.base.next = cx_hash_map_iter_next; |
| 377 iter.base.remove = false; |
368 iter.base.remove = false; |
| 378 iter.base.mutating = false; |
369 iter.base.allow_remove = true; |
| 379 |
370 |
| 380 iter.slot = 0; |
371 iter.slot = 0; |
| 381 iter.index = 0; |
372 iter.index = 0; |
| 382 |
373 |
| 383 if (map->collection.size > 0) { |
374 if (map->collection.size > 0) { |