Line data Source code
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/.
6 : *
7 : * This Original Code has been modified by IBM Corporation. Modifications made by IBM
8 : * described herein are Copyright (c) International Business Machines Corporation, 2000.
9 : * Modifications to Mozilla code or documentation identified per MPL Section 3.3
10 : *
11 : * Date Modified by Description of modification
12 : * 04/20/2000 IBM Corp. OS/2 VisualAge build.
13 : */
14 :
15 : /**
16 : * nsPropertyTable allows a set of arbitrary key/value pairs to be stored
17 : * for any number of nodes, in a global hashtable rather than on the nodes
18 : * themselves. Nodes can be any type of object; the hashtable keys are
19 : * nsIAtom pointers, and the values are void pointers.
20 : */
21 :
22 : #include "nsPropertyTable.h"
23 :
24 : #include "mozilla/MemoryReporting.h"
25 :
26 : #include "PLDHashTable.h"
27 : #include "nsError.h"
28 : #include "nsIAtom.h"
29 :
30 : struct PropertyListMapEntry : public PLDHashEntryHdr {
31 : const void *key;
32 : void *value;
33 : };
34 :
35 : //----------------------------------------------------------------------
36 :
37 : class nsPropertyTable::PropertyList {
38 : public:
39 : PropertyList(nsIAtom* aName,
40 : NSPropertyDtorFunc aDtorFunc,
41 : void* aDtorData,
42 : bool aTransfer);
43 : ~PropertyList();
44 :
45 : // Removes the property associated with the given object, and destroys
46 : // the property value
47 : bool DeletePropertyFor(nsPropertyOwner aObject);
48 :
49 : // Destroy all remaining properties (without removing them)
50 : void Destroy();
51 :
52 34853 : bool Equals(nsIAtom *aPropertyName)
53 : {
54 34853 : return mName == aPropertyName;
55 : }
56 :
57 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
58 :
59 : nsCOMPtr<nsIAtom> mName; // property name
60 : PLDHashTable mObjectValueMap; // map of object/value pairs
61 : NSPropertyDtorFunc mDtorFunc; // property specific value dtor function
62 : void* mDtorData; // pointer to pass to dtor
63 : bool mTransfer; // whether to transfer in
64 : // TransferOrDeleteAllPropertiesFor
65 :
66 : PropertyList* mNext;
67 : };
68 :
69 : void
70 0 : nsPropertyTable::DeleteAllProperties()
71 : {
72 0 : while (mPropertyList) {
73 0 : PropertyList* tmp = mPropertyList;
74 :
75 0 : mPropertyList = mPropertyList->mNext;
76 0 : tmp->Destroy();
77 0 : delete tmp;
78 : }
79 0 : }
80 :
81 : void
82 0 : nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject)
83 : {
84 0 : for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
85 0 : prop->DeletePropertyFor(aObject);
86 : }
87 0 : }
88 :
89 : nsresult
90 0 : nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
91 : nsPropertyTable *aOtherTable)
92 : {
93 0 : nsresult rv = NS_OK;
94 0 : for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
95 0 : if (prop->mTransfer) {
96 : auto entry = static_cast<PropertyListMapEntry*>
97 0 : (prop->mObjectValueMap.Search(aObject));
98 0 : if (entry) {
99 0 : rv = aOtherTable->SetProperty(aObject, prop->mName,
100 : entry->value, prop->mDtorFunc,
101 0 : prop->mDtorData, prop->mTransfer);
102 0 : if (NS_FAILED(rv)) {
103 0 : DeleteAllPropertiesFor(aObject);
104 0 : aOtherTable->DeleteAllPropertiesFor(aObject);
105 :
106 0 : break;
107 : }
108 :
109 0 : prop->mObjectValueMap.RemoveEntry(entry);
110 : }
111 : }
112 : else {
113 0 : prop->DeletePropertyFor(aObject);
114 : }
115 : }
116 :
117 0 : return rv;
118 : }
119 :
120 : void
121 1 : nsPropertyTable::Enumerate(nsPropertyOwner aObject,
122 : NSPropertyFunc aCallback, void *aData)
123 : {
124 : PropertyList* prop;
125 1 : for (prop = mPropertyList; prop; prop = prop->mNext) {
126 : auto entry = static_cast<PropertyListMapEntry*>
127 0 : (prop->mObjectValueMap.Search(aObject));
128 0 : if (entry) {
129 0 : aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
130 0 : aData);
131 : }
132 : }
133 1 : }
134 :
135 : void
136 0 : nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData)
137 : {
138 0 : for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
139 0 : for (auto iter = prop->mObjectValueMap.Iter(); !iter.Done(); iter.Next()) {
140 0 : auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
141 0 : aCallBack(const_cast<void*>(entry->key), prop->mName, entry->value,
142 0 : aData);
143 : }
144 : }
145 0 : }
146 :
147 : void*
148 4912 : nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
149 : nsIAtom *aPropertyName,
150 : bool aRemove,
151 : nsresult *aResult)
152 : {
153 4912 : NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
154 4912 : nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
155 4912 : void *propValue = nullptr;
156 :
157 4912 : PropertyList* propertyList = GetPropertyListFor(aPropertyName);
158 4912 : if (propertyList) {
159 : auto entry = static_cast<PropertyListMapEntry*>
160 2252 : (propertyList->mObjectValueMap.Search(aObject));
161 2252 : if (entry) {
162 977 : propValue = entry->value;
163 977 : if (aRemove) {
164 : // don't call propertyList->mDtorFunc. That's the caller's job now.
165 13 : propertyList->mObjectValueMap.RemoveEntry(entry);
166 : }
167 977 : rv = NS_OK;
168 : }
169 : }
170 :
171 4912 : if (aResult)
172 259 : *aResult = rv;
173 :
174 4912 : return propValue;
175 : }
176 :
177 : nsresult
178 402 : nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
179 : nsIAtom *aPropertyName,
180 : void *aPropertyValue,
181 : NSPropertyDtorFunc aPropDtorFunc,
182 : void *aPropDtorData,
183 : bool aTransfer,
184 : void **aOldValue)
185 : {
186 402 : NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
187 :
188 402 : PropertyList* propertyList = GetPropertyListFor(aPropertyName);
189 :
190 402 : if (propertyList) {
191 : // Make sure the dtor function and data and the transfer flag match
192 652 : if (aPropDtorFunc != propertyList->mDtorFunc ||
193 652 : aPropDtorData != propertyList->mDtorData ||
194 326 : aTransfer != propertyList->mTransfer) {
195 0 : NS_WARNING("Destructor/data mismatch while setting property");
196 0 : return NS_ERROR_INVALID_ARG;
197 : }
198 :
199 : } else {
200 76 : propertyList = new PropertyList(aPropertyName, aPropDtorFunc,
201 76 : aPropDtorData, aTransfer);
202 76 : propertyList->mNext = mPropertyList;
203 76 : mPropertyList = propertyList;
204 : }
205 :
206 : // The current property value (if there is one) is replaced and the current
207 : // value is destroyed
208 402 : nsresult result = NS_OK;
209 : auto entry = static_cast<PropertyListMapEntry*>
210 402 : (propertyList->mObjectValueMap.Add(aObject, mozilla::fallible));
211 402 : if (!entry)
212 0 : return NS_ERROR_OUT_OF_MEMORY;
213 : // A nullptr entry->key is the sign that the entry has just been allocated
214 : // for us. If it's non-nullptr then we have an existing entry.
215 402 : if (entry->key) {
216 257 : if (aOldValue)
217 0 : *aOldValue = entry->value;
218 257 : else if (propertyList->mDtorFunc)
219 257 : propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
220 257 : entry->value, propertyList->mDtorData);
221 257 : result = NS_PROPTABLE_PROP_OVERWRITTEN;
222 : }
223 145 : else if (aOldValue) {
224 0 : *aOldValue = nullptr;
225 : }
226 402 : entry->key = aObject;
227 402 : entry->value = aPropertyValue;
228 :
229 402 : return result;
230 : }
231 :
232 : nsresult
233 35 : nsPropertyTable::DeleteProperty(nsPropertyOwner aObject,
234 : nsIAtom *aPropertyName)
235 : {
236 35 : NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
237 :
238 35 : PropertyList* propertyList = GetPropertyListFor(aPropertyName);
239 35 : if (propertyList) {
240 17 : if (propertyList->DeletePropertyFor(aObject))
241 17 : return NS_OK;
242 : }
243 :
244 18 : return NS_PROPTABLE_PROP_NOT_THERE;
245 : }
246 :
247 : nsPropertyTable::PropertyList*
248 5349 : nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
249 : {
250 : PropertyList* result;
251 :
252 37607 : for (result = mPropertyList; result; result = result->mNext) {
253 34853 : if (result->Equals(aPropertyName)) {
254 2595 : break;
255 : }
256 : }
257 :
258 5349 : return result;
259 : }
260 :
261 : //----------------------------------------------------------------------
262 :
263 76 : nsPropertyTable::PropertyList::PropertyList(nsIAtom *aName,
264 : NSPropertyDtorFunc aDtorFunc,
265 : void *aDtorData,
266 76 : bool aTransfer)
267 : : mName(aName),
268 : mObjectValueMap(PLDHashTable::StubOps(), sizeof(PropertyListMapEntry)),
269 : mDtorFunc(aDtorFunc),
270 : mDtorData(aDtorData),
271 : mTransfer(aTransfer),
272 76 : mNext(nullptr)
273 : {
274 76 : }
275 :
276 0 : nsPropertyTable::PropertyList::~PropertyList()
277 : {
278 0 : }
279 :
280 : void
281 0 : nsPropertyTable::PropertyList::Destroy()
282 : {
283 : // Enumerate any remaining object/value pairs and destroy the value object.
284 0 : if (mDtorFunc) {
285 0 : for (auto iter = mObjectValueMap.Iter(); !iter.Done(); iter.Next()) {
286 0 : auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
287 0 : mDtorFunc(const_cast<void*>(entry->key), mName, entry->value, mDtorData);
288 : }
289 : }
290 0 : }
291 :
292 : bool
293 17 : nsPropertyTable::PropertyList::DeletePropertyFor(nsPropertyOwner aObject)
294 : {
295 : auto entry =
296 17 : static_cast<PropertyListMapEntry*>(mObjectValueMap.Search(aObject));
297 17 : if (!entry)
298 0 : return false;
299 :
300 17 : void* value = entry->value;
301 17 : mObjectValueMap.RemoveEntry(entry);
302 :
303 17 : if (mDtorFunc)
304 17 : mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
305 :
306 17 : return true;
307 : }
308 :
309 : size_t
310 23 : nsPropertyTable::PropertyList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
311 : {
312 23 : size_t n = aMallocSizeOf(this);
313 23 : n += mObjectValueMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
314 23 : return n;
315 : }
316 :
317 : size_t
318 21 : nsPropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
319 : {
320 21 : size_t n = 0;
321 :
322 44 : for (PropertyList *prop = mPropertyList; prop; prop = prop->mNext) {
323 23 : n += prop->SizeOfIncludingThis(aMallocSizeOf);
324 : }
325 :
326 21 : return n;
327 : }
328 :
329 : size_t
330 0 : nsPropertyTable::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
331 : {
332 0 : return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
333 : }
334 :
335 : /* static */
336 : void
337 1 : nsPropertyTable::SupportsDtorFunc(void *aObject, nsIAtom *aPropertyName,
338 : void *aPropertyValue, void *aData)
339 : {
340 1 : nsISupports *propertyValue = static_cast<nsISupports*>(aPropertyValue);
341 1 : NS_IF_RELEASE(propertyValue);
342 1 : }
|