1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
---|
2 | /* ***** BEGIN LICENSE BLOCK *****
|
---|
3 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
---|
4 | *
|
---|
5 | * The contents of this file are subject to the Mozilla Public License Version
|
---|
6 | * 1.1 (the "License"); you may not use this file except in compliance with
|
---|
7 | * the License. You may obtain a copy of the License at
|
---|
8 | * http://www.mozilla.org/MPL/
|
---|
9 | *
|
---|
10 | * Software distributed under the License is distributed on an "AS IS" basis,
|
---|
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
---|
12 | * for the specific language governing rights and limitations under the
|
---|
13 | * License.
|
---|
14 | *
|
---|
15 | * The Original Code is Mozilla JavaScript code.
|
---|
16 | *
|
---|
17 | * The Initial Developer of the Original Code is
|
---|
18 | * Netscape Communications Corporation.
|
---|
19 | * Portions created by the Initial Developer are Copyright (C) 1999-2001
|
---|
20 | * the Initial Developer. All Rights Reserved.
|
---|
21 | *
|
---|
22 | * Contributor(s):
|
---|
23 | * Brendan Eich <[email protected]> (Original Author)
|
---|
24 | *
|
---|
25 | * Alternatively, the contents of this file may be used under the terms of
|
---|
26 | * either of the GNU General Public License Version 2 or later (the "GPL"),
|
---|
27 | * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
---|
28 | * in which case the provisions of the GPL or the LGPL are applicable instead
|
---|
29 | * of those above. If you wish to allow use of your version of this file only
|
---|
30 | * under the terms of either the GPL or the LGPL, and not to allow others to
|
---|
31 | * use your version of this file under the terms of the MPL, indicate your
|
---|
32 | * decision by deleting the provisions above and replace them with the notice
|
---|
33 | * and other provisions required by the GPL or the LGPL. If you do not delete
|
---|
34 | * the provisions above, a recipient may use your version of this file under
|
---|
35 | * the terms of any one of the MPL, the GPL or the LGPL.
|
---|
36 | *
|
---|
37 | * ***** END LICENSE BLOCK ***** */
|
---|
38 |
|
---|
39 | #ifndef pldhash_h___
|
---|
40 | #define pldhash_h___
|
---|
41 | /*
|
---|
42 | * Double hashing, a la Knuth 6.
|
---|
43 | * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!!
|
---|
44 | */
|
---|
45 | #include "prtypes.h"
|
---|
46 |
|
---|
47 | PR_BEGIN_EXTERN_C
|
---|
48 |
|
---|
49 | #ifdef DEBUG_XXXbrendan
|
---|
50 | #define PL_DHASHMETER 1
|
---|
51 | #endif
|
---|
52 |
|
---|
53 | #if defined(__GNUC__) && defined(__i386__) && (__GNUC__ >= 3) && !defined(XP_OS2)
|
---|
54 | #define PL_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall))
|
---|
55 | #else
|
---|
56 | #define PL_DHASH_FASTCALL
|
---|
57 | #endif
|
---|
58 |
|
---|
59 | /* Table size limit, do not equal or exceed (see min&maxAlphaFrac, below). */
|
---|
60 | #undef PL_DHASH_SIZE_LIMIT
|
---|
61 | #define PL_DHASH_SIZE_LIMIT PR_BIT(24)
|
---|
62 |
|
---|
63 | /* Minimum table size, or gross entry count (net is at most .75 loaded). */
|
---|
64 | #ifndef PL_DHASH_MIN_SIZE
|
---|
65 | #define PL_DHASH_MIN_SIZE 16
|
---|
66 | #elif (PL_DHASH_MIN_SIZE & (PL_DHASH_MIN_SIZE - 1)) != 0
|
---|
67 | #error "PL_DHASH_MIN_SIZE must be a power of two!"
|
---|
68 | #endif
|
---|
69 |
|
---|
70 | /*
|
---|
71 | * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio,
|
---|
72 | * expressed as a fixed-point 32-bit fraction.
|
---|
73 | */
|
---|
74 | #define PL_DHASH_BITS 32
|
---|
75 | #define PL_DHASH_GOLDEN_RATIO 0x9E3779B9U
|
---|
76 |
|
---|
77 | /* Primitive and forward-struct typedefs. */
|
---|
78 | typedef PRUint32 PLDHashNumber;
|
---|
79 | typedef struct PLDHashEntryHdr PLDHashEntryHdr;
|
---|
80 | typedef struct PLDHashEntryStub PLDHashEntryStub;
|
---|
81 | typedef struct PLDHashTable PLDHashTable;
|
---|
82 | typedef struct PLDHashTableOps PLDHashTableOps;
|
---|
83 |
|
---|
84 | /*
|
---|
85 | * Table entry header structure.
|
---|
86 | *
|
---|
87 | * In order to allow in-line allocation of key and value, we do not declare
|
---|
88 | * either here. Instead, the API uses const void *key as a formal parameter,
|
---|
89 | * and asks each entry for its key when necessary via a getKey callback, used
|
---|
90 | * when growing or shrinking the table. Other callback types are defined
|
---|
91 | * below and grouped into the PLDHashTableOps structure, for single static
|
---|
92 | * initialization per hash table sub-type.
|
---|
93 | *
|
---|
94 | * Each hash table sub-type should nest the PLDHashEntryHdr structure at the
|
---|
95 | * front of its particular entry type. The keyHash member contains the result
|
---|
96 | * of multiplying the hash code returned from the hashKey callback (see below)
|
---|
97 | * by PL_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0
|
---|
98 | * and 1 values. The stored keyHash value is table size invariant, and it is
|
---|
99 | * maintained automatically by PL_DHashTableOperate -- users should never set
|
---|
100 | * it, and its only uses should be via the entry macros below.
|
---|
101 | *
|
---|
102 | * The PL_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor
|
---|
103 | * removed. An entry may be either busy or free; if busy, it may be live or
|
---|
104 | * removed. Consumers of this API should not access members of entries that
|
---|
105 | * are not live.
|
---|
106 | *
|
---|
107 | * However, use PL_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries
|
---|
108 | * returned by PL_DHashTableOperate, as PL_DHashTableOperate never returns a
|
---|
109 | * non-live, busy (i.e., removed) entry pointer to its caller. See below for
|
---|
110 | * more details on PL_DHashTableOperate's calling rules.
|
---|
111 | */
|
---|
112 | struct PLDHashEntryHdr {
|
---|
113 | PLDHashNumber keyHash; /* every entry must begin like this */
|
---|
114 | };
|
---|
115 |
|
---|
116 | #define PL_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0)
|
---|
117 | #define PL_DHASH_ENTRY_IS_BUSY(entry) (!PL_DHASH_ENTRY_IS_FREE(entry))
|
---|
118 | #define PL_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2)
|
---|
119 |
|
---|
120 | /*
|
---|
121 | * A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead)
|
---|
122 | * on most architectures, and may be allocated on the stack or within another
|
---|
123 | * structure or class (see below for the Init and Finish functions to use).
|
---|
124 | *
|
---|
125 | * To decide whether to use double hashing vs. chaining, we need to develop a
|
---|
126 | * trade-off relation, as follows:
|
---|
127 | *
|
---|
128 | * Let alpha be the load factor, esize the entry size in words, count the
|
---|
129 | * entry count, and pow2 the power-of-two table size in entries.
|
---|
130 | *
|
---|
131 | * (PLDHashTable overhead) > (PLHashTable overhead)
|
---|
132 | * (unused table entry space) > (malloc and .next overhead per entry) +
|
---|
133 | * (buckets overhead)
|
---|
134 | * (1 - alpha) * esize * pow2 > 2 * count + pow2
|
---|
135 | *
|
---|
136 | * Notice that alpha is by definition (count / pow2):
|
---|
137 | *
|
---|
138 | * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2
|
---|
139 | * (1 - alpha) * esize > 2 * alpha + 1
|
---|
140 | *
|
---|
141 | * esize > (1 + 2 * alpha) / (1 - alpha)
|
---|
142 | *
|
---|
143 | * This assumes both tables must keep keyHash, key, and value for each entry,
|
---|
144 | * where key and value point to separately allocated strings or structures.
|
---|
145 | * If key and value can be combined into one pointer, then the trade-off is:
|
---|
146 | *
|
---|
147 | * esize > (1 + 3 * alpha) / (1 - alpha)
|
---|
148 | *
|
---|
149 | * If the entry value can be a subtype of PLDHashEntryHdr, rather than a type
|
---|
150 | * that must be allocated separately and referenced by an entry.value pointer
|
---|
151 | * member, and provided key's allocation can be fused with its entry's, then
|
---|
152 | * k (the words wasted per entry with chaining) is 4.
|
---|
153 | *
|
---|
154 | * To see these curves, feed gnuplot input like so:
|
---|
155 | *
|
---|
156 | * gnuplot> f(x,k) = (1 + k * x) / (1 - x)
|
---|
157 | * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4)
|
---|
158 | *
|
---|
159 | * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4
|
---|
160 | * words for chaining to be more space-efficient than double hashing.
|
---|
161 | *
|
---|
162 | * Solving for alpha helps us decide when to shrink an underloaded table:
|
---|
163 | *
|
---|
164 | * esize > (1 + k * alpha) / (1 - alpha)
|
---|
165 | * esize - alpha * esize > 1 + k * alpha
|
---|
166 | * esize - 1 > (k + esize) * alpha
|
---|
167 | * (esize - 1) / (k + esize) > alpha
|
---|
168 | *
|
---|
169 | * alpha < (esize - 1) / (esize + k)
|
---|
170 | *
|
---|
171 | * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k),
|
---|
172 | * assuming esize is not too large (in which case, chaining should probably be
|
---|
173 | * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3
|
---|
174 | * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5
|
---|
175 | * would still obtain. See the PL_DHASH_MIN_ALPHA macro further below.
|
---|
176 | *
|
---|
177 | * The current implementation uses a configurable lower bound on alpha, which
|
---|
178 | * defaults to .25, when deciding to shrink the table (while still respecting
|
---|
179 | * PL_DHASH_MIN_SIZE).
|
---|
180 | *
|
---|
181 | * Note a qualitative difference between chaining and double hashing: under
|
---|
182 | * chaining, entry addresses are stable across table shrinks and grows. With
|
---|
183 | * double hashing, you can't safely hold an entry pointer and use it after an
|
---|
184 | * ADD or REMOVE operation, unless you sample table->generation before adding
|
---|
185 | * or removing, and compare the sample after, dereferencing the entry pointer
|
---|
186 | * only if table->generation has not changed.
|
---|
187 | *
|
---|
188 | * The moral of this story: there is no one-size-fits-all hash table scheme,
|
---|
189 | * but for small table entry size, and assuming entry address stability is not
|
---|
190 | * required, double hashing wins.
|
---|
191 | */
|
---|
192 | struct PLDHashTable {
|
---|
193 | const PLDHashTableOps *ops; /* virtual operations, see below */
|
---|
194 | void *data; /* ops- and instance-specific data */
|
---|
195 | PRInt16 hashShift; /* multiplicative hash shift */
|
---|
196 | uint8 maxAlphaFrac; /* 8-bit fixed point max alpha */
|
---|
197 | uint8 minAlphaFrac; /* 8-bit fixed point min alpha */
|
---|
198 | PRUint32 entrySize; /* number of bytes in an entry */
|
---|
199 | PRUint32 entryCount; /* number of entries in table */
|
---|
200 | PRUint32 removedCount; /* removed entry sentinels in table */
|
---|
201 | PRUint32 generation; /* entry storage generation number */
|
---|
202 | char *entryStore; /* entry storage */
|
---|
203 | #ifdef PL_DHASHMETER
|
---|
204 | struct PLDHashStats {
|
---|
205 | PRUint32 searches; /* total number of table searches */
|
---|
206 | PRUint32 steps; /* hash chain links traversed */
|
---|
207 | PRUint32 hits; /* searches that found key */
|
---|
208 | PRUint32 misses; /* searches that didn't find key */
|
---|
209 | PRUint32 lookups; /* number of PL_DHASH_LOOKUPs */
|
---|
210 | PRUint32 addMisses; /* adds that miss, and do work */
|
---|
211 | PRUint32 addOverRemoved; /* adds that recycled a removed entry */
|
---|
212 | PRUint32 addHits; /* adds that hit an existing entry */
|
---|
213 | PRUint32 addFailures; /* out-of-memory during add growth */
|
---|
214 | PRUint32 removeHits; /* removes that hit, and do work */
|
---|
215 | PRUint32 removeMisses; /* useless removes that miss */
|
---|
216 | PRUint32 removeFrees; /* removes that freed entry directly */
|
---|
217 | PRUint32 removeEnums; /* removes done by Enumerate */
|
---|
218 | PRUint32 grows; /* table expansions */
|
---|
219 | PRUint32 shrinks; /* table contractions */
|
---|
220 | PRUint32 compresses; /* table compressions */
|
---|
221 | PRUint32 enumShrinks; /* contractions after Enumerate */
|
---|
222 | } stats;
|
---|
223 | #endif
|
---|
224 | };
|
---|
225 |
|
---|
226 | /*
|
---|
227 | * Size in entries (gross, not net of free and removed sentinels) for table.
|
---|
228 | * We store hashShift rather than sizeLog2 to optimize the collision-free case
|
---|
229 | * in SearchTable.
|
---|
230 | */
|
---|
231 | #define PL_DHASH_TABLE_SIZE(table) PR_BIT(PL_DHASH_BITS - (table)->hashShift)
|
---|
232 |
|
---|
233 | /*
|
---|
234 | * Table space at entryStore is allocated and freed using these callbacks.
|
---|
235 | * The allocator should return null on error only (not if called with nbytes
|
---|
236 | * equal to 0; but note that pldhash.c code will never call with 0 nbytes).
|
---|
237 | */
|
---|
238 | typedef void *
|
---|
239 | (* PR_CALLBACK PLDHashAllocTable)(PLDHashTable *table, PRUint32 nbytes);
|
---|
240 |
|
---|
241 | typedef void
|
---|
242 | (* PR_CALLBACK PLDHashFreeTable) (PLDHashTable *table, void *ptr);
|
---|
243 |
|
---|
244 | /*
|
---|
245 | * When a table grows or shrinks, each entry is queried for its key using this
|
---|
246 | * callback. NB: in that event, entry is not in table any longer; it's in the
|
---|
247 | * old entryStore vector, which is due to be freed once all entries have been
|
---|
248 | * moved via moveEntry callbacks.
|
---|
249 | */
|
---|
250 | typedef const void *
|
---|
251 | (* PR_CALLBACK PLDHashGetKey) (PLDHashTable *table,
|
---|
252 | PLDHashEntryHdr *entry);
|
---|
253 |
|
---|
254 | /*
|
---|
255 | * Compute the hash code for a given key to be looked up, added, or removed
|
---|
256 | * from table. A hash code may have any PLDHashNumber value.
|
---|
257 | */
|
---|
258 | typedef PLDHashNumber
|
---|
259 | (* PR_CALLBACK PLDHashHashKey) (PLDHashTable *table, const void *key);
|
---|
260 |
|
---|
261 | /*
|
---|
262 | * Compare the key identifying entry in table with the provided key parameter.
|
---|
263 | * Return PR_TRUE if keys match, PR_FALSE otherwise.
|
---|
264 | */
|
---|
265 | typedef PRBool
|
---|
266 | (* PR_CALLBACK PLDHashMatchEntry)(PLDHashTable *table,
|
---|
267 | const PLDHashEntryHdr *entry,
|
---|
268 | const void *key);
|
---|
269 |
|
---|
270 | /*
|
---|
271 | * Copy the data starting at from to the new entry storage at to. Do not add
|
---|
272 | * reference counts for any strong references in the entry, however, as this
|
---|
273 | * is a "move" operation: the old entry storage at from will be freed without
|
---|
274 | * any reference-decrementing callback shortly.
|
---|
275 | */
|
---|
276 | typedef void
|
---|
277 | (* PR_CALLBACK PLDHashMoveEntry)(PLDHashTable *table,
|
---|
278 | const PLDHashEntryHdr *from,
|
---|
279 | PLDHashEntryHdr *to);
|
---|
280 |
|
---|
281 | /*
|
---|
282 | * Clear the entry and drop any strong references it holds. This callback is
|
---|
283 | * invoked during a PL_DHASH_REMOVE operation (see below for operation codes),
|
---|
284 | * but only if the given key is found in the table.
|
---|
285 | */
|
---|
286 | typedef void
|
---|
287 | (* PR_CALLBACK PLDHashClearEntry)(PLDHashTable *table,
|
---|
288 | PLDHashEntryHdr *entry);
|
---|
289 |
|
---|
290 | /*
|
---|
291 | * Called when a table (whether allocated dynamically by itself, or nested in
|
---|
292 | * a larger structure, or allocated on the stack) is finished. This callback
|
---|
293 | * allows table->ops-specific code to finalize table->data.
|
---|
294 | */
|
---|
295 | typedef void
|
---|
296 | (* PR_CALLBACK PLDHashFinalize) (PLDHashTable *table);
|
---|
297 |
|
---|
298 | /*
|
---|
299 | * Initialize a new entry, apart from keyHash. This function is called when
|
---|
300 | * PL_DHashTableOperate's PL_DHASH_ADD case finds no existing entry for the
|
---|
301 | * given key, and must add a new one. At that point, entry->keyHash is not
|
---|
302 | * set yet, to avoid claiming the last free entry in a severely overloaded
|
---|
303 | * table.
|
---|
304 | */
|
---|
305 | typedef PRBool
|
---|
306 | (* PR_CALLBACK PLDHashInitEntry)(PLDHashTable *table,
|
---|
307 | PLDHashEntryHdr *entry,
|
---|
308 | const void *key);
|
---|
309 |
|
---|
310 | /*
|
---|
311 | * Finally, the "vtable" structure for PLDHashTable. The first eight hooks
|
---|
312 | * must be provided by implementations; they're called unconditionally by the
|
---|
313 | * generic pldhash.c code. Hooks after these may be null.
|
---|
314 | *
|
---|
315 | * Summary of allocation-related hook usage with C++ placement new emphasis:
|
---|
316 | * allocTable Allocate raw bytes with malloc, no ctors run.
|
---|
317 | * freeTable Free raw bytes with free, no dtors run.
|
---|
318 | * initEntry Call placement new using default key-based ctor.
|
---|
319 | * Return PR_TRUE on success, PR_FALSE on error.
|
---|
320 | * moveEntry Call placement new using copy ctor, run dtor on old
|
---|
321 | * entry storage.
|
---|
322 | * clearEntry Run dtor on entry.
|
---|
323 | * finalize Stub unless table->data was initialized and needs to
|
---|
324 | * be finalized.
|
---|
325 | *
|
---|
326 | * Note the reason why initEntry is optional: the default hooks (stubs) clear
|
---|
327 | * entry storage: On successful PL_DHashTableOperate(tbl, key, PL_DHASH_ADD),
|
---|
328 | * the returned entry pointer addresses an entry struct whose keyHash member
|
---|
329 | * has been set non-zero, but all other entry members are still clear (null).
|
---|
330 | * PL_DHASH_ADD callers can test such members to see whether the entry was
|
---|
331 | * newly created by the PL_DHASH_ADD call that just succeeded. If placement
|
---|
332 | * new or similar initialization is required, define an initEntry hook. Of
|
---|
333 | * course, the clearEntry hook must zero or null appropriately.
|
---|
334 | *
|
---|
335 | * XXX assumes 0 is null for pointer types.
|
---|
336 | */
|
---|
337 | struct PLDHashTableOps {
|
---|
338 | /* Mandatory hooks. All implementations must provide these. */
|
---|
339 | PLDHashAllocTable allocTable;
|
---|
340 | PLDHashFreeTable freeTable;
|
---|
341 | PLDHashGetKey getKey;
|
---|
342 | PLDHashHashKey hashKey;
|
---|
343 | PLDHashMatchEntry matchEntry;
|
---|
344 | PLDHashMoveEntry moveEntry;
|
---|
345 | PLDHashClearEntry clearEntry;
|
---|
346 | PLDHashFinalize finalize;
|
---|
347 |
|
---|
348 | /* Optional hooks start here. If null, these are not called. */
|
---|
349 | PLDHashInitEntry initEntry;
|
---|
350 | };
|
---|
351 |
|
---|
352 | /*
|
---|
353 | * Default implementations for the above ops.
|
---|
354 | */
|
---|
355 | PR_EXTERN(void *)
|
---|
356 | PL_DHashAllocTable(PLDHashTable *table, PRUint32 nbytes);
|
---|
357 |
|
---|
358 | PR_EXTERN(void)
|
---|
359 | PL_DHashFreeTable(PLDHashTable *table, void *ptr);
|
---|
360 |
|
---|
361 | PR_EXTERN(PLDHashNumber)
|
---|
362 | PL_DHashStringKey(PLDHashTable *table, const void *key);
|
---|
363 |
|
---|
364 | /* A minimal entry contains a keyHash header and a void key pointer. */
|
---|
365 | struct PLDHashEntryStub {
|
---|
366 | PLDHashEntryHdr hdr;
|
---|
367 | const void *key;
|
---|
368 | };
|
---|
369 |
|
---|
370 | PR_EXTERN(const void *)
|
---|
371 | PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry);
|
---|
372 |
|
---|
373 | PR_EXTERN(PLDHashNumber)
|
---|
374 | PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key);
|
---|
375 |
|
---|
376 | PR_EXTERN(PRBool)
|
---|
377 | PL_DHashMatchEntryStub(PLDHashTable *table,
|
---|
378 | const PLDHashEntryHdr *entry,
|
---|
379 | const void *key);
|
---|
380 |
|
---|
381 | PR_EXTERN(PRBool)
|
---|
382 | PL_DHashMatchStringKey(PLDHashTable *table,
|
---|
383 | const PLDHashEntryHdr *entry,
|
---|
384 | const void *key);
|
---|
385 |
|
---|
386 | PR_EXTERN(void)
|
---|
387 | PL_DHashMoveEntryStub(PLDHashTable *table,
|
---|
388 | const PLDHashEntryHdr *from,
|
---|
389 | PLDHashEntryHdr *to);
|
---|
390 |
|
---|
391 | PR_EXTERN(void)
|
---|
392 | PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry);
|
---|
393 |
|
---|
394 | PR_EXTERN(void)
|
---|
395 | PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry);
|
---|
396 |
|
---|
397 | PR_EXTERN(void)
|
---|
398 | PL_DHashFinalizeStub(PLDHashTable *table);
|
---|
399 |
|
---|
400 | /*
|
---|
401 | * If you use PLDHashEntryStub or a subclass of it as your entry struct, and
|
---|
402 | * if your entries move via memcpy and clear via memset(0), you can use these
|
---|
403 | * stub operations.
|
---|
404 | */
|
---|
405 | PR_EXTERN(const PLDHashTableOps *)
|
---|
406 | PL_DHashGetStubOps(void);
|
---|
407 |
|
---|
408 | /*
|
---|
409 | * Dynamically allocate a new PLDHashTable using malloc, initialize it using
|
---|
410 | * PL_DHashTableInit, and return its address. Return null on malloc failure.
|
---|
411 | * Note that the entry storage at table->entryStore will be allocated using
|
---|
412 | * the ops->allocTable callback.
|
---|
413 | */
|
---|
414 | PR_EXTERN(PLDHashTable *)
|
---|
415 | PL_NewDHashTable(const PLDHashTableOps *ops, void *data, PRUint32 entrySize,
|
---|
416 | PRUint32 capacity);
|
---|
417 |
|
---|
418 | /*
|
---|
419 | * Finalize table's data, free its entry storage (via table->ops->freeTable),
|
---|
420 | * and return the memory starting at table to the malloc heap.
|
---|
421 | */
|
---|
422 | PR_EXTERN(void)
|
---|
423 | PL_DHashTableDestroy(PLDHashTable *table);
|
---|
424 |
|
---|
425 | /*
|
---|
426 | * Initialize table with ops, data, entrySize, and capacity. Capacity is a
|
---|
427 | * guess for the smallest table size at which the table will usually be less
|
---|
428 | * than 75% loaded (the table will grow or shrink as needed; capacity serves
|
---|
429 | * only to avoid inevitable early growth from PL_DHASH_MIN_SIZE).
|
---|
430 | */
|
---|
431 | PR_EXTERN(PRBool)
|
---|
432 | PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data,
|
---|
433 | PRUint32 entrySize, PRUint32 capacity);
|
---|
434 |
|
---|
435 | /*
|
---|
436 | * Set maximum and minimum alpha for table. The defaults are 0.75 and .25.
|
---|
437 | * maxAlpha must be in [0.5, 0.9375] for the default PL_DHASH_MIN_SIZE; or if
|
---|
438 | * MinSize=PL_DHASH_MIN_SIZE <= 256, in [0.5, (float)(MinSize-1)/MinSize]; or
|
---|
439 | * else in [0.5, 255.0/256]. minAlpha must be in [0, maxAlpha / 2), so that
|
---|
440 | * we don't shrink on the very next remove after growing a table upon adding
|
---|
441 | * an entry that brings entryCount past maxAlpha * tableSize.
|
---|
442 | */
|
---|
443 | PR_IMPLEMENT(void)
|
---|
444 | PL_DHashTableSetAlphaBounds(PLDHashTable *table,
|
---|
445 | float maxAlpha,
|
---|
446 | float minAlpha);
|
---|
447 |
|
---|
448 | /*
|
---|
449 | * Call this macro with k, the number of pointer-sized words wasted per entry
|
---|
450 | * under chaining, to compute the minimum alpha at which double hashing still
|
---|
451 | * beats chaining.
|
---|
452 | */
|
---|
453 | #define PL_DHASH_MIN_ALPHA(table, k) \
|
---|
454 | ((float)((table)->entrySize / sizeof(void *) - 1) \
|
---|
455 | / ((table)->entrySize / sizeof(void *) + (k)))
|
---|
456 |
|
---|
457 | /*
|
---|
458 | * Finalize table's data, free its entry storage using table->ops->freeTable,
|
---|
459 | * and leave its members unchanged from their last live values (which leaves
|
---|
460 | * pointers dangling). If you want to burn cycles clearing table, it's up to
|
---|
461 | * your code to call memset.
|
---|
462 | */
|
---|
463 | PR_EXTERN(void)
|
---|
464 | PL_DHashTableFinish(PLDHashTable *table);
|
---|
465 |
|
---|
466 | /*
|
---|
467 | * To consolidate keyHash computation and table grow/shrink code, we use a
|
---|
468 | * single entry point for lookup, add, and remove operations. The operation
|
---|
469 | * codes are declared here, along with codes returned by PLDHashEnumerator
|
---|
470 | * functions, which control PL_DHashTableEnumerate's behavior.
|
---|
471 | */
|
---|
472 | typedef enum PLDHashOperator {
|
---|
473 | PL_DHASH_LOOKUP = 0, /* lookup entry */
|
---|
474 | PL_DHASH_ADD = 1, /* add entry */
|
---|
475 | PL_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */
|
---|
476 | PL_DHASH_NEXT = 0, /* enumerator says continue */
|
---|
477 | PL_DHASH_STOP = 1 /* enumerator says stop */
|
---|
478 | } PLDHashOperator;
|
---|
479 |
|
---|
480 | /*
|
---|
481 | * To lookup a key in table, call:
|
---|
482 | *
|
---|
483 | * entry = PL_DHashTableOperate(table, key, PL_DHASH_LOOKUP);
|
---|
484 | *
|
---|
485 | * If PL_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies
|
---|
486 | * entry. If PL_DHASH_ENTRY_IS_FREE(entry) is true, key was not found.
|
---|
487 | *
|
---|
488 | * To add an entry identified by key to table, call:
|
---|
489 | *
|
---|
490 | * entry = PL_DHashTableOperate(table, key, PL_DHASH_ADD);
|
---|
491 | *
|
---|
492 | * If entry is null upon return, then either the table is severely overloaded,
|
---|
493 | * and memory can't be allocated for entry storage via table->ops->allocTable;
|
---|
494 | * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may
|
---|
495 | * have returned false.
|
---|
496 | *
|
---|
497 | * Otherwise, entry->keyHash has been set so that PL_DHASH_ENTRY_IS_BUSY(entry)
|
---|
498 | * is true, and it is up to the caller to initialize the key and value parts
|
---|
499 | * of the entry sub-type, if they have not been set already (i.e. if entry was
|
---|
500 | * not already in the table, and if the optional initEntry hook was not used).
|
---|
501 | *
|
---|
502 | * To remove an entry identified by key from table, call:
|
---|
503 | *
|
---|
504 | * (void) PL_DHashTableOperate(table, key, PL_DHASH_REMOVE);
|
---|
505 | *
|
---|
506 | * If key's entry is found, it is cleared (via table->ops->clearEntry) and
|
---|
507 | * the entry is marked so that PL_DHASH_ENTRY_IS_FREE(entry). This operation
|
---|
508 | * returns null unconditionally; you should ignore its return value.
|
---|
509 | */
|
---|
510 | PR_EXTERN(PLDHashEntryHdr *) PL_DHASH_FASTCALL
|
---|
511 | PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op);
|
---|
512 |
|
---|
513 | /*
|
---|
514 | * Remove an entry already accessed via LOOKUP or ADD.
|
---|
515 | *
|
---|
516 | * NB: this is a "raw" or low-level routine, intended to be used only where
|
---|
517 | * the inefficiency of a full PL_DHashTableOperate (which rehashes in order
|
---|
518 | * to find the entry given its key) is not tolerable. This function does not
|
---|
519 | * shrink the table if it is underloaded. It does not update stats #ifdef
|
---|
520 | * PL_DHASHMETER, either.
|
---|
521 | */
|
---|
522 | PR_EXTERN(void)
|
---|
523 | PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry);
|
---|
524 |
|
---|
525 | /*
|
---|
526 | * Enumerate entries in table using etor:
|
---|
527 | *
|
---|
528 | * count = PL_DHashTableEnumerate(table, etor, arg);
|
---|
529 | *
|
---|
530 | * PL_DHashTableEnumerate calls etor like so:
|
---|
531 | *
|
---|
532 | * op = etor(table, entry, number, arg);
|
---|
533 | *
|
---|
534 | * where number is a zero-based ordinal assigned to live entries according to
|
---|
535 | * their order in table->entryStore.
|
---|
536 | *
|
---|
537 | * The return value, op, is treated as a set of flags. If op is PL_DHASH_NEXT,
|
---|
538 | * then continue enumerating. If op contains PL_DHASH_REMOVE, then clear (via
|
---|
539 | * table->ops->clearEntry) and free entry. Then we check whether op contains
|
---|
540 | * PL_DHASH_STOP; if so, stop enumerating and return the number of live entries
|
---|
541 | * that were enumerated so far. Return the total number of live entries when
|
---|
542 | * enumeration completes normally.
|
---|
543 | *
|
---|
544 | * If etor calls PL_DHashTableOperate on table with op != PL_DHASH_LOOKUP, it
|
---|
545 | * must return PL_DHASH_STOP; otherwise undefined behavior results.
|
---|
546 | *
|
---|
547 | * If any enumerator returns PL_DHASH_REMOVE, table->entryStore may be shrunk
|
---|
548 | * or compressed after enumeration, but before PL_DHashTableEnumerate returns.
|
---|
549 | * Such an enumerator therefore can't safely set aside entry pointers, but an
|
---|
550 | * enumerator that never returns PL_DHASH_REMOVE can set pointers to entries
|
---|
551 | * aside, e.g., to avoid copying live entries into an array of the entry type.
|
---|
552 | * Copying entry pointers is cheaper, and safe so long as the caller of such a
|
---|
553 | * "stable" Enumerate doesn't use the set-aside pointers after any call either
|
---|
554 | * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might
|
---|
555 | * grow or shrink entryStore.
|
---|
556 | *
|
---|
557 | * If your enumerator wants to remove certain entries, but set aside pointers
|
---|
558 | * to other entries that it retains, it can use PL_DHashTableRawRemove on the
|
---|
559 | * entries to be removed, returning PL_DHASH_NEXT to skip them. Likewise, if
|
---|
560 | * you want to remove entries, but for some reason you do not want entryStore
|
---|
561 | * to be shrunk or compressed, you can call PL_DHashTableRawRemove safely on
|
---|
562 | * the entry being enumerated, rather than returning PL_DHASH_REMOVE.
|
---|
563 | */
|
---|
564 | typedef PLDHashOperator
|
---|
565 | (* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
---|
566 | PRUint32 number, void *arg);
|
---|
567 |
|
---|
568 | PR_EXTERN(PRUint32)
|
---|
569 | PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg);
|
---|
570 |
|
---|
571 | #ifdef PL_DHASHMETER
|
---|
572 | #include <stdio.h>
|
---|
573 |
|
---|
574 | PR_EXTERN(void)
|
---|
575 | PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp);
|
---|
576 | #endif
|
---|
577 |
|
---|
578 | PR_END_EXTERN_C
|
---|
579 |
|
---|
580 | #endif /* pldhash_h___ */
|
---|