Bug 1326028 - Allow moving a reference into nsInterfaceHashtable. r=smaug
Without this patch, it's impossible for clients to move a reference into an
nsInterfaceHashtable. That causes at least one extra addref/release pair when
they otherwise could. With this patch, a client can do `hashTable.Put(key,
comptr.forget());` to avoid the additional refcounting.
MozReview-Commit-ID: Ghm7n41ziZp
--- a/xpcom/ds/nsInterfaceHashtable.h
+++ b/xpcom/ds/nsInterfaceHashtable.h
@@ -50,16 +50,31 @@ public:
* Gets a weak reference to the hashtable entry.
* @param aFound If not nullptr, will be set to true if the entry is found,
* to false otherwise.
* @return The entry, or nullptr if not found. Do not release this pointer!
*/
Interface* GetWeak(KeyType aKey, bool* aFound = nullptr) const;
/**
+ * Allows inserting a value into the hashtable, moving its owning reference
+ * count into the hashtable, avoiding an AddRef.
+ */
+ void Put(KeyType aKey, already_AddRefed<Interface>&& aData)
+ {
+ if (!Put(aKey, mozilla::Move(aData), mozilla::fallible)) {
+ NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount());
+ }
+ }
+
+ MOZ_MUST_USE bool Put(KeyType aKey, already_AddRefed<Interface>&& aData,
+ const mozilla::fallible_t&);
+ using base_type::Put;
+
+ /**
* Remove the entry associated with aKey (if any), optionally _moving_ its
* current value into *aData, thereby avoiding calls to AddRef and Release.
* Return true if found.
* @param aKey the key to remove from the hashtable
* @param aData where to move the value (if non-null). If an entry is not
* found it will be set to nullptr.
* @return true if an entry for aKey was found (and removed)
*/
@@ -147,16 +162,31 @@ nsInterfaceHashtable<KeyClass, Interface
if (aFound) {
*aFound = false;
}
return nullptr;
}
template<class KeyClass, class Interface>
bool
+nsInterfaceHashtable<KeyClass, Interface>::Put(KeyType aKey,
+ already_AddRefed<Interface>&& aValue,
+ const mozilla::fallible_t&)
+{
+ typename base_type::EntryType* ent = this->PutEntry(aKey);
+ if (!ent) {
+ return false;
+ }
+
+ ent->mData = aValue;
+ return true;
+}
+
+template<class KeyClass, class Interface>
+bool
nsInterfaceHashtable<KeyClass, Interface>::Remove(KeyType aKey,
Interface** aData)
{
typename base_type::EntryType* ent = this->GetEntry(aKey);
if (ent) {
if (aData) {
ent->mData.forget(aData);