mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
c2df231328
This change splits PLDHashTable::Iterator::NextEntry() into two separate functions, which allow you to get the current element and advance the iterator separately, which means you can use a for-loop to iterate instead of a while-loop. As part of this change, the internals of PLDHashTable::Iterator were significantly changed and simplified (and modelled after js::HashTable's equivalent code). It's no longer duplicating code from PL_DHashTableEnumerator. The chaos mode code was a casualty of this, but given how unreliable that code has proven to be (see bug 1173212, bug 1174046) this is for the best. (We can reimplement chaos mode once PLDHashTable::Iterator is back on more solid footing again, if we think it's important.) All these changes will make it much easier to add an alternative Iterator that removes elements, which was turning out to be difficult with the prior code. In order to make the for-loop header usually fit on a single line, I deliberately renamed a bunch of things to have shorter names. In summary, you used to write this: PLDHashTable::Iterator iter(&table); while (iter.HasMoreEntries()) { auto entry = static_cast<FooEntry*>(iter.NextEntry()); // ... do stuff with |entry| ... } // iter's scope extends beyond here and now you write this: for (auto iter = table.Iter(); !iter.Done(); iter.Next()) { auto entry = static_cast<FooEntry*>(iter.Get()); // ... do stuff with |entry| ... } // iter's scope doesn't reach here
346 lines
10 KiB
C++
346 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This Original Code has been modified by IBM Corporation. Modifications made by IBM
|
|
* described herein are Copyright (c) International Business Machines Corporation, 2000.
|
|
* Modifications to Mozilla code or documentation identified per MPL Section 3.3
|
|
*
|
|
* Date Modified by Description of modification
|
|
* 04/20/2000 IBM Corp. OS/2 VisualAge build.
|
|
*/
|
|
|
|
/**
|
|
* nsPropertyTable allows a set of arbitrary key/value pairs to be stored
|
|
* for any number of nodes, in a global hashtable rather than on the nodes
|
|
* themselves. Nodes can be any type of object; the hashtable keys are
|
|
* nsIAtom pointers, and the values are void pointers.
|
|
*/
|
|
|
|
#include "nsPropertyTable.h"
|
|
|
|
#include "mozilla/MemoryReporting.h"
|
|
|
|
#include "pldhash.h"
|
|
#include "nsError.h"
|
|
#include "nsIAtom.h"
|
|
|
|
struct PropertyListMapEntry : public PLDHashEntryHdr {
|
|
const void *key;
|
|
void *value;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
class nsPropertyTable::PropertyList {
|
|
public:
|
|
PropertyList(nsIAtom* aName,
|
|
NSPropertyDtorFunc aDtorFunc,
|
|
void* aDtorData,
|
|
bool aTransfer);
|
|
~PropertyList();
|
|
|
|
// Removes the property associated with the given object, and destroys
|
|
// the property value
|
|
bool DeletePropertyFor(nsPropertyOwner aObject);
|
|
|
|
// Destroy all remaining properties (without removing them)
|
|
void Destroy();
|
|
|
|
bool Equals(nsIAtom *aPropertyName)
|
|
{
|
|
return mName == aPropertyName;
|
|
}
|
|
|
|
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
|
|
|
nsCOMPtr<nsIAtom> mName; // property name
|
|
PLDHashTable mObjectValueMap; // map of object/value pairs
|
|
NSPropertyDtorFunc mDtorFunc; // property specific value dtor function
|
|
void* mDtorData; // pointer to pass to dtor
|
|
bool mTransfer; // whether to transfer in
|
|
// TransferOrDeleteAllPropertiesFor
|
|
|
|
PropertyList* mNext;
|
|
};
|
|
|
|
void
|
|
nsPropertyTable::DeleteAllProperties()
|
|
{
|
|
while (mPropertyList) {
|
|
PropertyList* tmp = mPropertyList;
|
|
|
|
mPropertyList = mPropertyList->mNext;
|
|
tmp->Destroy();
|
|
delete tmp;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject)
|
|
{
|
|
for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
|
|
prop->DeletePropertyFor(aObject);
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
|
|
nsPropertyTable *aOtherTable)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
|
|
if (prop->mTransfer) {
|
|
PropertyListMapEntry *entry =
|
|
static_cast<PropertyListMapEntry*>
|
|
(PL_DHashTableSearch(&prop->mObjectValueMap, aObject));
|
|
if (entry) {
|
|
rv = aOtherTable->SetProperty(aObject, prop->mName,
|
|
entry->value, prop->mDtorFunc,
|
|
prop->mDtorData, prop->mTransfer);
|
|
if (NS_FAILED(rv)) {
|
|
DeleteAllPropertiesFor(aObject);
|
|
aOtherTable->DeleteAllPropertiesFor(aObject);
|
|
|
|
break;
|
|
}
|
|
|
|
PL_DHashTableRawRemove(&prop->mObjectValueMap, entry);
|
|
}
|
|
}
|
|
else {
|
|
prop->DeletePropertyFor(aObject);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
nsPropertyTable::Enumerate(nsPropertyOwner aObject,
|
|
NSPropertyFunc aCallback, void *aData)
|
|
{
|
|
PropertyList* prop;
|
|
for (prop = mPropertyList; prop; prop = prop->mNext) {
|
|
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
|
|
(PL_DHashTableSearch(&prop->mObjectValueMap, aObject));
|
|
if (entry) {
|
|
aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
|
|
aData);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData)
|
|
{
|
|
for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
|
|
for (auto iter = prop->mObjectValueMap.Iter(); !iter.Done(); iter.Next()) {
|
|
auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
|
|
aCallBack(const_cast<void*>(entry->key), prop->mName, entry->value,
|
|
aData);
|
|
}
|
|
}
|
|
}
|
|
|
|
void*
|
|
nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
|
|
nsIAtom *aPropertyName,
|
|
bool aRemove,
|
|
nsresult *aResult)
|
|
{
|
|
NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
|
|
nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
|
|
void *propValue = nullptr;
|
|
|
|
PropertyList* propertyList = GetPropertyListFor(aPropertyName);
|
|
if (propertyList) {
|
|
PropertyListMapEntry *entry =
|
|
static_cast<PropertyListMapEntry*>
|
|
(PL_DHashTableSearch(&propertyList->mObjectValueMap, aObject));
|
|
if (entry) {
|
|
propValue = entry->value;
|
|
if (aRemove) {
|
|
// don't call propertyList->mDtorFunc. That's the caller's job now.
|
|
PL_DHashTableRawRemove(&propertyList->mObjectValueMap, entry);
|
|
}
|
|
rv = NS_OK;
|
|
}
|
|
}
|
|
|
|
if (aResult)
|
|
*aResult = rv;
|
|
|
|
return propValue;
|
|
}
|
|
|
|
nsresult
|
|
nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
|
|
nsIAtom *aPropertyName,
|
|
void *aPropertyValue,
|
|
NSPropertyDtorFunc aPropDtorFunc,
|
|
void *aPropDtorData,
|
|
bool aTransfer,
|
|
void **aOldValue)
|
|
{
|
|
NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
|
|
|
|
PropertyList* propertyList = GetPropertyListFor(aPropertyName);
|
|
|
|
if (propertyList) {
|
|
// Make sure the dtor function and data and the transfer flag match
|
|
if (aPropDtorFunc != propertyList->mDtorFunc ||
|
|
aPropDtorData != propertyList->mDtorData ||
|
|
aTransfer != propertyList->mTransfer) {
|
|
NS_WARNING("Destructor/data mismatch while setting property");
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
} else {
|
|
propertyList = new PropertyList(aPropertyName, aPropDtorFunc,
|
|
aPropDtorData, aTransfer);
|
|
propertyList->mNext = mPropertyList;
|
|
mPropertyList = propertyList;
|
|
}
|
|
|
|
// The current property value (if there is one) is replaced and the current
|
|
// value is destroyed
|
|
nsresult result = NS_OK;
|
|
PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
|
|
(PL_DHashTableAdd(&propertyList->mObjectValueMap, aObject, mozilla::fallible));
|
|
if (!entry)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
// A nullptr entry->key is the sign that the entry has just been allocated
|
|
// for us. If it's non-nullptr then we have an existing entry.
|
|
if (entry->key) {
|
|
if (aOldValue)
|
|
*aOldValue = entry->value;
|
|
else if (propertyList->mDtorFunc)
|
|
propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
|
|
entry->value, propertyList->mDtorData);
|
|
result = NS_PROPTABLE_PROP_OVERWRITTEN;
|
|
}
|
|
else if (aOldValue) {
|
|
*aOldValue = nullptr;
|
|
}
|
|
entry->key = aObject;
|
|
entry->value = aPropertyValue;
|
|
|
|
return result;
|
|
}
|
|
|
|
nsresult
|
|
nsPropertyTable::DeleteProperty(nsPropertyOwner aObject,
|
|
nsIAtom *aPropertyName)
|
|
{
|
|
NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
|
|
|
|
PropertyList* propertyList = GetPropertyListFor(aPropertyName);
|
|
if (propertyList) {
|
|
if (propertyList->DeletePropertyFor(aObject))
|
|
return NS_OK;
|
|
}
|
|
|
|
return NS_PROPTABLE_PROP_NOT_THERE;
|
|
}
|
|
|
|
nsPropertyTable::PropertyList*
|
|
nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
|
|
{
|
|
PropertyList* result;
|
|
|
|
for (result = mPropertyList; result; result = result->mNext) {
|
|
if (result->Equals(aPropertyName)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
nsPropertyTable::PropertyList::PropertyList(nsIAtom *aName,
|
|
NSPropertyDtorFunc aDtorFunc,
|
|
void *aDtorData,
|
|
bool aTransfer)
|
|
: mName(aName),
|
|
mObjectValueMap(PL_DHashGetStubOps(), sizeof(PropertyListMapEntry)),
|
|
mDtorFunc(aDtorFunc),
|
|
mDtorData(aDtorData),
|
|
mTransfer(aTransfer),
|
|
mNext(nullptr)
|
|
{
|
|
}
|
|
|
|
nsPropertyTable::PropertyList::~PropertyList()
|
|
{
|
|
}
|
|
|
|
void
|
|
nsPropertyTable::PropertyList::Destroy()
|
|
{
|
|
// Enumerate any remaining object/value pairs and destroy the value object.
|
|
if (mDtorFunc) {
|
|
for (auto iter = mObjectValueMap.Iter(); !iter.Done(); iter.Next()) {
|
|
auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
|
|
mDtorFunc(const_cast<void*>(entry->key), mName, entry->value, mDtorData);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsPropertyTable::PropertyList::DeletePropertyFor(nsPropertyOwner aObject)
|
|
{
|
|
PropertyListMapEntry *entry =
|
|
static_cast<PropertyListMapEntry*>
|
|
(PL_DHashTableSearch(&mObjectValueMap, aObject));
|
|
if (!entry)
|
|
return false;
|
|
|
|
void* value = entry->value;
|
|
PL_DHashTableRawRemove(&mObjectValueMap, entry);
|
|
|
|
if (mDtorFunc)
|
|
mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t
|
|
nsPropertyTable::PropertyList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
|
{
|
|
size_t n = aMallocSizeOf(this);
|
|
n += PL_DHashTableSizeOfExcludingThis(&mObjectValueMap, nullptr, aMallocSizeOf);
|
|
return n;
|
|
}
|
|
|
|
size_t
|
|
nsPropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
size_t n = 0;
|
|
|
|
for (PropertyList *prop = mPropertyList; prop; prop = prop->mNext) {
|
|
n += prop->SizeOfIncludingThis(aMallocSizeOf);
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
size_t
|
|
nsPropertyTable::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
|
}
|
|
|
|
/* static */
|
|
void
|
|
nsPropertyTable::SupportsDtorFunc(void *aObject, nsIAtom *aPropertyName,
|
|
void *aPropertyValue, void *aData)
|
|
{
|
|
nsISupports *propertyValue = static_cast<nsISupports*>(aPropertyValue);
|
|
NS_IF_RELEASE(propertyValue);
|
|
}
|