170 } |
170 } |
171 |
171 |
172 /** |
172 /** |
173 * Helper function to avoid code duplication. |
173 * Helper function to avoid code duplication. |
174 * |
174 * |
|
175 * If \p remove is true, and \p targetbuf is \c NULL, the element |
|
176 * will be destroyed when found. |
|
177 * |
|
178 * If \p remove is true, and \p targetbuf is set, the element will |
|
179 * be copied to that buffer and no destructor function is called. |
|
180 * |
|
181 * If \p remove is false, \p targetbuf must not be non-null and |
|
182 * either the pointer, when the map is storing pointers, is copied |
|
183 * to the target buffer, or a pointer to the stored object will |
|
184 * be copied to the target buffer. |
|
185 * |
175 * @param map the map |
186 * @param map the map |
176 * @param key the key to look up |
187 * @param key the key to look up |
|
188 * @param targetbuf see description |
177 * @param remove flag indicating whether the looked up entry shall be removed |
189 * @param remove flag indicating whether the looked up entry shall be removed |
178 * @param destroy flag indicating whether the destructor shall be invoked |
190 * @return zero, if the key was found, non-zero otherwise |
179 * @return a pointer to the value corresponding to the key or \c NULL |
|
180 */ |
191 */ |
181 static void *cx_hash_map_get_remove( |
192 static int cx_hash_map_get_remove( |
182 CxMap *map, |
193 CxMap *map, |
183 CxHashKey key, |
194 CxHashKey key, |
184 bool remove, |
195 void *targetbuf, |
185 bool destroy |
196 bool remove |
186 ) { |
197 ) { |
187 struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; |
198 struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map; |
188 |
199 |
189 unsigned hash = key.hash; |
200 unsigned hash = key.hash; |
190 if (hash == 0) { |
201 if (hash == 0) { |
196 struct cx_hash_map_element_s *elm = hash_map->buckets[slot]; |
207 struct cx_hash_map_element_s *elm = hash_map->buckets[slot]; |
197 struct cx_hash_map_element_s *prev = NULL; |
208 struct cx_hash_map_element_s *prev = NULL; |
198 while (elm && elm->key.hash <= hash) { |
209 while (elm && elm->key.hash <= hash) { |
199 if (elm->key.hash == hash && elm->key.len == key.len) { |
210 if (elm->key.hash == hash && elm->key.len == key.len) { |
200 if (memcmp(elm->key.data, key.data, key.len) == 0) { |
211 if (memcmp(elm->key.data, key.data, key.len) == 0) { |
201 void *data = NULL; |
212 if (remove) { |
202 if (destroy) { |
213 if (targetbuf == NULL) { |
203 cx_invoke_destructor(map, elm->data); |
214 cx_invoke_destructor(map, elm->data); |
|
215 } else { |
|
216 memcpy(targetbuf, elm->data, map->collection.elem_size); |
|
217 } |
|
218 cx_hash_map_unlink(hash_map, slot, prev, elm); |
204 } else { |
219 } else { |
|
220 assert(targetbuf != NULL); |
|
221 void *data = NULL; |
205 if (map->collection.store_pointer) { |
222 if (map->collection.store_pointer) { |
206 data = *(void **) elm->data; |
223 data = *(void **) elm->data; |
207 } else { |
224 } else { |
208 data = elm->data; |
225 data = elm->data; |
209 } |
226 } |
|
227 memcpy(targetbuf, &data, sizeof(void *)); |
210 } |
228 } |
211 if (remove) { |
229 return 0; |
212 cx_hash_map_unlink(hash_map, slot, prev, elm); |
|
213 } |
|
214 return data; |
|
215 } |
230 } |
216 } |
231 } |
217 prev = elm; |
232 prev = elm; |
218 elm = prev->next; |
233 elm = prev->next; |
219 } |
234 } |
220 |
235 |
221 return NULL; |
236 return 1; |
222 } |
237 } |
223 |
238 |
224 static void *cx_hash_map_get( |
239 static void *cx_hash_map_get( |
225 const CxMap *map, |
240 const CxMap *map, |
226 CxHashKey key |
241 CxHashKey key |
227 ) { |
242 ) { |
228 // we can safely cast, because we know the map stays untouched |
243 // we can safely cast, because we know the map stays untouched |
229 return cx_hash_map_get_remove((CxMap *) map, key, false, false); |
244 void *ptr = NULL; |
230 } |
245 int found = cx_hash_map_get_remove((CxMap *) map, key, &ptr, false); |
231 |
246 return found == 0 ? ptr : NULL; |
232 static void *cx_hash_map_remove( |
247 } |
|
248 |
|
249 static int cx_hash_map_remove( |
233 CxMap *map, |
250 CxMap *map, |
234 CxHashKey key, |
251 CxHashKey key, |
235 bool destroy |
252 void *targetbuf |
236 ) { |
253 ) { |
237 return cx_hash_map_get_remove(map, key, true, destroy); |
254 return cx_hash_map_get_remove(map, key, targetbuf, true); |
238 } |
255 } |
239 |
256 |
240 static void *cx_hash_map_iter_current_entry(const void *it) { |
257 static void *cx_hash_map_iter_current_entry(const void *it) { |
241 const struct cx_iterator_s *iter = it; |
258 const struct cx_iterator_s *iter = it; |
242 // struct has to have a compatible signature |
259 // struct has to have a compatible signature |