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