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/. */
6
7 #ifndef nsRefPtrHashtable_h__
8 #define nsRefPtrHashtable_h__
9
10 #include "nsBaseHashtable.h"
11 #include "nsHashKeys.h"
12 #include "nsAutoPtr.h"
13
14 /**
15 * templated hashtable class maps keys to reference pointers.
16 * See nsBaseHashtable for complete declaration.
17 * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
18 * for a complete specification.
19 * @param PtrType the reference-type being wrapped
20 * @see nsDataHashtable, nsClassHashtable
21 */
22 template<class KeyClass, class PtrType>
23 class nsRefPtrHashtable
24 : public nsBaseHashtable<KeyClass, RefPtr<PtrType>, PtrType*>
25 {
26 public:
27 typedef typename KeyClass::KeyType KeyType;
28 typedef PtrType* UserDataType;
29 typedef nsBaseHashtable<KeyClass, RefPtr<PtrType>, PtrType*> base_type;
30
nsRefPtrHashtable()31 nsRefPtrHashtable() {}
nsRefPtrHashtable(uint32_t aInitLength)32 explicit nsRefPtrHashtable(uint32_t aInitLength)
33 : nsBaseHashtable<KeyClass, RefPtr<PtrType>, PtrType*>(aInitLength)
34 {
35 }
36
37 /**
38 * @copydoc nsBaseHashtable::Get
39 * @param aData This is an XPCOM getter, so aData is already_addrefed.
40 * If the key doesn't exist, aData will be set to nullptr.
41 */
42 bool Get(KeyType aKey, UserDataType* aData) const;
43
44 /**
45 * Gets a weak reference to the hashtable entry.
46 * @param aFound If not nullptr, will be set to true if the entry is found,
47 * to false otherwise.
48 * @return The entry, or nullptr if not found. Do not release this pointer!
49 */
50 PtrType* GetWeak(KeyType aKey, bool* aFound = nullptr) const;
51
52 // Overload Put, rather than overriding it.
53 using base_type::Put;
54
55 void Put(KeyType aKey, already_AddRefed<PtrType> aData);
56
57 MOZ_MUST_USE bool Put(KeyType aKey, already_AddRefed<PtrType> aData,
58 const mozilla::fallible_t&);
59
60 // Overload Remove, rather than overriding it.
61 using base_type::Remove;
62
63 /**
64 * Remove the data for the associated key, swapping the current value into
65 * pData, thereby avoiding calls to AddRef and Release.
66 * @param aKey the key to remove from the hashtable
67 * @param aData This is an XPCOM getter, so aData is already_addrefed.
68 * If the key doesn't exist, aData will be set to nullptr. Must be non-null.
69 */
70 bool Remove(KeyType aKey, UserDataType* aData);
71 };
72
73 template<typename K, typename T>
74 inline void
ImplCycleCollectionUnlink(nsRefPtrHashtable<K,T> & aField)75 ImplCycleCollectionUnlink(nsRefPtrHashtable<K, T>& aField)
76 {
77 aField.Clear();
78 }
79
80 template<typename K, typename T>
81 inline void
82 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
83 nsRefPtrHashtable<K, T>& aField,
84 const char* aName,
85 uint32_t aFlags = 0)
86 {
87 for (auto iter = aField.ConstIter(); !iter.Done(); iter.Next()) {
88 CycleCollectionNoteChild(aCallback, iter.UserData(), aName, aFlags);
89 }
90 }
91
92 //
93 // nsRefPtrHashtable definitions
94 //
95
96 template<class KeyClass, class PtrType>
97 bool
Get(KeyType aKey,UserDataType * aRefPtr)98 nsRefPtrHashtable<KeyClass, PtrType>::Get(KeyType aKey,
99 UserDataType* aRefPtr) const
100 {
101 typename base_type::EntryType* ent = this->GetEntry(aKey);
102
103 if (ent) {
104 if (aRefPtr) {
105 *aRefPtr = ent->mData;
106
107 NS_IF_ADDREF(*aRefPtr);
108 }
109
110 return true;
111 }
112
113 // if the key doesn't exist, set *aRefPtr to null
114 // so that it is a valid XPCOM getter
115 if (aRefPtr) {
116 *aRefPtr = nullptr;
117 }
118
119 return false;
120 }
121
122 template<class KeyClass, class PtrType>
123 PtrType*
GetWeak(KeyType aKey,bool * aFound)124 nsRefPtrHashtable<KeyClass, PtrType>::GetWeak(KeyType aKey, bool* aFound) const
125 {
126 typename base_type::EntryType* ent = this->GetEntry(aKey);
127
128 if (ent) {
129 if (aFound) {
130 *aFound = true;
131 }
132
133 return ent->mData;
134 }
135
136 // Key does not exist, return nullptr and set aFound to false
137 if (aFound) {
138 *aFound = false;
139 }
140
141 return nullptr;
142 }
143
144 template<class KeyClass, class PtrType>
145 void
Put(KeyType aKey,already_AddRefed<PtrType> aData)146 nsRefPtrHashtable<KeyClass, PtrType>::Put(KeyType aKey,
147 already_AddRefed<PtrType> aData)
148 {
149 if (!Put(aKey, mozilla::Move(aData), mozilla::fallible)) {
150 NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount());
151 }
152 }
153
154 template<class KeyClass, class PtrType>
155 bool
Put(KeyType aKey,already_AddRefed<PtrType> aData,const mozilla::fallible_t &)156 nsRefPtrHashtable<KeyClass, PtrType>::Put(KeyType aKey,
157 already_AddRefed<PtrType> aData,
158 const mozilla::fallible_t&)
159 {
160 typename base_type::EntryType* ent = this->PutEntry(aKey);
161
162 if (!ent) {
163 return false;
164 }
165
166 ent->mData = aData;
167
168 return true;
169 }
170
171 template<class KeyClass, class PtrType>
172 bool
Remove(KeyType aKey,UserDataType * aRefPtr)173 nsRefPtrHashtable<KeyClass, PtrType>::Remove(KeyType aKey,
174 UserDataType* aRefPtr)
175 {
176 MOZ_ASSERT(aRefPtr);
177 typename base_type::EntryType* ent = this->GetEntry(aKey);
178
179 if (ent) {
180 ent->mData.forget(aRefPtr);
181 this->Remove(aKey);
182 return true;
183 }
184
185 // If the key doesn't exist, set *aRefPtr to null
186 // so that it is a valid XPCOM getter.
187 *aRefPtr = nullptr;
188 return false;
189 }
190
191 #endif // nsRefPtrHashtable_h__
192