1
/* 
2
 * Copyright © 2004 Red Hat, Inc.
3
 * Copyright © 2005 Red Hat, Inc.
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is Red Hat, Inc.
31
 *
32
 * Contributor(s):
33
 *      Keith Packard <keithp@keithp.com>
34
 *	Graydon Hoare <graydon@redhat.com>
35
 *	Carl Worth <cworth@cworth.org>
36
 *	Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
37
 */
38

            
39
#include "config.h"
40

            
41
#include "cairo-script-private.h"
42

            
43
#include <stdlib.h>
44

            
45
/*
46
 * An entry can be in one of three states:
47
 *
48
 * FREE: Entry has never been used, terminates all searches.
49
 *       Appears in the table as a %NULL pointer.
50
 *
51
 * DEAD: Entry had been live in the past. A dead entry can be reused
52
 *       but does not terminate a search for an exact entry.
53
 *       Appears in the table as a pointer to DEAD_ENTRY.
54
 *
55
 * LIVE: Entry is currently being used.
56
 *       Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer.
57
 */
58

            
59
#define DEAD_ENTRY ((csi_hash_entry_t *) 0x1)
60

            
61
#define ENTRY_IS_FREE(entry) ((entry) == NULL)
62
#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY)
63
#define ENTRY_IS_LIVE(entry) ((entry) >  DEAD_ENTRY)
64

            
65

            
66
/* This table is open-addressed with double hashing. Each table size is a
67
 * prime chosen to be a little more than double the high water mark for a
68
 * given arrangement, so the tables should remain < 50% full. The table
69
 * size makes for the "first" hash modulus; a second prime (2 less than the
70
 * first prime) serves as the "second" hash modulus, which is co-prime and
71
 * thus guarantees a complete permutation of table indices.
72
 *
73
 * This structure, and accompanying table, is borrowed/modified from the
74
 * file xserver/render/glyph.c in the freedesktop.org x server, with
75
 * permission (and suggested modification of doubling sizes) by Keith
76
 * Packard.
77
 */
78

            
79
static const csi_hash_table_arrangement_t hash_table_arrangements [] = {
80
    { 16,		43,		41		},
81
    { 32,		73,		71		},
82
    { 64,		151,		149		},
83
    { 128,		283,		281		},
84
    { 256,		571,		569		},
85
    { 512,		1153,		1151		},
86
    { 1024,		2269,		2267		},
87
    { 2048,		4519,		4517		},
88
    { 4096,		9013,		9011		},
89
    { 8192,		18043,		18041		},
90
    { 16384,		36109,		36107		},
91
    { 32768,		72091,		72089		},
92
    { 65536,		144409,		144407		},
93
    { 131072,		288361,		288359		},
94
    { 262144,		576883,		576881		},
95
    { 524288,		1153459,	1153457		},
96
    { 1048576,		2307163,	2307161		},
97
    { 2097152,		4613893,	4613891		},
98
    { 4194304,		9227641,	9227639		},
99
    { 8388608,		18455029,	18455027	},
100
    { 16777216,		36911011,	36911009	},
101
    { 33554432,		73819861,	73819859	},
102
    { 67108864,		147639589,	147639587	},
103
    { 134217728,	295279081,	295279079	},
104
    { 268435456,	590559793,	590559791	}
105
};
106

            
107
#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements)
108

            
109
/**
110
 * _csi_hash_table_create:
111
 * @keys_equal: a function to return %TRUE if two keys are equal
112
 *
113
 * Creates a new hash table which will use the keys_equal() function
114
 * to compare hash keys. Data is provided to the hash table in the
115
 * form of user-derived versions of #csi_hash_entry_t. A hash entry
116
 * must be able to hold both a key (including a hash code) and a
117
 * value. Sometimes only the key will be necessary, (as in
118
 * _csi_hash_table_remove), and other times both a key and a value
119
 * will be necessary, (as in _csi_hash_table_insert).
120
 *
121
 * See #csi_hash_entry_t for more details.
122
 *
123
 * Return value: the new hash table or %NULL if out of memory.
124
 **/
125
csi_status_t
126
_csi_hash_table_init (csi_hash_table_t *hash_table,
127
		      csi_hash_keys_equal_func_t keys_equal)
