Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim:cindent:ts=2:et:sw=2:
3 *
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/.
7 *
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
11 *
12 * Date Modified by Description of modification
13 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
14 */
16 /**
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.
21 */
23 #include "nsPropertyTable.h"
25 #include "mozilla/MemoryReporting.h"
27 #include "pldhash.h"
28 #include "nsError.h"
29 #include "nsIAtom.h"
31 struct PropertyListMapEntry : public PLDHashEntryHdr {
32 const void *key;
33 void *value;
34 };
36 //----------------------------------------------------------------------
38 class nsPropertyTable::PropertyList {
39 public:
40 PropertyList(nsIAtom* aName,
41 NSPropertyDtorFunc aDtorFunc,
42 void* aDtorData,
43 bool aTransfer) NS_HIDDEN;
44 ~PropertyList() NS_HIDDEN;
46 // Removes the property associated with the given object, and destroys
47 // the property value
48 NS_HIDDEN_(bool) DeletePropertyFor(nsPropertyOwner aObject);
50 // Destroy all remaining properties (without removing them)
51 NS_HIDDEN_(void) Destroy();
53 NS_HIDDEN_(bool) Equals(nsIAtom *aPropertyName)
54 {
55 return mName == aPropertyName;
56 }
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
67 PropertyList* mNext;
68 };
70 void
71 nsPropertyTable::DeleteAllProperties()
72 {
73 while (mPropertyList) {
74 PropertyList* tmp = mPropertyList;
76 mPropertyList = mPropertyList->mNext;
77 tmp->Destroy();
78 delete tmp;
79 }
80 }
82 void
83 nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject)
84 {
85 for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
86 prop->DeletePropertyFor(aObject);
87 }
88 }
90 nsresult
91 nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
92 nsPropertyTable *aOtherTable)
93 {
94 nsresult rv = NS_OK;
95 for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
96 if (prop->mTransfer) {
97 PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
98 (PL_DHashTableOperate(&prop->mObjectValueMap, aObject,
99 PL_DHASH_LOOKUP));
100 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
101 rv = aOtherTable->SetProperty(aObject, prop->mName,
102 entry->value, prop->mDtorFunc,
103 prop->mDtorData, prop->mTransfer);
104 if (NS_FAILED(rv)) {
105 DeleteAllPropertiesFor(aObject);
106 aOtherTable->DeleteAllPropertiesFor(aObject);
108 break;
109 }
111 PL_DHashTableRawRemove(&prop->mObjectValueMap, entry);
112 }
113 }
114 else {
115 prop->DeletePropertyFor(aObject);
116 }
117 }
119 return rv;
120 }
122 void
123 nsPropertyTable::Enumerate(nsPropertyOwner aObject,
124 NSPropertyFunc aCallback, void *aData)
125 {
126 PropertyList* prop;
127 for (prop = mPropertyList; prop; prop = prop->mNext) {
128 PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
129 (PL_DHashTableOperate(&prop->mObjectValueMap, aObject, PL_DHASH_LOOKUP));
130 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
131 aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
132 aData);
133 }
134 }
135 }
137 struct PropertyEnumeratorData
138 {
139 nsIAtom* mName;
140 NSPropertyFunc mCallBack;
141 void* mData;
142 };
144 static PLDHashOperator
145 PropertyEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
146 uint32_t aNumber, void* aArg)
147 {
148 PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(aHdr);
149 PropertyEnumeratorData* data = static_cast<PropertyEnumeratorData*>(aArg);
150 data->mCallBack(const_cast<void*>(entry->key), data->mName, entry->value,
151 data->mData);
152 return PL_DHASH_NEXT;
153 }
155 void
156 nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData)
157 {
158 for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
159 PropertyEnumeratorData data = { prop->mName, aCallBack, aData };
160 PL_DHashTableEnumerate(&prop->mObjectValueMap, PropertyEnumerator, &data);
161 }
162 }
164 void*
165 nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
166 nsIAtom *aPropertyName,
167 bool aRemove,
168 nsresult *aResult)
169 {
170 NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
171 nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
172 void *propValue = nullptr;
174 PropertyList* propertyList = GetPropertyListFor(aPropertyName);
175 if (propertyList) {
176 PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
177 (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject,
178 PL_DHASH_LOOKUP));
179 if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
180 propValue = entry->value;
181 if (aRemove) {
182 // don't call propertyList->mDtorFunc. That's the caller's job now.
183 PL_DHashTableRawRemove(&propertyList->mObjectValueMap, entry);
184 }
185 rv = NS_OK;
186 }
187 }
189 if (aResult)
190 *aResult = rv;
192 return propValue;
193 }
195 nsresult
196 nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
197 nsIAtom *aPropertyName,
198 void *aPropertyValue,
199 NSPropertyDtorFunc aPropDtorFunc,
200 void *aPropDtorData,
201 bool aTransfer,
202 void **aOldValue)
203 {
204 NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
206 PropertyList* propertyList = GetPropertyListFor(aPropertyName);
208 if (propertyList) {
209 // Make sure the dtor function and data and the transfer flag match
210 if (aPropDtorFunc != propertyList->mDtorFunc ||
211 aPropDtorData != propertyList->mDtorData ||
212 aTransfer != propertyList->mTransfer) {
213 NS_WARNING("Destructor/data mismatch while setting property");
214 return NS_ERROR_INVALID_ARG;
215 }
217 } else {
218 propertyList = new PropertyList(aPropertyName, aPropDtorFunc,
219 aPropDtorData, aTransfer);
220 if (!propertyList || !propertyList->mObjectValueMap.ops) {
221 delete propertyList;
222 return NS_ERROR_OUT_OF_MEMORY;
223 }
225 propertyList->mNext = mPropertyList;
226 mPropertyList = propertyList;
227 }
229 // The current property value (if there is one) is replaced and the current
230 // value is destroyed
231 nsresult result = NS_OK;
232 PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
233 (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject, PL_DHASH_ADD));
234 if (!entry)
235 return NS_ERROR_OUT_OF_MEMORY;
236 // A nullptr entry->key is the sign that the entry has just been allocated
237 // for us. If it's non-nullptr then we have an existing entry.
238 if (entry->key) {
239 if (aOldValue)
240 *aOldValue = entry->value;
241 else if (propertyList->mDtorFunc)
242 propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
243 entry->value, propertyList->mDtorData);
244 result = NS_PROPTABLE_PROP_OVERWRITTEN;
245 }
246 else if (aOldValue) {
247 *aOldValue = nullptr;
248 }
249 entry->key = aObject;
250 entry->value = aPropertyValue;
252 return result;
253 }
255 nsresult
256 nsPropertyTable::DeleteProperty(nsPropertyOwner aObject,
257 nsIAtom *aPropertyName)
258 {
259 NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
261 PropertyList* propertyList = GetPropertyListFor(aPropertyName);
262 if (propertyList) {
263 if (propertyList->DeletePropertyFor(aObject))
264 return NS_OK;
265 }
267 return NS_PROPTABLE_PROP_NOT_THERE;
268 }
270 nsPropertyTable::PropertyList*
271 nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
272 {
273 PropertyList* result;
275 for (result = mPropertyList; result; result = result->mNext) {
276 if (result->Equals(aPropertyName)) {
277 break;
278 }
279 }
281 return result;
282 }
284 //----------------------------------------------------------------------
286 nsPropertyTable::PropertyList::PropertyList(nsIAtom *aName,
287 NSPropertyDtorFunc aDtorFunc,
288 void *aDtorData,
289 bool aTransfer)
290 : mName(aName),
291 mDtorFunc(aDtorFunc),
292 mDtorData(aDtorData),
293 mTransfer(aTransfer),
294 mNext(nullptr)
295 {
296 PL_DHashTableInit(&mObjectValueMap, PL_DHashGetStubOps(), this,
297 sizeof(PropertyListMapEntry), 16);
298 }
300 nsPropertyTable::PropertyList::~PropertyList()
301 {
302 PL_DHashTableFinish(&mObjectValueMap);
303 }
306 static PLDHashOperator
307 DestroyPropertyEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
308 uint32_t number, void *arg)
309 {
310 nsPropertyTable::PropertyList *propList =
311 static_cast<nsPropertyTable::PropertyList*>(table->data);
312 PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(hdr);
314 propList->mDtorFunc(const_cast<void*>(entry->key), propList->mName,
315 entry->value, propList->mDtorData);
316 return PL_DHASH_NEXT;
317 }
319 void
320 nsPropertyTable::PropertyList::Destroy()
321 {
322 // Enumerate any remaining object/value pairs and destroy the value object
323 if (mDtorFunc)
324 PL_DHashTableEnumerate(&mObjectValueMap, DestroyPropertyEnumerator,
325 nullptr);
326 }
328 bool
329 nsPropertyTable::PropertyList::DeletePropertyFor(nsPropertyOwner aObject)
330 {
331 PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
332 (PL_DHashTableOperate(&mObjectValueMap, aObject, PL_DHASH_LOOKUP));
333 if (!PL_DHASH_ENTRY_IS_BUSY(entry))
334 return false;
336 void* value = entry->value;
337 PL_DHashTableRawRemove(&mObjectValueMap, entry);
339 if (mDtorFunc)
340 mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
342 return true;
343 }
345 size_t
346 nsPropertyTable::PropertyList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
347 {
348 size_t n = aMallocSizeOf(this);
349 n += PL_DHashTableSizeOfExcludingThis(&mObjectValueMap, nullptr, aMallocSizeOf);
350 return n;
351 }
353 size_t
354 nsPropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
355 {
356 size_t n = 0;
358 for (PropertyList *prop = mPropertyList; prop; prop = prop->mNext) {
359 n += prop->SizeOfIncludingThis(aMallocSizeOf);
360 }
362 return n;
363 }
365 /* static */
366 void
367 nsPropertyTable::SupportsDtorFunc(void *aObject, nsIAtom *aPropertyName,
368 void *aPropertyValue, void *aData)
369 {
370 nsISupports *propertyValue = static_cast<nsISupports*>(aPropertyValue);
371 NS_IF_RELEASE(propertyValue);
372 }