mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1059550 - Add an iterator to PLDHashtable, r=froydnj
This commit is contained in:
parent
4cf96ddcba
commit
095e8ec91b
@ -697,6 +697,8 @@ PLDHashTable::Enumerate(PLDHashEnumerator aEtor, void* aArg)
|
||||
{
|
||||
INCREMENT_RECURSION_LEVEL(this);
|
||||
|
||||
// Please keep this method in sync with the PLDHashTable::Iterator constructor
|
||||
// and ::NextEntry methods below in this file.
|
||||
char* entryAddr = mEntryStore;
|
||||
uint32_t capacity = Capacity();
|
||||
uint32_t tableSize = capacity * mEntrySize;
|
||||
@ -835,6 +837,97 @@ PL_DHashTableSizeOfIncludingThis(
|
||||
aMallocSizeOf, aArg);
|
||||
}
|
||||
|
||||
PLDHashTable::Iterator::Iterator(const PLDHashTable* aTable)
|
||||
: mTable(aTable),
|
||||
mEntryAddr(mTable->mEntryStore),
|
||||
mEntryOffset(0)
|
||||
{
|
||||
// Make sure that modifications can't simultaneously happen while the iterator
|
||||
// is active.
|
||||
INCREMENT_RECURSION_LEVEL(mTable);
|
||||
|
||||
// The following code is taken from, and should be kept in sync with, the
|
||||
// PLDHashTable::Enumerate method above. The variables i and entryAddr (which
|
||||
// vary over the course of the for loop) are converted into mEntryOffset and
|
||||
// mEntryAddr, respectively.
|
||||
uint32_t capacity = mTable->Capacity();
|
||||
uint32_t tableSize = capacity * mTable->EntrySize();
|
||||
char* entryLimit = mEntryAddr + tableSize;
|
||||
|
||||
if (ChaosMode::isActive()) {
|
||||
// Start iterating at a random point in the hashtable. It would be
|
||||
// even more chaotic to iterate in fully random order, but that's a lot
|
||||
// more work.
|
||||
mEntryAddr += ChaosMode::randomUint32LessThan(capacity) * mTable->mEntrySize;
|
||||
if (mEntryAddr >= entryLimit) {
|
||||
mEntryAddr -= tableSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PLDHashTable::Iterator::Iterator(const Iterator& aIterator)
|
||||
: mTable(aIterator.mTable),
|
||||
mEntryAddr(aIterator.mEntryAddr),
|
||||
mEntryOffset(aIterator.mEntryOffset)
|
||||
{
|
||||
// We need the copy constructor only so that we can keep the recursion level
|
||||
// consistent.
|
||||
INCREMENT_RECURSION_LEVEL(mTable);
|
||||
}
|
||||
|
||||
PLDHashTable::Iterator::~Iterator()
|
||||
{
|
||||
DECREMENT_RECURSION_LEVEL(mTable);
|
||||
}
|
||||
|
||||
bool PLDHashTable::Iterator::HasMoreEntries() const
|
||||
{
|
||||
// Check the number of live entries seen, not the total number of entries
|
||||
// seen. To see why, consider what happens if the last entry is not live: we
|
||||
// would have to iterate after returning an entry to see if more live entries
|
||||
// exist.
|
||||
return mEntryOffset < mTable->EntryCount();
|
||||
}
|
||||
|
||||
PLDHashEntryHdr* PLDHashTable::Iterator::NextEntry()
|
||||
{
|
||||
MOZ_ASSERT(HasMoreEntries());
|
||||
|
||||
// The following code is taken from, and should be kept in sync with, the
|
||||
// PLDHashTable::Enumerate method above. The variables i and entryAddr (which
|
||||
// vary over the course of the for loop) are converted into mEntryOffset and
|
||||
// mEntryAddr, respectively.
|
||||
uint32_t capacity = mTable->Capacity();
|
||||
uint32_t tableSize = capacity * mTable->mEntrySize;
|
||||
char* entryLimit = mEntryAddr + tableSize;
|
||||
|
||||
// Strictly speaking, we don't need to iterate over the full capacity each
|
||||
// time. However, it is simpler to do so rather than unnecessarily track the
|
||||
// current number of entries checked as opposed to only live entries. If debug
|
||||
// checks pass, then this method will only iterate through the full capacity
|
||||
// once. If they fail, then this loop may end up returning the early entries
|
||||
// more than once.
|
||||
for (uint32_t e = 0; e < capacity; ++e) {
|
||||
PLDHashEntryHdr* entry = (PLDHashEntryHdr*)mEntryAddr;
|
||||
|
||||
// Increment the count before returning so we don't keep returning the same
|
||||
// address. This may wrap around if ChaosMode is enabled.
|
||||
mEntryAddr += mTable->mEntrySize;
|
||||
if (mEntryAddr >= entryLimit) {
|
||||
mEntryAddr -= tableSize;
|
||||
}
|
||||
if (ENTRY_IS_LIVE(entry)) {
|
||||
++mEntryOffset;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
// If the debug checks pass, then the above loop should always find a live
|
||||
// entry. If those checks are disabled, then it may be possible to reach this
|
||||
// if the table is empty and this method is called.
|
||||
MOZ_CRASH("Flagrant misuse of hashtable iterators not caught by checks.");
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ALWAYS_INLINE void
|
||||
PLDHashTable::MarkImmutable()
|
||||
|
@ -194,7 +194,7 @@ private:
|
||||
* non-DEBUG components. (Actually, even if it were removed,
|
||||
* sizeof(PLDHashTable) wouldn't change, due to struct padding.)
|
||||
*/
|
||||
uint16_t mRecursionLevel;/* used to detect unsafe re-entry */
|
||||
mutable uint16_t mRecursionLevel;/* used to detect unsafe re-entry */
|
||||
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 */
|
||||
@ -272,6 +272,27 @@ public:
|
||||
void DumpMeter(PLDHashEnumerator aDump, FILE* aFp);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is an iterator that works over the elements of PLDHashtable. It is not
|
||||
* safe to modify the hashtable while it is being iterated over; on debug
|
||||
* builds, attempting to do so will result in an assertion failure.
|
||||
*/
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(const PLDHashTable* aTable);
|
||||
Iterator(const Iterator& aIterator);
|
||||
~Iterator();
|
||||
bool HasMoreEntries() const;
|
||||
PLDHashEntryHdr* NextEntry();
|
||||
|
||||
private:
|
||||
const PLDHashTable* mTable; /* Main table pointer */
|
||||
char* mEntryAddr; /* Pointer to the next entry to check */
|
||||
uint32_t mEntryOffset; /* The number of the elements returned */
|
||||
};
|
||||
|
||||
Iterator Iterate() const { return Iterator(this); }
|
||||
|
||||
private:
|
||||
PLDHashEntryHdr* PL_DHASH_FASTCALL
|
||||
SearchTable(const void* aKey, PLDHashNumber aKeyHash, PLDHashOperator aOp);
|
||||
|
Loading…
Reference in New Issue
Block a user