зеркало из https://github.com/mozilla/gecko-dev.git
Add optional JSDHashTableOps.initEntry hook, spruce up comments (74883, r=waterson, sr=shaver).
This commit is contained in:
Родитель
e62a3ac64a
Коммит
38fa3fed08
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче