Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1892 | Rev 3959 | ||
---|---|---|---|
Line 57... | Line 57... | ||
57 | 57 | ||
58 | #define ENTRY_IS_FREE(entry) ((entry) == NULL) |
58 | #define ENTRY_IS_FREE(entry) ((entry) == NULL) |
59 | #define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY) |
59 | #define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY) |
Line -... | Line 60... | ||
- | 60 | #define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY) |
|
60 | #define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY) |
61 | |
61 | 62 | /* |
|
62 | /* We expect keys will not be destroyed frequently, so our table does not |
63 | * This table is open-addressed with double hashing. Each table size |
63 | * contain any explicit shrinking code nor any chain-coalescing code for |
64 | * is a prime and it makes for the "first" hash modulus; a second |
64 | * entries randomly deleted by memory pressure (except during rehashing, of |
65 | * prime (2 less than the first prime) serves as the "second" hash |
65 | * course). These assumptions are potentially bad, but they make the |
66 | * modulus, which is smaller and thus guarantees a complete |
- | 67 | * permutation of table indices. |
|
66 | * implementation straightforward. |
68 | * |
67 | * |
69 | * Hash tables are rehashed in order to keep between 12.5% and 50% |
68 | * Revisit later if evidence appears that we're using excessive memory from |
70 | * entries in the hash table alive and at least 25% free. When table |
69 | * a mostly-dead table. |
- | |
70 | * |
71 | * size is changed, the new table has about 25% live elements. |
71 | * This table is open-addressed with double hashing. Each table size is a |
72 | * |
72 | * prime chosen to be a little more than double the high water mark for a |
- | |
73 | * given arrangement, so the tables should remain < 50% full. The table |
- | |
74 | * size makes for the "first" hash modulus; a second prime (2 less than the |
73 | * The free entries guarantee an expected constant-time lookup. |
75 | * first prime) serves as the "second" hash modulus, which is co-prime and |
74 | * Doubling/halving the table in the described fashion guarantees |
76 | * thus guarantees a complete permutation of table indices. |
75 | * amortized O(1) insertion/removal. |
77 | * |
76 | * |
78 | * This structure, and accompanying table, is borrowed/modified from the |
77 | * This structure, and accompanying table, is borrowed/modified from the |
79 | * file xserver/render/glyph.c in the freedesktop.org x server, with |
78 | * file xserver/render/glyph.c in the freedesktop.org x server, with |
80 | * permission (and suggested modification of doubling sizes) by Keith |
79 | * permission (and suggested modification of doubling sizes) by Keith |
Line 81... | Line -... | ||
81 | * Packard. |
- | |
82 | */ |
- | |
83 | - | ||
84 | typedef struct _cairo_hash_table_arrangement { |
- | |
85 | unsigned long high_water_mark; |
- | |
86 | unsigned long size; |
- | |
87 | unsigned long rehash; |
80 | * Packard. |
88 | } cairo_hash_table_arrangement_t; |
81 | */ |
89 | 82 | ||
90 | static const cairo_hash_table_arrangement_t hash_table_arrangements [] = { |
83 | static const unsigned long hash_table_sizes[] = { |
91 | { 16, 43, 41 }, |
84 | 43, |
92 | { 32, 73, 71 }, |
85 | 73, |
93 | { 64, 151, 149 }, |
86 | 151, |
94 | { 128, 283, 281 }, |
87 | 283, |
95 | { 256, 571, 569 }, |
88 | 571, |
96 | { 512, 1153, 1151 }, |
89 | 1153, |
97 | { 1024, 2269, 2267 }, |
90 | 2269, |
98 | { 2048, 4519, 4517 }, |
91 | 4519, |
99 | { 4096, 9013, 9011 }, |
92 | 9013, |
100 | { 8192, 18043, 18041 }, |
93 | 18043, |
101 | { 16384, 36109, 36107 }, |
94 | 36109, |
102 | { 32768, 72091, 72089 }, |
95 | 72091, |
103 | { 65536, 144409, 144407 }, |
96 | 144409, |
104 | { 131072, 288361, 288359 }, |
97 | 288361, |
105 | { 262144, 576883, 576881 }, |
98 | 576883, |
106 | { 524288, 1153459, 1153457 }, |
99 | 1153459, |
107 | { 1048576, 2307163, 2307161 }, |
100 | 2307163, |
108 | { 2097152, 4613893, 4613891 }, |
101 | 4613893, |
109 | { 4194304, 9227641, 9227639 }, |
102 | 9227641, |
110 | { 8388608, 18455029, 18455027 }, |
103 | 18455029, |
111 | { 16777216, 36911011, 36911009 }, |
104 | 36911011, |
112 | { 33554432, 73819861, 73819859 }, |
105 | 73819861, |
113 | { 67108864, 147639589, 147639587 }, |
106 | 147639589, |
Line 114... | Line -... | ||
114 | { 134217728, 295279081, 295279079 }, |
- | |
115 | { 268435456, 590559793, 590559791 } |
- | |
116 | }; |
107 | 295279081, |
117 | 108 | 590559793 |
|
Line 118... | Line 109... | ||
118 | #define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements) |
109 | }; |
- | 110 | ||
- | 111 | struct _cairo_hash_table { |
|
119 | 112 | cairo_hash_keys_equal_func_t keys_equal; |
|
Line 120... | Line 113... | ||
120 | struct _cairo_hash_table { |
113 | |
- | 114 | cairo_hash_entry_t *cache[32]; |
|
121 | cairo_hash_keys_equal_func_t keys_equal; |
115 | |
122 | 116 | const unsigned long *table_size; |
|
Line 123... | Line 117... | ||
123 | const cairo_hash_table_arrangement_t *arrangement; |
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 | **/ |
|
124 | cairo_hash_entry_t **entries; |
137 | static cairo_bool_t |
125 | 138 | _cairo_hash_table_uid_keys_equal (const void *key_a, const void *key_b) |
|
126 | unsigned long live_entries; |
139 | { |
127 | unsigned long iterating; /* Iterating, no insert, no resize */ |
140 | return TRUE; |
128 | }; |
141 | } |
Line 137... | Line 150... | ||
137 | * must be able to hold both a key (including a hash code) and a |
150 | * must be able to hold both a key (including a hash code) and a |
138 | * value. Sometimes only the key will be necessary, (as in |
151 | * value. Sometimes only the key will be necessary, (as in |
139 | * _cairo_hash_table_remove), and other times both a key and a value |
152 | * _cairo_hash_table_remove), and other times both a key and a value |
140 | * will be necessary, (as in _cairo_hash_table_insert). |
153 | * will be necessary, (as in _cairo_hash_table_insert). |
141 | * |
154 | * |
- | 155 | * If @keys_equal is %NULL, two keys will be considered equal if and |
|
- | 156 | * only if their hashes are equal. |
|
- | 157 | * |
|
142 | * See #cairo_hash_entry_t for more details. |
158 | * See #cairo_hash_entry_t for more details. |
143 | * |
159 | * |
144 | * Return value: the new hash table or %NULL if out of memory. |
160 | * Return value: the new hash table or %NULL if out of memory. |
145 | **/ |
161 | **/ |
146 | cairo_hash_table_t * |
162 | cairo_hash_table_t * |
Line 152... | Line 168... | ||
152 | if (unlikely (hash_table == NULL)) { |
168 | if (unlikely (hash_table == NULL)) { |
153 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
169 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
154 | return NULL; |
170 | return NULL; |
155 | } |
171 | } |
Line -... | Line 172... | ||
- | 172 | ||
- | 173 | if (keys_equal == NULL) |
|
- | 174 | hash_table->keys_equal = _cairo_hash_table_uid_keys_equal; |
|
156 | 175 | else |
|
Line -... | Line 176... | ||
- | 176 | hash_table->keys_equal = keys_equal; |
|
157 | hash_table->keys_equal = keys_equal; |
177 | |
Line 158... | Line 178... | ||
158 | 178 | memset (&hash_table->cache, 0, sizeof (hash_table->cache)); |
|
159 | hash_table->arrangement = &hash_table_arrangements[0]; |
179 | hash_table->table_size = &hash_table_sizes[0]; |
160 | 180 | ||
161 | hash_table->entries = calloc (hash_table->arrangement->size, |
181 | hash_table->entries = calloc (*hash_table->table_size, |
162 | sizeof(cairo_hash_entry_t *)); |
182 | sizeof (cairo_hash_entry_t *)); |
163 | if (unlikely (hash_table->entries == NULL)) { |
183 | if (unlikely (hash_table->entries == NULL)) { |
164 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
184 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
Line 165... | Line 185... | ||
165 | free (hash_table); |
185 | free (hash_table); |
- | 186 | return NULL; |
|
166 | return NULL; |
187 | } |
Line 167... | Line 188... | ||
167 | } |
188 | |
168 | 189 | hash_table->live_entries = 0; |
|
Line 196... | Line 217... | ||
196 | assert (hash_table->live_entries == 0); |
217 | assert (hash_table->live_entries == 0); |
197 | /* No iterators can be running. Otherwise, halt. */ |
218 | /* No iterators can be running. Otherwise, halt. */ |
198 | assert (hash_table->iterating == 0); |
219 | assert (hash_table->iterating == 0); |
Line 199... | Line 220... | ||
199 | 220 | ||
200 | free (hash_table->entries); |
- | |
201 | hash_table->entries = NULL; |
- | |
202 | 221 | free (hash_table->entries); |
|
203 | free (hash_table); |
222 | free (hash_table); |
Line 204... | Line 223... | ||
204 | } |
223 | } |
205 | 224 | ||
206 | static cairo_hash_entry_t ** |
225 | static cairo_hash_entry_t ** |
207 | _cairo_hash_table_lookup_unique_key (cairo_hash_table_t *hash_table, |
226 | _cairo_hash_table_lookup_unique_key (cairo_hash_table_t *hash_table, |
208 | cairo_hash_entry_t *key) |
227 | cairo_hash_entry_t *key) |
209 | { |
228 | { |
Line 210... | Line 229... | ||
210 | unsigned long table_size, i, idx, step; |
229 | unsigned long table_size, i, idx, step; |
211 | cairo_hash_entry_t **entry; |
230 | cairo_hash_entry_t **entry; |
Line 212... | Line 231... | ||
212 | 231 | ||
213 | table_size = hash_table->arrangement->size; |
232 | table_size = *hash_table->table_size; |
214 | idx = key->hash % table_size; |
233 | idx = key->hash % table_size; |
Line 215... | Line 234... | ||
215 | 234 | ||
216 | entry = &hash_table->entries[idx]; |
235 | entry = &hash_table->entries[idx]; |
217 | if (! ENTRY_IS_LIVE (*entry)) |
- | |
218 | return entry; |
- | |
219 | 236 | if (! ENTRY_IS_LIVE (*entry)) |
|
220 | i = 1; |
237 | return entry; |
221 | step = key->hash % hash_table->arrangement->rehash; |
238 | |
222 | if (step == 0) |
239 | i = 1; |
Line 234... | Line 251... | ||
234 | ASSERT_NOT_REACHED; |
251 | ASSERT_NOT_REACHED; |
235 | return NULL; |
252 | return NULL; |
236 | } |
253 | } |
Line 237... | Line 254... | ||
237 | 254 | ||
238 | /** |
255 | /** |
239 | * _cairo_hash_table_resize: |
256 | * _cairo_hash_table_manage: |
240 | * @hash_table: a hash table |
257 | * @hash_table: a hash table |
241 | * |
258 | * |
242 | * Resize the hash table if the number of entries has gotten much |
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 |
|
243 | * bigger or smaller than the ideal number of entries for the current |
261 | * size and guarantee some free entries to be used as lookup |
244 | * size. |
262 | * termination points. |
245 | * |
263 | * |
246 | * Return value: %CAIRO_STATUS_SUCCESS if successful or |
264 | * Return value: %CAIRO_STATUS_SUCCESS if successful or |
247 | * %CAIRO_STATUS_NO_MEMORY if out of memory. |
265 | * %CAIRO_STATUS_NO_MEMORY if out of memory. |
248 | **/ |
266 | **/ |
249 | static cairo_status_t |
267 | static cairo_status_t |
250 | _cairo_hash_table_resize (cairo_hash_table_t *hash_table) |
268 | _cairo_hash_table_manage (cairo_hash_table_t *hash_table) |
251 | { |
269 | { |
252 | cairo_hash_table_t tmp; |
270 | cairo_hash_table_t tmp; |
Line 253... | Line 271... | ||
253 | unsigned long new_size, i; |
271 | unsigned long new_size, i; |
- | 272 | ||
254 | 273 | /* Keep between 12.5% and 50% entries in the hash table alive and |
|
255 | /* This keeps the hash table between 25% and 50% full. */ |
274 | * at least 25% free. */ |
256 | unsigned long high = hash_table->arrangement->high_water_mark; |
- | |
257 | unsigned long low = high >> 2; |
275 | unsigned long live_high = *hash_table->table_size >> 1; |
258 | - | ||
Line 259... | Line 276... | ||
259 | if (hash_table->live_entries >= low && hash_table->live_entries <= high) |
276 | unsigned long live_low = live_high >> 2; |
Line 260... | Line 277... | ||
260 | return CAIRO_STATUS_SUCCESS; |
277 | unsigned long free_low = live_high >> 1; |
261 | 278 | ||
262 | tmp = *hash_table; |
279 | tmp = *hash_table; |
263 | 280 | ||
264 | if (hash_table->live_entries > high) |
281 | if (hash_table->live_entries > live_high) |
265 | { |
282 | { |
266 | tmp.arrangement = hash_table->arrangement + 1; |
283 | tmp.table_size = hash_table->table_size + 1; |
267 | /* This code is being abused if we can't make a table big enough. */ |
284 | /* This code is being abused if we can't make a table big enough. */ |
268 | assert (tmp.arrangement - hash_table_arrangements < |
285 | assert (tmp.table_size - hash_table_sizes < |
269 | NUM_HASH_TABLE_ARRANGEMENTS); |
286 | ARRAY_LENGTH (hash_table_sizes)); |
270 | } |
287 | } |
- | 288 | else if (hash_table->live_entries < live_low) |
|
- | 289 | { |
|
- | 290 | /* Can't shrink if we're at the smallest size */ |
|
- | 291 | if (hash_table->table_size == &hash_table_sizes[0]) |
|
- | 292 | tmp.table_size = hash_table->table_size; |
|
- | 293 | else |
|
- | 294 | tmp.table_size = hash_table->table_size - 1; |
|
- | 295 | } |
|
- | 296 | ||
- | 297 | if (tmp.table_size == hash_table->table_size && |
|
- | 298 | hash_table->free_entries > free_low) |
|
271 | else /* hash_table->live_entries < low */ |
299 | { |
272 | { |
- | |
273 | /* Can't shrink if we're at the smallest size */ |
300 | /* The number of live entries is within the desired bounds |
Line 274... | Line 301... | ||
274 | if (hash_table->arrangement == &hash_table_arrangements[0]) |
301 | * (we're not going to resize the table) and we have enough |
275 | return CAIRO_STATUS_SUCCESS; |
302 | * free entries. Do nothing. */ |
276 | tmp.arrangement = hash_table->arrangement - 1; |
303 | return CAIRO_STATUS_SUCCESS; |
277 | } |
304 | } |
Line 278... | Line 305... | ||
278 | 305 | ||
279 | new_size = tmp.arrangement->size; |
306 | new_size = *tmp.table_size; |
280 | tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*)); |
307 | tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*)); |
281 | if (unlikely (tmp.entries == NULL)) |
308 | if (unlikely (tmp.entries == NULL)) |
282 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
309 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
283 | 310 | ||
Line 284... | Line 311... | ||
284 | for (i = 0; i < hash_table->arrangement->size; ++i) { |
311 | for (i = 0; i < *hash_table->table_size; ++i) { |
285 | if (ENTRY_IS_LIVE (hash_table->entries[i])) { |
312 | if (ENTRY_IS_LIVE (hash_table->entries[i])) { |
286 | *_cairo_hash_table_lookup_unique_key (&tmp, hash_table->entries[i]) |
313 | *_cairo_hash_table_lookup_unique_key (&tmp, hash_table->entries[i]) |
- | 314 | = hash_table->entries[i]; |
|
Line 287... | Line 315... | ||
287 | = hash_table->entries[i]; |
315 | } |
288 | } |
316 | } |
Line 289... | Line 317... | ||
289 | } |
317 | |
Line 310... | Line 338... | ||
310 | _cairo_hash_table_lookup (cairo_hash_table_t *hash_table, |
338 | _cairo_hash_table_lookup (cairo_hash_table_t *hash_table, |
311 | cairo_hash_entry_t *key) |
339 | cairo_hash_entry_t *key) |
312 | { |
340 | { |
313 | cairo_hash_entry_t *entry; |
341 | cairo_hash_entry_t *entry; |
314 | unsigned long table_size, i, idx, step; |
342 | unsigned long table_size, i, idx, step; |
- | 343 | unsigned long hash = key->hash; |
|
Line -... | Line 344... | ||
- | 344 | ||
- | 345 | entry = hash_table->cache[hash & 31]; |
|
- | 346 | if (entry && entry->hash == hash && hash_table->keys_equal (key, entry)) |
|
- | 347 | return entry; |
|
315 | 348 | ||
316 | table_size = hash_table->arrangement->size; |
349 | table_size = *hash_table->table_size; |
Line 317... | Line 350... | ||
317 | idx = key->hash % table_size; |
350 | idx = hash % table_size; |
318 | 351 | ||
319 | entry = hash_table->entries[idx]; |
352 | entry = hash_table->entries[idx]; |
320 | if (ENTRY_IS_LIVE (entry)) { |
353 | if (ENTRY_IS_LIVE (entry)) { |
321 | if (hash_table->keys_equal (key, entry)) |
354 | if (entry->hash == hash && hash_table->keys_equal (key, entry)) |
322 | return entry; |
355 | goto insert_cache; |
Line 323... | Line 356... | ||
323 | } else if (ENTRY_IS_FREE (entry)) |
356 | } else if (ENTRY_IS_FREE (entry)) |
324 | return NULL; |
357 | return NULL; |
325 | - | ||
326 | i = 1; |
- | |
327 | step = key->hash % hash_table->arrangement->rehash; |
358 | |
328 | if (step == 0) |
359 | i = 1; |
329 | step = 1; |
360 | step = 1 + hash % (table_size - 2); |
330 | do { |
361 | do { |
Line 331... | Line 362... | ||
331 | idx += step; |
362 | idx += step; |
332 | if (idx >= table_size) |
363 | if (idx >= table_size) |
333 | idx -= table_size; |
364 | idx -= table_size; |
334 | 365 | ||
335 | entry = hash_table->entries[idx]; |
366 | entry = hash_table->entries[idx]; |
336 | if (ENTRY_IS_LIVE (entry)) { |
367 | if (ENTRY_IS_LIVE (entry)) { |
337 | if (hash_table->keys_equal (key, entry)) |
368 | if (entry->hash == hash && hash_table->keys_equal (key, entry)) |
Line -... | Line 369... | ||
- | 369 | goto insert_cache; |
|
338 | return entry; |
370 | } else if (ENTRY_IS_FREE (entry)) |
- | 371 | return NULL; |
|
- | 372 | } while (++i < table_size); |
|
- | 373 | ||
- | 374 | ASSERT_NOT_REACHED; |
|
339 | } else if (ENTRY_IS_FREE (entry)) |
375 | return NULL; |
Line 340... | Line 376... | ||
340 | return NULL; |
376 | |
341 | } while (++i < table_size); |
377 | insert_cache: |
342 | 378 | hash_table->cache[hash & 31] = entry; |
|
Line 370... | Line 406... | ||
370 | unsigned long hash; |
406 | unsigned long hash; |
371 | unsigned long table_size, i, idx, step; |
407 | unsigned long table_size, i, idx, step; |
Line 372... | Line 408... | ||
372 | 408 | ||
Line 373... | Line 409... | ||
373 | assert (predicate != NULL); |
409 | assert (predicate != NULL); |
374 | 410 | ||
375 | table_size = hash_table->arrangement->size; |
411 | table_size = *hash_table->table_size; |
Line 376... | Line 412... | ||
376 | hash = rand (); |
412 | hash = rand (); |
377 | idx = hash % table_size; |
413 | idx = hash % table_size; |
378 | 414 | ||
Line 379... | Line 415... | ||
379 | entry = hash_table->entries[idx]; |
415 | entry = hash_table->entries[idx]; |
380 | if (ENTRY_IS_LIVE (entry) && predicate (entry)) |
416 | if (ENTRY_IS_LIVE (entry) && predicate (entry)) |
381 | return entry; |
- | |
382 | - | ||
383 | i = 1; |
417 | return entry; |
384 | step = hash % hash_table->arrangement->rehash; |
418 | |
385 | if (step == 0) |
419 | i = 1; |
386 | step = 1; |
420 | step = 1 + hash % (table_size - 2); |
Line 419... | Line 453... | ||
419 | **/ |
453 | **/ |
420 | cairo_status_t |
454 | cairo_status_t |
421 | _cairo_hash_table_insert (cairo_hash_table_t *hash_table, |
455 | _cairo_hash_table_insert (cairo_hash_table_t *hash_table, |
422 | cairo_hash_entry_t *key_and_value) |
456 | cairo_hash_entry_t *key_and_value) |
423 | { |
457 | { |
- | 458 | cairo_hash_entry_t **entry; |
|
424 | cairo_status_t status; |
459 | cairo_status_t status; |
Line 425... | Line 460... | ||
425 | 460 | ||
426 | /* Insert is illegal while an iterator is running. */ |
461 | /* Insert is illegal while an iterator is running. */ |
Line 427... | Line -... | ||
427 | assert (hash_table->iterating == 0); |
- | |
428 | 462 | assert (hash_table->iterating == 0); |
|
429 | hash_table->live_entries++; |
463 | |
430 | status = _cairo_hash_table_resize (hash_table); |
- | |
431 | if (unlikely (status)) { |
- | |
432 | /* abort the insert... */ |
464 | status = _cairo_hash_table_manage (hash_table); |
433 | hash_table->live_entries--; |
- | |
Line 434... | Line 465... | ||
434 | return status; |
465 | if (unlikely (status)) |
- | 466 | return status; |
|
- | 467 | ||
- | 468 | entry = _cairo_hash_table_lookup_unique_key (hash_table, key_and_value); |
|
- | 469 | ||
435 | } |
470 | if (ENTRY_IS_FREE (*entry)) |
- | 471 | hash_table->free_entries--; |
|
- | 472 | ||
Line 436... | Line 473... | ||
436 | 473 | *entry = key_and_value; |
|
437 | *_cairo_hash_table_lookup_unique_key (hash_table, |
474 | hash_table->cache[key_and_value->hash & 31] = key_and_value; |
Line 438... | Line 475... | ||
438 | key_and_value) = key_and_value; |
475 | hash_table->live_entries++; |
Line 445... | Line 482... | ||
445 | cairo_hash_entry_t *key) |
482 | cairo_hash_entry_t *key) |
446 | { |
483 | { |
447 | unsigned long table_size, i, idx, step; |
484 | unsigned long table_size, i, idx, step; |
448 | cairo_hash_entry_t **entry; |
485 | cairo_hash_entry_t **entry; |
Line 449... | Line 486... | ||
449 | 486 | ||
450 | table_size = hash_table->arrangement->size; |
487 | table_size = *hash_table->table_size; |
Line 451... | Line 488... | ||
451 | idx = key->hash % table_size; |
488 | idx = key->hash % table_size; |
452 | 489 | ||
453 | entry = &hash_table->entries[idx]; |
490 | entry = &hash_table->entries[idx]; |
Line 454... | Line 491... | ||
454 | if (*entry == key) |
491 | if (*entry == key) |
455 | return entry; |
492 | return entry; |
456 | - | ||
457 | i = 1; |
- | |
458 | step = key->hash % hash_table->arrangement->rehash; |
493 | |
459 | if (step == 0) |
494 | i = 1; |
460 | step = 1; |
495 | step = 1 + key->hash % (table_size - 2); |
461 | do { |
496 | do { |
Line 485... | Line 520... | ||
485 | _cairo_hash_table_remove (cairo_hash_table_t *hash_table, |
520 | _cairo_hash_table_remove (cairo_hash_table_t *hash_table, |
486 | cairo_hash_entry_t *key) |
521 | cairo_hash_entry_t *key) |
487 | { |
522 | { |
488 | *_cairo_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY; |
523 | *_cairo_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY; |
489 | hash_table->live_entries--; |
524 | hash_table->live_entries--; |
- | 525 | hash_table->cache[key->hash & 31] = NULL; |
|
Line 490... | Line 526... | ||
490 | 526 | ||
491 | /* Check for table resize. Don't do this when iterating as this will |
527 | /* Check for table resize. Don't do this when iterating as this will |
492 | * reorder elements of the table and cause the iteration to potentially |
528 | * reorder elements of the table and cause the iteration to potentially |
493 | * skip some elements. */ |
529 | * skip some elements. */ |
494 | if (hash_table->iterating == 0) { |
530 | if (hash_table->iterating == 0) { |
495 | /* This call _can_ fail, but only in failing to allocate new |
531 | /* This call _can_ fail, but only in failing to allocate new |
496 | * memory to shrink the hash table. It does leave the table in a |
532 | * memory to shrink the hash table. It does leave the table in a |
497 | * consistent state, and we've already succeeded in removing the |
533 | * consistent state, and we've already succeeded in removing the |
498 | * entry, so we don't examine the failure status of this call. */ |
534 | * entry, so we don't examine the failure status of this call. */ |
499 | _cairo_hash_table_resize (hash_table); |
535 | _cairo_hash_table_manage (hash_table); |
500 | } |
536 | } |
Line 501... | Line 537... | ||
501 | } |
537 | } |
502 | 538 | ||
Line 523... | Line 559... | ||
523 | unsigned long i; |
559 | unsigned long i; |
524 | cairo_hash_entry_t *entry; |
560 | cairo_hash_entry_t *entry; |
Line 525... | Line 561... | ||
525 | 561 | ||
526 | /* Mark the table for iteration */ |
562 | /* Mark the table for iteration */ |
527 | ++hash_table->iterating; |
563 | ++hash_table->iterating; |
528 | for (i = 0; i < hash_table->arrangement->size; i++) { |
564 | for (i = 0; i < *hash_table->table_size; i++) { |
529 | entry = hash_table->entries[i]; |
565 | entry = hash_table->entries[i]; |
530 | if (ENTRY_IS_LIVE(entry)) |
566 | if (ENTRY_IS_LIVE(entry)) |
531 | hash_callback (entry, closure); |
567 | hash_callback (entry, closure); |
532 | } |
568 | } |
Line 535... | Line 571... | ||
535 | * as the check is inexpensive. |
571 | * as the check is inexpensive. |
536 | */ |
572 | */ |
537 | if (--hash_table->iterating == 0) { |
573 | if (--hash_table->iterating == 0) { |
538 | /* Should we fail to shrink the hash table, it is left unaltered, |
574 | /* Should we fail to shrink the hash table, it is left unaltered, |
539 | * and we don't need to propagate the error status. */ |
575 | * and we don't need to propagate the error status. */ |
540 | _cairo_hash_table_resize (hash_table); |
576 | _cairo_hash_table_manage (hash_table); |
541 | } |
577 | } |
542 | }>>>>>> |
578 | }>>>>>> |