Add optional JSDHashTableOps.initEntry hook, spruce up comments (74883, r=waterson, sr=shaver).

This commit is contained in:
brendan%mozilla.org 2001-05-15 21:07:10 +00:00
Родитель ac5cbe4720
Коммит 3de6d8412c
6 изменённых файлов: 162 добавлений и 65 удалений

Просмотреть файл

@ -14,13 +14,12 @@
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999,2000 Netscape Communications Corporation.
* Copyright (C) 1999-2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Original Contributor:
* Brendan Eich <brendan@mozilla.org>
*
* Contributor(s):
* Contributor(s):
* Brendan Eich <brendan@mozilla.org> (Original Author)
* Chris Waterson <waterson@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -78,7 +77,7 @@ JS_PUBLIC_API(const void *)
JS_DHashGetKeyStub(JSDHashTable *table, JSDHashEntryHdr *entry)
{
JSDHashEntryStub *stub = (JSDHashEntryStub *)entry;
return stub->key;
}
@ -125,7 +124,8 @@ static JSDHashTableOps stub_ops = {
JS_DHashMatchEntryStub,
JS_DHashMoveEntryStub,
JS_DHashClearEntryStub,
JS_DHashFinalizeStub
JS_DHashFinalizeStub,
NULL
};
JS_PUBLIC_API(JSDHashTableOps *)
@ -206,7 +206,7 @@ JS_DHashTableInit(JSDHashTable *table, JSDHashTableOps *ops, void *data,
/* Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. */
#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0)
#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1)
#define ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2)
#define ENTRY_IS_LIVE(entry) JS_DHASH_ENTRY_IS_LIVE(entry)
#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0
/* Compute the address of the indexed entry in table. */
@ -218,7 +218,9 @@ JS_DHashTableFinish(JSDHashTable *table)
{
char *entryAddr, *entryLimit;
uint32 entrySize;
JSDHashEntryHdr *entry;
/* Call finalize before clearing entries. */
table->ops->finalize(table);
/* Clear any remaining live entries. */
@ -226,15 +228,15 @@ JS_DHashTableFinish(JSDHashTable *table)
entrySize = table->entrySize;
entryLimit = entryAddr + JS_BIT(table->sizeLog2) * entrySize;
while (entryAddr < entryLimit) {
JSDHashEntryHdr *entry = (JSDHashEntryHdr *)entryAddr;
entry = (JSDHashEntryHdr *)entryAddr;
if (ENTRY_IS_LIVE(entry)) {
METER(table->stats.removeEnums++);
table->ops->clearEntry(table, entry);
}
entryAddr += entrySize;
}
/* Free entry storage last. */
table->ops->freeTable(table, table->entryStore);
}
@ -284,7 +286,7 @@ SearchTable(JSDHashTable *table, const void *key, JSDHashNumber keyHash)
}
static JSBool
ChangeTable(JSDHashTable *table, int deltaLog2, JSDHashEntryHdr *skipEntry)
ChangeTable(JSDHashTable *table, int deltaLog2, JSDHashEntryHdr **findEntry)
{
int oldLog2, newLog2;
uint32 oldCapacity, newCapacity;
@ -306,26 +308,30 @@ ChangeTable(JSDHashTable *table, int deltaLog2, JSDHashEntryHdr *skipEntry)
if (!newEntryStore)
return JS_FALSE;
/* We can't fail from here on, so update table parameters. */
table->hashShift = JS_DHASH_BITS - newLog2;
table->sizeLog2 = newLog2;
table->sizeMask = JS_BITMASK(newLog2);
table->removedCount = 0;
/* Assign the new entry store to table. */
memset(newEntryStore, 0, nbytes);
oldEntryAddr = oldEntryStore = table->entryStore;
table->entryStore = newEntryStore;
getKey = table->ops->getKey;
moveEntry = table->ops->moveEntry;
/* Copy only live entries, leaving removed ones (and skipEntry) behind. */
/* Copy only live entries, leaving removed ones behind. */
for (i = 0; i < oldCapacity; i++) {
oldEntry = (JSDHashEntryHdr *)oldEntryAddr;
if (oldEntry != skipEntry && ENTRY_IS_LIVE(oldEntry)) {
if (ENTRY_IS_LIVE(oldEntry)) {
newEntry = SearchTable(table, getKey(table, oldEntry),
oldEntry->keyHash);
JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(newEntry));
moveEntry(table, oldEntry, newEntry);
newEntry->keyHash = oldEntry->keyHash;
if (findEntry && *findEntry == oldEntry)
*findEntry = newEntry;
}
oldEntryAddr += entrySize;
}
@ -366,6 +372,8 @@ JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
if (JS_DHASH_ENTRY_IS_FREE(entry)) {
/* Initialize the entry, indicating that it's no longer free. */
METER(table->stats.addMisses++);
if (table->ops->initEntry)
table->ops->initEntry(table, entry, key);
entry->keyHash = keyHash;
table->entryCount++;
@ -406,22 +414,17 @@ JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
}
if (biasedDeltaLog2) {
if (!ChangeTable(table, biasedDeltaLog2 - DELTA_LOG2_BIAS, entry)) {
/* Grow, compress, or shrink table, keeping entry valid if non-null. */
if (!ChangeTable(table, biasedDeltaLog2 - DELTA_LOG2_BIAS, &entry)) {
/* If we just grabbed the last free entry, undo and fail hard. */
if (op == JS_DHASH_ADD &&
table->entryCount + table->removedCount == size) {
METER(table->stats.addFailures++);
table->ops->clearEntry(table, entry);
MARK_ENTRY_FREE(entry);
table->entryCount--;
entry = NULL;
}
} else {
if (op == JS_DHASH_ADD) {
/* If the table grew, add the new (skipped) entry. */
entry = SearchTable(table, key, keyHash);
JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(entry));
entry->keyHash = keyHash;
}
}
}

Просмотреть файл

@ -14,13 +14,11 @@
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999,2000 Netscape Communications Corporation.
* Copyright (C) 1999-2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Original Contributor:
* Brendan Eich <brendan@mozilla.org>
*
* Contributor(s):
* Brendan Eich <brendan@mozilla.org> (Original Author)
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -78,6 +76,11 @@ typedef struct JSDHashTableOps JSDHashTableOps;
* by JS_DHASH_GOLDEN_RATIO. Its value is table size invariant. keyHash is
* maintained automatically by JS_DHashTableOperate -- users should never set
* it, and its only uses should be via the entry macros below.
*
* The JS_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor
* removed. An entry may be either busy or free; if busy, it may be live or
* removed. Consumers of this API should not access members of entries that
* are not live.
*/
struct JSDHashEntryHdr {
JSDHashNumber keyHash; /* every entry must begin like this */
@ -85,6 +88,7 @@ struct JSDHashEntryHdr {
#define JS_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0)
#define JS_DHASH_ENTRY_IS_BUSY(entry) (!JS_DHASH_ENTRY_IS_FREE(entry))
#define JS_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2)
/*
* A JSDHashTable is currently 8 words (without the JS_DHASHMETER overhead)
@ -239,7 +243,8 @@ typedef void
* but only if the given key is found in the table.
*/
typedef void
(* JS_DLL_CALLBACK JSDHashClearEntry)(JSDHashTable *table, JSDHashEntryHdr *entry);
(* JS_DLL_CALLBACK JSDHashClearEntry)(JSDHashTable *table,
JSDHashEntryHdr *entry);
/*
* Called when a table (whether allocated dynamically by itself, or nested in
@ -249,8 +254,44 @@ typedef void
typedef void
(* JS_DLL_CALLBACK JSDHashFinalize) (JSDHashTable *table);
/* Finally, the "vtable" structure for JSDHashTable. */
/*
* Initialize a new entry, apart from keyHash. This function is called when
* JS_DHashTableOperate's JS_DHASH_ADD case finds no existing entry for the
* given key, and must add a new one. At that point, entry->keyHash is not
* set yet, to avoid claiming the last free entry in a severely overloaded
* table.
*/
typedef void
(* JS_DLL_CALLBACK JSDHashInitEntry)(JSDHashTable *table,
const JSDHashEntryHdr *entry,
const void *key);
/*
* Finally, the "vtable" structure for JSDHashTable. The first eight hooks
* must be provided by implementations; they're called unconditionally by the
* generic jsdhash.c code. Hooks after these may be null.
*
* Summary of allocation-related hook usage with C++ placement new emphasis:
* allocTable Allocate raw bytes with malloc, no ctors run.
* freeTable Free raw bytes with free, no dtors run.
* initEntry Call placement new using default key-based ctor.
* moveEntry Call placement new using copy ctor, run dtor on old
* entry storage.
* clearEntry Run dtor on entry.
* finalize Stub unless table->data was initialized and needs to
* be finalized.
*
* Note the reason why initEntry is optional: the default hooks (stubs) clear
* entry storage: On successful JS_DHashTableOperate(tbl, key, JS_DHASH_ADD),
* the returned entry pointer addresses an entry struct whose keyHash member
* has been set non-zero, but all other entry members are still clear (null).
* JS_DHASH_ADD callers can test such members to see whether the entry was
* newly created by the JS_DHASH_ADD call that just succeeded. If placement
* new or similar initialization is required, define an initEntry hook. Of
* course, the clearEntry hook must zero or null appropriately.
*/
struct JSDHashTableOps {
/* Mandatory hooks. All implementations must provide these. */
JSDHashAllocTable allocTable;
JSDHashFreeTable freeTable;
JSDHashGetKey getKey;
@ -259,6 +300,9 @@ struct JSDHashTableOps {
JSDHashMoveEntry moveEntry;
JSDHashClearEntry clearEntry;
JSDHashFinalize finalize;
/* Optional hooks start here. If null, these are not called. */
JSDHashInitEntry initEntry;
};
/*

Просмотреть файл

@ -6,6 +6,7 @@ s/jsdhash_h___/pldhash_h___/
s/jstypes\.h/prtypes.h/
s/jsbit\.h/prbit.h/
s/jsdhash\.h/pldhash.h/
s/jsdhash\.c/pldhash.c/
s/jsdhash:/pldhash:/
s/jsutil\.h/prlog.h/
s/JS_DHASH/PL_DHASH/g
@ -25,4 +26,5 @@ s/extern JS_PUBLIC_API/PR_EXTERN/
s/JS_PUBLIC_API/PR_IMPLEMENT/
s/JS_DLL_CALLBACK/PR_CALLBACK/
s/JS_STATIC_DLL_CALLBACK/PR_STATIC_CALLBACK/
s/JS_NewDHashTable/PL_NewDHashTable/
s/JS_/PR_/g

Просмотреть файл

@ -107,7 +107,7 @@ nsresult nsMsgDatabase::AddHdrToCache(nsIMsgDBHdr *hdr, nsMsgKey key) // do we w
if (m_bCacheHeaders)
{
if (!m_cachedHeaders)
m_cachedHeaders = PR_NewDHashTable(&gMsgDBHashTableOps, (void *) nsnull, sizeof(struct MsgHdrHashElement), kMaxHdrsInCache );
m_cachedHeaders = PL_NewDHashTable(&gMsgDBHashTableOps, (void *) nsnull, sizeof(struct MsgHdrHashElement), kMaxHdrsInCache );
if (m_cachedHeaders)
{
if (key == nsMsgKey_None)
@ -217,7 +217,8 @@ PLDHashTableOps nsMsgDatabase::gMsgDBHashTableOps =
MatchEntry,
MoveEntry,
ClearEntry,
PL_DHashFinalizeStub
PL_DHashFinalizeStub,
nsnull
};
const void* PR_CALLBACK
@ -276,7 +277,7 @@ nsresult nsMsgDatabase::AddHdrToUseCache(nsIMsgDBHdr *hdr, nsMsgKey key)
mdb_count numHdrs = MSG_HASH_SIZE;
if (m_mdbAllMsgHeadersTable)
m_mdbAllMsgHeadersTable->GetCount(GetEnv(), &numHdrs);
m_headersInUse = PR_NewDHashTable(&gMsgDBHashTableOps, (void *) nsnull, sizeof(struct MsgHdrHashElement), PR_MAX(MSG_HASH_SIZE, numHdrs));
m_headersInUse = PL_NewDHashTable(&gMsgDBHashTableOps, (void *) nsnull, sizeof(struct MsgHdrHashElement), PR_MAX(MSG_HASH_SIZE, numHdrs));
}
if (m_headersInUse)
{

Просмотреть файл

@ -14,13 +14,12 @@
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999,2000 Netscape Communications Corporation.
* Copyright (C) 1999-2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Original Contributor:
* Brendan Eich <brendan@mozilla.org>
*
* Contributor(s):
* Contributor(s):
* Brendan Eich <brendan@mozilla.org> (Original Author)
* Chris Waterson <waterson@netscape.com>
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -79,7 +78,7 @@ PR_IMPLEMENT(const void *)
PL_DHashGetKeyStub(PLDHashTable *table, PLDHashEntryHdr *entry)
{
PLDHashEntryStub *stub = (PLDHashEntryStub *)entry;
return stub->key;
}
@ -126,7 +125,8 @@ static PLDHashTableOps stub_ops = {
PL_DHashMatchEntryStub,
PL_DHashMoveEntryStub,
PL_DHashClearEntryStub,
PL_DHashFinalizeStub
PL_DHashFinalizeStub,
NULL
};
PR_IMPLEMENT(PLDHashTableOps *)
@ -136,7 +136,7 @@ PL_DHashGetStubOps(void)
}
PR_IMPLEMENT(PLDHashTable *)
PR_NewDHashTable(PLDHashTableOps *ops, void *data, PRUint32 entrySize,
PL_NewDHashTable(PLDHashTableOps *ops, void *data, PRUint32 entrySize,
PRUint32 capacity)
{
PLDHashTable *table;
@ -207,7 +207,7 @@ PL_DHashTableInit(PLDHashTable *table, PLDHashTableOps *ops, void *data,
/* Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. */
#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0)
#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1)
#define ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2)
#define ENTRY_IS_LIVE(entry) PL_DHASH_ENTRY_IS_LIVE(entry)
#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0
/* Compute the address of the indexed entry in table. */
@ -219,7 +219,9 @@ PL_DHashTableFinish(PLDHashTable *table)
{
char *entryAddr, *entryLimit;
PRUint32 entrySize;
PLDHashEntryHdr *entry;
/* Call finalize before clearing entries. */
table->ops->finalize(table);
/* Clear any remaining live entries. */
@ -227,15 +229,15 @@ PL_DHashTableFinish(PLDHashTable *table)
entrySize = table->entrySize;
entryLimit = entryAddr + PR_BIT(table->sizeLog2) * entrySize;
while (entryAddr < entryLimit) {
PLDHashEntryHdr *entry = (PLDHashEntryHdr *)entryAddr;
entry = (PLDHashEntryHdr *)entryAddr;
if (ENTRY_IS_LIVE(entry)) {
METER(table->stats.removeEnums++);
table->ops->clearEntry(table, entry);
}
entryAddr += entrySize;
}
/* Free entry storage last. */
table->ops->freeTable(table, table->entryStore);
}
@ -285,7 +287,7 @@ SearchTable(PLDHashTable *table, const void *key, PLDHashNumber keyHash)
}
static PRBool
ChangeTable(PLDHashTable *table, int deltaLog2, PLDHashEntryHdr *skipEntry)
ChangeTable(PLDHashTable *table, int deltaLog2, PLDHashEntryHdr **findEntry)
{
int oldLog2, newLog2;
PRUint32 oldCapacity, newCapacity;
@ -307,26 +309,30 @@ ChangeTable(PLDHashTable *table, int deltaLog2, PLDHashEntryHdr *skipEntry)
if (!newEntryStore)
return PR_FALSE;
/* We can't fail from here on, so update table parameters. */
table->hashShift = PL_DHASH_BITS - newLog2;
table->sizeLog2 = newLog2;
table->sizeMask = PR_BITMASK(newLog2);
table->removedCount = 0;
/* Assign the new entry store to table. */
memset(newEntryStore, 0, nbytes);
oldEntryAddr = oldEntryStore = table->entryStore;
table->entryStore = newEntryStore;
getKey = table->ops->getKey;
moveEntry = table->ops->moveEntry;
/* Copy only live entries, leaving removed ones (and skipEntry) behind. */
/* Copy only live entries, leaving removed ones behind. */
for (i = 0; i < oldCapacity; i++) {
oldEntry = (PLDHashEntryHdr *)oldEntryAddr;
if (oldEntry != skipEntry && ENTRY_IS_LIVE(oldEntry)) {
if (ENTRY_IS_LIVE(oldEntry)) {
newEntry = SearchTable(table, getKey(table, oldEntry),
oldEntry->keyHash);
PR_ASSERT(PL_DHASH_ENTRY_IS_FREE(newEntry));
moveEntry(table, oldEntry, newEntry);
newEntry->keyHash = oldEntry->keyHash;
if (findEntry && *findEntry == oldEntry)
*findEntry = newEntry;
}
oldEntryAddr += entrySize;
}
@ -367,6 +373,8 @@ PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op)
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
/* Initialize the entry, indicating that it's no longer free. */
METER(table->stats.addMisses++);
if (table->ops->initEntry)
table->ops->initEntry(table, entry, key);
entry->keyHash = keyHash;
table->entryCount++;
@ -407,22 +415,17 @@ PL_DHashTableOperate(PLDHashTable *table, const void *key, PLDHashOperator op)
}
if (biasedDeltaLog2) {
if (!ChangeTable(table, biasedDeltaLog2 - DELTA_LOG2_BIAS, entry)) {
/* Grow, compress, or shrink table, keeping entry valid if non-null. */
if (!ChangeTable(table, biasedDeltaLog2 - DELTA_LOG2_BIAS, &entry)) {
/* If we just grabbed the last free entry, undo and fail hard. */
if (op == PL_DHASH_ADD &&
table->entryCount + table->removedCount == size) {
METER(table->stats.addFailures++);
table->ops->clearEntry(table, entry);
MARK_ENTRY_FREE(entry);
table->entryCount--;
entry = NULL;
}
} else {
if (op == PL_DHASH_ADD) {
/* If the table grew, add the new (skipped) entry. */
entry = SearchTable(table, key, keyHash);
PR_ASSERT(PL_DHASH_ENTRY_IS_FREE(entry));
entry->keyHash = keyHash;
}
}
}

Просмотреть файл

@ -14,13 +14,11 @@
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999,2000 Netscape Communications Corporation.
* Copyright (C) 1999-2001 Netscape Communications Corporation.
* All Rights Reserved.
*
* Original Contributor:
* Brendan Eich <brendan@mozilla.org>
*
* Contributor(s):
* Brendan Eich <brendan@mozilla.org> (Original Author)
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@ -79,6 +77,11 @@ typedef struct PLDHashTableOps PLDHashTableOps;
* by PL_DHASH_GOLDEN_RATIO. Its value is table size invariant. keyHash is
* maintained automatically by PL_DHashTableOperate -- users should never set
* it, and its only uses should be via the entry macros below.
*
* The PL_DHASH_ENTRY_IS_LIVE macro tests whether entry is neither free nor
* removed. An entry may be either busy or free; if busy, it may be live or
* removed. Consumers of this API should not access members of entries that
* are not live.
*/
struct PLDHashEntryHdr {
PLDHashNumber keyHash; /* every entry must begin like this */
@ -86,6 +89,7 @@ struct PLDHashEntryHdr {
#define PL_DHASH_ENTRY_IS_FREE(entry) ((entry)->keyHash == 0)
#define PL_DHASH_ENTRY_IS_BUSY(entry) (!PL_DHASH_ENTRY_IS_FREE(entry))
#define PL_DHASH_ENTRY_IS_LIVE(entry) ((entry)->keyHash >= 2)
/*
* A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead)
@ -190,7 +194,7 @@ struct PLDHashTable {
/*
* Table space at entryStore is allocated and freed using these callbacks.
* The allocator should return null on error only (not if called with nbytes
* equal to 0; but note that jsdhash.c code will never call with 0 nbytes).
* equal to 0; but note that pldhash.c code will never call with 0 nbytes).
*/
typedef void *
(* PR_CALLBACK PLDHashAllocTable)(PLDHashTable *table, PRUint32 nbytes);
@ -220,8 +224,8 @@ typedef PLDHashNumber
*/
typedef PRBool
(* PR_CALLBACK PLDHashMatchEntry)(PLDHashTable *table,
const PLDHashEntryHdr *entry,
const void *key);
const PLDHashEntryHdr *entry,
const void *key);
/*
* Copy the data starting at from to the new entry storage at to. Do not add
@ -231,8 +235,8 @@ typedef PRBool
*/
typedef void
(* PR_CALLBACK PLDHashMoveEntry)(PLDHashTable *table,
const PLDHashEntryHdr *from,
PLDHashEntryHdr *to);
const PLDHashEntryHdr *from,
PLDHashEntryHdr *to);
/*
* Clear the entry and drop any strong references it holds. This callback is
@ -240,7 +244,8 @@ typedef void
* but only if the given key is found in the table.
*/
typedef void
(* PR_CALLBACK PLDHashClearEntry)(PLDHashTable *table, PLDHashEntryHdr *entry);
(* PR_CALLBACK PLDHashClearEntry)(PLDHashTable *table,
PLDHashEntryHdr *entry);
/*
* Called when a table (whether allocated dynamically by itself, or nested in
@ -250,8 +255,44 @@ typedef void
typedef void
(* PR_CALLBACK PLDHashFinalize) (PLDHashTable *table);
/* Finally, the "vtable" structure for PLDHashTable. */
/*
* Initialize a new entry, apart from keyHash. This function is called when
* PL_DHashTableOperate's PL_DHASH_ADD case finds no existing entry for the
* given key, and must add a new one. At that point, entry->keyHash is not
* set yet, to avoid claiming the last free entry in a severely overloaded
* table.
*/
typedef void
(* PR_CALLBACK PLDHashInitEntry)(PLDHashTable *table,
const PLDHashEntryHdr *entry,
const void *key);
/*
* Finally, the "vtable" structure for PLDHashTable. The first eight hooks
* must be provided by implementations; they're called unconditionally by the
* generic pldhash.c code. Hooks after these may be null.
*
* Summary of allocation-related hook usage with C++ placement new emphasis:
* allocTable Allocate raw bytes with malloc, no ctors run.
* freeTable Free raw bytes with free, no dtors run.
* initEntry Call placement new using default key-based ctor.
* moveEntry Call placement new using copy ctor, run dtor on old
* entry storage.
* clearEntry Run dtor on entry.
* finalize Stub unless table->data was initialized and needs to
* be finalized.
*
* Note the reason why initEntry is optional: the default hooks (stubs) clear
* entry storage: On successful PL_DHashTableOperate(tbl, key, PL_DHASH_ADD),
* the returned entry pointer addresses an entry struct whose keyHash member
* has been set non-zero, but all other entry members are still clear (null).
* PL_DHASH_ADD callers can test such members to see whether the entry was
* newly created by the PL_DHASH_ADD call that just succeeded. If placement
* new or similar initialization is required, define an initEntry hook. Of
* course, the clearEntry hook must zero or null appropriately.
*/
struct PLDHashTableOps {
/* Mandatory hooks. All implementations must provide these. */
PLDHashAllocTable allocTable;
PLDHashFreeTable freeTable;
PLDHashGetKey getKey;
@ -260,6 +301,9 @@ struct PLDHashTableOps {
PLDHashMoveEntry moveEntry;
PLDHashClearEntry clearEntry;
PLDHashFinalize finalize;
/* Optional hooks start here. If null, these are not called. */
PLDHashInitEntry initEntry;
};
/*
@ -317,7 +361,7 @@ PL_DHashGetStubOps(void);
* the ops->allocTable callback.
*/
PR_EXTERN(PLDHashTable *)
PR_NewDHashTable(PLDHashTableOps *ops, void *data, PRUint32 entrySize,
PL_NewDHashTable(PLDHashTableOps *ops, void *data, PRUint32 entrySize,
PRUint32 capacity);
/*
@ -426,7 +470,7 @@ PL_DHashTableRawRemove(PLDHashTable *table, PLDHashEntryHdr *entry);
*/
typedef PLDHashOperator
(* PR_CALLBACK PLDHashEnumerator)(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRUint32 number, void *arg);
PRUint32 number, void *arg);
PR_EXTERN(PRUint32)
PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg);