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 +}