/work/workdir/UnpackedTarball/cairo/src/cairo-hash.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* cairo - a vector graphics library with display and print output |
2 | | * |
3 | | * Copyright © 2004 Red Hat, Inc. |
4 | | * Copyright © 2005 Red Hat, Inc. |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it either under the terms of the GNU Lesser General Public |
8 | | * License version 2.1 as published by the Free Software Foundation |
9 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
10 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
11 | | * notice, a recipient may use your version of this file under either |
12 | | * the MPL or the LGPL. |
13 | | * |
14 | | * You should have received a copy of the LGPL along with this library |
15 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
17 | | * You should have received a copy of the MPL along with this library |
18 | | * in the file COPYING-MPL-1.1 |
19 | | * |
20 | | * The contents of this file are subject to the Mozilla Public License |
21 | | * Version 1.1 (the "License"); you may not use this file except in |
22 | | * compliance with the License. You may obtain a copy of the License at |
23 | | * http://www.mozilla.org/MPL/ |
24 | | * |
25 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
26 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
27 | | * the specific language governing rights and limitations. |
28 | | * |
29 | | * The Original Code is the cairo graphics library. |
30 | | * |
31 | | * The Initial Developer of the Original Code is Red Hat, Inc. |
32 | | * |
33 | | * Contributor(s): |
34 | | * Keith Packard <keithp@keithp.com> |
35 | | * Graydon Hoare <graydon@redhat.com> |
36 | | * Carl Worth <cworth@cworth.org> |
37 | | */ |
38 | | |
39 | | #include "cairoint.h" |
40 | | #include "cairo-error-private.h" |
41 | | |
42 | | /* |
43 | | * An entry can be in one of three states: |
44 | | * |
45 | | * FREE: Entry has never been used, terminates all searches. |
46 | | * Appears in the table as a %NULL pointer. |
47 | | * |
48 | | * DEAD: Entry had been live in the past. A dead entry can be reused |
49 | | * but does not terminate a search for an exact entry. |
50 | | * Appears in the table as a pointer to DEAD_ENTRY. |
51 | | * |
52 | | * LIVE: Entry is currently being used. |
53 | | * Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer. |
54 | | */ |
55 | | |
56 | 755k | #define DEAD_ENTRY ((cairo_hash_entry_t *) 0x1) |
57 | | |
58 | 82.9k | #define ENTRY_IS_FREE(entry) ((entry) == NULL) |
59 | | #define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY) |
60 | 735k | #define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY) |
61 | | |
62 | | /* |
63 | | * This table is open-addressed with double hashing. Each table size |
64 | | * is a prime and it makes for the "first" hash modulus; a second |
65 | | * prime (2 less than the first prime) serves as the "second" hash |
66 | | * modulus, which is smaller and thus guarantees a complete |
67 | | * permutation of table indices. |
68 | | * |
69 | | * Hash tables are rehashed in order to keep between 12.5% and 50% |
70 | | * entries in the hash table alive and at least 25% free. When table |
71 | | * size is changed, the new table has about 25% live elements. |
72 | | * |
73 | | * The free entries guarantee an expected constant-time lookup. |
74 | | * Doubling/halving the table in the described fashion guarantees |
75 | | * amortized O(1) insertion/removal. |
76 | | * |
77 | | * This structure, and accompanying table, is borrowed/modified from the |
78 | | * file xserver/render/glyph.c in the freedesktop.org x server, with |
79 | | * permission (and suggested modification of doubling sizes) by Keith |
80 | | * Packard. |
81 | | */ |
82 | | |
83 | | static const unsigned long hash_table_sizes[] = { |
84 | | 43, |
85 | | 73, |
86 | | 151, |
87 | | 283, |
88 | | 571, |
89 | | 1153, |
90 | | 2269, |
91 | | 4519, |
92 | | 9013, |
93 | | 18043, |
94 | | 36109, |
95 | | 72091, |
96 | | 144409, |
97 | | 288361, |
98 | | 576883, |
99 | | 1153459, |
100 | | 2307163, |
101 | | 4613893, |
102 | | 9227641, |
103 | | 18455029, |
104 | | 36911011, |
105 | | 73819861, |
106 | | 147639589, |
107 | | 295279081, |
108 | | 590559793 |
109 | | }; |
110 | | |
111 | | struct _cairo_hash_table { |
112 | | cairo_hash_keys_equal_func_t keys_equal; |
113 | | |
114 | | cairo_hash_entry_t *cache[32]; |
115 | | |
116 | | const unsigned long *table_size; |
117 | | cairo_hash_entry_t **entries; |
118 | | |
119 | | unsigned long live_entries; |
120 | | unsigned long free_entries; |
121 | | unsigned long iterating; /* Iterating, no insert, no resize */ |
122 | | }; |
123 | | |
124 | | /** |
125 | | * _cairo_hash_table_uid_keys_equal: |
126 | | * @key_a: the first key to be compared |
127 | | * @key_b: the second key to be compared |
128 | | * |
129 | | * Provides a #cairo_hash_keys_equal_func_t which always returns |
130 | | * %TRUE. This is useful to create hash tables using keys whose hash |
131 | | * completely describes the key, because in this special case |
132 | | * comparing the hashes is sufficient to guarantee that the keys are |
133 | | * equal. |
134 | | * |
135 | | * Return value: %TRUE. |
136 | | **/ |
137 | | static cairo_bool_t |
138 | | _cairo_hash_table_uid_keys_equal (const void *key_a, const void *key_b) |
139 | 769k | { |
140 | 769k | return TRUE; |
141 | 769k | } |
142 | | |
143 | | /** |
144 | | * _cairo_hash_table_create: |
145 | | * @keys_equal: a function to return %TRUE if two keys are equal |
146 | | * |
147 | | * Creates a new hash table which will use the keys_equal() function |
148 | | * to compare hash keys. Data is provided to the hash table in the |
149 | | * form of user-derived versions of #cairo_hash_entry_t. A hash entry |
150 | | * must be able to hold both a key (including a hash code) and a |
151 | | * value. Sometimes only the key will be necessary, (as in |
152 | | * _cairo_hash_table_remove), and other times both a key and a value |
153 | | * will be necessary, (as in _cairo_hash_table_insert). |
154 | | * |
155 | | * If @keys_equal is %NULL, two keys will be considered equal if and |
156 | | * only if their hashes are equal. |
157 | | * |
158 | | * See #cairo_hash_entry_t for more details. |
159 | | * |
160 | | * Return value: the new hash table or %NULL if out of memory. |
161 | | **/ |
162 | | cairo_hash_table_t * |
163 | | _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal) |
164 | 208 | { |
165 | 208 | cairo_hash_table_t *hash_table; |
166 | | |
167 | 208 | hash_table = _cairo_malloc (sizeof (cairo_hash_table_t)); |
168 | 208 | if (unlikely (hash_table == NULL)) { |
169 | 0 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
170 | 0 | return NULL; |
171 | 0 | } |
172 | | |
173 | 208 | if (keys_equal == NULL) |
174 | 196 | hash_table->keys_equal = _cairo_hash_table_uid_keys_equal; |
175 | 12 | else |
176 | 12 | hash_table->keys_equal = keys_equal; |
177 | | |
178 | 208 | memset (&hash_table->cache, 0, sizeof (hash_table->cache)); |
179 | 208 | hash_table->table_size = &hash_table_sizes[0]; |
180 | | |
181 | 208 | hash_table->entries = calloc (*hash_table->table_size, |
182 | 208 | sizeof (cairo_hash_entry_t *)); |
183 | 208 | if (unlikely (hash_table->entries == NULL)) { |
184 | 0 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
185 | 0 | free (hash_table); |
186 | 0 | return NULL; |
187 | 0 | } |
188 | | |
189 | 208 | hash_table->live_entries = 0; |
190 | 208 | hash_table->free_entries = *hash_table->table_size; |
191 | 208 | hash_table->iterating = 0; |
192 | | |
193 | 208 | return hash_table; |
194 | 208 | } |
195 | | |
196 | | /** |
197 | | * _cairo_hash_table_destroy: |
198 | | * @hash_table: an empty hash table to destroy |
199 | | * |
200 | | * Immediately destroys the given hash table, freeing all resources |
201 | | * associated with it. |
202 | | * |
203 | | * WARNING: The hash_table must have no live entries in it before |
204 | | * _cairo_hash_table_destroy is called. It is a fatal error otherwise, |
205 | | * and this function will halt. The rationale for this behavior is to |
206 | | * avoid memory leaks and to avoid needless complication of the API |
207 | | * with destroy notify callbacks. |
208 | | * |
209 | | * WARNING: The hash_table must have no running iterators in it when |
210 | | * _cairo_hash_table_destroy is called. It is a fatal error otherwise, |
211 | | * and this function will halt. |
212 | | **/ |
213 | | void |
214 | | _cairo_hash_table_destroy (cairo_hash_table_t *hash_table) |
215 | 8 | { |
216 | | /* The hash table must be empty. Otherwise, halt. */ |
217 | 8 | assert (hash_table->live_entries == 0); |
218 | | /* No iterators can be running. Otherwise, halt. */ |
219 | 8 | assert (hash_table->iterating == 0); |
220 | | |
221 | 8 | free (hash_table->entries); |
222 | 8 | free (hash_table); |
223 | 8 | } |
224 | | |
225 | | static cairo_hash_entry_t ** |
226 | | _cairo_hash_table_lookup_unique_key (cairo_hash_table_t *hash_table, |
227 | | cairo_hash_entry_t *key) |
228 | 77.1k | { |
229 | 77.1k | unsigned long table_size, i, idx, step; |
230 | 77.1k | cairo_hash_entry_t **entry; |
231 | | |
232 | 77.1k | table_size = *hash_table->table_size; |
233 | 77.1k | idx = key->hash % table_size; |
234 | | |
235 | 77.1k | entry = &hash_table->entries[idx]; |
236 | 77.1k | if (! ENTRY_IS_LIVE (*entry)) |
237 | 63.1k | return entry; |
238 | | |
239 | 13.9k | i = 1; |
240 | 13.9k | step = 1 + key->hash % (table_size - 2); |
241 | 46.7k | do { |
242 | 46.7k | idx += step; |
243 | 46.7k | if (idx >= table_size) |
244 | 22.2k | idx -= table_size; |
245 | | |
246 | 46.7k | entry = &hash_table->entries[idx]; |
247 | 46.7k | if (! ENTRY_IS_LIVE (*entry)) |
248 | 13.9k | return entry; |
249 | 46.7k | } while (++i < table_size); |
250 | | |
251 | 0 | ASSERT_NOT_REACHED; |
252 | 0 | return NULL; |
253 | 0 | } |
254 | | |
255 | | /** |
256 | | * _cairo_hash_table_manage: |
257 | | * @hash_table: a hash table |
258 | | * |
259 | | * Resize the hash table if the number of entries has gotten much |
260 | | * bigger or smaller than the ideal number of entries for the current |
261 | | * size and guarantee some free entries to be used as lookup |
262 | | * termination points. |
263 | | * |
264 | | * Return value: %CAIRO_STATUS_SUCCESS if successful or |
265 | | * %CAIRO_STATUS_NO_MEMORY if out of memory. |
266 | | **/ |
267 | | static cairo_status_t |
268 | | _cairo_hash_table_manage (cairo_hash_table_t *hash_table) |
269 | 59.1k | { |
270 | 59.1k | cairo_hash_table_t tmp; |
271 | 59.1k | unsigned long new_size, i; |
272 | | |
273 | | /* Keep between 12.5% and 50% entries in the hash table alive and |
274 | | * at least 25% free. */ |
275 | 59.1k | unsigned long live_high = *hash_table->table_size >> 1; |
276 | 59.1k | unsigned long live_low = live_high >> 2; |
277 | 59.1k | unsigned long free_low = live_high >> 1; |
278 | | |
279 | 59.1k | tmp = *hash_table; |
280 | | |
281 | 59.1k | if (hash_table->live_entries > live_high) |
282 | 275 | { |
283 | 275 | tmp.table_size = hash_table->table_size + 1; |
284 | | /* This code is being abused if we can't make a table big enough. */ |
285 | 275 | assert (tmp.table_size - hash_table_sizes < |
286 | 275 | ARRAY_LENGTH (hash_table_sizes)); |
287 | 275 | } |
288 | 58.8k | else if (hash_table->live_entries < live_low) |
289 | 917 | { |
290 | | /* Can't shrink if we're at the smallest size */ |
291 | 917 | if (hash_table->table_size == &hash_table_sizes[0]) |
292 | 867 | tmp.table_size = hash_table->table_size; |
293 | 50 | else |
294 | 50 | tmp.table_size = hash_table->table_size - 1; |
295 | 917 | } |
296 | | |
297 | 59.1k | if (tmp.table_size == hash_table->table_size && |
298 | 59.1k | hash_table->free_entries > free_low) |
299 | 58.8k | { |
300 | | /* The number of live entries is within the desired bounds |
301 | | * (we're not going to resize the table) and we have enough |
302 | | * free entries. Do nothing. */ |
303 | 58.8k | return CAIRO_STATUS_SUCCESS; |
304 | 58.8k | } |
305 | | |
306 | 325 | new_size = *tmp.table_size; |
307 | 325 | tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*)); |
308 | 325 | if (unlikely (tmp.entries == NULL)) |
309 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
310 | | |
311 | 97.7k | for (i = 0; i < *hash_table->table_size; ++i) { |
312 | 97.3k | if (ENTRY_IS_LIVE (hash_table->entries[i])) { |
313 | 39.6k | *_cairo_hash_table_lookup_unique_key (&tmp, hash_table->entries[i]) |
314 | 39.6k | = hash_table->entries[i]; |
315 | 39.6k | } |
316 | 97.3k | } |
317 | | |
318 | 325 | free (hash_table->entries); |
319 | 325 | hash_table->entries = tmp.entries; |
320 | 325 | hash_table->table_size = tmp.table_size; |
321 | 325 | hash_table->free_entries = new_size - hash_table->live_entries; |
322 | | |
323 | 325 | return CAIRO_STATUS_SUCCESS; |
324 | 325 | } |
325 | | |
326 | | /** |
327 | | * _cairo_hash_table_lookup: |
328 | | * @hash_table: a hash table |
329 | | * @key: the key of interest |
330 | | * |
331 | | * Performs a lookup in @hash_table looking for an entry which has a |
332 | | * key that matches @key, (as determined by the keys_equal() function |
333 | | * passed to _cairo_hash_table_create). |
334 | | * |
335 | | * Return value: the matching entry, of %NULL if no match was found. |
336 | | **/ |
337 | | void * |
338 | | _cairo_hash_table_lookup (cairo_hash_table_t *hash_table, |
339 | | cairo_hash_entry_t *key) |
340 | 1.99M | { |
341 | 1.99M | cairo_hash_entry_t *entry; |
342 | 1.99M | unsigned long table_size, i, idx, step; |
343 | 1.99M | uintptr_t hash = key->hash; |
344 | | |
345 | 1.99M | entry = hash_table->cache[hash & 31]; |
346 | 1.99M | if (entry && entry->hash == hash && hash_table->keys_equal (key, entry)) |
347 | 1.57M | return entry; |
348 | | |
349 | 424k | table_size = *hash_table->table_size; |
350 | 424k | idx = hash % table_size; |
351 | | |
352 | 424k | entry = hash_table->entries[idx]; |
353 | 424k | if (ENTRY_IS_LIVE (entry)) { |
354 | 396k | if (entry->hash == hash && hash_table->keys_equal (key, entry)) |
355 | 348k | goto insert_cache; |
356 | 396k | } else if (ENTRY_IS_FREE (entry)) |
357 | 21.7k | return NULL; |
358 | | |
359 | 54.9k | i = 1; |
360 | 54.9k | step = 1 + hash % (table_size - 2); |
361 | 85.5k | do { |
362 | 85.5k | idx += step; |
363 | 85.5k | if (idx >= table_size) |
364 | 30.3k | idx -= table_size; |
365 | | |
366 | 85.5k | entry = hash_table->entries[idx]; |
367 | 85.5k | if (ENTRY_IS_LIVE (entry)) { |
368 | 67.9k | if (entry->hash == hash && hash_table->keys_equal (key, entry)) |
369 | 40.4k | goto insert_cache; |
370 | 67.9k | } else if (ENTRY_IS_FREE (entry)) |
371 | 14.4k | return NULL; |
372 | 85.5k | } while (++i < table_size); |
373 | | |
374 | 0 | ASSERT_NOT_REACHED; |
375 | 0 | return NULL; |
376 | | |
377 | 388k | insert_cache: |
378 | 388k | hash_table->cache[hash & 31] = entry; |
379 | 388k | return entry; |
380 | 0 | } |
381 | | |
382 | | /** |
383 | | * _cairo_hash_table_random_entry: |
384 | | * @hash_table: a hash table |
385 | | * @predicate: a predicate function. |
386 | | * |
387 | | * Find a random entry in the hash table satisfying the given |
388 | | * @predicate. |
389 | | * |
390 | | * We use the same algorithm as the lookup algorithm to walk over the |
391 | | * entries in the hash table in a pseudo-random order. Walking |
392 | | * linearly would favor entries following gaps in the hash table. We |
393 | | * could also call rand() repeatedly, which works well for almost-full |
394 | | * tables, but degrades when the table is almost empty, or predicate |
395 | | * returns %TRUE for most entries. |
396 | | * |
397 | | * Return value: a random live entry or %NULL if there are no entries |
398 | | * that match the given predicate. In particular, if predicate is |
399 | | * %NULL, a %NULL return value indicates that the table is empty. |
400 | | **/ |
401 | | void * |
402 | | _cairo_hash_table_random_entry (cairo_hash_table_t *hash_table, |
403 | | cairo_hash_predicate_func_t predicate) |
404 | 710 | { |
405 | 710 | cairo_hash_entry_t *entry; |
406 | 710 | unsigned long hash; |
407 | 710 | unsigned long table_size, i, idx, step; |
408 | | |
409 | 710 | assert (predicate != NULL); |
410 | | |
411 | 710 | table_size = *hash_table->table_size; |
412 | 710 | hash = rand (); |
413 | 710 | idx = hash % table_size; |
414 | | |
415 | 710 | entry = hash_table->entries[idx]; |
416 | 710 | if (ENTRY_IS_LIVE (entry) && predicate (entry)) |
417 | 329 | return entry; |
418 | | |
419 | 381 | i = 1; |
420 | 381 | step = 1 + hash % (table_size - 2); |
421 | 895 | do { |
422 | 895 | idx += step; |
423 | 895 | if (idx >= table_size) |
424 | 426 | idx -= table_size; |
425 | | |
426 | 895 | entry = hash_table->entries[idx]; |
427 | 895 | if (ENTRY_IS_LIVE (entry) && predicate (entry)) |
428 | 381 | return entry; |
429 | 895 | } while (++i < table_size); |
430 | | |
431 | 0 | return NULL; |
432 | 381 | } |
433 | | |
434 | | /** |
435 | | * _cairo_hash_table_insert: |
436 | | * @hash_table: a hash table |
437 | | * @key_and_value: an entry to be inserted |
438 | | * |
439 | | * Insert the entry #key_and_value into the hash table. |
440 | | * |
441 | | * WARNING: There must not be an existing entry in the hash table |
442 | | * with a matching key. |
443 | | * |
444 | | * WARNING: It is a fatal error to insert an element while |
445 | | * an iterator is running |
446 | | * |
447 | | * Instead of using insert to replace an entry, consider just editing |
448 | | * the entry obtained with _cairo_hash_table_lookup. Or if absolutely |
449 | | * necessary, use _cairo_hash_table_remove first. |
450 | | * |
451 | | * Return value: %CAIRO_STATUS_SUCCESS if successful or |
452 | | * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available. |
453 | | **/ |
454 | | cairo_status_t |
455 | | _cairo_hash_table_insert (cairo_hash_table_t *hash_table, |
456 | | cairo_hash_entry_t *key_and_value) |
457 | 37.4k | { |
458 | 37.4k | cairo_hash_entry_t **entry; |
459 | 37.4k | cairo_status_t status; |
460 | | |
461 | | /* Insert is illegal while an iterator is running. */ |
462 | 37.4k | assert (hash_table->iterating == 0); |
463 | | |
464 | 37.4k | status = _cairo_hash_table_manage (hash_table); |
465 | 37.4k | if (unlikely (status)) |
466 | 0 | return status; |
467 | | |
468 | 37.4k | entry = _cairo_hash_table_lookup_unique_key (hash_table, key_and_value); |
469 | | |
470 | 37.4k | if (ENTRY_IS_FREE (*entry)) |
471 | 31.0k | hash_table->free_entries--; |
472 | | |
473 | 37.4k | *entry = key_and_value; |
474 | 37.4k | hash_table->cache[key_and_value->hash & 31] = key_and_value; |
475 | 37.4k | hash_table->live_entries++; |
476 | | |
477 | 37.4k | return CAIRO_STATUS_SUCCESS; |
478 | 37.4k | } |
479 | | |
480 | | static cairo_hash_entry_t ** |
481 | | _cairo_hash_table_lookup_exact_key (cairo_hash_table_t *hash_table, |
482 | | cairo_hash_entry_t *key) |
483 | 21.6k | { |
484 | 21.6k | unsigned long table_size, i, idx, step; |
485 | 21.6k | cairo_hash_entry_t **entry; |
486 | | |
487 | 21.6k | table_size = *hash_table->table_size; |
488 | 21.6k | idx = key->hash % table_size; |
489 | | |
490 | 21.6k | entry = &hash_table->entries[idx]; |
491 | 21.6k | if (*entry == key) |
492 | 18.1k | return entry; |
493 | | |
494 | 3.52k | i = 1; |
495 | 3.52k | step = 1 + key->hash % (table_size - 2); |
496 | 16.7k | do { |
497 | 16.7k | idx += step; |
498 | 16.7k | if (idx >= table_size) |
499 | 8.91k | idx -= table_size; |
500 | | |
501 | 16.7k | entry = &hash_table->entries[idx]; |
502 | 16.7k | if (*entry == key) |
503 | 3.52k | return entry; |
504 | 16.7k | } while (++i < table_size); |
505 | | |
506 | 0 | ASSERT_NOT_REACHED; |
507 | 0 | return NULL; |
508 | 0 | } |
509 | | /** |
510 | | * _cairo_hash_table_remove: |
511 | | * @hash_table: a hash table |
512 | | * @key: key of entry to be removed |
513 | | * |
514 | | * Remove an entry from the hash table which points to @key. |
515 | | * |
516 | | * Return value: %CAIRO_STATUS_SUCCESS if successful or |
517 | | * %CAIRO_STATUS_NO_MEMORY if out of memory. |
518 | | **/ |
519 | | void |
520 | | _cairo_hash_table_remove (cairo_hash_table_t *hash_table, |
521 | | cairo_hash_entry_t *key) |
522 | 21.6k | { |
523 | 21.6k | *_cairo_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY; |
524 | 21.6k | hash_table->live_entries--; |
525 | 21.6k | hash_table->cache[key->hash & 31] = NULL; |
526 | | |
527 | | /* Check for table resize. Don't do this when iterating as this will |
528 | | * reorder elements of the table and cause the iteration to potentially |
529 | | * skip some elements. */ |
530 | 21.6k | if (hash_table->iterating == 0) { |
531 | | /* This call _can_ fail, but only in failing to allocate new |
532 | | * memory to shrink the hash table. It does leave the table in a |
533 | | * consistent state, and we've already succeeded in removing the |
534 | | * entry, so we don't examine the failure status of this call. */ |
535 | 21.6k | _cairo_hash_table_manage (hash_table); |
536 | 21.6k | } |
537 | 21.6k | } |
538 | | |
539 | | /** |
540 | | * _cairo_hash_table_foreach: |
541 | | * @hash_table: a hash table |
542 | | * @hash_callback: function to be called for each live entry |
543 | | * @closure: additional argument to be passed to @hash_callback |
544 | | * |
545 | | * Call @hash_callback for each live entry in the hash table, in a |
546 | | * non-specified order. |
547 | | * |
548 | | * Entries in @hash_table may be removed by code executed from @hash_callback. |
549 | | * |
550 | | * Entries may not be inserted to @hash_table, nor may @hash_table |
551 | | * be destroyed by code executed from @hash_callback. The relevant |
552 | | * functions will halt in these cases. |
553 | | **/ |
554 | | void |
555 | | _cairo_hash_table_foreach (cairo_hash_table_t *hash_table, |
556 | | cairo_hash_callback_func_t hash_callback, |
557 | | void *closure) |
558 | 8 | { |
559 | 8 | unsigned long i; |
560 | 8 | cairo_hash_entry_t *entry; |
561 | | |
562 | | /* Mark the table for iteration */ |
563 | 8 | ++hash_table->iterating; |
564 | 352 | for (i = 0; i < *hash_table->table_size; i++) { |
565 | 344 | entry = hash_table->entries[i]; |
566 | 344 | if (ENTRY_IS_LIVE(entry)) |
567 | 0 | hash_callback (entry, closure); |
568 | 344 | } |
569 | | /* If some elements were deleted during the iteration, |
570 | | * the table may need resizing. Just do this every time |
571 | | * as the check is inexpensive. |
572 | | */ |
573 | 8 | if (--hash_table->iterating == 0) { |
574 | | /* Should we fail to shrink the hash table, it is left unaltered, |
575 | | * and we don't need to propagate the error status. */ |
576 | 8 | _cairo_hash_table_manage (hash_table); |
577 | 8 | } |
578 | 8 | } |