128
{
129
    hash_table->keys_equal = keys_equal;
130

            
131
    hash_table->arrangement = &hash_table_arrangements[0];
132

            
133
    hash_table->entries = calloc (hash_table->arrangement->size,
134
				  sizeof(csi_hash_entry_t *));
135
    if (hash_table->entries == NULL)
136
	return _csi_error (CAIRO_STATUS_NO_MEMORY);
137

            
138
    hash_table->live_entries = 0;
139
    hash_table->used_entries = 0;
140
    hash_table->iterating = 0;
141

            
142
    return CSI_STATUS_SUCCESS;
143
}
144

            
145
/**
146
 * _csi_hash_table_destroy:
147
 * @hash_table: an empty hash table to destroy
148
 *
149
 * Immediately destroys the given hash table, freeing all resources
150
 * associated with it.
151
 *
152
 * WARNING: The hash_table must have no live entries in it before
153
 * _csi_hash_table_destroy is called. It is a fatal error otherwise,
154
 * and this function will halt. The rationale for this behavior is to
155
 * avoid memory leaks and to avoid needless complication of the API
156
 * with destroy notify callbacks.
157
 *
158
 * WARNING: The hash_table must have no running iterators in it when
159
 * _csi_hash_table_destroy is called. It is a fatal error otherwise,
160
 * and this function will halt.
161
 **/
162
void
163
_csi_hash_table_fini (csi_hash_table_t *hash_table)
164
{
165
    free (hash_table->entries);
166
}
167

            
168
static csi_hash_entry_t **
169
_csi_hash_table_lookup_unique_key (csi_hash_table_t *hash_table,
170
				     csi_hash_entry_t *key)
171
{
172
    unsigned long table_size, i, idx, step;
173
    csi_hash_entry_t **entry;
174

            
175
    table_size = hash_table->arrangement->size;
176
    idx = key->hash % table_size;
177

            
178
    entry = &hash_table->entries[idx];
179
    if (! ENTRY_IS_LIVE (*entry))
180
	return entry;
181

            
182
    i = 1;
183
    step = key->hash % hash_table->arrangement->rehash;
184
    if (step == 0)
185
	step = 1;
186
    do {
187
	idx += step;
188
	if (idx >= table_size)
189
	    idx -= table_size;
190

            
191
	entry = &hash_table->entries[idx];
192
	if (! ENTRY_IS_LIVE (*entry))
193
	    return entry;
194
    } while (++i < table_size);
195

            
196
    return NULL;
197
}
198

            
199
/**
200
 * _csi_hash_table_manage:
201
 * @hash_table: a hash table
202
 *
203
 * Resize the hash table if the number of entries has gotten much
204
 * bigger or smaller than the ideal number of entries for the current
205
 * size, or control the number of dead entries by moving the entries
206
 * within the table.
207
 *
208
 * Return value: %CAIRO_STATUS_SUCCESS if successful or
209
 * %CAIRO_STATUS_NO_MEMORY if out of memory.
210
 **/
