Backed out changeset 1d9301697aa0 (bug 1887752) for causing failures on browser_all_f...
[gecko.git] / dom / base / nsPropertyTable.cpp
blob63343a8141275f29881dfbce41e7c9b1b9556a3e
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /**
8 * nsPropertyTable allows a set of arbitrary key/value pairs to be stored
9 * for any number of nodes, in a global hashtable rather than on the nodes
10 * themselves. Nodes can be any type of object; the hashtable keys are
11 * nsAtom pointers, and the values are void pointers.
14 #include "nsPropertyTable.h"
16 #include "mozilla/MemoryReporting.h"
18 #include "PLDHashTable.h"
19 #include "nsError.h"
20 #include "nsAtom.h"
22 struct PropertyListMapEntry : public PLDHashEntryHdr {
23 const void* key;
24 void* value;
27 //----------------------------------------------------------------------
29 class nsPropertyTable::PropertyList {
30 public:
31 PropertyList(nsAtom* aName, NSPropertyDtorFunc aDtorFunc, void* aDtorData,
32 bool aTransfer);
33 ~PropertyList();
35 // Removes the property associated with the given object, and destroys
36 // the property value
37 bool RemovePropertyFor(nsPropertyOwner aObject);
39 // Destroy all remaining properties (without removing them)
40 void Destroy();
42 bool Equals(const nsAtom* aPropertyName) { return mName == aPropertyName; }
44 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
46 RefPtr<nsAtom> mName; // property name
47 PLDHashTable mObjectValueMap; // map of object/value pairs
48 NSPropertyDtorFunc mDtorFunc; // property specific value dtor function
49 void* mDtorData; // pointer to pass to dtor
50 bool mTransfer; // whether to transfer in
51 // TransferOrRemoveAllPropertiesFor
53 PropertyList* mNext;
56 void nsPropertyTable::RemoveAllProperties() {
57 while (mPropertyList) {
58 PropertyList* tmp = mPropertyList;
60 mPropertyList = mPropertyList->mNext;
61 tmp->Destroy();
62 delete tmp;
66 void nsPropertyTable::RemoveAllPropertiesFor(nsPropertyOwner aObject) {
67 for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
68 prop->RemovePropertyFor(aObject);
72 nsresult nsPropertyTable::TransferOrRemoveAllPropertiesFor(
73 nsPropertyOwner aObject, nsPropertyTable& aOtherTable) {
74 nsresult rv = NS_OK;
75 for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
76 if (prop->mTransfer) {
77 auto entry = static_cast<PropertyListMapEntry*>(
78 prop->mObjectValueMap.Search(aObject));
79 if (entry) {
80 rv = aOtherTable.SetProperty(aObject, prop->mName, entry->value,
81 prop->mDtorFunc, prop->mDtorData,
82 prop->mTransfer);
83 if (NS_FAILED(rv)) {
84 RemoveAllPropertiesFor(aObject);
85 aOtherTable.RemoveAllPropertiesFor(aObject);
86 break;
89 prop->mObjectValueMap.RemoveEntry(entry);
91 } else {
92 prop->RemovePropertyFor(aObject);
96 return rv;
99 void nsPropertyTable::Enumerate(nsPropertyOwner aObject,
100 NSPropertyFunc aCallback, void* aData) {
101 PropertyList* prop;
102 for (prop = mPropertyList; prop; prop = prop->mNext) {
103 auto entry = static_cast<PropertyListMapEntry*>(
104 prop->mObjectValueMap.Search(aObject));
105 if (entry) {
106 aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
107 aData);
112 void nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData) {
113 for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
114 for (auto iter = prop->mObjectValueMap.ConstIter(); !iter.Done();
115 iter.Next()) {
116 auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
117 aCallBack(const_cast<void*>(entry->key), prop->mName, entry->value,
118 aData);
123 void* nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
124 const nsAtom* aPropertyName,
125 bool aRemove, nsresult* aResult) {
126 MOZ_ASSERT(aPropertyName && aObject, "unexpected null param");
127 nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
128 void* propValue = nullptr;
130 PropertyList* propertyList = GetPropertyListFor(aPropertyName);
131 if (propertyList) {
132 auto entry = static_cast<PropertyListMapEntry*>(
133 propertyList->mObjectValueMap.Search(aObject));
134 if (entry) {
135 propValue = entry->value;
136 if (aRemove) {
137 // don't call propertyList->mDtorFunc. That's the caller's job now.
138 propertyList->mObjectValueMap.RemoveEntry(entry);
140 rv = NS_OK;
144 if (aResult) *aResult = rv;
146 return propValue;
149 nsresult nsPropertyTable::SetPropertyInternal(
150 nsPropertyOwner aObject, nsAtom* aPropertyName, void* aPropertyValue,
151 NSPropertyDtorFunc aPropDtorFunc, void* aPropDtorData, bool aTransfer) {
152 MOZ_ASSERT(aPropertyName && aObject, "unexpected null param");
154 PropertyList* propertyList = GetPropertyListFor(aPropertyName);
156 if (propertyList) {
157 // Make sure the dtor function and data and the transfer flag match
158 if (aPropDtorFunc != propertyList->mDtorFunc ||
159 aPropDtorData != propertyList->mDtorData ||
160 aTransfer != propertyList->mTransfer) {
161 NS_WARNING("Destructor/data mismatch while setting property");
162 return NS_ERROR_INVALID_ARG;
165 } else {
166 propertyList = new PropertyList(aPropertyName, aPropDtorFunc, aPropDtorData,
167 aTransfer);
168 propertyList->mNext = mPropertyList;
169 mPropertyList = propertyList;
172 // The current property value (if there is one) is replaced and the current
173 // value is destroyed
174 nsresult result = NS_OK;
175 auto entry = static_cast<PropertyListMapEntry*>(
176 propertyList->mObjectValueMap.Add(aObject, mozilla::fallible));
177 if (!entry) return NS_ERROR_OUT_OF_MEMORY;
178 // A nullptr entry->key is the sign that the entry has just been allocated
179 // for us. If it's non-nullptr then we have an existing entry.
180 if (entry->key) {
181 if (propertyList->mDtorFunc) {
182 propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
183 entry->value, propertyList->mDtorData);
185 result = NS_PROPTABLE_PROP_OVERWRITTEN;
187 entry->key = aObject;
188 entry->value = aPropertyValue;
190 return result;
193 nsresult nsPropertyTable::RemoveProperty(nsPropertyOwner aObject,
194 const nsAtom* aPropertyName) {
195 MOZ_ASSERT(aPropertyName && aObject, "unexpected null param");
197 PropertyList* propertyList = GetPropertyListFor(aPropertyName);
198 if (propertyList) {
199 if (propertyList->RemovePropertyFor(aObject)) {
200 return NS_OK;
204 return NS_PROPTABLE_PROP_NOT_THERE;
207 nsPropertyTable::PropertyList* nsPropertyTable::GetPropertyListFor(
208 const nsAtom* aPropertyName) const {
209 PropertyList* result;
211 for (result = mPropertyList; result; result = result->mNext) {
212 if (result->Equals(aPropertyName)) {
213 break;
217 return result;
220 //----------------------------------------------------------------------
222 nsPropertyTable::PropertyList::PropertyList(nsAtom* aName,
223 NSPropertyDtorFunc aDtorFunc,
224 void* aDtorData, bool aTransfer)
225 : mName(aName),
226 mObjectValueMap(PLDHashTable::StubOps(), sizeof(PropertyListMapEntry)),
227 mDtorFunc(aDtorFunc),
228 mDtorData(aDtorData),
229 mTransfer(aTransfer),
230 mNext(nullptr) {}
232 nsPropertyTable::PropertyList::~PropertyList() = default;
234 void nsPropertyTable::PropertyList::Destroy() {
235 // Enumerate any remaining object/value pairs and destroy the value object.
236 if (mDtorFunc) {
237 for (auto iter = mObjectValueMap.ConstIter(); !iter.Done(); iter.Next()) {
238 auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
239 mDtorFunc(const_cast<void*>(entry->key), mName, entry->value, mDtorData);
244 bool nsPropertyTable::PropertyList::RemovePropertyFor(nsPropertyOwner aObject) {
245 auto entry =
246 static_cast<PropertyListMapEntry*>(mObjectValueMap.Search(aObject));
247 if (!entry) return false;
249 void* value = entry->value;
250 mObjectValueMap.RemoveEntry(entry);
252 if (mDtorFunc)
253 mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
255 return true;
258 size_t nsPropertyTable::PropertyList::SizeOfIncludingThis(
259 mozilla::MallocSizeOf aMallocSizeOf) {
260 size_t n = aMallocSizeOf(this);
261 n += mObjectValueMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
262 return n;
265 size_t nsPropertyTable::SizeOfExcludingThis(
266 mozilla::MallocSizeOf aMallocSizeOf) const {
267 size_t n = 0;
269 for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
270 n += prop->SizeOfIncludingThis(aMallocSizeOf);
273 return n;
276 size_t nsPropertyTable::SizeOfIncludingThis(
277 mozilla::MallocSizeOf aMallocSizeOf) const {
278 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
281 /* static */
282 void nsPropertyTable::SupportsDtorFunc(void* aObject, nsAtom* aPropertyName,
283 void* aPropertyValue, void* aData) {
284 nsISupports* propertyValue = static_cast<nsISupports*>(aPropertyValue);
285 NS_IF_RELEASE(propertyValue);