mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1161377 (part 1) - Add an initializing constructor and destructor to PLDHashTable. r=froydnj.
The destructor is "opt-in" -- there's a flag that makes it a no-op unless the table was initialized with the initializing constructor. This will allow us to incrementally convert existing tables from manual to automatic initialization/finalization. This is important because some of the existing uses are tricky (impossible?) to convert to the automatic style.
This commit is contained in:
parent
d671e16e9b
commit
9978627ce0
@ -406,10 +406,6 @@ nsTHashtable<EntryType>::nsTHashtable(nsTHashtable<EntryType>&& aOther)
|
||||
// aOther shouldn't touch mTable after this, because we've stolen the table's
|
||||
// pointers but not overwitten them.
|
||||
MOZ_MAKE_MEM_UNDEFINED(&aOther.mTable, sizeof(aOther.mTable));
|
||||
|
||||
// Indicate that aOther is not initialized. This will make its destructor a
|
||||
// nop, which is what we want.
|
||||
aOther.mTable.SetOps(nullptr);
|
||||
}
|
||||
|
||||
template<class EntryType>
|
||||
|
@ -218,6 +218,7 @@ MOZ_ALWAYS_INLINE void
|
||||
PLDHashTable::Init(const PLDHashTableOps* aOps,
|
||||
uint32_t aEntrySize, uint32_t aLength)
|
||||
{
|
||||
MOZ_ASSERT(!mAutoFinish);
|
||||
MOZ_ASSERT(!IsInitialized());
|
||||
|
||||
// Check that the important fields have been set by the constructor.
|
||||
@ -266,6 +267,19 @@ PL_DHashTableInit(PLDHashTable* aTable, const PLDHashTableOps* aOps,
|
||||
aTable->Init(aOps, aEntrySize, aLength);
|
||||
}
|
||||
|
||||
PLDHashTable::PLDHashTable(const PLDHashTableOps* aOps, uint32_t aEntrySize,
|
||||
uint32_t aLength)
|
||||
: mOps(nullptr)
|
||||
, mAutoFinish(0)
|
||||
, mEntryStore(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mRecursionLevel()
|
||||
#endif
|
||||
{
|
||||
Init(aOps, aEntrySize, aLength);
|
||||
mAutoFinish = 1;
|
||||
}
|
||||
|
||||
PLDHashTable& PLDHashTable::operator=(PLDHashTable&& aOther)
|
||||
{
|
||||
if (this == &aOther) {
|
||||
@ -273,6 +287,7 @@ PLDHashTable& PLDHashTable::operator=(PLDHashTable&& aOther)
|
||||
}
|
||||
|
||||
// Destruct |this|.
|
||||
mAutoFinish = 0;
|
||||
Finish();
|
||||
|
||||
// Move pieces over.
|
||||
@ -281,7 +296,9 @@ PLDHashTable& PLDHashTable::operator=(PLDHashTable&& aOther)
|
||||
mEntrySize = Move(aOther.mEntrySize);
|
||||
mEntryCount = Move(aOther.mEntryCount);
|
||||
mRemovedCount = Move(aOther.mRemovedCount);
|
||||
mGeneration = Move(aOther.mGeneration);
|
||||
// We can't use Move() on bitfields. Fortunately, '=' suffices.
|
||||
mGeneration = aOther.mGeneration;
|
||||
mAutoFinish = aOther.mAutoFinish;
|
||||
mEntryStore = Move(aOther.mEntryStore);
|
||||
#ifdef PL_DHASHMETER
|
||||
mStats = Move(aOther.mStats);
|
||||
@ -340,6 +357,8 @@ PLDHashTable::EntryIsFree(PLDHashEntryHdr* aEntry)
|
||||
MOZ_ALWAYS_INLINE void
|
||||
PLDHashTable::Finish()
|
||||
{
|
||||
MOZ_ASSERT(!mAutoFinish);
|
||||
|
||||
if (!IsInitialized()) {
|
||||
MOZ_ASSERT(!mEntryStore);
|
||||
return;
|
||||
@ -375,6 +394,20 @@ PL_DHashTableFinish(PLDHashTable* aTable)
|
||||
aTable->Finish();
|
||||
}
|
||||
|
||||
PLDHashTable::~PLDHashTable()
|
||||
{
|
||||
// If we used automatic initialization, then finalize the table here.
|
||||
// Otherwise, Finish() should have already been called manually.
|
||||
if (mAutoFinish) {
|
||||
mAutoFinish = 0;
|
||||
Finish();
|
||||
} else {
|
||||
// XXX: actually, we can't assert this here because some tables never get
|
||||
// finalized.
|
||||
//MOZ_ASSERT(!IsInitialized());
|
||||
}
|
||||
}
|
||||
|
||||
// If |IsAdd| is true, the return value is always non-null and it may be a
|
||||
// previously-removed entry. If |IsAdd| is false, the return value is null on a
|
||||
// miss, and will never be a previously-removed entry on a hit. This
|
||||
|
@ -145,12 +145,21 @@ typedef size_t (*PLDHashSizeOfEntryExcludingThisFun)(
|
||||
PLDHashEntryHdr* aHdr, mozilla::MallocSizeOf aMallocSizeOf, void* aArg);
|
||||
|
||||
/*
|
||||
* A PLDHashTable is currently 8 words (without the PL_DHASHMETER overhead)
|
||||
* on most architectures, and may be allocated on the stack or within another
|
||||
* structure or class (see below for the Init and Finish functions to use).
|
||||
* A PLDHashTable may be allocated on the stack or within another structure or
|
||||
* class. No entry storage is allocated until the first element is added. This
|
||||
* means that empty hash tables are cheap, which is good because they are
|
||||
* common.
|
||||
*
|
||||
* No entry storage is allocated until the first element is added. This means
|
||||
* that empty hash tables are cheap, which is good because they are common.
|
||||
* Due to historical reasons, there are two ways to manage the initialization
|
||||
* and finalization of a PLDHashTable. There are assertions that will trigger
|
||||
* if the two styles are mixed for a single table.
|
||||
*
|
||||
* - Automatic, C++ style: via the multi-arg constructor and the destructor.
|
||||
* This is the preferred style.
|
||||
*
|
||||
* - Manual, C style: via the Init() and Finish() methods. If Init() is
|
||||
* called on a table, then the Finish() must be called to finalize the
|
||||
* table, and the destructor will be a no-op.
|
||||
*
|
||||
* There used to be a long, math-heavy comment here about the merits of
|
||||
* double hashing vs. chaining; it was removed in bug 1058335. In short, double
|
||||
@ -169,7 +178,8 @@ private:
|
||||
uint32_t mEntrySize; /* number of bytes in an entry */
|
||||
uint32_t mEntryCount; /* number of entries in table */
|
||||
uint32_t mRemovedCount; /* removed entry sentinels in table */
|
||||
uint32_t mGeneration; /* entry storage generation number */
|
||||
uint32_t mGeneration:31; /* entry storage generation number */
|
||||
uint32_t mAutoFinish:1; /* should the destructor call Finish()? */
|
||||
char* mEntryStore; /* entry storage; allocated lazily */
|
||||
#ifdef PL_DHASHMETER
|
||||
struct PLDHashStats
|
||||
@ -214,6 +224,7 @@ public:
|
||||
, mEntryCount(0)
|
||||
, mRemovedCount(0)
|
||||
, mGeneration(0)
|
||||
, mAutoFinish(0)
|
||||
, mEntryStore(nullptr)
|
||||
#ifdef PL_DHASHMETER
|
||||
, mStats()
|
||||
@ -223,8 +234,21 @@ public:
|
||||
#endif
|
||||
{}
|
||||
|
||||
// Initialize the table with aOps and aEntrySize. The table's initial
|
||||
// capacity will be chosen such that |aLength| elements can be inserted
|
||||
// without rehashing; if |aLength| is a power-of-two, this capacity will be
|
||||
// |2*length|. However, because entry storage is allocated lazily, this
|
||||
// initial capacity won't be relevant until the first element is added; prior
|
||||
// to that the capacity will be zero.
|
||||
//
|
||||
// This function will crash if |aEntrySize| and/or |aLength| are too large.
|
||||
//
|
||||
PLDHashTable(const PLDHashTableOps* aOps, uint32_t aEntrySize,
|
||||
uint32_t aLength = PL_DHASH_DEFAULT_INITIAL_LENGTH);
|
||||
|
||||
PLDHashTable(PLDHashTable&& aOther)
|
||||
: mOps(nullptr)
|
||||
, mAutoFinish(0)
|
||||
, mEntryStore(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mRecursionLevel(0)
|
||||
@ -235,6 +259,8 @@ public:
|
||||
|
||||
PLDHashTable& operator=(PLDHashTable&& aOther);
|
||||
|
||||
~PLDHashTable();
|
||||
|
||||
bool IsInitialized() const { return !!mOps; }
|
||||
|
||||
// These should be used rarely.
|
||||
@ -466,23 +492,20 @@ PLDHashTable* PL_NewDHashTable(
|
||||
void PL_DHashTableDestroy(PLDHashTable* aTable);
|
||||
|
||||
/*
|
||||
* Initialize aTable with aOps and aEntrySize. The table's initial capacity
|
||||
* will be chosen such that |aLength| elements can be inserted without
|
||||
* rehashing; if |aLength| is a power-of-two, this capacity will be |2*length|.
|
||||
* However, because entry storage is allocated lazily, this initial capacity
|
||||
* won't be relevant until the first element is added; prior to that the
|
||||
* capacity will be zero.
|
||||
* This function works similarly to the multi-arg constructor.
|
||||
*
|
||||
* This function will crash if |aEntrySize| and/or |aLength| are too large.
|
||||
* Any table initialized with this function must be finalized via
|
||||
* PL_DHashTableFinish(). The alternative (and preferred) way to
|
||||
* initialize a PLDHashTable is via the multi-arg constructor; any such table
|
||||
* will be auto-finalized by the destructor.
|
||||
*/
|
||||
void PL_DHashTableInit(
|
||||
PLDHashTable* aTable, const PLDHashTableOps* aOps,
|
||||
uint32_t aEntrySize, uint32_t aLength = PL_DHASH_DEFAULT_INITIAL_LENGTH);
|
||||
|
||||
/*
|
||||
* Free |aTable|'s entry storage (via aTable->mOps->freeTable). Use this
|
||||
* function to destroy a PLDHashTable that is allocated on the stack or in
|
||||
* static memory and was created via PL_DHashTableInit().
|
||||
* Free |aTable|'s entry storage. Use this function to finalize a PLDHashTable
|
||||
* that was initialized with PL_DHashTableInit().
|
||||
*/
|
||||
void PL_DHashTableFinish(PLDHashTable* aTable);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user