211
static csi_status_t
212
_csi_hash_table_manage (csi_hash_table_t *hash_table)
213
{
214
    csi_hash_table_t tmp;
215
    csi_boolean_t realloc = TRUE;
216
    unsigned long i;
217

            
218
    /* This keeps the size of the hash table between 2 and approximately 8
219
     * times the number of live entries and keeps the proportion of free
220
     * entries (search-terminations) > 25%.
221
     */
222
    unsigned long high = hash_table->arrangement->high_water_mark;
223
    unsigned long low = high >> 2;
224
    unsigned long max_used = high  + high / 2;
225

            
226
    tmp = *hash_table;
227

            
228
    if (hash_table->live_entries > high) {
229
	tmp.arrangement = hash_table->arrangement + 1;
230
	/* This code is being abused if we can't make a table big enough. */
231
    } else if (hash_table->live_entries < low &&
232
	       /* Can't shrink if we're at the smallest size */
233
	       hash_table->arrangement != &hash_table_arrangements[0])
234
    {
235
	tmp.arrangement = hash_table->arrangement - 1;
236
    }
237
    else if (hash_table->used_entries > max_used)
238
    {
239
	/* Clean out dead entries to prevent lookups from becoming too slow. */
240
	for (i = 0; i < hash_table->arrangement->size; ++i) {
241
	    if (ENTRY_IS_DEAD (hash_table->entries[i]))
242
		hash_table->entries[i] = NULL;
243
	}
244
	hash_table->used_entries = hash_table->live_entries;
245

            
246
	/* There is no need to reallocate but some entries may need to be
247
	 * moved.  Typically the proportion of entries needing to be moved is
248
	 * small, but, if the moving should leave a large number of dead
249
	 * entries, they will be cleaned out next time this code is
250
	 * executed. */
251
	realloc = FALSE;
252
    }
253
    else
254
    {
255
	return CAIRO_STATUS_SUCCESS;
256
    }
257

            
258
    if (realloc) {
259
	tmp.entries = calloc (tmp.arrangement->size,
260
		              sizeof (csi_hash_entry_t*));
261
	if (tmp.entries == NULL)
262
	    return _csi_error (CAIRO_STATUS_NO_MEMORY);
263

            
264
	hash_table->used_entries = 0;
265
    }
266

            
267
    for (i = 0; i < hash_table->arrangement->size; ++i) {
268
	csi_hash_entry_t *entry, **pos;
269

            
270
	entry = hash_table->entries[i];
271
	if (ENTRY_IS_LIVE (entry)) {
272
	    hash_table->entries[i] = DEAD_ENTRY;
273

            
274
	    pos = _csi_hash_table_lookup_unique_key (&tmp, entry);
275
	    if (ENTRY_IS_FREE (*pos))
276
		hash_table->used_entries++;
277

            
278
	    *pos = entry;
279
	}
280
    }
281

            
282
    if (realloc) {
283
	free (hash_table->entries);
284
	hash_table->entries = tmp.entries;
285
	hash_table->arrangement = tmp.arrangement;
286
    }
287

            
288
    return CAIRO_STATUS_SUCCESS;
289
}
290

            
291
/**
292
 * _csi_hash_table_lookup:
293
 * @hash_table: a hash table
294
 * @key: the key of interest
295
 *
296
 * Performs a lookup in @hash_table looking for an entry which has a
297
 * key that matches @key, (as determined by the keys_equal() function
298
 * passed to _csi_hash_table_create).
299
 *
300
 * Return value: the matching entry, of %NULL if no match was found.
301
 **/
302
void *
303
_csi_hash_table_lookup (csi_hash_table_t *hash_table,
304
			csi_hash_entry_t *key)
305
{
306
    csi_hash_entry_t **entry;
307
    unsigned long table_size, i, idx, step;
308

            
309
    table_size = hash_table->arrangement->size;
310
    idx = key->hash % table_size;
311
    entry = &hash_table->entries[idx];
312

            
313
    if (ENTRY_IS_LIVE (*entry)) {
314
	if ((*entry)->hash == key->hash && hash_table->keys_equal (key, *entry))
315
	    return *entry;
316
    } else if (ENTRY_IS_FREE (*entry))
317
	return NULL;
318

            
319
    i = 1;
320
    step = key->hash % hash_table->arrangement->rehash;
321
    if (step == 0)
322
	step = 1;
323
    do {
324
	idx += step;
325
	if (idx >= table_size)
326
	    idx -= table_size;
327

            
328
	entry = &hash_table->entries[idx];
329
	if (ENTRY_IS_LIVE (*entry)) {
330
	    if ((*entry)->hash == key->hash &&
331
		hash_table->keys_equal (key, *entry))
332
	    {
333
		return *entry;
334
	    }
335
	} else if (ENTRY_IS_FREE (*entry))
336
	    return NULL;
337
    } while (++i < table_size);
338

            
339
    return NULL;
340
}
341

            
342
/**
343
 * _csi_hash_table_insert:
344
 * @hash_table: a hash table
345
 * @key_and_value: an entry to be inserted
346
 *
347
 * Insert the entry #key_and_value into the hash table.
348
 *
349
 * WARNING: There must not be an existing entry in the hash table
350
 * with a matching key.
351
 *
352
 * WARNING: It is a fatal error to insert an element while
353
 * an iterator is running
354
 *
355
 * Instead of using insert to replace an entry, consider just editing
356
 * the entry obtained with _csi_hash_table_lookup. Or if absolutely
357
 * necessary, use _csi_hash_table_remove first.
358
 *
359
 * Return value: %CAIRO_STATUS_SUCCESS if successful or
360
 * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
361
 **/
362
csi_status_t
363
_csi_hash_table_insert (csi_hash_table_t *hash_table,
364
			  csi_hash_entry_t *key_and_value)
