mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Bug 1262826 - specialize nsTHashtable<nsPtrHashKey<T>> to share a common implementation; r=erahm
We have a number of nsTHashtable<nsPtrHashKey<T>> instantiations, mostly from IPDL-generated code. There's no reason in principle that all of these instantiations couldn't share code, since they're all storing POD entries of the same size. Let's specialize nsTHashtable for such types, providing a thin layer over a hashtable that stores void pointers. This change saves about 90K of space (!) on x86-64 Linux.
This commit is contained in:
parent
41ba39b3b0
commit
e255fd3842
@ -44,6 +44,7 @@ EXPORTS += [
|
||||
'nsIWeakReferenceUtils.h',
|
||||
'nsJSThingHashtable.h',
|
||||
'nsMemory.h',
|
||||
'nsPointerHashKeys.h',
|
||||
'nsProxyRelease.h',
|
||||
'nsQuickSort.h',
|
||||
'nsRefPtrHashtable.h',
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsStringGlue.h"
|
||||
#include "nsCRTGlue.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsPointerHashKeys.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -358,36 +359,6 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
CycleCollectionNoteChild(aCallback, aField.GetKey(), aName, aFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* hashkey wrapper using T* KeyType
|
||||
*
|
||||
* @see nsTHashtable::EntryType for specification
|
||||
*/
|
||||
template<class T>
|
||||
class nsPtrHashKey : public PLDHashEntryHdr
|
||||
{
|
||||
public:
|
||||
typedef T* KeyType;
|
||||
typedef const T* KeyTypePointer;
|
||||
|
||||
explicit nsPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
|
||||
nsPtrHashKey(const nsPtrHashKey<T>& aToCopy) : mKey(aToCopy.mKey) {}
|
||||
~nsPtrHashKey() {}
|
||||
|
||||
KeyType GetKey() const { return mKey; }
|
||||
bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
||||
{
|
||||
return NS_PTR_TO_UINT32(aKey) >> 2;
|
||||
}
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
protected:
|
||||
T* MOZ_NON_OWNING_REF mKey;
|
||||
};
|
||||
|
||||
/**
|
||||
* hashkey wrapper using T* KeyType that sets key to nullptr upon
|
||||
* destruction. Relevant only in cases where a memory pointer-scanner
|
||||
@ -408,7 +379,6 @@ public:
|
||||
~nsClearingPtrHashKey() { nsPtrHashKey<T>::mKey = nullptr; }
|
||||
};
|
||||
|
||||
typedef nsPtrHashKey<const void> nsVoidPtrHashKey;
|
||||
typedef nsClearingPtrHashKey<const void> nsClearingVoidPtrHashKey;
|
||||
|
||||
/**
|
||||
|
48
xpcom/glue/nsPointerHashKeys.h
Normal file
48
xpcom/glue/nsPointerHashKeys.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* Definitions for nsPtrHashKey<T> and nsVoidPtrHashKey. */
|
||||
|
||||
#ifndef nsPointerHashKeys_h
|
||||
#define nsPointerHashKeys_h
|
||||
|
||||
#include "nscore.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/**
|
||||
* hashkey wrapper using T* KeyType
|
||||
*
|
||||
* @see nsTHashtable::EntryType for specification
|
||||
*/
|
||||
template<class T>
|
||||
class nsPtrHashKey : public PLDHashEntryHdr
|
||||
{
|
||||
public:
|
||||
typedef T* KeyType;
|
||||
typedef const T* KeyTypePointer;
|
||||
|
||||
explicit nsPtrHashKey(const T* aKey) : mKey(const_cast<T*>(aKey)) {}
|
||||
nsPtrHashKey(const nsPtrHashKey<T>& aToCopy) : mKey(aToCopy.mKey) {}
|
||||
~nsPtrHashKey() {}
|
||||
|
||||
KeyType GetKey() const { return mKey; }
|
||||
bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey)
|
||||
{
|
||||
return NS_PTR_TO_UINT32(aKey) >> 2;
|
||||
}
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
protected:
|
||||
T* MOZ_NON_OWNING_REF mKey;
|
||||
};
|
||||
|
||||
typedef nsPtrHashKey<const void> nsVoidPtrHashKey;
|
||||
|
||||
#endif // nsPointerHashKeys_h
|
@ -8,6 +8,7 @@
|
||||
#define nsTHashtable_h__
|
||||
|
||||
#include "PLDHashTable.h"
|
||||
#include "nsPointerHashKeys.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/fallible.h"
|
||||
@ -435,4 +436,142 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For nsTHashtable with pointer entries, we can have a template specialization
|
||||
* that layers a typed T* interface on top of a common implementation that
|
||||
* works internally with void pointers. This arrangement saves code size and
|
||||
* might slightly improve performance as well.
|
||||
*/
|
||||
|
||||
/**
|
||||
* We need a separate entry type class for the inheritance structure of the
|
||||
* nsTHashtable specialization below; nsVoidPtrHashKey is simply typedefed to a
|
||||
* specialization of nsPtrHashKey, and the formulation:
|
||||
*
|
||||
* class nsTHashtable<nsPtrHashKey<T>> : protected nsTHashtable<nsPtrHashKey<const void>
|
||||
*
|
||||
* is not going to turn out very well, since we'd wind up with an nsTHashtable
|
||||
* instantiation that is its own base class.
|
||||
*/
|
||||
namespace detail {
|
||||
|
||||
class VoidPtrHashKey : public nsPtrHashKey<const void>
|
||||
{
|
||||
typedef nsPtrHashKey<const void> Base;
|
||||
|
||||
public:
|
||||
explicit VoidPtrHashKey(const void* aKey) : Base(aKey) {}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* See the main nsTHashtable documentation for descriptions of this class's
|
||||
* methods.
|
||||
*/
|
||||
template<typename T>
|
||||
class nsTHashtable<nsPtrHashKey<T>> : protected nsTHashtable<::detail::VoidPtrHashKey>
|
||||
{
|
||||
typedef nsTHashtable<::detail::VoidPtrHashKey> Base;
|
||||
typedef nsPtrHashKey<T> EntryType;
|
||||
|
||||
// We play games with reinterpret_cast'ing between these two classes, so
|
||||
// try to ensure that playing said games is reasonable.
|
||||
static_assert(sizeof(nsPtrHashKey<T>) == sizeof(::detail::VoidPtrHashKey),
|
||||
"hash keys must be the same size");
|
||||
|
||||
nsTHashtable(const nsTHashtable& aOther) = delete;
|
||||
nsTHashtable& operator=(const nsTHashtable& aOther) = delete;
|
||||
|
||||
public:
|
||||
nsTHashtable() = default;
|
||||
explicit nsTHashtable(uint32_t aInitLength)
|
||||
: Base(aInitLength)
|
||||
{}
|
||||
|
||||
~nsTHashtable() = default;
|
||||
|
||||
nsTHashtable(nsTHashtable&&) = default;
|
||||
|
||||
/* Wrapper functions */
|
||||
using Base::GetGeneration;
|
||||
using Base::Count;
|
||||
using Base::IsEmpty;
|
||||
using Base::Clear;
|
||||
|
||||
using Base::ShallowSizeOfExcludingThis;
|
||||
using Base::ShallowSizeOfIncludingThis;
|
||||
|
||||
#ifdef DEBUG
|
||||
using Base::MarkImmutable;
|
||||
#endif
|
||||
|
||||
EntryType* GetEntry(T* aKey) const
|
||||
{
|
||||
return reinterpret_cast<EntryType*>(Base::GetEntry(aKey));
|
||||
}
|
||||
|
||||
bool Contains(T* aKey) const
|
||||
{
|
||||
return Base::Contains(aKey);
|
||||
}
|
||||
|
||||
EntryType* PutEntry(T* aKey)
|
||||
{
|
||||
return reinterpret_cast<EntryType*>(Base::PutEntry(aKey));
|
||||
}
|
||||
|
||||
MOZ_MUST_USE
|
||||
EntryType* PutEntry(T* aKey, const mozilla::fallible_t&)
|
||||
{
|
||||
return reinterpret_cast<EntryType*>(
|
||||
Base::PutEntry(aKey, mozilla::fallible));
|
||||
}
|
||||
|
||||
void RemoveEntry(T* aKey)
|
||||
{
|
||||
Base::RemoveEntry(aKey);
|
||||
}
|
||||
|
||||
void RemoveEntry(EntryType* aEntry)
|
||||
{
|
||||
Base::RemoveEntry(reinterpret_cast<::detail::VoidPtrHashKey*>(aEntry));
|
||||
}
|
||||
|
||||
void RawRemoveEntry(EntryType* aEntry)
|
||||
{
|
||||
Base::RawRemoveEntry(reinterpret_cast<::detail::VoidPtrHashKey*>(aEntry));
|
||||
}
|
||||
|
||||
class Iterator : public Base::Iterator
|
||||
{
|
||||
public:
|
||||
typedef nsTHashtable::Base::Iterator Base;
|
||||
|
||||
explicit Iterator(nsTHashtable* aTable) : Base(aTable) {}
|
||||
Iterator(Iterator&& aOther) : Base(mozilla::Move(aOther)) {}
|
||||
~Iterator() = default;
|
||||
|
||||
EntryType* Get() const { return reinterpret_cast<EntryType*>(Base::Get()); }
|
||||
|
||||
private:
|
||||
Iterator() = delete;
|
||||
Iterator(const Iterator&) = delete;
|
||||
Iterator& operator=(const Iterator&) = delete;
|
||||
Iterator& operator=(Iterator&&) = delete;
|
||||
};
|
||||
|
||||
Iterator Iter() { return Iterator(this); }
|
||||
|
||||
Iterator ConstIter() const
|
||||
{
|
||||
return Iterator(const_cast<nsTHashtable*>(this));
|
||||
}
|
||||
|
||||
void SwapElements(nsTHashtable& aOther)
|
||||
{
|
||||
Base::SwapElements(aOther);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // nsTHashtable_h__
|
||||
|
Loading…
Reference in New Issue
Block a user