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/. */
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"
22 struct PropertyListMapEntry
: public PLDHashEntryHdr
{
27 //----------------------------------------------------------------------
29 class nsPropertyTable::PropertyList
{
31 PropertyList(nsAtom
* aName
, NSPropertyDtorFunc aDtorFunc
, void* aDtorData
,
35 // Removes the property associated with the given object, and destroys
37 bool RemovePropertyFor(nsPropertyOwner aObject
);
39 // Destroy all remaining properties (without removing them)
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
56 void nsPropertyTable::RemoveAllProperties() {
57 while (mPropertyList
) {
58 PropertyList
* tmp
= mPropertyList
;
60 mPropertyList
= mPropertyList
->mNext
;
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
) {
75 for (PropertyList
* prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
76 if (prop
->mTransfer
) {
77 auto entry
= static_cast<PropertyListMapEntry
*>(
78 prop
->mObjectValueMap
.Search(aObject
));
80 rv
= aOtherTable
.SetProperty(aObject
, prop
->mName
, entry
->value
,
81 prop
->mDtorFunc
, prop
->mDtorData
,
84 RemoveAllPropertiesFor(aObject
);
85 aOtherTable
.RemoveAllPropertiesFor(aObject
);
89 prop
->mObjectValueMap
.RemoveEntry(entry
);
92 prop
->RemovePropertyFor(aObject
);
99 void nsPropertyTable::Enumerate(nsPropertyOwner aObject
,
100 NSPropertyFunc aCallback
, void* aData
) {
102 for (prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
103 auto entry
= static_cast<PropertyListMapEntry
*>(
104 prop
->mObjectValueMap
.Search(aObject
));
106 aCallback(const_cast<void*>(aObject
.get()), prop
->mName
, entry
->value
,
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();
116 auto entry
= static_cast<PropertyListMapEntry
*>(iter
.Get());
117 aCallBack(const_cast<void*>(entry
->key
), prop
->mName
, entry
->value
,
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
);
132 auto entry
= static_cast<PropertyListMapEntry
*>(
133 propertyList
->mObjectValueMap
.Search(aObject
));
135 propValue
= entry
->value
;
137 // don't call propertyList->mDtorFunc. That's the caller's job now.
138 propertyList
->mObjectValueMap
.RemoveEntry(entry
);
144 if (aResult
) *aResult
= rv
;
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
);
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
;
166 propertyList
= new PropertyList(aPropertyName
, aPropDtorFunc
, aPropDtorData
,
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.
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
;
193 nsresult
nsPropertyTable::RemoveProperty(nsPropertyOwner aObject
,
194 const nsAtom
* aPropertyName
) {
195 MOZ_ASSERT(aPropertyName
&& aObject
, "unexpected null param");
197 PropertyList
* propertyList
= GetPropertyListFor(aPropertyName
);
199 if (propertyList
->RemovePropertyFor(aObject
)) {
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
)) {
220 //----------------------------------------------------------------------
222 nsPropertyTable::PropertyList::PropertyList(nsAtom
* aName
,
223 NSPropertyDtorFunc aDtorFunc
,
224 void* aDtorData
, bool aTransfer
)
226 mObjectValueMap(PLDHashTable::StubOps(), sizeof(PropertyListMapEntry
)),
227 mDtorFunc(aDtorFunc
),
228 mDtorData(aDtorData
),
229 mTransfer(aTransfer
),
232 nsPropertyTable::PropertyList::~PropertyList() = default;
234 void nsPropertyTable::PropertyList::Destroy() {
235 // Enumerate any remaining object/value pairs and destroy the value object.
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
) {
246 static_cast<PropertyListMapEntry
*>(mObjectValueMap
.Search(aObject
));
247 if (!entry
) return false;
249 void* value
= entry
->value
;
250 mObjectValueMap
.RemoveEntry(entry
);
253 mDtorFunc(const_cast<void*>(aObject
.get()), mName
, value
, mDtorData
);
258 size_t nsPropertyTable::PropertyList::SizeOfIncludingThis(
259 mozilla::MallocSizeOf aMallocSizeOf
) {
260 size_t n
= aMallocSizeOf(this);
261 n
+= mObjectValueMap
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
265 size_t nsPropertyTable::SizeOfExcludingThis(
266 mozilla::MallocSizeOf aMallocSizeOf
) const {
269 for (PropertyList
* prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
270 n
+= prop
->SizeOfIncludingThis(aMallocSizeOf
);
276 size_t nsPropertyTable::SizeOfIncludingThis(
277 mozilla::MallocSizeOf aMallocSizeOf
) const {
278 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
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
);