1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
/* -*- 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/. */
#ifndef XPCOM_DS_NSTHASHSET_H_
#define XPCOM_DS_NSTHASHSET_H_
#include "nsHashtablesFwd.h"
#include "nsTHashMap.h" // for nsKeyClass
/**
* Templated hash set. Don't use this directly, but use nsTHashSet instead
* (defined as a type alias in nsHashtablesFwd.h).
*
* @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
* for a complete specification.
*/
template <class KeyClass>
class nsTBaseHashSet : protected nsTHashtable<KeyClass> {
using Base = nsTHashtable<KeyClass>;
typedef mozilla::fallible_t fallible_t;
public:
// XXX We have a similar situation here like with DataType/UserDataType in
// nsBaseHashtable. It's less problematic here due to the more constrained
// interface, but it may still be confusing. KeyType is not the stored key
// type, but the one exposed to the user, i.e. as a parameter type, and as the
// value type when iterating. It is currently impossible to move-insert a
// RefPtr<T>, e.g., since the KeyType is T* in that case.
using ValueType = typename KeyClass::KeyType;
// KeyType is defined just for compatibility with nsTHashMap. For a set, the
// key type is conceptually equivalent to the value type.
using KeyType = typename KeyClass::KeyType;
using Base::Base;
// Query operations.
using Base::Contains;
using Base::GetGeneration;
using Base::ShallowSizeOfExcludingThis;
using Base::ShallowSizeOfIncludingThis;
using Base::SizeOfExcludingThis;
using Base::SizeOfIncludingThis;
/**
* Return the number of entries in the table.
* @return number of entries
*/
[[nodiscard]] uint32_t Count() const { return Base::Count(); }
/**
* Return whether the table is empty.
* @return whether empty
*/
[[nodiscard]] bool IsEmpty() const { return Base::IsEmpty(); }
using iterator = ::detail::nsTHashtableKeyIterator<KeyClass>;
using const_iterator = iterator;
[[nodiscard]] auto begin() const { return Base::Keys().begin(); }
[[nodiscard]] auto end() const { return Base::Keys().end(); }
[[nodiscard]] auto cbegin() const { return Base::Keys().cbegin(); }
[[nodiscard]] auto cend() const { return Base::Keys().cend(); }
// Mutating operations.
using Base::Clear;
using Base::MarkImmutable;
/**
* Inserts a value into the set. Has no effect if the value is already in the
* set. This overload is infallible and crashes if memory is exhausted.
*
* \note For strict consistency with nsTHashtable::EntryHandle method naming,
* this should rather be called OrInsert, as it is legal to call it when the
* value is already in the set. For simplicity, as we don't have two methods,
* we still use "Insert" instead.
*/
void Insert(ValueType aValue) { Base::PutEntry(aValue); }
/**
* Inserts a value into the set. Has no effect if the value is already in the
* set. This overload is fallible and returns false if memory is exhausted.
*
* \note See note on infallible overload.
*/
[[nodiscard]] bool Insert(ValueType aValue, const mozilla::fallible_t&) {
return Base::PutEntry(aValue, mozilla::fallible);
}
/**
* Inserts a value into the set. Has no effect if the value is already in the
* set. This member function is infallible and crashes if memory is exhausted.
*
* \return true if the value was actually inserted, false if it was already in
* the set.
*/
bool EnsureInserted(ValueType aValue) { return Base::EnsureInserted(aValue); }
using Base::Remove;
/**
* Removes a value from the set. Has no effect if the value is not in the set.
*
* \note For strict consistency with nsTHashtable::EntryHandle method naming,
* this should rather be called OrRemove, as it is legal to call it when the
* value is not in the set. For simplicity, as we don't have two methods,
* we still use "Remove" instead.
*/
void Remove(ValueType aValue) { Base::RemoveEntry(aValue); }
using Base::EnsureRemoved;
/**
* Removes all elements matching a predicate.
*
* The predicate must be compatible with signature bool (ValueType).
*/
template <typename Pred>
void RemoveIf(Pred&& aPred) {
for (auto it = cbegin(), end = cend(); it != end; ++it) {
if (aPred(static_cast<ValueType>(*it))) {
Remove(it);
}
}
}
};
template <typename KeyClass>
size_t RangeSizeEstimate(const nsTBaseHashSet<KeyClass>& aRange) {
return aRange.Count();
}
class nsCycleCollectionTraversalCallback;
template <class KeyClass>
inline void ImplCycleCollectionUnlink(nsTBaseHashSet<KeyClass>& aField) {
aField.Clear();
}
template <class KeyClass>
inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback,
const nsTBaseHashSet<KeyClass>& aField, const char* aName,
uint32_t aFlags = 0) {
for (const auto& entry : aField) {
CycleCollectionNoteChild(aCallback, mozilla::detail::PtrGetWeak(entry),
aName, aFlags);
}
}
namespace mozilla {
template <typename SetT>
class nsTSetInserter {
SetT* mSet;
class Proxy {
SetT& mSet;
public:
explicit Proxy(SetT& aSet) : mSet{aSet} {}
template <typename E2>
void operator=(E2&& aValue) {
mSet.Insert(std::forward<E2>(aValue));
}
};
public:
using iterator_category = std::output_iterator_tag;
explicit nsTSetInserter(SetT& aSet) : mSet{&aSet} {}
Proxy operator*() { return Proxy(*mSet); }
nsTSetInserter& operator++() { return *this; }
nsTSetInserter& operator++(int) { return *this; }
};
} // namespace mozilla
template <typename E>
auto MakeInserter(nsTBaseHashSet<E>& aSet) {
return mozilla::nsTSetInserter<nsTBaseHashSet<E>>{aSet};
}
#endif // XPCOM_DS_NSTHASHSET_H_
|