1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/pldhash.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,586 @@ 1.4 +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef pldhash_h___ 1.10 +#define pldhash_h___ 1.11 +/* 1.12 + * Double hashing, a la Knuth 6. 1.13 + */ 1.14 +#include "mozilla/fallible.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "mozilla/Types.h" 1.17 +#include "nscore.h" 1.18 + 1.19 +#if defined(__GNUC__) && defined(__i386__) 1.20 +#define PL_DHASH_FASTCALL __attribute__ ((regparm (3),stdcall)) 1.21 +#elif defined(XP_WIN) 1.22 +#define PL_DHASH_FASTCALL __fastcall 1.23 +#else 1.24 +#define PL_DHASH_FASTCALL 1.25 +#endif 1.26 + 1.27 +/* 1.28 + * Table size limit; do not exceed. The max capacity used to be 1<<23 but that 1.29 + * occasionally that wasn't enough. Making it much bigger than 1<<26 probably 1.30 + * isn't worthwhile -- tables that big are kind of ridiculous. Also, the 1.31 + * growth operation will (deliberately) fail if |capacity * entrySize| 1.32 + * overflows a uint32_t, and entrySize is always at least 8 bytes. 1.33 + */ 1.34 +#undef PL_DHASH_MAX_SIZE 1.35 +#define PL_DHASH_MAX_SIZE ((uint32_t)1 << 26) 1.36 + 1.37 +/* Minimum table size, or gross entry count (net is at most .75 loaded). */ 1.38 +#ifndef PL_DHASH_MIN_SIZE 1.39 +#define PL_DHASH_MIN_SIZE 16 1.40 +#elif (PL_DHASH_MIN_SIZE & (PL_DHASH_MIN_SIZE - 1)) != 0 1.41 +#error "PL_DHASH_MIN_SIZE must be a power of two!" 1.42 +#endif 1.43 + 1.44 +/* 1.45 + * Multiplicative hash uses an unsigned 32 bit integer and the golden ratio, 1.46 + * expressed as a fixed-point 32-bit fraction. 1.47 + */ 1.48 +#define PL_DHASH_BITS 32 1.49 +#define PL_DHASH_GOLDEN_RATIO 0x9E3779B9U 1.50 + 1.51 +/* Primitive and forward-struct typedefs. */ 1.52 +typedef uint32_t PLDHashNumber; 1.53 +typedef struct PLDHashEntryHdr PLDHashEntryHdr; 1.54 +typedef struct PLDHashEntryStub PLDHashEntryStub; 1.55 +typedef struct PLDHashTable PLDHashTable; 1.56 +typedef struct PLDHashTableOps PLDHashTableOps; 1.57 + 1.58 +/* 1.59 + * Table entry header structure. 1.60 + * 1.61 + * In order to allow in-line allocation of key and value, we do not declare 1.62 + * either here. Instead, the API uses const void *key as a formal parameter. 1.63 + * The key need not be stored in the entry; it may be part of the value, but 1.64 + * need not be stored at all. 1.65 + * 1.66 + * Callback types are defined below and grouped into the PLDHashTableOps 1.67 + * structure, for single static initialization per hash table sub-type. 1.68 + * 1.69 + * Each hash table sub-type should nest the PLDHashEntryHdr structure at the 1.70 + * front of its particular entry type. The keyHash member contains the result 1.71 + * of multiplying the hash code returned from the hashKey callback (see below) 1.72 + * by PL_DHASH_GOLDEN_RATIO, then constraining the result to avoid the magic 0 1.73 + * and 1 values. The stored keyHash value is table size invariant, and it is 1.74 + * maintained automatically by PL_DHashTableOperate -- users should never set 1.75 + * it, and its only uses should be via the entry macros below. 1.76 + * 1.77 + * The PL_DHASH_ENTRY_IS_LIVE function tests whether entry is neither free nor 1.78 + * removed. An entry may be either busy or free; if busy, it may be live or 1.79 + * removed. Consumers of this API should not access members of entries that 1.80 + * are not live. 1.81 + * 1.82 + * However, use PL_DHASH_ENTRY_IS_BUSY for faster liveness testing of entries 1.83 + * returned by PL_DHashTableOperate, as PL_DHashTableOperate never returns a 1.84 + * non-live, busy (i.e., removed) entry pointer to its caller. See below for 1.85 + * more details on PL_DHashTableOperate's calling rules. 1.86 + */ 1.87 +struct PLDHashEntryHdr { 1.88 + PLDHashNumber keyHash; /* every entry must begin like this */ 1.89 +}; 1.90 + 1.91 +MOZ_ALWAYS_INLINE bool 1.92 +PL_DHASH_ENTRY_IS_FREE(PLDHashEntryHdr* entry) 1.93 +{ 1.94 + return entry->keyHash == 0; 1.95 +} 1.96 + 1.97 +MOZ_ALWAYS_INLINE bool 1.98 +PL_DHASH_ENTRY_IS_BUSY(PLDHashEntryHdr* entry) 1.99 +{ 1.100 + return !PL_DHASH_ENTRY_IS_FREE(entry); 1.101 +} 1.102 + 1.103 +MOZ_ALWAYS_INLINE bool 1.104 +PL_DHASH_ENTRY_IS_LIVE(PLDHashEntryHdr* entry) 1.105 +{ 1.106 + return entry->keyHash >= 2; 1.107 +} 1.108 + 1.109 +/* 1.110 + * A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead) 1.111 + * on most architectures, and may be allocated on the stack or within another 1.112 + * structure or class (see below for the Init and Finish functions to use). 1.113 + * 1.114 + * To decide whether to use double hashing vs. chaining, we need to develop a 1.115 + * trade-off relation, as follows: 1.116 + * 1.117 + * Let alpha be the load factor, esize the entry size in words, count the 1.118 + * entry count, and pow2 the power-of-two table size in entries. 1.119 + * 1.120 + * (PLDHashTable overhead) > (PLHashTable overhead) 1.121 + * (unused table entry space) > (malloc and .next overhead per entry) + 1.122 + * (buckets overhead) 1.123 + * (1 - alpha) * esize * pow2 > 2 * count + pow2 1.124 + * 1.125 + * Notice that alpha is by definition (count / pow2): 1.126 + * 1.127 + * (1 - alpha) * esize * pow2 > 2 * alpha * pow2 + pow2 1.128 + * (1 - alpha) * esize > 2 * alpha + 1 1.129 + * 1.130 + * esize > (1 + 2 * alpha) / (1 - alpha) 1.131 + * 1.132 + * This assumes both tables must keep keyHash, key, and value for each entry, 1.133 + * where key and value point to separately allocated strings or structures. 1.134 + * If key and value can be combined into one pointer, then the trade-off is: 1.135 + * 1.136 + * esize > (1 + 3 * alpha) / (1 - alpha) 1.137 + * 1.138 + * If the entry value can be a subtype of PLDHashEntryHdr, rather than a type 1.139 + * that must be allocated separately and referenced by an entry.value pointer 1.140 + * member, and provided key's allocation can be fused with its entry's, then 1.141 + * k (the words wasted per entry with chaining) is 4. 1.142 + * 1.143 + * To see these curves, feed gnuplot input like so: 1.144 + * 1.145 + * gnuplot> f(x,k) = (1 + k * x) / (1 - x) 1.146 + * gnuplot> plot [0:.75] f(x,2), f(x,3), f(x,4) 1.147 + * 1.148 + * For k of 2 and a well-loaded table (alpha > .5), esize must be more than 4 1.149 + * words for chaining to be more space-efficient than double hashing. 1.150 + * 1.151 + * Solving for alpha helps us decide when to shrink an underloaded table: 1.152 + * 1.153 + * esize > (1 + k * alpha) / (1 - alpha) 1.154 + * esize - alpha * esize > 1 + k * alpha 1.155 + * esize - 1 > (k + esize) * alpha 1.156 + * (esize - 1) / (k + esize) > alpha 1.157 + * 1.158 + * alpha < (esize - 1) / (esize + k) 1.159 + * 1.160 + * Therefore double hashing should keep alpha >= (esize - 1) / (esize + k), 1.161 + * assuming esize is not too large (in which case, chaining should probably be 1.162 + * used for any alpha). For esize=2 and k=3, we want alpha >= .2; for esize=3 1.163 + * and k=2, we want alpha >= .4. For k=4, esize could be 6, and alpha >= .5 1.164 + * would still obtain. 1.165 + * 1.166 + * The current implementation uses a configurable lower bound on alpha, which 1.167 + * defaults to .25, when deciding to shrink the table (while still respecting 1.168 + * PL_DHASH_MIN_SIZE). 1.169 + * 1.170 + * Note a qualitative difference between chaining and double hashing: under 1.171 + * chaining, entry addresses are stable across table shrinks and grows. With 1.172 + * double hashing, you can't safely hold an entry pointer and use it after an 1.173 + * ADD or REMOVE operation, unless you sample table->generation before adding 1.174 + * or removing, and compare the sample after, dereferencing the entry pointer 1.175 + * only if table->generation has not changed. 1.176 + * 1.177 + * The moral of this story: there is no one-size-fits-all hash table scheme, 1.178 + * but for small table entry size, and assuming entry address stability is not 1.179 + * required, double hashing wins. 1.180 + */ 1.181 +struct PLDHashTable { 1.182 + const PLDHashTableOps *ops; /* virtual operations, see below */ 1.183 + void *data; /* ops- and instance-specific data */ 1.184 + int16_t hashShift; /* multiplicative hash shift */ 1.185 + /* 1.186 + * |recursionLevel| is only used in debug builds, but is present in opt 1.187 + * builds to avoid binary compatibility problems when mixing DEBUG and 1.188 + * non-DEBUG components. (Actually, even if it were removed, 1.189 + * sizeof(PLDHashTable) wouldn't change, due to struct padding.) 1.190 + */ 1.191 + uint16_t recursionLevel; /* used to detect unsafe re-entry */ 1.192 + uint32_t entrySize; /* number of bytes in an entry */ 1.193 + uint32_t entryCount; /* number of entries in table */ 1.194 + uint32_t removedCount; /* removed entry sentinels in table */ 1.195 + uint32_t generation; /* entry storage generation number */ 1.196 + char *entryStore; /* entry storage */ 1.197 +#ifdef PL_DHASHMETER 1.198 + struct PLDHashStats { 1.199 + uint32_t searches; /* total number of table searches */ 1.200 + uint32_t steps; /* hash chain links traversed */ 1.201 + uint32_t hits; /* searches that found key */ 1.202 + uint32_t misses; /* searches that didn't find key */ 1.203 + uint32_t lookups; /* number of PL_DHASH_LOOKUPs */ 1.204 + uint32_t addMisses; /* adds that miss, and do work */ 1.205 + uint32_t addOverRemoved; /* adds that recycled a removed entry */ 1.206 + uint32_t addHits; /* adds that hit an existing entry */ 1.207 + uint32_t addFailures; /* out-of-memory during add growth */ 1.208 + uint32_t removeHits; /* removes that hit, and do work */ 1.209 + uint32_t removeMisses; /* useless removes that miss */ 1.210 + uint32_t removeFrees; /* removes that freed entry directly */ 1.211 + uint32_t removeEnums; /* removes done by Enumerate */ 1.212 + uint32_t grows; /* table expansions */ 1.213 + uint32_t shrinks; /* table contractions */ 1.214 + uint32_t compresses; /* table compressions */ 1.215 + uint32_t enumShrinks; /* contractions after Enumerate */ 1.216 + } stats; 1.217 +#endif 1.218 +}; 1.219 + 1.220 +/* 1.221 + * Size in entries (gross, not net of free and removed sentinels) for table. 1.222 + * We store hashShift rather than sizeLog2 to optimize the collision-free case 1.223 + * in SearchTable. 1.224 + */ 1.225 +#define PL_DHASH_TABLE_SIZE(table) \ 1.226 + ((uint32_t)1 << (PL_DHASH_BITS - (table)->hashShift)) 1.227 + 1.228 +/* 1.229 + * Table space at entryStore is allocated and freed using these callbacks. 1.230 + * The allocator should return null on error only (not if called with nbytes 1.231 + * equal to 0; but note that pldhash.c code will never call with 0 nbytes). 1.232 + */ 1.233 +typedef void * 1.234 +(* PLDHashAllocTable)(PLDHashTable *table, uint32_t nbytes); 1.235 + 1.236 +typedef void 1.237 +(* PLDHashFreeTable) (PLDHashTable *table, void *ptr); 1.238 + 1.239 +/* 1.240 + * Compute the hash code for a given key to be looked up, added, or removed 1.241 + * from table. A hash code may have any PLDHashNumber value. 1.242 + */ 1.243 +typedef PLDHashNumber 1.244 +(* PLDHashHashKey) (PLDHashTable *table, const void *key); 1.245 + 1.246 +/* 1.247 + * Compare the key identifying entry in table with the provided key parameter. 1.248 + * Return true if keys match, false otherwise. 1.249 + */ 1.250 +typedef bool 1.251 +(* PLDHashMatchEntry)(PLDHashTable *table, const PLDHashEntryHdr *entry, 1.252 + const void *key); 1.253 + 1.254 +/* 1.255 + * Copy the data starting at from to the new entry storage at to. Do not add 1.256 + * reference counts for any strong references in the entry, however, as this 1.257 + * is a "move" operation: the old entry storage at from will be freed without 1.258 + * any reference-decrementing callback shortly. 1.259 + */ 1.260 +typedef void 1.261 +(* PLDHashMoveEntry)(PLDHashTable *table, const PLDHashEntryHdr *from, 1.262 + PLDHashEntryHdr *to); 1.263 + 1.264 +/* 1.265 + * Clear the entry and drop any strong references it holds. This callback is 1.266 + * invoked during a PL_DHASH_REMOVE operation (see below for operation codes), 1.267 + * but only if the given key is found in the table. 1.268 + */ 1.269 +typedef void 1.270 +(* PLDHashClearEntry)(PLDHashTable *table, PLDHashEntryHdr *entry); 1.271 + 1.272 +/* 1.273 + * Called when a table (whether allocated dynamically by itself, or nested in 1.274 + * a larger structure, or allocated on the stack) is finished. This callback 1.275 + * allows table->ops-specific code to finalize table->data. 1.276 + */ 1.277 +typedef void 1.278 +(* PLDHashFinalize) (PLDHashTable *table); 1.279 + 1.280 +/* 1.281 + * Initialize a new entry, apart from keyHash. This function is called when 1.282 + * PL_DHashTableOperate's PL_DHASH_ADD case finds no existing entry for the 1.283 + * given key, and must add a new one. At that point, entry->keyHash is not 1.284 + * set yet, to avoid claiming the last free entry in a severely overloaded 1.285 + * table. 1.286 + */ 1.287 +typedef bool 1.288 +(* PLDHashInitEntry)(PLDHashTable *table, PLDHashEntryHdr *entry, 1.289 + const void *key); 1.290 + 1.291 +/* 1.292 + * Finally, the "vtable" structure for PLDHashTable. The first eight hooks 1.293 + * must be provided by implementations; they're called unconditionally by the 1.294 + * generic pldhash.c code. Hooks after these may be null. 1.295 + * 1.296 + * Summary of allocation-related hook usage with C++ placement new emphasis: 1.297 + * allocTable Allocate raw bytes with malloc, no ctors run. 1.298 + * freeTable Free raw bytes with free, no dtors run. 1.299 + * initEntry Call placement new using default key-based ctor. 1.300 + * Return true on success, false on error. 1.301 + * moveEntry Call placement new using copy ctor, run dtor on old 1.302 + * entry storage. 1.303 + * clearEntry Run dtor on entry. 1.304 + * finalize Stub unless table->data was initialized and needs to 1.305 + * be finalized. 1.306 + * 1.307 + * Note the reason why initEntry is optional: the default hooks (stubs) clear 1.308 + * entry storage: On successful PL_DHashTableOperate(tbl, key, PL_DHASH_ADD), 1.309 + * the returned entry pointer addresses an entry struct whose keyHash member 1.310 + * has been set non-zero, but all other entry members are still clear (null). 1.311 + * PL_DHASH_ADD callers can test such members to see whether the entry was 1.312 + * newly created by the PL_DHASH_ADD call that just succeeded. If placement 1.313 + * new or similar initialization is required, define an initEntry hook. Of 1.314 + * course, the clearEntry hook must zero or null appropriately. 1.315 + * 1.316 + * XXX assumes 0 is null for pointer types. 1.317 + */ 1.318 +struct PLDHashTableOps { 1.319 + /* Mandatory hooks. All implementations must provide these. */ 1.320 + PLDHashAllocTable allocTable; 1.321 + PLDHashFreeTable freeTable; 1.322 + PLDHashHashKey hashKey; 1.323 + PLDHashMatchEntry matchEntry; 1.324 + PLDHashMoveEntry moveEntry; 1.325 + PLDHashClearEntry clearEntry; 1.326 + PLDHashFinalize finalize; 1.327 + 1.328 + /* Optional hooks start here. If null, these are not called. */ 1.329 + PLDHashInitEntry initEntry; 1.330 +}; 1.331 + 1.332 +/* 1.333 + * Default implementations for the above ops. 1.334 + */ 1.335 +NS_COM_GLUE void * 1.336 +PL_DHashAllocTable(PLDHashTable *table, uint32_t nbytes); 1.337 + 1.338 +NS_COM_GLUE void 1.339 +PL_DHashFreeTable(PLDHashTable *table, void *ptr); 1.340 + 1.341 +NS_COM_GLUE PLDHashNumber 1.342 +PL_DHashStringKey(PLDHashTable *table, const void *key); 1.343 + 1.344 +/* A minimal entry contains a keyHash header and a void key pointer. */ 1.345 +struct PLDHashEntryStub { 1.346 + PLDHashEntryHdr hdr; 1.347 + const void *key; 1.348 +}; 1.349 + 1.350 +NS_COM_GLUE PLDHashNumber 1.351 +PL_DHashVoidPtrKeyStub(PLDHashTable *table, const void *key); 1.352 + 1.353 +NS_COM_GLUE bool 1.354 +PL_DHashMatchEntryStub(PLDHashTable *table, 1.355 + const PLDHashEntryHdr *entry, 1.356 + const void *key); 1.357 + 1.358 +NS_COM_GLUE bool 1.359 +PL_DHashMatchStringKey(PLDHashTable *table, 1.360 + const PLDHashEntryHdr *entry, 1.361 + const void *key); 1.362 + 1.363 +NS_COM_GLUE void 1.364 +PL_DHashMoveEntryStub(PLDHashTable *table, 1.365 + const PLDHashEntryHdr *from, 1.366 + PLDHashEntryHdr *to); 1.367 + 1.368 +NS_COM_GLUE void 1.369 +PL_DHashClearEntryStub(PLDHashTable *table, PLDHashEntryHdr *entry); 1.370 + 1.371 +NS_COM_GLUE void 1.372 +PL_DHashFreeStringKey(PLDHashTable *table, PLDHashEntryHdr *entry); 1.373 + 1.374 +NS_COM_GLUE void 1.375 +PL_DHashFinalizeStub(PLDHashTable *table); 1.376 + 1.377 +/* 1.378 + * If you use PLDHashEntryStub or a subclass of it as your entry struct, and 1.379 + * if your entries move via memcpy and clear via memset(0), you can use these 1.380 + * stub operations. 1.381 + */ 1.382 +NS_COM_GLUE const PLDHashTableOps * 1.383 +PL_DHashGetStubOps(void); 1.384 + 1.385 +/* 1.386 + * Dynamically allocate a new PLDHashTable using malloc, initialize it using 1.387 + * PL_DHashTableInit, and return its address. Return null on malloc failure. 1.388 + * Note that the entry storage at table->entryStore will be allocated using 1.389 + * the ops->allocTable callback. 1.390 + */ 1.391 +NS_COM_GLUE PLDHashTable * 1.392 +PL_NewDHashTable(const PLDHashTableOps *ops, void *data, uint32_t entrySize, 1.393 + uint32_t capacity); 1.394 + 1.395 +/* 1.396 + * Finalize table's data, free its entry storage (via table->ops->freeTable), 1.397 + * and return the memory starting at table to the malloc heap. 1.398 + */ 1.399 +NS_COM_GLUE void 1.400 +PL_DHashTableDestroy(PLDHashTable *table); 1.401 + 1.402 +/* 1.403 + * Initialize table with ops, data, entrySize, and capacity. Capacity is a 1.404 + * guess for the smallest table size at which the table will usually be less 1.405 + * than 75% loaded (the table will grow or shrink as needed; capacity serves 1.406 + * only to avoid inevitable early growth from PL_DHASH_MIN_SIZE). This will 1.407 + * crash if it can't allocate enough memory, or if entrySize or capacity are 1.408 + * too large. 1.409 + */ 1.410 +NS_COM_GLUE void 1.411 +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, 1.412 + uint32_t entrySize, uint32_t capacity); 1.413 + 1.414 +/* 1.415 + * Initialize table. This is the same as PL_DHashTableInit, except that it 1.416 + * returns a boolean indicating success, rather than crashing on failure. 1.417 + */ 1.418 +NS_COM_GLUE bool 1.419 +PL_DHashTableInit(PLDHashTable *table, const PLDHashTableOps *ops, void *data, 1.420 + uint32_t entrySize, uint32_t capacity, 1.421 + const mozilla::fallible_t& ) MOZ_WARN_UNUSED_RESULT; 1.422 + 1.423 +/* 1.424 + * Finalize table's data, free its entry storage using table->ops->freeTable, 1.425 + * and leave its members unchanged from their last live values (which leaves 1.426 + * pointers dangling). If you want to burn cycles clearing table, it's up to 1.427 + * your code to call memset. 1.428 + */ 1.429 +NS_COM_GLUE void 1.430 +PL_DHashTableFinish(PLDHashTable *table); 1.431 + 1.432 +/* 1.433 + * To consolidate keyHash computation and table grow/shrink code, we use a 1.434 + * single entry point for lookup, add, and remove operations. The operation 1.435 + * codes are declared here, along with codes returned by PLDHashEnumerator 1.436 + * functions, which control PL_DHashTableEnumerate's behavior. 1.437 + */ 1.438 +typedef enum PLDHashOperator { 1.439 + PL_DHASH_LOOKUP = 0, /* lookup entry */ 1.440 + PL_DHASH_ADD = 1, /* add entry */ 1.441 + PL_DHASH_REMOVE = 2, /* remove entry, or enumerator says remove */ 1.442 + PL_DHASH_NEXT = 0, /* enumerator says continue */ 1.443 + PL_DHASH_STOP = 1 /* enumerator says stop */ 1.444 +} PLDHashOperator; 1.445 + 1.446 +/* 1.447 + * To lookup a key in table, call: 1.448 + * 1.449 + * entry = PL_DHashTableOperate(table, key, PL_DHASH_LOOKUP); 1.450 + * 1.451 + * If PL_DHASH_ENTRY_IS_BUSY(entry) is true, key was found and it identifies 1.452 + * entry. If PL_DHASH_ENTRY_IS_FREE(entry) is true, key was not found. 1.453 + * 1.454 + * To add an entry identified by key to table, call: 1.455 + * 1.456 + * entry = PL_DHashTableOperate(table, key, PL_DHASH_ADD); 1.457 + * 1.458 + * If entry is null upon return, then either the table is severely overloaded, 1.459 + * and memory can't be allocated for entry storage via table->ops->allocTable; 1.460 + * Or if table->ops->initEntry is non-null, the table->ops->initEntry op may 1.461 + * have returned false. 1.462 + * 1.463 + * Otherwise, entry->keyHash has been set so that PL_DHASH_ENTRY_IS_BUSY(entry) 1.464 + * is true, and it is up to the caller to initialize the key and value parts 1.465 + * of the entry sub-type, if they have not been set already (i.e. if entry was 1.466 + * not already in the table, and if the optional initEntry hook was not used). 1.467 + * 1.468 + * To remove an entry identified by key from table, call: 1.469 + * 1.470 + * (void) PL_DHashTableOperate(table, key, PL_DHASH_REMOVE); 1.471 + * 1.472 + * If key's entry is found, it is cleared (via table->ops->clearEntry) and 1.473 + * the entry is marked so that PL_DHASH_ENTRY_IS_FREE(entry). This operation 1.474 + * returns null unconditionally; you should ignore its return value. 1.475 + */ 1.476 +NS_COM_GLUE PLDHashEntryHdr * PL_DHASH_FASTCALL 1.477 +PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op); 1.478 + 1.479 +/* 1.480 + * Remove an entry already accessed via LOOKUP or ADD. 1.481 + * 1.482 + * NB: this is a "raw" or low-level routine, intended to be used only where 1.483 + * the inefficiency of a full PL_DHashTableOperate (which rehashes in order 1.484 + * to find the entry given its key) is not tolerable. This function does not 1.485 + * shrink the table if it is underloaded. It does not update stats #ifdef 1.486 + * PL_DHASHMETER, either. 1.487 + */ 1.488 +NS_COM_GLUE void 1.489 +PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry); 1.490 + 1.491 +/* 1.492 + * Enumerate entries in table using etor: 1.493 + * 1.494 + * count = PL_DHashTableEnumerate(table, etor, arg); 1.495 + * 1.496 + * PL_DHashTableEnumerate calls etor like so: 1.497 + * 1.498 + * op = etor(table, entry, number, arg); 1.499 + * 1.500 + * where number is a zero-based ordinal assigned to live entries according to 1.501 + * their order in table->entryStore. 1.502 + * 1.503 + * The return value, op, is treated as a set of flags. If op is PL_DHASH_NEXT, 1.504 + * then continue enumerating. If op contains PL_DHASH_REMOVE, then clear (via 1.505 + * table->ops->clearEntry) and free entry. Then we check whether op contains 1.506 + * PL_DHASH_STOP; if so, stop enumerating and return the number of live entries 1.507 + * that were enumerated so far. Return the total number of live entries when 1.508 + * enumeration completes normally. 1.509 + * 1.510 + * If etor calls PL_DHashTableOperate on table with op != PL_DHASH_LOOKUP, it 1.511 + * must return PL_DHASH_STOP; otherwise undefined behavior results. 1.512 + * 1.513 + * If any enumerator returns PL_DHASH_REMOVE, table->entryStore may be shrunk 1.514 + * or compressed after enumeration, but before PL_DHashTableEnumerate returns. 1.515 + * Such an enumerator therefore can't safely set aside entry pointers, but an 1.516 + * enumerator that never returns PL_DHASH_REMOVE can set pointers to entries 1.517 + * aside, e.g., to avoid copying live entries into an array of the entry type. 1.518 + * Copying entry pointers is cheaper, and safe so long as the caller of such a 1.519 + * "stable" Enumerate doesn't use the set-aside pointers after any call either 1.520 + * to PL_DHashTableOperate, or to an "unstable" form of Enumerate, which might 1.521 + * grow or shrink entryStore. 1.522 + * 1.523 + * If your enumerator wants to remove certain entries, but set aside pointers 1.524 + * to other entries that it retains, it can use PL_DHashTableRawRemove on the 1.525 + * entries to be removed, returning PL_DHASH_NEXT to skip them. Likewise, if 1.526 + * you want to remove entries, but for some reason you do not want entryStore 1.527 + * to be shrunk or compressed, you can call PL_DHashTableRawRemove safely on 1.528 + * the entry being enumerated, rather than returning PL_DHASH_REMOVE. 1.529 + */ 1.530 +typedef PLDHashOperator 1.531 +(* PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number, 1.532 + void *arg); 1.533 + 1.534 +NS_COM_GLUE uint32_t 1.535 +PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg); 1.536 + 1.537 +typedef size_t 1.538 +(* PLDHashSizeOfEntryExcludingThisFun)(PLDHashEntryHdr *hdr, 1.539 + mozilla::MallocSizeOf mallocSizeOf, 1.540 + void *arg); 1.541 + 1.542 +/** 1.543 + * Measure the size of the table's entry storage, and if 1.544 + * |sizeOfEntryExcludingThis| is non-nullptr, measure the size of things 1.545 + * pointed to by entries. Doesn't measure |ops| because it's often shared 1.546 + * between tables, nor |data| because it's opaque. 1.547 + */ 1.548 +NS_COM_GLUE size_t 1.549 +PL_DHashTableSizeOfExcludingThis(const PLDHashTable *table, 1.550 + PLDHashSizeOfEntryExcludingThisFun sizeOfEntryExcludingThis, 1.551 + mozilla::MallocSizeOf mallocSizeOf, 1.552 + void *arg = nullptr); 1.553 + 1.554 +/** 1.555 + * Like PL_DHashTableSizeOfExcludingThis, but includes sizeof(*this). 1.556 + */ 1.557 +NS_COM_GLUE size_t 1.558 +PL_DHashTableSizeOfIncludingThis(const PLDHashTable *table, 1.559 + PLDHashSizeOfEntryExcludingThisFun sizeOfEntryExcludingThis, 1.560 + mozilla::MallocSizeOf mallocSizeOf, 1.561 + void *arg = nullptr); 1.562 + 1.563 +#ifdef DEBUG 1.564 +/** 1.565 + * Mark a table as immutable for the remainder of its lifetime. This 1.566 + * changes the implementation from ASSERTing one set of invariants to 1.567 + * ASSERTing a different set. 1.568 + * 1.569 + * When a table is NOT marked as immutable, the table implementation 1.570 + * asserts that the table is not mutated from its own callbacks. It 1.571 + * assumes the caller protects the table from being accessed on multiple 1.572 + * threads simultaneously. 1.573 + * 1.574 + * When the table is marked as immutable, the re-entry assertions will 1.575 + * no longer trigger erroneously due to multi-threaded access. Instead, 1.576 + * mutations will cause assertions. 1.577 + */ 1.578 +NS_COM_GLUE void 1.579 +PL_DHashMarkTableImmutable(PLDHashTable *table); 1.580 +#endif 1.581 + 1.582 +#ifdef PL_DHASHMETER 1.583 +#include <stdio.h> 1.584 + 1.585 +NS_COM_GLUE void 1.586 +PL_DHashTableDumpMeter(PLDHashTable *table, PLDHashEnumerator dump, FILE *fp); 1.587 +#endif 1.588 + 1.589 +#endif /* pldhash_h___ */