tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsPropertyTable.cpp (9422B)


      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 /**
      8 * nsPropertyTable allows a set of arbitrary key/value pairs to be stored
      9 * for any number of nodes, in a global hashtable rather than on the nodes
     10 * themselves.  Nodes can be any type of object; the hashtable keys are
     11 * nsAtom pointers, and the values are void pointers.
     12 */
     13 
     14 #include "nsPropertyTable.h"
     15 
     16 #include "PLDHashTable.h"
     17 #include "mozilla/MemoryReporting.h"
     18 #include "nsAtom.h"
     19 #include "nsError.h"
     20 
     21 struct PropertyListMapEntry : public PLDHashEntryHdr {
     22  const void* key;
     23  void* value;
     24 };
     25 
     26 //----------------------------------------------------------------------
     27 
     28 class nsPropertyTable::PropertyList {
     29 public:
     30  PropertyList(nsAtom* aName, NSPropertyDtorFunc aDtorFunc, void* aDtorData,
     31               bool aTransfer);
     32  ~PropertyList();
     33 
     34  // Removes the property associated with the given object, and destroys
     35  // the property value
     36  bool RemovePropertyFor(nsPropertyOwner aObject);
     37 
     38  // Destroy all remaining properties (without removing them)
     39  void Destroy();
     40 
     41  bool Equals(const nsAtom* aPropertyName) { return mName == aPropertyName; }
     42 
     43  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
     44 
     45  RefPtr<nsAtom> mName;          // property name
     46  PLDHashTable mObjectValueMap;  // map of object/value pairs
     47  NSPropertyDtorFunc mDtorFunc;  // property specific value dtor function
     48  void* mDtorData;               // pointer to pass to dtor
     49  bool mTransfer;                // whether to transfer in
     50                                 // TransferOrRemoveAllPropertiesFor
     51 
     52  PropertyList* mNext;
     53 };
     54 
     55 void nsPropertyTable::RemoveAllProperties() {
     56  while (mPropertyList) {
     57    PropertyList* tmp = mPropertyList;
     58 
     59    mPropertyList = mPropertyList->mNext;
     60    tmp->Destroy();
     61    delete tmp;
     62  }
     63 }
     64 
     65 void nsPropertyTable::RemoveAllPropertiesFor(nsPropertyOwner aObject) {
     66  for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
     67    prop->RemovePropertyFor(aObject);
     68  }
     69 }
     70 
     71 nsresult nsPropertyTable::TransferOrRemoveAllPropertiesFor(
     72    nsPropertyOwner aObject, nsPropertyTable& aOtherTable) {
     73  nsresult rv = NS_OK;
     74  for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
     75    if (prop->mTransfer) {
     76      auto entry = static_cast<PropertyListMapEntry*>(
     77          prop->mObjectValueMap.Search(aObject));
     78      if (entry) {
     79        rv = aOtherTable.SetProperty(aObject, prop->mName, entry->value,
     80                                     prop->mDtorFunc, prop->mDtorData,
     81                                     prop->mTransfer);
     82        if (NS_FAILED(rv)) {
     83          RemoveAllPropertiesFor(aObject);
     84          aOtherTable.RemoveAllPropertiesFor(aObject);
     85          break;
     86        }
     87 
     88        prop->mObjectValueMap.RemoveEntry(entry);
     89      }
     90    } else {
     91      prop->RemovePropertyFor(aObject);
     92    }
     93  }
     94 
     95  return rv;
     96 }
     97 
     98 void nsPropertyTable::Enumerate(nsPropertyOwner aObject,
     99                                NSPropertyFunc aCallback, void* aData) {
    100  PropertyList* prop;
    101  for (prop = mPropertyList; prop; prop = prop->mNext) {
    102    auto entry = static_cast<PropertyListMapEntry*>(
    103        prop->mObjectValueMap.Search(aObject));
    104    if (entry) {
    105      aCallback(const_cast<void*>(aObject.get()), prop->mName, entry->value,
    106                aData);
    107    }
    108  }
    109 }
    110 
    111 void nsPropertyTable::EnumerateAll(NSPropertyFunc aCallBack, void* aData) {
    112  for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
    113    for (auto iter = prop->mObjectValueMap.ConstIter(); !iter.Done();
    114         iter.Next()) {
    115      auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
    116      aCallBack(const_cast<void*>(entry->key), prop->mName, entry->value,
    117                aData);
    118    }
    119  }
    120 }
    121 
    122 void* nsPropertyTable::GetPropertyInternal(nsPropertyOwner aObject,
    123                                           const nsAtom* aPropertyName,
    124                                           bool aRemove, nsresult* aResult) {
    125  MOZ_ASSERT(aPropertyName && aObject, "unexpected null param");
    126  nsresult rv = NS_PROPTABLE_PROP_NOT_THERE;
    127  void* propValue = nullptr;
    128 
    129  PropertyList* propertyList = GetPropertyListFor(aPropertyName);
    130  if (propertyList) {
    131    auto entry = static_cast<PropertyListMapEntry*>(
    132        propertyList->mObjectValueMap.Search(aObject));
    133    if (entry) {
    134      propValue = entry->value;
    135      if (aRemove) {
    136        // don't call propertyList->mDtorFunc.  That's the caller's job now.
    137        propertyList->mObjectValueMap.RemoveEntry(entry);
    138      }
    139      rv = NS_OK;
    140    }
    141  }
    142 
    143  if (aResult) *aResult = rv;
    144 
    145  return propValue;
    146 }
    147 
    148 nsresult nsPropertyTable::SetPropertyInternal(
    149    nsPropertyOwner aObject, nsAtom* aPropertyName, void* aPropertyValue,
    150    NSPropertyDtorFunc aPropDtorFunc, void* aPropDtorData, bool aTransfer) {
    151  MOZ_ASSERT(aPropertyName && aObject, "unexpected null param");
    152 
    153  PropertyList* propertyList = GetPropertyListFor(aPropertyName);
    154 
    155  if (propertyList) {
    156    // Make sure the dtor function and data and the transfer flag match
    157    if (aPropDtorFunc != propertyList->mDtorFunc ||
    158        aPropDtorData != propertyList->mDtorData ||
    159        aTransfer != propertyList->mTransfer) {
    160      NS_WARNING("Destructor/data mismatch while setting property");
    161      return NS_ERROR_INVALID_ARG;
    162    }
    163 
    164  } else {
    165    propertyList = new PropertyList(aPropertyName, aPropDtorFunc, aPropDtorData,
    166                                    aTransfer);
    167    propertyList->mNext = mPropertyList;
    168    mPropertyList = propertyList;
    169  }
    170 
    171  // The current property value (if there is one) is replaced and the current
    172  // value is destroyed
    173  nsresult result = NS_OK;
    174  auto entry = static_cast<PropertyListMapEntry*>(
    175      propertyList->mObjectValueMap.Add(aObject, mozilla::fallible));
    176  if (!entry) return NS_ERROR_OUT_OF_MEMORY;
    177  // A nullptr entry->key is the sign that the entry has just been allocated
    178  // for us.  If it's non-nullptr then we have an existing entry.
    179  if (entry->key) {
    180    if (propertyList->mDtorFunc) {
    181      propertyList->mDtorFunc(const_cast<void*>(entry->key), aPropertyName,
    182                              entry->value, propertyList->mDtorData);
    183    }
    184    result = NS_PROPTABLE_PROP_OVERWRITTEN;
    185  }
    186  entry->key = aObject;
    187  entry->value = aPropertyValue;
    188 
    189  return result;
    190 }
    191 
    192 nsresult nsPropertyTable::RemoveProperty(nsPropertyOwner aObject,
    193                                         const nsAtom* aPropertyName) {
    194  MOZ_ASSERT(aPropertyName && aObject, "unexpected null param");
    195 
    196  PropertyList* propertyList = GetPropertyListFor(aPropertyName);
    197  if (propertyList) {
    198    if (propertyList->RemovePropertyFor(aObject)) {
    199      return NS_OK;
    200    }
    201  }
    202 
    203  return NS_PROPTABLE_PROP_NOT_THERE;
    204 }
    205 
    206 nsPropertyTable::PropertyList* nsPropertyTable::GetPropertyListFor(
    207    const nsAtom* aPropertyName) const {
    208  PropertyList* result;
    209 
    210  for (result = mPropertyList; result; result = result->mNext) {
    211    if (result->Equals(aPropertyName)) {
    212      break;
    213    }
    214  }
    215 
    216  return result;
    217 }
    218 
    219 //----------------------------------------------------------------------
    220 
    221 nsPropertyTable::PropertyList::PropertyList(nsAtom* aName,
    222                                            NSPropertyDtorFunc aDtorFunc,
    223                                            void* aDtorData, bool aTransfer)
    224    : mName(aName),
    225      mObjectValueMap(PLDHashTable::StubOps(), sizeof(PropertyListMapEntry)),
    226      mDtorFunc(aDtorFunc),
    227      mDtorData(aDtorData),
    228      mTransfer(aTransfer),
    229      mNext(nullptr) {}
    230 
    231 nsPropertyTable::PropertyList::~PropertyList() = default;
    232 
    233 void nsPropertyTable::PropertyList::Destroy() {
    234  // Enumerate any remaining object/value pairs and destroy the value object.
    235  if (mDtorFunc) {
    236    for (auto iter = mObjectValueMap.ConstIter(); !iter.Done(); iter.Next()) {
    237      auto entry = static_cast<PropertyListMapEntry*>(iter.Get());
    238      mDtorFunc(const_cast<void*>(entry->key), mName, entry->value, mDtorData);
    239    }
    240  }
    241 }
    242 
    243 bool nsPropertyTable::PropertyList::RemovePropertyFor(nsPropertyOwner aObject) {
    244  auto entry =
    245      static_cast<PropertyListMapEntry*>(mObjectValueMap.Search(aObject));
    246  if (!entry) return false;
    247 
    248  void* value = entry->value;
    249  mObjectValueMap.RemoveEntry(entry);
    250 
    251  if (mDtorFunc)
    252    mDtorFunc(const_cast<void*>(aObject.get()), mName, value, mDtorData);
    253 
    254  return true;
    255 }
    256 
    257 size_t nsPropertyTable::PropertyList::SizeOfIncludingThis(
    258    mozilla::MallocSizeOf aMallocSizeOf) {
    259  size_t n = aMallocSizeOf(this);
    260  n += mObjectValueMap.ShallowSizeOfExcludingThis(aMallocSizeOf);
    261  return n;
    262 }
    263 
    264 size_t nsPropertyTable::SizeOfExcludingThis(
    265    mozilla::MallocSizeOf aMallocSizeOf) const {
    266  size_t n = 0;
    267 
    268  for (PropertyList* prop = mPropertyList; prop; prop = prop->mNext) {
    269    n += prop->SizeOfIncludingThis(aMallocSizeOf);
    270  }
    271 
    272  return n;
    273 }
    274 
    275 size_t nsPropertyTable::SizeOfIncludingThis(
    276    mozilla::MallocSizeOf aMallocSizeOf) const {
    277  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    278 }
    279 
    280 /* static */
    281 void nsPropertyTable::SupportsDtorFunc(void* aObject, nsAtom* aPropertyName,
    282                                       void* aPropertyValue, void* aData) {
    283  nsISupports* propertyValue = static_cast<nsISupports*>(aPropertyValue);
    284  NS_IF_RELEASE(propertyValue);
    285 }