365
{
366
    csi_status_t status;
367
    csi_hash_entry_t **entry;
368

            
369
    hash_table->live_entries++;
370
    status = _csi_hash_table_manage (hash_table);
371
    if (_csi_unlikely (status)) {
372
	/* abort the insert... */
373
	hash_table->live_entries--;
374
	return status;
375
    }
376

            
377
    entry = _csi_hash_table_lookup_unique_key (hash_table,
378
					       key_and_value);
379
    if (ENTRY_IS_FREE (*entry))
380
	hash_table->used_entries++;
381

            
382
    *entry = key_and_value;
383
    return CAIRO_STATUS_SUCCESS;
384
}
385

            
386
static csi_hash_entry_t **
387
_csi_hash_table_lookup_exact_key (csi_hash_table_t *hash_table,
388
				    csi_hash_entry_t *key)
389
{
390
    unsigned long table_size, i, idx, step;
391
    csi_hash_entry_t **entry;
392

            
393
    table_size = hash_table->arrangement->size;
394
    idx = key->hash % table_size;
395

            
396
    entry = &hash_table->entries[idx];
397
    if (*entry == key)
398
	return entry;
399

            
400
    i = 1;
401
    step = key->hash % hash_table->arrangement->rehash;
402
    if (step == 0)
403
	step = 1;
404
    do {
405
	idx += step;
406
	if (idx >= table_size)
407
	    idx -= table_size;
408

            
409
	entry = &hash_table->entries[idx];
410
	if (*entry == key)
411
	    return entry;
412
    } while (++i < table_size);
413

            
414
    return NULL;
415
}
416
/**
417
 * _csi_hash_table_remove:
418
 * @hash_table: a hash table
419
 * @key: key of entry to be removed
420
 *
421
 * Remove an entry from the hash table which points to @key.
422
 *
423
 * Return value: %CAIRO_STATUS_SUCCESS if successful or
424
 * %CAIRO_STATUS_NO_MEMORY if out of memory.
425
 **/
426
void
427
_csi_hash_table_remove (csi_hash_table_t *hash_table,
428
			  csi_hash_entry_t *key)
429
{
430
    *_csi_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY;
431
    hash_table->live_entries--;
432

            
433
    /* Check for table resize. Don't do this when iterating as this will
434
     * reorder elements of the table and cause the iteration to potentially
435
     * skip some elements. */
436
    if (hash_table->iterating == 0) {
437
	/* This call _can_ fail, but only in failing to allocate new
438
	 * memory to shrink the hash table. It does leave the table in a
439
	 * consistent state, and we've already succeeded in removing the
440
	 * entry, so we don't examine the failure status of this call. */
441
	_csi_hash_table_manage (hash_table);
442
    }
443
}
444

            
445
/**
446
 * _csi_hash_table_foreach:
447
 * @hash_table: a hash table
448
 * @hash_callback: function to be called for each live entry
449
 * @closure: additional argument to be passed to @hash_callback
450
 *
451
 * Call @hash_callback for each live entry in the hash table, in a
452
 * non-specified order.
453
 *
454
 * Entries in @hash_table may be removed by code executed from @hash_callback.
455
 *
456
 * Entries may not be inserted to @hash_table, nor may @hash_table
457
 * be destroyed by code executed from @hash_callback. The relevant
458
 * functions will halt in these cases.
459
 **/
460
void
461
_csi_hash_table_foreach (csi_hash_table_t	      *hash_table,
462
			 csi_hash_callback_func_t  hash_callback,
463
			 void			      *closure)
464
{
465
    unsigned long i;
466
    csi_hash_entry_t *entry;
467

            
468
    /* Mark the table for iteration */
469
    ++hash_table->iterating;
470
    for (i = 0; i < hash_table->arrangement->size; i++) {
471
	entry = hash_table->entries[i];
472
	if (ENTRY_IS_LIVE(entry))
473
	    hash_callback (entry, closure);
474
    }
475
    /* If some elements were deleted during the iteration,
476
     * the table may need resizing. Just do this every time
477
     * as the check is inexpensive.
478
     */
479
    if (--hash_table->iterating == 0) {
480
	/* Should we fail to shrink the hash table, it is left unaltered,
481
	 * and we don't need to propagate the error status. */
482
	_csi_hash_table_manage (hash_table);
483
    }
484
}