1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim:cindent:ts=2:et:sw=2:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This Original Code has been modified by IBM Corporation. Modifications made by IBM
9 * described herein are Copyright (c) International Business Machines Corporation, 2000.
10 * Modifications to Mozilla code or documentation identified per MPL Section 3.3
12 * Date Modified by Description of modification
13 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
17 * nsPropertyTable allows a set of arbitrary key/value pairs to be stored
18 * for any number of nodes, in a global hashtable rather than on the nodes
19 * themselves. Nodes can be any type of object; the hashtable keys are
20 * nsIAtom pointers, and the values are void pointers.
23 #include "nsPropertyTable.h"
25 #include "mozilla/MemoryReporting.h"
31 struct PropertyListMapEntry
: public PLDHashEntryHdr
{
36 //----------------------------------------------------------------------
38 class nsPropertyTable::PropertyList
{
40 PropertyList(nsIAtom
* aName
,
41 NSPropertyDtorFunc aDtorFunc
,
46 // Removes the property associated with the given object, and destroys
48 bool DeletePropertyFor(nsPropertyOwner aObject
);
50 // Destroy all remaining properties (without removing them)
53 bool Equals(nsIAtom
*aPropertyName
)
55 return mName
== aPropertyName
;
58 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
);
60 nsCOMPtr
<nsIAtom
> mName
; // property name
61 PLDHashTable mObjectValueMap
; // map of object/value pairs
62 NSPropertyDtorFunc mDtorFunc
; // property specific value dtor function
63 void* mDtorData
; // pointer to pass to dtor
64 bool mTransfer
; // whether to transfer in
65 // TransferOrDeleteAllPropertiesFor
71 nsPropertyTable::DeleteAllProperties()
73 while (mPropertyList
) {
74 PropertyList
* tmp
= mPropertyList
;
76 mPropertyList
= mPropertyList
->mNext
;
83 nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject
)
85 for (PropertyList
* prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
86 prop
->DeletePropertyFor(aObject
);
91 nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject
,
92 nsPropertyTable
*aOtherTable
)
95 for (PropertyList
* prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
96 if (prop
->mTransfer
) {
97 PropertyListMapEntry
*entry
= static_cast<PropertyListMapEntry
*>
98 (PL_DHashTableLookup(&prop
->mObjectValueMap
, aObject
));
99 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
100 rv
= aOtherTable
->SetProperty(aObject
, prop
->mName
,
101 entry
->value
, prop
->mDtorFunc
,
102 prop
->mDtorData
, prop
->mTransfer
);
104 DeleteAllPropertiesFor(aObject
);
105 aOtherTable
->DeleteAllPropertiesFor(aObject
);
110 PL_DHashTableRawRemove(&prop
->mObjectValueMap
, entry
);
114 prop
->DeletePropertyFor(aObject
);
122 nsPropertyTable::Enumerate(nsPropertyOwner aObject
,
123 NSPropertyFunc aCallback
, void *aData
)
126 for (prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
127 PropertyListMapEntry
*entry
= static_cast<PropertyListMapEntry
*>
128 (PL_DHashTableLookup(&prop
->mObjectValueMap
, aObject
));
129 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
130 aCallback(const_cast<void*>(aObject
.get()), prop
->mName
, entry
->value
,
136 struct PropertyEnumeratorData
139 NSPropertyFunc mCallBack
;
143 static PLDHashOperator
144 PropertyEnumerator(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
145 uint32_t aNumber
, void* aArg
)
147 PropertyListMapEntry
* entry
= static_cast<PropertyListMapEntry
*>(aHdr
);
148 PropertyEnumeratorData
* data
= static_cast<PropertyEnumeratorData
*>(aArg
);
149 data
->mCallBack(const_cast<void*>(entry
->key
), data
->mName
, entry
->value
,
151 return PL_DHASH_NEXT
;
155 nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack
, void* aData
)
157 for (PropertyList
* prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
158 PropertyEnumeratorData data
= { prop
->mName
, aCallBack
, aData
};
159 PL_DHashTableEnumerate(&prop
->mObjectValueMap
, PropertyEnumerator
, &data
);
164 nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject
,
165 nsIAtom
*aPropertyName
,
169 NS_PRECONDITION(aPropertyName
&& aObject
, "unexpected null param");
170 nsresult rv
= NS_PROPTABLE_PROP_NOT_THERE
;
171 void *propValue
= nullptr;
173 PropertyList
* propertyList
= GetPropertyListFor(aPropertyName
);
175 PropertyListMapEntry
*entry
= static_cast<PropertyListMapEntry
*>
176 (PL_DHashTableLookup(&propertyList
->mObjectValueMap
, aObject
));
177 if (PL_DHASH_ENTRY_IS_BUSY(entry
)) {
178 propValue
= entry
->value
;
180 // don't call propertyList->mDtorFunc. That's the caller's job now.
181 PL_DHashTableRawRemove(&propertyList
->mObjectValueMap
, entry
);
194 nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject
,
195 nsIAtom
*aPropertyName
,
196 void *aPropertyValue
,
197 NSPropertyDtorFunc aPropDtorFunc
,
202 NS_PRECONDITION(aPropertyName
&& aObject
, "unexpected null param");
204 PropertyList
* propertyList
= GetPropertyListFor(aPropertyName
);
207 // Make sure the dtor function and data and the transfer flag match
208 if (aPropDtorFunc
!= propertyList
->mDtorFunc
||
209 aPropDtorData
!= propertyList
->mDtorData
||
210 aTransfer
!= propertyList
->mTransfer
) {
211 NS_WARNING("Destructor/data mismatch while setting property");
212 return NS_ERROR_INVALID_ARG
;
216 propertyList
= new PropertyList(aPropertyName
, aPropDtorFunc
,
217 aPropDtorData
, aTransfer
);
218 if (!propertyList
|| !propertyList
->mObjectValueMap
.ops
) {
220 return NS_ERROR_OUT_OF_MEMORY
;
223 propertyList
->mNext
= mPropertyList
;
224 mPropertyList
= propertyList
;
227 // The current property value (if there is one) is replaced and the current
228 // value is destroyed
229 nsresult result
= NS_OK
;
230 PropertyListMapEntry
*entry
= static_cast<PropertyListMapEntry
*>
231 (PL_DHashTableAdd(&propertyList
->mObjectValueMap
, aObject
));
233 return NS_ERROR_OUT_OF_MEMORY
;
234 // A nullptr entry->key is the sign that the entry has just been allocated
235 // for us. If it's non-nullptr then we have an existing entry.
238 *aOldValue
= entry
->value
;
239 else if (propertyList
->mDtorFunc
)
240 propertyList
->mDtorFunc(const_cast<void*>(entry
->key
), aPropertyName
,
241 entry
->value
, propertyList
->mDtorData
);
242 result
= NS_PROPTABLE_PROP_OVERWRITTEN
;
244 else if (aOldValue
) {
245 *aOldValue
= nullptr;
247 entry
->key
= aObject
;
248 entry
->value
= aPropertyValue
;
254 nsPropertyTable::DeleteProperty(nsPropertyOwner aObject
,
255 nsIAtom
*aPropertyName
)
257 NS_PRECONDITION(aPropertyName
&& aObject
, "unexpected null param");
259 PropertyList
* propertyList
= GetPropertyListFor(aPropertyName
);
261 if (propertyList
->DeletePropertyFor(aObject
))
265 return NS_PROPTABLE_PROP_NOT_THERE
;
268 nsPropertyTable::PropertyList
*
269 nsPropertyTable::GetPropertyListFor(nsIAtom
* aPropertyName
) const
271 PropertyList
* result
;
273 for (result
= mPropertyList
; result
; result
= result
->mNext
) {
274 if (result
->Equals(aPropertyName
)) {
282 //----------------------------------------------------------------------
284 nsPropertyTable::PropertyList::PropertyList(nsIAtom
*aName
,
285 NSPropertyDtorFunc aDtorFunc
,
289 mDtorFunc(aDtorFunc
),
290 mDtorData(aDtorData
),
291 mTransfer(aTransfer
),
294 PL_DHashTableInit(&mObjectValueMap
, PL_DHashGetStubOps(), this,
295 sizeof(PropertyListMapEntry
));
298 nsPropertyTable::PropertyList::~PropertyList()
300 PL_DHashTableFinish(&mObjectValueMap
);
304 static PLDHashOperator
305 DestroyPropertyEnumerator(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
306 uint32_t number
, void *arg
)
308 nsPropertyTable::PropertyList
*propList
=
309 static_cast<nsPropertyTable::PropertyList
*>(table
->data
);
310 PropertyListMapEntry
* entry
= static_cast<PropertyListMapEntry
*>(hdr
);
312 propList
->mDtorFunc(const_cast<void*>(entry
->key
), propList
->mName
,
313 entry
->value
, propList
->mDtorData
);
314 return PL_DHASH_NEXT
;
318 nsPropertyTable::PropertyList::Destroy()
320 // Enumerate any remaining object/value pairs and destroy the value object
322 PL_DHashTableEnumerate(&mObjectValueMap
, DestroyPropertyEnumerator
,
327 nsPropertyTable::PropertyList::DeletePropertyFor(nsPropertyOwner aObject
)
329 PropertyListMapEntry
*entry
= static_cast<PropertyListMapEntry
*>
330 (PL_DHashTableLookup(&mObjectValueMap
, aObject
));
331 if (!PL_DHASH_ENTRY_IS_BUSY(entry
))
334 void* value
= entry
->value
;
335 PL_DHashTableRawRemove(&mObjectValueMap
, entry
);
338 mDtorFunc(const_cast<void*>(aObject
.get()), mName
, value
, mDtorData
);
344 nsPropertyTable::PropertyList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
)
346 size_t n
= aMallocSizeOf(this);
347 n
+= PL_DHashTableSizeOfExcludingThis(&mObjectValueMap
, nullptr, aMallocSizeOf
);
352 nsPropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const
356 for (PropertyList
*prop
= mPropertyList
; prop
; prop
= prop
->mNext
) {
357 n
+= prop
->SizeOfIncludingThis(aMallocSizeOf
);
364 nsPropertyTable::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const
366 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
371 nsPropertyTable::SupportsDtorFunc(void *aObject
, nsIAtom
*aPropertyName
,
372 void *aPropertyValue
, void *aData
)
374 nsISupports
*propertyValue
= static_cast<nsISupports
*>(aPropertyValue
);
375 NS_IF_RELEASE(propertyValue
);