Back to index

lightning-sunbird  0.9+nobinonly
nsPropertyTable.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * vim:cindent:ts=2:et:sw=2:
00003  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is mozilla.org code.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK *****
00039  *
00040  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
00041  * described herein are Copyright (c) International Business Machines Corporation, 2000.
00042  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
00043  *
00044  * Date             Modified by     Description of modification
00045  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
00046  */
00047 
00048 #include "nsPropertyTable.h"
00049 #include "pldhash.h"
00050 #include "nsContentErrors.h"
00051 #include "nsIAtom.h"
00052 
00053 struct PropertyListMapEntry : public PLDHashEntryHdr {
00054   const void  *key;
00055   void        *value;
00056 };
00057 
00058 //----------------------------------------------------------------------
00059 
00060 struct nsPropertyTable::PropertyList {
00061   nsCOMPtr<nsIAtom>       mName;          // property name
00062   PLDHashTable            mObjectValueMap; // map of object/value pairs
00063   NSPropertyDtorFunc      mDtorFunc;      // property specific value dtor function
00064   void*                   mDtorData;
00065   PropertyList*           mNext;
00066 
00067   PropertyList(nsIAtom*           aName,
00068                NSPropertyDtorFunc aDtorFunc,
00069                void*              aDtorData) NS_HIDDEN;
00070   ~PropertyList() NS_HIDDEN;
00071 
00072   // Removes the property associated with the given object, and destroys
00073   // the property value
00074   NS_HIDDEN_(PRBool) DeletePropertyFor(const void    * aObject);
00075 
00076   // Destroy all remaining properties (without removing them)
00077   NS_HIDDEN_(void) Destroy();
00078 };
00079 
00080 void
00081 nsPropertyTable::DeleteAllProperties()
00082 {
00083   while (mPropertyList) {
00084     PropertyList* tmp = mPropertyList;
00085 
00086     mPropertyList = mPropertyList->mNext;
00087     tmp->Destroy();
00088     delete tmp;
00089   }
00090 }
00091  
00092 void
00093 nsPropertyTable::DeleteAllPropertiesFor(const void *aObject)
00094 {
00095   for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
00096     prop->DeletePropertyFor(aObject);
00097   }
00098 }
00099 
00100 void*
00101 nsPropertyTable::GetPropertyInternal(const void *aObject,
00102                                      nsIAtom    *aPropertyName,
00103                                      PRBool      aRemove,
00104                                      nsresult   *aResult)
00105 {
00106   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
00107   nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
00108   void *propValue = nsnull;
00109 
00110   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
00111   if (propertyList) {
00112     PropertyListMapEntry *entry = NS_STATIC_CAST(PropertyListMapEntry*,
00113         PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject,
00114                              PL_DHASH_LOOKUP));
00115     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
00116       propValue = entry->value;
00117       if (aRemove) {
00118         // don't call propertyList->mDtorFunc.  That's the caller's job now.
00119         PL_DHashTableRawRemove(&propertyList->mObjectValueMap, entry);
00120       }
00121       rv = NS_OK;
00122     }
00123   }
00124 
00125   if (aResult)
00126     *aResult = rv;
00127 
00128   return propValue;
00129 }
00130 
00131 nsresult
00132 nsPropertyTable::SetProperty(const void         *aObject,
00133                              nsIAtom            *aPropertyName,
00134                              void               *aPropertyValue,
00135                              NSPropertyDtorFunc  aPropDtorFunc,
00136                              void               *aPropDtorData)
00137 {
00138   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
00139 
00140   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
00141 
00142   if (propertyList) {
00143     // Make sure the dtor function and data match
00144     if (aPropDtorFunc != propertyList->mDtorFunc ||
00145         aPropDtorData != propertyList->mDtorData) {
00146       return NS_ERROR_INVALID_ARG;
00147     }
00148 
00149   } else {
00150     propertyList = new PropertyList(aPropertyName, aPropDtorFunc,
00151                                     aPropDtorData);
00152     if (!propertyList)
00153       return NS_ERROR_OUT_OF_MEMORY;
00154     if (!propertyList->mObjectValueMap.ops) {
00155       delete propertyList;
00156       return NS_ERROR_OUT_OF_MEMORY;
00157     }
00158 
00159     propertyList->mNext = mPropertyList;
00160     mPropertyList = propertyList;
00161   }
00162 
00163   // The current property value (if there is one) is replaced and the current
00164   // value is destroyed
00165   nsresult result = NS_OK;
00166   PropertyListMapEntry *entry = NS_STATIC_CAST(PropertyListMapEntry*,
00167     PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject, PL_DHASH_ADD));
00168   if (!entry)
00169     return NS_ERROR_OUT_OF_MEMORY;
00170   // A NULL entry->key is the sign that the entry has just been allocated
00171   // for us.  If it's non-NULL then we have an existing entry.
00172   if (entry->key && propertyList->mDtorFunc) {
00173     propertyList->mDtorFunc(NS_CONST_CAST(void*, entry->key), aPropertyName,
00174                             entry->value, propertyList->mDtorData);
00175     result = NS_PROPTABLE_PROP_OVERWRITTEN;
00176   }
00177   entry->key = aObject;
00178   entry->value = aPropertyValue;
00179 
00180   return result;
00181 }
00182 
00183 nsresult
00184 nsPropertyTable::DeleteProperty(const void *aObject,
00185                                 nsIAtom    *aPropertyName)
00186 {
00187   NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
00188 
00189   PropertyList* propertyList = GetPropertyListFor(aPropertyName);
00190   if (propertyList) {
00191     if (propertyList->DeletePropertyFor(aObject))
00192       return NS_OK;
00193   }
00194 
00195   return NS_PROPTABLE_PROP_NOT_THERE;
00196 }
00197 
00198 nsPropertyTable::PropertyList*
00199 nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
00200 {
00201   PropertyList* result;
00202 
00203   for (result = mPropertyList; result; result = result->mNext) {
00204     if (result->mName.get() == aPropertyName) {
00205       break;
00206     }
00207   }
00208 
00209   return result;
00210 }
00211 
00212 //----------------------------------------------------------------------
00213     
00214 nsPropertyTable::PropertyList::PropertyList(nsIAtom            *aName,
00215                                             NSPropertyDtorFunc  aDtorFunc,
00216                                             void               *aDtorData)
00217   : mName(aName), mDtorFunc(aDtorFunc), mDtorData(aDtorData), mNext(nsnull)
00218 {
00219   PL_DHashTableInit(&mObjectValueMap, PL_DHashGetStubOps(), this,
00220                     sizeof(PropertyListMapEntry), 16);
00221 }
00222 
00223 nsPropertyTable::PropertyList::~PropertyList()
00224 {
00225   PL_DHashTableFinish(&mObjectValueMap);
00226 }
00227 
00228 
00229 PR_STATIC_CALLBACK(PLDHashOperator)
00230 DestroyPropertyEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
00231                           PRUint32 number, void *arg)
00232 {
00233   nsPropertyTable::PropertyList *propList =
00234       NS_STATIC_CAST(nsPropertyTable::PropertyList*, table->data);
00235   PropertyListMapEntry* entry = NS_STATIC_CAST(PropertyListMapEntry*, hdr);
00236 
00237   propList->mDtorFunc(NS_CONST_CAST(void*, entry->key), propList->mName,
00238                       entry->value, propList->mDtorData);
00239   return PL_DHASH_NEXT;
00240 }
00241 
00242 void
00243 nsPropertyTable::PropertyList::Destroy()
00244 {
00245   // Enumerate any remaining frame/value pairs and destroy the value object
00246   if (mDtorFunc)
00247     PL_DHashTableEnumerate(&mObjectValueMap, DestroyPropertyEnumerator,
00248                            nsnull);
00249 }
00250 
00251 PRBool
00252 nsPropertyTable::PropertyList::DeletePropertyFor(const void* aObject)
00253 {
00254   PropertyListMapEntry *entry = NS_STATIC_CAST(PropertyListMapEntry*,
00255       PL_DHashTableOperate(&mObjectValueMap, aObject, PL_DHASH_LOOKUP));
00256   if (!PL_DHASH_ENTRY_IS_BUSY(entry))
00257     return PR_FALSE;
00258 
00259   void* value = entry->value;
00260   PL_DHashTableRawRemove(&mObjectValueMap, entry);
00261 
00262   if (mDtorFunc)
00263     mDtorFunc(NS_CONST_CAST(void*, aObject), mName, value, mDtorData);
00264 
00265   return PR_TRUE;
00266 }