| 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 |