Bug 1367207 part 3 - Introduce nsClassHashtable::LookupRemoveIf() for consumers that wants to do a Get() then inspect/modify the value then, maybe, Remove() the entry. This is to avoid a second hashtable lookup for the Remove(). r=froydnj
authorMats Palmgren <mats@mozilla.com>
Wed, 07 Jun 2017 15:22:41 +0200
changeset 410810 7307d037a9227f8441674713dd754ac893d243d8
parent 410809 6d87a5768954e46ed37af5d46f7ac8fa14a75135
child 410811 7fc0cbe0d71cfd101e6e9f536c28b7f7830c4e5b
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1367207
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 1367207 part 3 - Introduce nsClassHashtable::LookupRemoveIf() for consumers that wants to do a Get() then inspect/modify the value then, maybe, Remove() the entry. This is to avoid a second hashtable lookup for the Remove(). r=froydnj Also, make RemoveAndForget() use RemoveEntry(), not Remove(), to remove the entry to avoid a second hashtable lookup. MozReview-Commit-ID: Bj5Heo8YLFJ
xpcom/ds/nsClassHashtable.h
--- a/xpcom/ds/nsClassHashtable.h
+++ b/xpcom/ds/nsClassHashtable.h
@@ -106,17 +106,17 @@ public:
       if (!mEntry.mData) {
         mEntry.mData = func();
       }
       return mEntry.mData;
     }
   };
 
   /**
-   * Looks up aKey in the hash table and returns an object that allows you to
+   * Looks up aKey in the hashtable 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;
    *   });
@@ -131,16 +131,51 @@ public:
    *   }
    *
    * 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);
+
+  /**
+   * Looks up aKey in the hashtable and if found calls the given callback
+   * aFunction with the value.  If the callback returns true then the entry
+   * is removed.  If aKey doesn't exist nothing happens.
+   * The hashtable must not be modified in the callback function.
+   *
+   * A typical usage of this API looks like this:
+   *
+   *   table.LookupRemoveIf(key, [](T* aValue) {
+   *     // ... do stuff using aValue ...
+   *     return aValue->IsEmpty(); // or some other condition to remove it
+   *   });
+   *
+   * This is useful for cases where you want to lookup and possibly modify
+   * the value and then maybe remove the entry but would like to avoid two
+   * hashtable lookups.
+   */
+  template<class F>
+  void LookupRemoveIf(KeyType aKey, F aFunction)
+  {
+#ifdef DEBUG
+    auto tableGeneration = base_type::GetGeneration();
+#endif
+    typename base_type::EntryType* ent = this->GetEntry(aKey);
+    if (!ent) {
+      return;
+    }
+    bool shouldRemove = aFunction(ent->mData);
+    MOZ_ASSERT(tableGeneration == base_type::GetGeneration(),
+               "hashtable was modified by the LookupRemoveIf callback!");
+    if (shouldRemove) {
+      this->RemoveEntry(ent);
+    }
+  }
 };
 
 //
 // nsClassHashtable definitions
 //
 
 template<class KeyClass, class T>
 template<typename... Args>
@@ -205,12 +240,12 @@ nsClassHashtable<KeyClass, T>::RemoveAnd
   typename base_type::EntryType* ent = this->GetEntry(aKey);
   if (!ent) {
     return;
   }
 
   // Transfer ownership from ent->mData into aOut.
   aOut = mozilla::Move(ent->mData);
 
-  this->Remove(aKey);
+  this->RemoveEntry(ent);
 }
 
 #endif // nsClassHashtable_h__