1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim:cindent:ts=2:et:sw=2:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is mozilla.org code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK *****
39 : *
40 : * This Original Code has been modified by IBM Corporation. Modifications made by IBM
41 : * described herein are Copyright (c) International Business Machines Corporation, 2000.
42 : * Modifications to Mozilla code or documentation identified per MPL Section 3.3
43 : *
44 : * Date Modified by Description of modification
45 : * 04/20/2000 IBM Corp. OS/2 VisualAge build.
46 : */
47 :
48 : /**
49 : * nsPropertyTable allows a set of arbitrary key/value pairs to be stored
50 : * for any number of nodes, in a global hashtable rather than on the nodes
51 : * themselves. Nodes can be any type of object; the hashtable keys are
52 : * nsIAtom pointers, and the values are void pointers.
53 : */
54 :
55 : #include "nsPropertyTable.h"
56 : #include "pldhash.h"
57 : #include "nsContentErrors.h"
58 : #include "nsIAtom.h"
59 :
60 : struct PropertyListMapEntry : public PLDHashEntryHdr {
61 : const void *key;
62 : void *value;
63 : };
64 :
65 : //----------------------------------------------------------------------
66 :
67 : class nsPropertyTable::PropertyList {
68 : public:
69 : PropertyList(nsIAtom* aName,
70 : NSPropertyDtorFunc aDtorFunc,
71 : void* aDtorData,
72 : bool aTransfer) NS_HIDDEN;
73 : ~PropertyList() NS_HIDDEN;
74 :
75 : // Removes the property associated with the given object, and destroys
76 : // the property value
77 : NS_HIDDEN_(bool) DeletePropertyFor(nsPropertyOwner aObject);
78 :
79 : // Destroy all remaining properties (without removing them)
80 : NS_HIDDEN_(void) Destroy();
81 :
82 0 : NS_HIDDEN_(bool) Equals(nsIAtom *aPropertyName)
83 : {
84 0 : return mName == aPropertyName;
85 : }
86 :
87 : nsCOMPtr<nsIAtom> mName; // property name
88 : PLDHashTable mObjectValueMap; // map of object/value pairs
89 : NSPropertyDtorFunc mDtorFunc; // property specific value dtor function
90 : void* mDtorData; // pointer to pass to dtor
91 : bool mTransfer; // whether to transfer in
92 : // TransferOrDeleteAllPropertiesFor
93 :
94 : PropertyList* mNext;
95 : };
96 :
97 : void
98 2558 : nsPropertyTable::DeleteAllProperties()
99 : {
100 5116 : while (mPropertyList) {
101 0 : PropertyList* tmp = mPropertyList;
102 :
103 0 : mPropertyList = mPropertyList->mNext;
104 0 : tmp->Destroy();
105 0 : delete tmp;
106 : }
107 2558 : }
108 :
109 : void
110 0 : nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject)
111 : {
112 0 : for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
113 0 : prop->DeletePropertyFor(aObject);
114 : }
115 0 : }
116 :
117 : nsresult
118 0 : nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
119 : nsPropertyTable *aOtherTable)
120 : {
121 0 : nsresult rv = NS_OK;
122 0 : for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
123 0 : if (prop->mTransfer) {
124 : PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
125 : (PL_DHashTableOperate(&prop->mObjectValueMap, aObject,
126 0 : PL_DHASH_LOOKUP));
127 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
128 : rv = aOtherTable->SetProperty(aObject, prop->mName,
129 : entry->value, prop->mDtorFunc,
130 0 : prop->mDtorData, prop->mTransfer);
131 0 : if (NS_FAILED(rv)) {
132 0 : DeleteAllPropertiesFor(aObject);
133 0 : aOtherTable->DeleteAllPropertiesFor(aObject);
134 :
135 0 : break;
136 : }
137 :
138 0 : PL_DHashTableRawRemove(&prop->mObjectValueMap, entry);
139 : }
140 : }
141 : else {
142 0 : prop->DeletePropertyFor(aObject);
143 : }
144 : }
145 :
146 0 : return rv;
147 : }
148 :
149 : void
150 0 : nsPropertyTable::Enumerate(nsPropertyOwner aObject,
151 : NSPropertyFunc aCallback, void *aData)
152 : {
153 : PropertyList* prop;
154 0 : for (prop = mPropertyList; prop; prop = prop->mNext) {
155 : PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
156 0 : (PL_DHashTableOperate(&prop->mObjectValueMap, aObject, PL_DHASH_LOOKUP));
157 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
158 0 : aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
159 0 : aData);
160 : }
161 : }
162 0 : }
163 :
164 : struct PropertyEnumeratorData
165 : {
166 : nsIAtom* mName;
167 : NSPropertyFunc mCallBack;
168 : void* mData;
169 : };
170 :
171 : static PLDHashOperator
172 0 : PropertyEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
173 : PRUint32 aNumber, void* aArg)
174 : {
175 0 : PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(aHdr);
176 0 : PropertyEnumeratorData* data = static_cast<PropertyEnumeratorData*>(aArg);
177 : data->mCallBack(const_cast<void*>(entry->key), data->mName, entry->value,
178 0 : data->mData);
179 0 : return PL_DHASH_NEXT;
180 : }
181 :
182 : void
183 0 : nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData)
184 : {
185 0 : for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
186 0 : PropertyEnumeratorData data = { prop->mName, aCallBack, aData };
187 0 : PL_DHashTableEnumerate(&prop->mObjectValueMap, PropertyEnumerator, &data);
188 : }
189 0 : }
190 :
191 : void*
192 0 : nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
193 : nsIAtom *aPropertyName,
194 : bool aRemove,
195 : nsresult *aResult)
196 : {
197 0 : NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
198 0 : nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
199 0 : void *propValue = nsnull;
200 :
201 0 : PropertyList* propertyList = GetPropertyListFor(aPropertyName);
202 0 : if (propertyList) {
203 : PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
204 : (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject,
205 0 : PL_DHASH_LOOKUP));
206 0 : if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
207 0 : propValue = entry->value;
208 0 : if (aRemove) {
209 : // don't call propertyList->mDtorFunc. That's the caller's job now.
210 0 : PL_DHashTableRawRemove(&propertyList->mObjectValueMap, entry);
211 : }
212 0 : rv = NS_OK;
213 : }
214 : }
215 :
216 0 : if (aResult)
217 0 : *aResult = rv;
218 :
219 0 : return propValue;
220 : }
221 :
222 : nsresult
223 0 : nsPropertyTable::SetPropertyInternal(nsPropertyOwner aObject,
224 : nsIAtom *aPropertyName,
225 : void *aPropertyValue,
226 : NSPropertyDtorFunc aPropDtorFunc,
227 : void *aPropDtorData,
228 : bool aTransfer,
229 : void **aOldValue)
230 : {
231 0 : NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
232 :
233 0 : PropertyList* propertyList = GetPropertyListFor(aPropertyName);
234 :
235 0 : if (propertyList) {
236 : // Make sure the dtor function and data and the transfer flag match
237 0 : if (aPropDtorFunc != propertyList->mDtorFunc ||
238 : aPropDtorData != propertyList->mDtorData ||
239 : aTransfer != propertyList->mTransfer) {
240 0 : NS_WARNING("Destructor/data mismatch while setting property");
241 0 : return NS_ERROR_INVALID_ARG;
242 : }
243 :
244 : } else {
245 : propertyList = new PropertyList(aPropertyName, aPropDtorFunc,
246 0 : aPropDtorData, aTransfer);
247 0 : if (!propertyList || !propertyList->mObjectValueMap.ops) {
248 0 : delete propertyList;
249 0 : return NS_ERROR_OUT_OF_MEMORY;
250 : }
251 :
252 0 : propertyList->mNext = mPropertyList;
253 0 : mPropertyList = propertyList;
254 : }
255 :
256 : // The current property value (if there is one) is replaced and the current
257 : // value is destroyed
258 0 : nsresult result = NS_OK;
259 : PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
260 0 : (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject, PL_DHASH_ADD));
261 0 : if (!entry)
262 0 : return NS_ERROR_OUT_OF_MEMORY;
263 : // A NULL entry->key is the sign that the entry has just been allocated
264 : // for us. If it's non-NULL then we have an existing entry.
265 0 : if (entry->key) {
266 0 : if (aOldValue)
267 0 : *aOldValue = entry->value;
268 0 : else if (propertyList->mDtorFunc)
269 : propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
270 0 : entry->value, propertyList->mDtorData);
271 0 : result = NS_PROPTABLE_PROP_OVERWRITTEN;
272 : }
273 0 : else if (aOldValue) {
274 0 : *aOldValue = nsnull;
275 : }
276 0 : entry->key = aObject;
277 0 : entry->value = aPropertyValue;
278 :
279 0 : return result;
280 : }
281 :
282 : nsresult
283 0 : nsPropertyTable::DeleteProperty(nsPropertyOwner aObject,
284 : nsIAtom *aPropertyName)
285 : {
286 0 : NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
287 :
288 0 : PropertyList* propertyList = GetPropertyListFor(aPropertyName);
289 0 : if (propertyList) {
290 0 : if (propertyList->DeletePropertyFor(aObject))
291 0 : return NS_OK;
292 : }
293 :
294 0 : return NS_PROPTABLE_PROP_NOT_THERE;
295 : }
296 :
297 : nsPropertyTable::PropertyList*
298 0 : nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
299 : {
300 : PropertyList* result;
301 :
302 0 : for (result = mPropertyList; result; result = result->mNext) {
303 0 : if (result->Equals(aPropertyName)) {
304 0 : break;
305 : }
306 : }
307 :
308 0 : return result;
309 : }
310 :
311 : //----------------------------------------------------------------------
312 :
313 0 : nsPropertyTable::PropertyList::PropertyList(nsIAtom *aName,
314 : NSPropertyDtorFunc aDtorFunc,
315 : void *aDtorData,
316 : bool aTransfer)
317 : : mName(aName),
318 : mDtorFunc(aDtorFunc),
319 : mDtorData(aDtorData),
320 : mTransfer(aTransfer),
321 0 : mNext(nsnull)
322 : {
323 : PL_DHashTableInit(&mObjectValueMap, PL_DHashGetStubOps(), this,
324 0 : sizeof(PropertyListMapEntry), 16);
325 0 : }
326 :
327 0 : nsPropertyTable::PropertyList::~PropertyList()
328 : {
329 0 : PL_DHashTableFinish(&mObjectValueMap);
330 0 : }
331 :
332 :
333 : static PLDHashOperator
334 0 : DestroyPropertyEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
335 : PRUint32 number, void *arg)
336 : {
337 : nsPropertyTable::PropertyList *propList =
338 0 : static_cast<nsPropertyTable::PropertyList*>(table->data);
339 0 : PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(hdr);
340 :
341 : propList->mDtorFunc(const_cast<void*>(entry->key), propList->mName,
342 0 : entry->value, propList->mDtorData);
343 0 : return PL_DHASH_NEXT;
344 : }
345 :
346 : void
347 0 : nsPropertyTable::PropertyList::Destroy()
348 : {
349 : // Enumerate any remaining object/value pairs and destroy the value object
350 0 : if (mDtorFunc)
351 : PL_DHashTableEnumerate(&mObjectValueMap, DestroyPropertyEnumerator,
352 0 : nsnull);
353 0 : }
354 :
355 : bool
356 0 : nsPropertyTable::PropertyList::DeletePropertyFor(nsPropertyOwner aObject)
357 : {
358 : PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
359 0 : (PL_DHashTableOperate(&mObjectValueMap, aObject, PL_DHASH_LOOKUP));
360 0 : if (!PL_DHASH_ENTRY_IS_BUSY(entry))
361 0 : return false;
362 :
363 0 : void* value = entry->value;
364 0 : PL_DHashTableRawRemove(&mObjectValueMap, entry);
365 :
366 0 : if (mDtorFunc)
367 0 : mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
368 :
369 0 : return true;
370 : }
371 :
372 : /* static */
373 : void
374 0 : nsPropertyTable::SupportsDtorFunc(void *aObject, nsIAtom *aPropertyName,
375 : void *aPropertyValue, void *aData)
376 : {
377 0 : nsISupports *propertyValue = static_cast<nsISupports*>(aPropertyValue);
378 0 : NS_IF_RELEASE(propertyValue);
379 0 : }
|