summaryrefslogtreecommitdiffstats
path: root/xpcom/ds/nsTHashSet.h
blob: 4d905299dbfa331d502a6eb57ad0f786fdbad7aa (plain)
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>
auto RangeSize(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_