Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / xpcom / ds / nsTHashtable.h
bloba88bc6f4e224c06c318d6f144b1bebe7c164e8e5
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__
13 #include <iterator>
14 #include <new>
15 #include <type_traits>
16 #include <utility>
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"
28 namespace detail {
29 // STL-style iterators to allow the use in range-based for loops, e.g.
30 template <typename T>
31 class nsTHashtable_base_iterator
32 : public std::iterator<std::forward_iterator_tag, T, int32_t> {
33 public:
34 using
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());
60 return *this;
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++() {
85 mIterator.Next();
86 return *this;
88 iterator_type operator++(int) {
89 iterator_type it = *this;
90 ++*this;
91 return it;
94 operator const_iterator_type() const {
95 return const_iterator_type{mIterator.Clone()};
98 private:
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
113 * PLDHashTable code.
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!
133 * ~EntryType();
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 };
147 * }</pre>
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");
161 public:
162 // Separate constructors instead of default aInitLength parameter since
163 // otherwise the default no-arg constructor isn't found.
164 nsTHashtable()
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
208 * key doesn't exist
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
237 * be allocated
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
250 * found or created
251 * @return true if a new entry was created, or false if an existing entry
252 * was found
254 [[nodiscard]] bool EnsureInserted(KeyType aKey,
255 EntryType** aEntry = nullptr) {
256 auto oldCount = Count();
257 EntryType* entry = PutEntry(aKey);
258 if (aEntry) {
259 *aEntry = entry;
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
274 * do nothing.
275 * @param aKey of the entry to remove
276 * @return true if an entry was found and removed, or false if no entry
277 * was found for aKey
279 bool EnsureRemoved(KeyType aKey) {
280 auto* entry = GetEntry(aKey);
281 if (entry) {
282 RemoveEntry(entry);
283 return true;
285 return false;
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); }
303 protected:
304 class EntryHandle {
305 public:
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() {
324 if (!HasEntry()) {
325 Insert();
327 return Entry();
330 void Remove() { mEntryHandle.Remove(); }
332 void OrRemove() { mEntryHandle.OrRemove(); }
334 protected:
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)...);
344 private:
345 friend class nsTHashtable;
347 EntryHandle(KeyType aKey, PLDHashTable::EntryHandle&& aEntryHandle)
348 : mKey(aKey), mEntryHandle(std::move(aEntryHandle)) {}
350 KeyType mKey;
351 PLDHashTable::EntryHandle mEntryHandle;
354 template <class F>
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)});
365 template <class F>
366 auto WithEntryHandle(KeyType aKey, const mozilla::fallible_t& aFallible,
367 F&& aFunc)
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)(
373 maybeEntryHandle
374 ? mozilla::Some(EntryHandle{aKey, maybeEntryHandle.extract()})
375 : mozilla::Nothing());
379 public:
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 ...
386 // }
388 class Iterator : public PLDHashTable::Iterator {
389 public:
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()); }
398 private:
399 Iterator() = delete;
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(); }
417 iterator end() {
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
428 * constructor.
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
455 * entries.
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);
462 return n;
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(); }
489 protected:
490 PLDHashTable mTable;
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);
501 private:
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) =
512 delete;
515 namespace mozilla {
516 namespace detail {
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.
524 template <size_t N>
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);
545 return *this;
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)>
557 : s_CopyEntry,
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
561 // constructed).
562 s_ClearEntry, nullptr};
563 return &sOps;
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,
575 const void* aKey) {
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) {
602 aField.Clear();
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.
633 namespace detail {
635 class VoidPtrHashKey : public nsPtrHashKey<const void> {
636 typedef nsPtrHashKey<const void> Base;
638 public:
639 explicit VoidPtrHashKey(const void* aKey) : Base(aKey) {}
642 } // namespace detail
645 * See the main nsTHashtable documentation for descriptions of this class's
646 * methods.
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;
662 public:
663 nsTHashtable() = default;
664 explicit nsTHashtable(uint32_t aInitLength) : Base(aInitLength) {}
666 ~nsTHashtable() = default;
668 nsTHashtable(nsTHashtable&&) = default;
670 using Base::Clear;
671 using Base::Count;
672 using Base::GetGeneration;
673 using Base::IsEmpty;
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));
712 protected:
713 class EntryHandle : protected Base::EntryHandle {
714 public:
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;
724 using Base::Key;
726 using Base::HasEntry;
728 using Base::operator bool;
730 EntryType* Entry() { return reinterpret_cast<EntryType*>(Base::Entry()); }
732 using Base::Insert;
734 EntryType* OrInsert() {
735 if (!HasEntry()) {
736 Insert();
738 return Entry();
741 using Base::Remove;
743 using Base::OrRemove;
745 private:
746 friend class nsTHashtable;
748 explicit EntryHandle(Base&& aBase) : Base(std::move(aBase)) {}
751 template <class F>
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)});
759 template <class F>
760 auto WithEntryHandle(KeyType aKey, const mozilla::fallible_t& aFallible,
761 F aFunc)
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());
771 public:
772 class Iterator : public Base::Iterator {
773 public:
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()); }
782 private:
783 Iterator() = delete;
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(); }
801 iterator end() {
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__