content/base/src/nsPropertyTable.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/base/src/nsPropertyTable.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,372 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * vim:cindent:ts=2:et:sw=2:
     1.6 + *
     1.7 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    1.10 + *
    1.11 + * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
    1.12 + * described herein are Copyright (c) International Business Machines Corporation, 2000.
    1.13 + * Modifications to Mozilla code or documentation identified per MPL Section 3.3
    1.14 + *
    1.15 + * Date             Modified by     Description of modification
    1.16 + * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
    1.17 + */
    1.18 +
    1.19 +/**
    1.20 + * nsPropertyTable allows a set of arbitrary key/value pairs to be stored
    1.21 + * for any number of nodes, in a global hashtable rather than on the nodes
    1.22 + * themselves.  Nodes can be any type of object; the hashtable keys are
    1.23 + * nsIAtom pointers, and the values are void pointers.
    1.24 + */
    1.25 +
    1.26 +#include "nsPropertyTable.h"
    1.27 +
    1.28 +#include "mozilla/MemoryReporting.h"
    1.29 +
    1.30 +#include "pldhash.h"
    1.31 +#include "nsError.h"
    1.32 +#include "nsIAtom.h"
    1.33 +
    1.34 +struct PropertyListMapEntry : public PLDHashEntryHdr {
    1.35 +  const void  *key;
    1.36 +  void        *value;
    1.37 +};
    1.38 +
    1.39 +//----------------------------------------------------------------------
    1.40 +
    1.41 +class nsPropertyTable::PropertyList {
    1.42 +public:
    1.43 +  PropertyList(nsIAtom*           aName,
    1.44 +               NSPropertyDtorFunc aDtorFunc,
    1.45 +               void*              aDtorData,
    1.46 +               bool               aTransfer) NS_HIDDEN;
    1.47 +  ~PropertyList() NS_HIDDEN;
    1.48 +
    1.49 +  // Removes the property associated with the given object, and destroys
    1.50 +  // the property value
    1.51 +  NS_HIDDEN_(bool) DeletePropertyFor(nsPropertyOwner aObject);
    1.52 +
    1.53 +  // Destroy all remaining properties (without removing them)
    1.54 +  NS_HIDDEN_(void) Destroy();
    1.55 +
    1.56 +  NS_HIDDEN_(bool) Equals(nsIAtom *aPropertyName)
    1.57 +  {
    1.58 +    return mName == aPropertyName;
    1.59 +  }
    1.60 +
    1.61 +  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
    1.62 +
    1.63 +  nsCOMPtr<nsIAtom>  mName;           // property name
    1.64 +  PLDHashTable       mObjectValueMap; // map of object/value pairs
    1.65 +  NSPropertyDtorFunc mDtorFunc;       // property specific value dtor function
    1.66 +  void*              mDtorData;       // pointer to pass to dtor
    1.67 +  bool               mTransfer;       // whether to transfer in
    1.68 +                                      // TransferOrDeleteAllPropertiesFor
    1.69 +  
    1.70 +  PropertyList*      mNext;
    1.71 +};
    1.72 +
    1.73 +void
    1.74 +nsPropertyTable::DeleteAllProperties()
    1.75 +{
    1.76 +  while (mPropertyList) {
    1.77 +    PropertyList* tmp = mPropertyList;
    1.78 +
    1.79 +    mPropertyList = mPropertyList->mNext;
    1.80 +    tmp->Destroy();
    1.81 +    delete tmp;
    1.82 +  }
    1.83 +}
    1.84 +
    1.85 +void
    1.86 +nsPropertyTable::DeleteAllPropertiesFor(nsPropertyOwner aObject)
    1.87 +{
    1.88 +  for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
    1.89 +    prop->DeletePropertyFor(aObject);
    1.90 +  }
    1.91 +}
    1.92 +
    1.93 +nsresult
    1.94 +nsPropertyTable::TransferOrDeleteAllPropertiesFor(nsPropertyOwner aObject,
    1.95 +                                                  nsPropertyTable *aOtherTable)
    1.96 +{
    1.97 +  nsresult rv = NS_OK;
    1.98 +  for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
    1.99 +    if (prop->mTransfer) {
   1.100 +      PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
   1.101 +                                               (PL_DHashTableOperate(&prop->mObjectValueMap, aObject,
   1.102 +                               PL_DHASH_LOOKUP));
   1.103 +      if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
   1.104 +        rv = aOtherTable->SetProperty(aObject, prop->mName,
   1.105 +                                      entry->value, prop->mDtorFunc,
   1.106 +                                      prop->mDtorData, prop->mTransfer);
   1.107 +        if (NS_FAILED(rv)) {
   1.108 +          DeleteAllPropertiesFor(aObject);
   1.109 +          aOtherTable->DeleteAllPropertiesFor(aObject);
   1.110 +
   1.111 +          break;
   1.112 +        }
   1.113 +
   1.114 +        PL_DHashTableRawRemove(&prop->mObjectValueMap, entry);
   1.115 +      }
   1.116 +    }
   1.117 +    else {
   1.118 +      prop->DeletePropertyFor(aObject);
   1.119 +    }
   1.120 +  }
   1.121 +
   1.122 +  return rv;
   1.123 +}
   1.124 +
   1.125 +void
   1.126 +nsPropertyTable::Enumerate(nsPropertyOwner aObject,
   1.127 +                           NSPropertyFunc aCallback, void *aData)
   1.128 +{
   1.129 +  PropertyList* prop;
   1.130 +  for (prop = mPropertyList; prop; prop = prop->mNext) {
   1.131 +    PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
   1.132 +      (PL_DHashTableOperate(&prop->mObjectValueMap, aObject, PL_DHASH_LOOKUP));
   1.133 +    if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
   1.134 +      aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
   1.135 +                 aData);
   1.136 +    }
   1.137 +  }
   1.138 +}
   1.139 +
   1.140 +struct PropertyEnumeratorData
   1.141 +{
   1.142 +  nsIAtom* mName;
   1.143 +  NSPropertyFunc mCallBack;
   1.144 +  void* mData;
   1.145 +};
   1.146 +
   1.147 +static PLDHashOperator
   1.148 +PropertyEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   1.149 +                   uint32_t aNumber, void* aArg)
   1.150 +{
   1.151 +  PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(aHdr);
   1.152 +  PropertyEnumeratorData* data = static_cast<PropertyEnumeratorData*>(aArg);
   1.153 +  data->mCallBack(const_cast<void*>(entry->key), data->mName, entry->value,
   1.154 +                  data->mData);
   1.155 +  return PL_DHASH_NEXT;
   1.156 +}
   1.157 +
   1.158 +void
   1.159 +nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData)
   1.160 +{
   1.161 +  for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
   1.162 +    PropertyEnumeratorData data = { prop->mName, aCallBack, aData };
   1.163 +    PL_DHashTableEnumerate(&prop->mObjectValueMap, PropertyEnumerator, &data);
   1.164 +  }
   1.165 +}
   1.166 +
   1.167 +void*
   1.168 +nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
   1.169 +                                     nsIAtom    *aPropertyName,
   1.170 +                                     bool        aRemove,
   1.171 +                                     nsresult   *aResult)
   1.172 +{
   1.173 +  NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
   1.174 +  nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
   1.175 +  void *propValue = nullptr;
   1.176 +
   1.177 +  PropertyList* propertyList = GetPropertyListFor(aPropertyName);
   1.178 +  if (propertyList) {
   1.179 +    PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
   1.180 +                                             (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject,
   1.181 +                             PL_DHASH_LOOKUP));
   1.182 +    if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
   1.183 +      propValue = entry->value;
   1.184 +      if (aRemove) {
   1.185 +        // don't call propertyList->mDtorFunc.  That's the caller's job now.
   1.186 +        PL_DHashTableRawRemove(&propertyList->mObjectValueMap, entry);
   1.187 +      }
   1.188 +      rv = NS_OK;
   1.189 +    }
   1.190 +  }
   1.191 +
   1.192 +  if (aResult)
   1.193 +    *aResult = rv;
   1.194 +
   1.195 +  return propValue;
   1.196 +}
   1.197 +
   1.198 +nsresult
   1.199 +nsPropertyTable::SetPropertyInternal(nsPropertyOwner     aObject,
   1.200 +                                     nsIAtom            *aPropertyName,
   1.201 +                                     void               *aPropertyValue,
   1.202 +                                     NSPropertyDtorFunc  aPropDtorFunc,
   1.203 +                                     void               *aPropDtorData,
   1.204 +                                     bool                aTransfer,
   1.205 +                                     void              **aOldValue)
   1.206 +{
   1.207 +  NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
   1.208 +
   1.209 +  PropertyList* propertyList = GetPropertyListFor(aPropertyName);
   1.210 +
   1.211 +  if (propertyList) {
   1.212 +    // Make sure the dtor function and data and the transfer flag match
   1.213 +    if (aPropDtorFunc != propertyList->mDtorFunc ||
   1.214 +        aPropDtorData != propertyList->mDtorData ||
   1.215 +        aTransfer != propertyList->mTransfer) {
   1.216 +      NS_WARNING("Destructor/data mismatch while setting property");
   1.217 +      return NS_ERROR_INVALID_ARG;
   1.218 +    }
   1.219 +
   1.220 +  } else {
   1.221 +    propertyList = new PropertyList(aPropertyName, aPropDtorFunc,
   1.222 +                                    aPropDtorData, aTransfer);
   1.223 +    if (!propertyList || !propertyList->mObjectValueMap.ops) {
   1.224 +      delete propertyList;
   1.225 +      return NS_ERROR_OUT_OF_MEMORY;
   1.226 +    }
   1.227 +
   1.228 +    propertyList->mNext = mPropertyList;
   1.229 +    mPropertyList = propertyList;
   1.230 +  }
   1.231 +
   1.232 +  // The current property value (if there is one) is replaced and the current
   1.233 +  // value is destroyed
   1.234 +  nsresult result = NS_OK;
   1.235 +  PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
   1.236 +                                           (PL_DHashTableOperate(&propertyList->mObjectValueMap, aObject, PL_DHASH_ADD));
   1.237 +  if (!entry)
   1.238 +    return NS_ERROR_OUT_OF_MEMORY;
   1.239 +  // A nullptr entry->key is the sign that the entry has just been allocated
   1.240 +  // for us.  If it's non-nullptr then we have an existing entry.
   1.241 +  if (entry->key) {
   1.242 +    if (aOldValue)
   1.243 +      *aOldValue = entry->value;
   1.244 +    else if (propertyList->mDtorFunc)
   1.245 +      propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
   1.246 +                              entry->value, propertyList->mDtorData);
   1.247 +    result = NS_PROPTABLE_PROP_OVERWRITTEN;
   1.248 +  }
   1.249 +  else if (aOldValue) {
   1.250 +    *aOldValue = nullptr;
   1.251 +  }
   1.252 +  entry->key = aObject;
   1.253 +  entry->value = aPropertyValue;
   1.254 +
   1.255 +  return result;
   1.256 +}
   1.257 +
   1.258 +nsresult
   1.259 +nsPropertyTable::DeleteProperty(nsPropertyOwner aObject,
   1.260 +                                nsIAtom    *aPropertyName)
   1.261 +{
   1.262 +  NS_PRECONDITION(aPropertyName && aObject, "unexpected null param");
   1.263 +
   1.264 +  PropertyList* propertyList = GetPropertyListFor(aPropertyName);
   1.265 +  if (propertyList) {
   1.266 +    if (propertyList->DeletePropertyFor(aObject))
   1.267 +      return NS_OK;
   1.268 +  }
   1.269 +
   1.270 +  return NS_PROPTABLE_PROP_NOT_THERE;
   1.271 +}
   1.272 +
   1.273 +nsPropertyTable::PropertyList*
   1.274 +nsPropertyTable::GetPropertyListFor(nsIAtom* aPropertyName) const
   1.275 +{
   1.276 +  PropertyList* result;
   1.277 +
   1.278 +  for (result = mPropertyList; result; result = result->mNext) {
   1.279 +    if (result->Equals(aPropertyName)) {
   1.280 +      break;
   1.281 +    }
   1.282 +  }
   1.283 +
   1.284 +  return result;
   1.285 +}
   1.286 +
   1.287 +//----------------------------------------------------------------------
   1.288 +    
   1.289 +nsPropertyTable::PropertyList::PropertyList(nsIAtom            *aName,
   1.290 +                                            NSPropertyDtorFunc  aDtorFunc,
   1.291 +                                            void               *aDtorData,
   1.292 +                                            bool                aTransfer)
   1.293 +  : mName(aName),
   1.294 +    mDtorFunc(aDtorFunc),
   1.295 +    mDtorData(aDtorData),
   1.296 +    mTransfer(aTransfer),
   1.297 +    mNext(nullptr)
   1.298 +{
   1.299 +  PL_DHashTableInit(&mObjectValueMap, PL_DHashGetStubOps(), this,
   1.300 +                    sizeof(PropertyListMapEntry), 16);
   1.301 +}
   1.302 +
   1.303 +nsPropertyTable::PropertyList::~PropertyList()
   1.304 +{
   1.305 +  PL_DHashTableFinish(&mObjectValueMap);
   1.306 +}
   1.307 +
   1.308 +
   1.309 +static PLDHashOperator
   1.310 +DestroyPropertyEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
   1.311 +                          uint32_t number, void *arg)
   1.312 +{
   1.313 +  nsPropertyTable::PropertyList *propList =
   1.314 +      static_cast<nsPropertyTable::PropertyList*>(table->data);
   1.315 +  PropertyListMapEntry* entry = static_cast<PropertyListMapEntry*>(hdr);
   1.316 +
   1.317 +  propList->mDtorFunc(const_cast<void*>(entry->key), propList->mName,
   1.318 +                      entry->value, propList->mDtorData);
   1.319 +  return PL_DHASH_NEXT;
   1.320 +}
   1.321 +
   1.322 +void
   1.323 +nsPropertyTable::PropertyList::Destroy()
   1.324 +{
   1.325 +  // Enumerate any remaining object/value pairs and destroy the value object
   1.326 +  if (mDtorFunc)
   1.327 +    PL_DHashTableEnumerate(&mObjectValueMap, DestroyPropertyEnumerator,
   1.328 +                           nullptr);
   1.329 +}
   1.330 +
   1.331 +bool
   1.332 +nsPropertyTable::PropertyList::DeletePropertyFor(nsPropertyOwner aObject)
   1.333 +{
   1.334 +  PropertyListMapEntry *entry = static_cast<PropertyListMapEntry*>
   1.335 +                                           (PL_DHashTableOperate(&mObjectValueMap, aObject, PL_DHASH_LOOKUP));
   1.336 +  if (!PL_DHASH_ENTRY_IS_BUSY(entry))
   1.337 +    return false;
   1.338 +
   1.339 +  void* value = entry->value;
   1.340 +  PL_DHashTableRawRemove(&mObjectValueMap, entry);
   1.341 +
   1.342 +  if (mDtorFunc)
   1.343 +    mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
   1.344 +
   1.345 +  return true;
   1.346 +}
   1.347 +
   1.348 +size_t
   1.349 +nsPropertyTable::PropertyList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
   1.350 +{
   1.351 +  size_t n = aMallocSizeOf(this);
   1.352 +  n += PL_DHashTableSizeOfExcludingThis(&mObjectValueMap, nullptr, aMallocSizeOf);
   1.353 +  return n;
   1.354 +}
   1.355 +
   1.356 +size_t
   1.357 +nsPropertyTable::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   1.358 +{
   1.359 +  size_t n = 0;
   1.360 +
   1.361 +  for (PropertyList *prop = mPropertyList; prop; prop = prop->mNext) {
   1.362 +    n += prop->SizeOfIncludingThis(aMallocSizeOf);
   1.363 +  }
   1.364 +
   1.365 +  return n;
   1.366 +}
   1.367 +
   1.368 +/* static */
   1.369 +void
   1.370 +nsPropertyTable::SupportsDtorFunc(void *aObject, nsIAtom *aPropertyName,
   1.371 +                                  void *aPropertyValue, void *aData)
   1.372 +{
   1.373 +  nsISupports *propertyValue = static_cast<nsISupports*>(aPropertyValue);
   1.374 +  NS_IF_RELEASE(propertyValue);
   1.375 +}

mercurial