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/. */
7 // See the comment at the top of mfbt/HashTable.h for a comparison between
8 // PLDHashTable and mozilla::HashTable.
10 #ifndef nsTHashtable_h__
11 #define nsTHashtable_h__
15 #include <type_traits>
18 #include "PLDHashTable.h"
19 #include "mozilla/Assertions.h"
20 #include "mozilla/Attributes.h"
21 #include "mozilla/Maybe.h"
22 #include "mozilla/MemoryReporting.h"
23 #include "mozilla/OperatorNewExtensions.h"
24 #include "mozilla/PodOperations.h"
25 #include "mozilla/fallible.h"
26 #include "nsPointerHashKeys.h"
29 // STL-style iterators to allow the use in range-based for loops, e.g.
31 class nsTHashtable_base_iterator
32 : public std::iterator
<std::forward_iterator_tag
, T
, int32_t> {
35 typename
std::iterator
<std::forward_iterator_tag
, T
, int32_t>::value_type
;
36 using typename
std::iterator
<std::forward_iterator_tag
, T
,
37 int32_t>::difference_type
;
39 using iterator_type
= nsTHashtable_base_iterator
;
40 using const_iterator_type
= nsTHashtable_base_iterator
<const T
>;
42 using EndIteratorTag
= PLDHashTable::Iterator::EndIteratorTag
;
44 nsTHashtable_base_iterator(nsTHashtable_base_iterator
&& aOther
) = default;
46 nsTHashtable_base_iterator
& operator=(nsTHashtable_base_iterator
&& aOther
) {
47 // User-defined because the move assignment operator is deleted in
48 // PLDHashtable::Iterator.
49 return operator=(static_cast<const nsTHashtable_base_iterator
&>(aOther
));
52 nsTHashtable_base_iterator(const nsTHashtable_base_iterator
& aOther
)
53 : mIterator
{aOther
.mIterator
.Clone()} {}
54 nsTHashtable_base_iterator
& operator=(
55 const nsTHashtable_base_iterator
& aOther
) {
56 // Since PLDHashTable::Iterator has no assignment operator, we destroy and
57 // recreate mIterator.
58 mIterator
.~Iterator();
59 new (&mIterator
) PLDHashTable::Iterator(aOther
.mIterator
.Clone());
63 explicit nsTHashtable_base_iterator(PLDHashTable::Iterator aFrom
)
64 : mIterator
{std::move(aFrom
)} {}
66 explicit nsTHashtable_base_iterator(const PLDHashTable
& aTable
)
67 : mIterator
{&const_cast<PLDHashTable
&>(aTable
)} {}
69 nsTHashtable_base_iterator(const PLDHashTable
& aTable
, EndIteratorTag aTag
)
70 : mIterator
{&const_cast<PLDHashTable
&>(aTable
), aTag
} {}
72 bool operator==(const iterator_type
& aRhs
) const {
73 return mIterator
== aRhs
.mIterator
;
75 bool operator!=(const iterator_type
& aRhs
) const { return !(*this == aRhs
); }
77 value_type
* operator->() const {
78 return static_cast<value_type
*>(mIterator
.Get());
80 value_type
& operator*() const {
81 return *static_cast<value_type
*>(mIterator
.Get());
84 iterator_type
& operator++() {
88 iterator_type
operator++(int) {
89 iterator_type it
= *this;
94 operator const_iterator_type() const {
95 return const_iterator_type
{mIterator
.Clone()};
99 PLDHashTable::Iterator mIterator
;
101 } // namespace detail
104 * a base class for templated hashtables.
106 * Clients will rarely need to use this class directly. Check the derived
107 * classes first, to see if they will meet your needs.
109 * @param EntryType the templated entry-type class that is managed by the
110 * hashtable. <code>EntryType</code> must extend the following declaration,
111 * and <strong>must not declare any virtual functions or derive from classes
112 * with virtual functions.</strong> Any vtable pointer would break the
114 *<pre> class EntryType : public PLDHashEntryHdr
116 * public: or friend nsTHashtable<EntryType>;
117 * // KeyType is what we use when Get()ing or Put()ing this entry
118 * // this should either be a simple datatype (uint32_t, nsISupports*) or
119 * // a const reference (const nsAString&)
120 * typedef something KeyType;
121 * // KeyTypePointer is the pointer-version of KeyType, because
122 * // PLDHashTable.h requires keys to cast to <code>const void*</code>
123 * typedef const something* KeyTypePointer;
125 * EntryType(KeyTypePointer aKey);
127 * // A copy or C++11 Move constructor must be defined, even if
128 * // AllowMemMove() == true, otherwise you will cause link errors.
129 * EntryType(const EntryType& aEnt); // Either this...
130 * EntryType(EntryType&& aEnt); // ...or this
132 * // the destructor must be defined... or you will cause link errors!
135 * // KeyEquals(): does this entry match this key?
136 * bool KeyEquals(KeyTypePointer aKey) const;
138 * // KeyToPointer(): Convert KeyType to KeyTypePointer
139 * static KeyTypePointer KeyToPointer(KeyType aKey);
141 * // HashKey(): calculate the hash number
142 * static PLDHashNumber HashKey(KeyTypePointer aKey);
144 * // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
145 * // to use the copy constructor?
146 * enum { ALLOW_MEMMOVE = true/false };
149 * @see nsInterfaceHashtable
150 * @see nsDataHashtable
151 * @see nsClassHashtable
152 * @author "Benjamin Smedberg <bsmedberg@covad.net>"
155 template <class EntryType
>
156 class MOZ_NEEDS_NO_VTABLE_TYPE nsTHashtable
{
157 typedef mozilla::fallible_t fallible_t
;
158 static_assert(std::is_pointer_v
<typename
EntryType::KeyTypePointer
>,
159 "KeyTypePointer should be a pointer");
162 // Separate constructors instead of default aInitLength parameter since
163 // otherwise the default no-arg constructor isn't found.
165 : mTable(Ops(), sizeof(EntryType
), PLDHashTable::kDefaultInitialLength
) {}
166 explicit nsTHashtable(uint32_t aInitLength
)
167 : mTable(Ops(), sizeof(EntryType
), aInitLength
) {}
170 * destructor, cleans up and deallocates
172 ~nsTHashtable() = default;
174 nsTHashtable(nsTHashtable
<EntryType
>&& aOther
);
175 nsTHashtable
<EntryType
>& operator=(nsTHashtable
<EntryType
>&& aOther
);
178 * Return the generation number for the table. This increments whenever
179 * the table data items are moved.
181 uint32_t GetGeneration() const { return mTable
.Generation(); }
184 * KeyType is typedef'ed for ease of use.
186 typedef typename
EntryType::KeyType KeyType
;
189 * KeyTypePointer is typedef'ed for ease of use.
191 typedef typename
EntryType::KeyTypePointer KeyTypePointer
;
194 * Return the number of entries in the table.
195 * @return number of entries
197 uint32_t Count() const { return mTable
.EntryCount(); }
200 * Return true if the hashtable is empty.
202 bool IsEmpty() const { return Count() == 0; }
205 * Get the entry associated with a key.
206 * @param aKey the key to retrieve
207 * @return pointer to the entry class, if the key exists; nullptr if the
210 EntryType
* GetEntry(KeyType aKey
) const {
211 return static_cast<EntryType
*>(
212 mTable
.Search(EntryType::KeyToPointer(aKey
)));
216 * Return true if an entry for the given key exists, false otherwise.
217 * @param aKey the key to retrieve
218 * @return true if the key exists, false if the key doesn't exist
220 bool Contains(KeyType aKey
) const { return !!GetEntry(aKey
); }
223 * Infallibly get the entry associated with a key, or create a new entry,
224 * @param aKey the key to retrieve
225 * @return pointer to the entry retrieved; never nullptr
227 EntryType
* PutEntry(KeyType aKey
) {
228 // Infallible WithEntryHandle.
229 return WithEntryHandle(
230 aKey
, [](auto entryHandle
) { return entryHandle
.OrInsert(); });
234 * Fallibly get the entry associated with a key, or create a new entry,
235 * @param aKey the key to retrieve
236 * @return pointer to the entry retrieved; nullptr only if memory can't
239 [[nodiscard
]] EntryType
* PutEntry(KeyType aKey
, const fallible_t
& aFallible
) {
240 return WithEntryHandle(aKey
, aFallible
, [](auto maybeEntryHandle
) {
241 return maybeEntryHandle
? maybeEntryHandle
->OrInsert() : nullptr;
246 * Get the entry associated with a key, or create a new entry using infallible
247 * allocation and insert that.
248 * @param aKey the key to retrieve
249 * @param aEntry will be assigned (if non-null) to the entry that was
251 * @return true if a new entry was created, or false if an existing entry
254 [[nodiscard
]] bool EnsureInserted(KeyType aKey
,
255 EntryType
** aEntry
= nullptr) {
256 auto oldCount
= Count();
257 EntryType
* entry
= PutEntry(aKey
);
261 return oldCount
!= Count();
265 * Remove the entry associated with a key.
266 * @param aKey of the entry to remove
268 void RemoveEntry(KeyType aKey
) {
269 mTable
.Remove(EntryType::KeyToPointer(aKey
));
273 * Lookup the entry associated with aKey and remove it if found, otherwise
275 * @param aKey of the entry to remove
276 * @return true if an entry was found and removed, or false if no entry
279 bool EnsureRemoved(KeyType aKey
) {
280 auto* entry
= GetEntry(aKey
);
289 * Remove the entry associated with a key.
290 * @param aEntry the entry-pointer to remove (obtained from GetEntry)
292 void RemoveEntry(EntryType
* aEntry
) { mTable
.RemoveEntry(aEntry
); }
295 * Remove the entry associated with a key, but don't resize the hashtable.
296 * This is a low-level method, and is not recommended unless you know what
297 * you're doing. If you use it, please add a comment explaining why you
298 * didn't use RemoveEntry().
299 * @param aEntry the entry-pointer to remove (obtained from GetEntry)
301 void RawRemoveEntry(EntryType
* aEntry
) { mTable
.RawRemove(aEntry
); }
306 EntryHandle(EntryHandle
&& aOther
) = default;
307 ~EntryHandle() = default;
309 EntryHandle(const EntryHandle
&) = delete;
310 EntryHandle
& operator=(const EntryHandle
&) = delete;
311 EntryHandle
& operator=(const EntryHandle
&&) = delete;
313 KeyType
Key() const { return mKey
; }
315 bool HasEntry() const { return mEntryHandle
.HasEntry(); }
317 explicit operator bool() const { return mEntryHandle
.operator bool(); }
319 EntryType
* Entry() { return static_cast<EntryType
*>(mEntryHandle
.Entry()); }
321 void Insert() { InsertInternal(); }
323 EntryType
* OrInsert() {
330 void Remove() { mEntryHandle
.Remove(); }
332 void OrRemove() { mEntryHandle
.OrRemove(); }
335 template <typename
... Args
>
336 void InsertInternal(Args
&&... aArgs
) {
337 MOZ_RELEASE_ASSERT(!HasEntry());
338 mEntryHandle
.Insert([&](PLDHashEntryHdr
* entry
) {
339 new (mozilla::KnownNotNull
, entry
) EntryType(
340 EntryType::KeyToPointer(mKey
), std::forward
<Args
>(aArgs
)...);
345 friend class nsTHashtable
;
347 EntryHandle(KeyType aKey
, PLDHashTable::EntryHandle
&& aEntryHandle
)
348 : mKey(aKey
), mEntryHandle(std::move(aEntryHandle
)) {}
351 PLDHashTable::EntryHandle mEntryHandle
;
355 auto WithEntryHandle(KeyType aKey
, F
&& aFunc
)
356 -> std::invoke_result_t
<F
, EntryHandle
&&> {
357 return this->mTable
.WithEntryHandle(
358 EntryType::KeyToPointer(aKey
),
359 [&aKey
, &aFunc
](auto entryHandle
) -> decltype(auto) {
360 return std::forward
<F
>(aFunc
)(
361 EntryHandle
{aKey
, std::move(entryHandle
)});
366 auto WithEntryHandle(KeyType aKey
, const mozilla::fallible_t
& aFallible
,
368 -> std::invoke_result_t
<F
, mozilla::Maybe
<EntryHandle
>&&> {
369 return this->mTable
.WithEntryHandle(
370 EntryType::KeyToPointer(aKey
), aFallible
,
371 [&aKey
, &aFunc
](auto maybeEntryHandle
) {
372 return std::forward
<F
>(aFunc
)(
374 ? mozilla::Some(EntryHandle
{aKey
, maybeEntryHandle
.extract()})
375 : mozilla::Nothing());
380 // This is an iterator that also allows entry removal. Example usage:
382 // for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
383 // Entry* entry = iter.Get();
384 // // ... do stuff with |entry| ...
385 // // ... possibly call iter.Remove() once ...
388 class Iterator
: public PLDHashTable::Iterator
{
390 typedef PLDHashTable::Iterator Base
;
392 explicit Iterator(nsTHashtable
* aTable
) : Base(&aTable
->mTable
) {}
393 Iterator(Iterator
&& aOther
) : Base(aOther
.mTable
) {}
394 ~Iterator() = default;
396 EntryType
* Get() const { return static_cast<EntryType
*>(Base::Get()); }
400 Iterator(const Iterator
&) = delete;
401 Iterator
& operator=(const Iterator
&) = delete;
402 Iterator
& operator=(const Iterator
&&) = delete;
405 Iterator
Iter() { return Iterator(this); }
407 Iterator
ConstIter() const {
408 return Iterator(const_cast<nsTHashtable
*>(this));
411 using const_iterator
= ::detail::nsTHashtable_base_iterator
<const EntryType
>;
412 using iterator
= ::detail::nsTHashtable_base_iterator
<EntryType
>;
414 iterator
begin() { return iterator
{mTable
}; }
415 const_iterator
begin() const { return const_iterator
{mTable
}; }
416 const_iterator
cbegin() const { return begin(); }
418 return iterator
{mTable
, typename
iterator::EndIteratorTag
{}};
420 const_iterator
end() const {
421 return const_iterator
{mTable
, typename
const_iterator::EndIteratorTag
{}};
423 const_iterator
cend() const { return end(); }
426 * Remove all entries, return hashtable to "pristine" state. It's
427 * conceptually the same as calling the destructor and then re-calling the
430 void Clear() { mTable
.Clear(); }
433 * Measure the size of the table's entry storage. Does *not* measure anything
434 * hanging off table entries; hence the "Shallow" prefix. To measure that,
435 * either use SizeOfExcludingThis() or iterate manually over the entries,
436 * calling SizeOfExcludingThis() on each one.
438 * @param aMallocSizeOf the function used to measure heap-allocated blocks
439 * @return the measured shallow size of the table
441 size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const {
442 return mTable
.ShallowSizeOfExcludingThis(aMallocSizeOf
);
446 * Like ShallowSizeOfExcludingThis, but includes sizeof(*this).
448 size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const {
449 return aMallocSizeOf(this) + ShallowSizeOfExcludingThis(aMallocSizeOf
);
453 * This is a "deep" measurement of the table. To use it, |EntryType| must
454 * define SizeOfExcludingThis, and that method will be called on all live
457 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const {
458 size_t n
= ShallowSizeOfExcludingThis(aMallocSizeOf
);
459 for (auto iter
= ConstIter(); !iter
.Done(); iter
.Next()) {
460 n
+= (*iter
.Get()).SizeOfExcludingThis(aMallocSizeOf
);
466 * Like SizeOfExcludingThis, but includes sizeof(*this).
468 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const {
469 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
473 * Swap the elements in this hashtable with the elements in aOther.
475 void SwapElements(nsTHashtable
<EntryType
>& aOther
) {
476 MOZ_ASSERT_IF(this->mTable
.Ops() && aOther
.mTable
.Ops(),
477 this->mTable
.Ops() == aOther
.mTable
.Ops());
478 std::swap(this->mTable
, aOther
.mTable
);
482 * Mark the table as constant after initialization.
484 * This will prevent assertions when a read-only hash is accessed on multiple
485 * threads without synchronization.
487 void MarkImmutable() { mTable
.MarkImmutable(); }
492 static PLDHashNumber
s_HashKey(const void* aKey
);
494 static bool s_MatchEntry(const PLDHashEntryHdr
* aEntry
, const void* aKey
);
496 static void s_CopyEntry(PLDHashTable
* aTable
, const PLDHashEntryHdr
* aFrom
,
497 PLDHashEntryHdr
* aTo
);
499 static void s_ClearEntry(PLDHashTable
* aTable
, PLDHashEntryHdr
* aEntry
);
502 // copy constructor, not implemented
503 nsTHashtable(nsTHashtable
<EntryType
>& aToCopy
) = delete;
506 * Gets the table's ops.
508 static const PLDHashTableOps
* Ops();
510 // assignment operator, not implemented
511 nsTHashtable
<EntryType
>& operator=(nsTHashtable
<EntryType
>& aToEqual
) =
518 // Like PLDHashTable::MoveEntryStub, but specialized for fixed N (i.e. the size
519 // of the entries in the hashtable). Saves a memory read to figure out the size
520 // from the table and gives the compiler the opportunity to inline the memcpy.
522 // We define this outside of nsTHashtable so only one copy exists for every N,
523 // rather than separate copies for every EntryType used with nsTHashtable.
525 static void FixedSizeEntryMover(PLDHashTable
*, const PLDHashEntryHdr
* aFrom
,
526 PLDHashEntryHdr
* aTo
) {
527 memcpy(aTo
, aFrom
, N
);
530 } // namespace detail
531 } // namespace mozilla
534 // template definitions
537 template <class EntryType
>
538 nsTHashtable
<EntryType
>::nsTHashtable(nsTHashtable
<EntryType
>&& aOther
)
539 : mTable(std::move(aOther
.mTable
)) {}
541 template <class EntryType
>
542 nsTHashtable
<EntryType
>& nsTHashtable
<EntryType
>::operator=(
543 nsTHashtable
<EntryType
>&& aOther
) {
544 mTable
= std::move(aOther
.mTable
);
548 template <class EntryType
>
549 /* static */ const PLDHashTableOps
* nsTHashtable
<EntryType
>::Ops() {
550 // If this variable is a global variable, we get strange start-up failures on
551 // WindowsCrtPatch.h (see bug 1166598 comment 20). But putting it inside a
552 // function avoids that problem.
553 static const PLDHashTableOps sOps
= {
554 s_HashKey
, s_MatchEntry
,
555 EntryType::ALLOW_MEMMOVE
556 ? mozilla::detail::FixedSizeEntryMover
<sizeof(EntryType
)>
558 // We don't use a generic initEntry hook because we want to allow
559 // initialization of data members defined in derived classes directly
560 // in the entry constructor (for example when a member can't be default
562 s_ClearEntry
, nullptr};
566 // static definitions
568 template <class EntryType
>
569 PLDHashNumber nsTHashtable
<EntryType
>::s_HashKey(const void* aKey
) {
570 return EntryType::HashKey(static_cast<KeyTypePointer
>(aKey
));
573 template <class EntryType
>
574 bool nsTHashtable
<EntryType
>::s_MatchEntry(const PLDHashEntryHdr
* aEntry
,
576 return (static_cast<const EntryType
*>(aEntry
))
577 ->KeyEquals(static_cast<KeyTypePointer
>(aKey
));
580 template <class EntryType
>
581 void nsTHashtable
<EntryType
>::s_CopyEntry(PLDHashTable
* aTable
,
582 const PLDHashEntryHdr
* aFrom
,
583 PLDHashEntryHdr
* aTo
) {
584 auto* fromEntry
= const_cast<std::remove_const_t
<EntryType
>*>(
585 static_cast<const EntryType
*>(aFrom
));
587 new (mozilla::KnownNotNull
, aTo
) EntryType(std::move(*fromEntry
));
589 fromEntry
->~EntryType();
592 template <class EntryType
>
593 void nsTHashtable
<EntryType
>::s_ClearEntry(PLDHashTable
* aTable
,
594 PLDHashEntryHdr
* aEntry
) {
595 static_cast<EntryType
*>(aEntry
)->~EntryType();
598 class nsCycleCollectionTraversalCallback
;
600 template <class EntryType
>
601 inline void ImplCycleCollectionUnlink(nsTHashtable
<EntryType
>& aField
) {
605 template <class EntryType
>
606 inline void ImplCycleCollectionTraverse(
607 nsCycleCollectionTraversalCallback
& aCallback
,
608 nsTHashtable
<EntryType
>& aField
, const char* aName
, uint32_t aFlags
= 0) {
609 for (auto iter
= aField
.Iter(); !iter
.Done(); iter
.Next()) {
610 EntryType
* entry
= iter
.Get();
611 ImplCycleCollectionTraverse(aCallback
, *entry
, aName
, aFlags
);
616 * For nsTHashtable with pointer entries, we can have a template specialization
617 * that layers a typed T* interface on top of a common implementation that
618 * works internally with void pointers. This arrangement saves code size and
619 * might slightly improve performance as well.
623 * We need a separate entry type class for the inheritance structure of the
624 * nsTHashtable specialization below; nsVoidPtrHashKey is simply typedefed to a
625 * specialization of nsPtrHashKey, and the formulation:
627 * class nsTHashtable<nsPtrHashKey<T>> :
628 * protected nsTHashtable<nsPtrHashKey<const void>
630 * is not going to turn out very well, since we'd wind up with an nsTHashtable
631 * instantiation that is its own base class.
635 class VoidPtrHashKey
: public nsPtrHashKey
<const void> {
636 typedef nsPtrHashKey
<const void> Base
;
639 explicit VoidPtrHashKey(const void* aKey
) : Base(aKey
) {}
642 } // namespace detail
645 * See the main nsTHashtable documentation for descriptions of this class's
648 template <typename T
>
649 class nsTHashtable
<nsPtrHashKey
<T
>>
650 : protected nsTHashtable
<::detail::VoidPtrHashKey
> {
651 typedef nsTHashtable
<::detail::VoidPtrHashKey
> Base
;
652 typedef nsPtrHashKey
<T
> EntryType
;
654 // We play games with reinterpret_cast'ing between these two classes, so
655 // try to ensure that playing said games is reasonable.
656 static_assert(sizeof(nsPtrHashKey
<T
>) == sizeof(::detail::VoidPtrHashKey
),
657 "hash keys must be the same size");
659 nsTHashtable(const nsTHashtable
& aOther
) = delete;
660 nsTHashtable
& operator=(const nsTHashtable
& aOther
) = delete;
663 nsTHashtable() = default;
664 explicit nsTHashtable(uint32_t aInitLength
) : Base(aInitLength
) {}
666 ~nsTHashtable() = default;
668 nsTHashtable(nsTHashtable
&&) = default;
672 using Base::GetGeneration
;
675 using Base::MarkImmutable
;
676 using Base::ShallowSizeOfExcludingThis
;
677 using Base::ShallowSizeOfIncludingThis
;
679 /* Wrapper functions */
680 EntryType
* GetEntry(T
* aKey
) const {
681 return reinterpret_cast<EntryType
*>(Base::GetEntry(aKey
));
684 bool Contains(T
* aKey
) const { return Base::Contains(aKey
); }
686 EntryType
* PutEntry(T
* aKey
) {
687 return reinterpret_cast<EntryType
*>(Base::PutEntry(aKey
));
690 [[nodiscard
]] EntryType
* PutEntry(T
* aKey
,
691 const mozilla::fallible_t
& aFallible
) {
692 return reinterpret_cast<EntryType
*>(Base::PutEntry(aKey
, aFallible
));
695 [[nodiscard
]] bool EnsureInserted(T
* aKey
, EntryType
** aEntry
= nullptr) {
696 return Base::EnsureInserted(
697 aKey
, reinterpret_cast<::detail::VoidPtrHashKey
**>(aEntry
));
700 void RemoveEntry(T
* aKey
) { Base::RemoveEntry(aKey
); }
702 bool EnsureRemoved(T
* aKey
) { return Base::EnsureRemoved(aKey
); }
704 void RemoveEntry(EntryType
* aEntry
) {
705 Base::RemoveEntry(reinterpret_cast<::detail::VoidPtrHashKey
*>(aEntry
));
708 void RawRemoveEntry(EntryType
* aEntry
) {
709 Base::RawRemoveEntry(reinterpret_cast<::detail::VoidPtrHashKey
*>(aEntry
));
713 class EntryHandle
: protected Base::EntryHandle
{
715 using Base
= nsTHashtable::Base::EntryHandle
;
717 EntryHandle(EntryHandle
&& aOther
) = default;
718 ~EntryHandle() = default;
720 EntryHandle(const EntryHandle
&) = delete;
721 EntryHandle
& operator=(const EntryHandle
&) = delete;
722 EntryHandle
& operator=(const EntryHandle
&&) = delete;
726 using Base::HasEntry
;
728 using Base::operator bool;
730 EntryType
* Entry() { return reinterpret_cast<EntryType
*>(Base::Entry()); }
734 EntryType
* OrInsert() {
743 using Base::OrRemove
;
746 friend class nsTHashtable
;
748 explicit EntryHandle(Base
&& aBase
) : Base(std::move(aBase
)) {}
752 auto WithEntryHandle(KeyType aKey
, F aFunc
)
753 -> std::invoke_result_t
<F
, EntryHandle
&&> {
754 return Base::WithEntryHandle(aKey
, [&aFunc
](auto entryHandle
) {
755 return aFunc(EntryHandle
{std::move(entryHandle
)});
760 auto WithEntryHandle(KeyType aKey
, const mozilla::fallible_t
& aFallible
,
762 -> std::invoke_result_t
<F
, mozilla::Maybe
<EntryHandle
>&&> {
763 return Base::WithEntryHandle(
764 aKey
, aFallible
, [&aFunc
](auto maybeEntryHandle
) {
765 return aFunc(maybeEntryHandle
? mozilla::Some(EntryHandle
{
766 maybeEntryHandle
.extract()})
767 : mozilla::Nothing());
772 class Iterator
: public Base::Iterator
{
774 typedef nsTHashtable::Base::Iterator Base
;
776 explicit Iterator(nsTHashtable
* aTable
) : Base(aTable
) {}
777 Iterator(Iterator
&& aOther
) : Base(std::move(aOther
)) {}
778 ~Iterator() = default;
780 EntryType
* Get() const { return reinterpret_cast<EntryType
*>(Base::Get()); }
784 Iterator(const Iterator
&) = delete;
785 Iterator
& operator=(const Iterator
&) = delete;
786 Iterator
& operator=(Iterator
&&) = delete;
789 Iterator
Iter() { return Iterator(this); }
791 Iterator
ConstIter() const {
792 return Iterator(const_cast<nsTHashtable
*>(this));
795 using const_iterator
= ::detail::nsTHashtable_base_iterator
<const EntryType
>;
796 using iterator
= ::detail::nsTHashtable_base_iterator
<EntryType
>;
798 iterator
begin() { return iterator
{mTable
}; }
799 const_iterator
begin() const { return const_iterator
{mTable
}; }
800 const_iterator
cbegin() const { return begin(); }
802 return iterator
{mTable
, typename
iterator::EndIteratorTag
{}};
804 const_iterator
end() const {
805 return const_iterator
{mTable
, typename
const_iterator::EndIteratorTag
{}};
807 const_iterator
cend() const { return end(); }
809 void SwapElements(nsTHashtable
& aOther
) { Base::SwapElements(aOther
); }
812 #endif // nsTHashtable_h__