Bug 1361745 - Part 1: Improve the nsClassHashtable::LookupForAdd() API; r=froydnj
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 05 May 2017 22:20:24 -0400
changeset 357100 d93f890967c0573ebe56a8dd56947f6d183739f5
parent 357099 93bc09fa99ee53680388cad97fac6a01e956f3bc
child 357101 00b0dbfee0d6ce3f0533e238d4dc4f9920cf8540
push id31782
push userkwierso@gmail.com
push dateMon, 08 May 2017 23:07:35 +0000
treeherdermozilla-central@b21b974d60d3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1361745
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1361745 - Part 1: Improve the nsClassHashtable::LookupForAdd() API; r=froydnj The OrInsert() method adds the new entry to the hashtable if needed, and returns the newly added entry or the pre-existing one. It allows for a more concise syntax at the call site.
modules/libpref/nsPrefBranch.cpp
xpcom/ds/nsClassHashtable.h
--- a/modules/libpref/nsPrefBranch.cpp
+++ b/modules/libpref/nsPrefBranch.cpp
@@ -725,17 +725,19 @@ NS_IMETHODIMP nsPrefBranch::AddObserver(
 
   auto p = mObservers.LookupForAdd(pCallback);
   if (p) {
     NS_WARNING("Ignoring duplicate observer.");
     delete pCallback;
     return NS_OK;
   }
 
-  mObservers.Insert(p, pCallback);
+  p.OrInsert([&pCallback]() {
+    return pCallback;
+  });
 
   // We must pass a fully qualified preference name to the callback
   // aDomain == nullptr is the only possible failure, and we trapped it with
   // NS_ENSURE_ARG above.
   const PrefName& pref = getPrefName(aDomain);
   PREF_RegisterCallback(pref.get(), NotifyObserver, pCallback);
   return NS_OK;
 }
--- a/xpcom/ds/nsClassHashtable.h
+++ b/xpcom/ds/nsClassHashtable.h
@@ -94,55 +94,53 @@ public:
 
     explicit operator bool() const
     {
       // Is there something stored in the table already?
       MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
       return !!mEntry.mData;
     }
 
-    T& operator*()
+    template <class F>
+    T* OrInsert(F func)
     {
-      MOZ_ASSERT(mEntry.mData);
       MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
-      return *mEntry.mData;
-    }
-
-    void TakeOwnership(T* aPtr)
-    {
-      MOZ_ASSERT(!mEntry.mData);
-      MOZ_ASSERT(mTableGeneration == mTable.GetGeneration());
-      mEntry.mData = aPtr;
+      if (!mEntry.mData) {
+        mEntry.mData = func();
+      }
+      return mEntry.mData;
     }
   };
 
   /**
    * Looks up aKey in the hash table and returns an object that allows you to
    * insert a new entry into the hashtable for that key if an existing entry
    * isn't found for it.
    *
    * A typical usage of this API looks like this:
    *
+   *   auto insertedValue = table.LookupForAdd(key).OrInsert([]() {
+   *     return newValue;
+   *   });
+   *
    *   auto p = table.LookupForAdd(key);
    *   if (p) {
    *     // The entry already existed in the table.
-   *     Use(*p);
+   *     DoSomething();
    *   } else {
    *     // An existing entry wasn't found, store a new entry in the hashtable.
-   *     table.Insert(p, newValue);
+   *     p.OrInsert([]() { return newValue; });
    *   }
    *
-   * We ensure that the hashtable isn't modified before Insert() is called.
+   * We ensure that the hashtable isn't modified before OrInsert() is called.
    * This is useful for cases where you want to insert a new entry into the
    * hashtable if one doesn't exist before but would like to avoid two hashtable
    * lookups.
    */
   MOZ_MUST_USE EntryPtr LookupForAdd(KeyType aKey);
-
-  void Insert(EntryPtr& aEntryPtr, T* aPtr);
 };
 
 //
 // nsClassHashtable definitions
 //
 
 template<class KeyClass, class T>
 template<typename... Args>
@@ -161,24 +159,16 @@ template<class KeyClass, class T>
 typename nsClassHashtable<KeyClass, T>::EntryPtr
 nsClassHashtable<KeyClass, T>::LookupForAdd(KeyType aKey)
 {
   typename base_type::EntryType* ent = this->PutEntry(aKey);
   return EntryPtr(*this, ent);
 }
 
 template<class KeyClass, class T>
-void
-nsClassHashtable<KeyClass, T>::Insert(typename nsClassHashtable<KeyClass, T>::EntryPtr& aEntryPtr,
-                                      T* aPtr)
-{
-  aEntryPtr.TakeOwnership(aPtr);
-}
-
-template<class KeyClass, class T>
 bool
 nsClassHashtable<KeyClass, T>::Get(KeyType aKey, T** aRetVal) const
 {
   typename base_type::EntryType* ent = this->GetEntry(aKey);
 
   if (ent) {
     if (aRetVal) {
       *aRetVal = ent->mData;