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 nsClassHashtable_h__
8 #define nsClassHashtable_h__
9 
10 #include "mozilla/Move.h"
11 #include "nsBaseHashtable.h"
12 #include "nsHashKeys.h"
13 #include "nsAutoPtr.h"
14 
15 /**
16  * templated hashtable class maps keys to C++ object pointers.
17  * See nsBaseHashtable for complete declaration.
18  * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
19  *   for a complete specification.
20  * @param Class the class-type being wrapped
21  * @see nsInterfaceHashtable, nsClassHashtable
22  */
23 template<class KeyClass, class T>
24 class nsClassHashtable
25   : public nsBaseHashtable<KeyClass, nsAutoPtr<T>, T*>
26 {
27 public:
28   typedef typename KeyClass::KeyType KeyType;
29   typedef T* UserDataType;
30   typedef nsBaseHashtable<KeyClass, nsAutoPtr<T>, T*> base_type;
31 
32   using base_type::IsEmpty;
33 
nsClassHashtable()34   nsClassHashtable() {}
nsClassHashtable(uint32_t aInitLength)35   explicit nsClassHashtable(uint32_t aInitLength)
36     : nsBaseHashtable<KeyClass, nsAutoPtr<T>, T*>(aInitLength)
37   {
38   }
39 
40   /**
41    * Looks up aKey in the hash table. If it doesn't exist a new object of
42    * KeyClass will be created (using the arguments provided) and then returned.
43    */
44   template<typename... Args>
45   UserDataType LookupOrAdd(KeyType aKey, Args&&... aConstructionArgs);
46 
47   /**
48    * @copydoc nsBaseHashtable::Get
49    * @param aData if the key doesn't exist, pData will be set to nullptr.
50    */
51   bool Get(KeyType aKey, UserDataType* aData) const;
52 
53   /**
54    * @copydoc nsBaseHashtable::Get
55    * @returns nullptr if the key is not present.
56    */
57   UserDataType Get(KeyType aKey) const;
58 
59   /**
60    * Remove the entry for the given key from the hashtable and return it in
61    * aOut.  If the key is not in the hashtable, aOut's pointer is set to
62    * nullptr.
63    *
64    * Normally, an entry is deleted when it's removed from an nsClassHashtable,
65    * but this function transfers ownership of the entry back to the caller
66    * through aOut -- the entry will be deleted when aOut goes out of scope.
67    *
68    * @param aKey the key to get and remove from the hashtable
69    */
70   void RemoveAndForget(KeyType aKey, nsAutoPtr<T>& aOut);
71 };
72 
73 //
74 // nsClassHashtable definitions
75 //
76 
77 template<class KeyClass, class T>
78 template<typename... Args>
79 T*
LookupOrAdd(KeyType aKey,Args &&...aConstructionArgs)80 nsClassHashtable<KeyClass, T>::LookupOrAdd(KeyType aKey,
81                                            Args&&... aConstructionArgs)
82 {
83   typename base_type::EntryType* ent = this->PutEntry(aKey);
84   if (!ent->mData) {
85     ent->mData = new T(mozilla::Forward<Args>(aConstructionArgs)...);
86   }
87   return ent->mData;
88 }
89 
90 template<class KeyClass, class T>
91 bool
Get(KeyType aKey,T ** aRetVal)92 nsClassHashtable<KeyClass, T>::Get(KeyType aKey, T** aRetVal) const
93 {
94   typename base_type::EntryType* ent = this->GetEntry(aKey);
95 
96   if (ent) {
97     if (aRetVal) {
98       *aRetVal = ent->mData;
99     }
100 
101     return true;
102   }
103 
104   if (aRetVal) {
105     *aRetVal = nullptr;
106   }
107 
108   return false;
109 }
110 
111 template<class KeyClass, class T>
112 T*
Get(KeyType aKey)113 nsClassHashtable<KeyClass, T>::Get(KeyType aKey) const
114 {
115   typename base_type::EntryType* ent = this->GetEntry(aKey);
116   if (!ent) {
117     return nullptr;
118   }
119 
120   return ent->mData;
121 }
122 
123 template<class KeyClass, class T>
124 void
RemoveAndForget(KeyType aKey,nsAutoPtr<T> & aOut)125 nsClassHashtable<KeyClass, T>::RemoveAndForget(KeyType aKey, nsAutoPtr<T>& aOut)
126 {
127   aOut = nullptr;
128 
129   typename base_type::EntryType* ent = this->GetEntry(aKey);
130   if (!ent) {
131     return;
132   }
133 
134   // Transfer ownership from ent->mData into aOut.
135   aOut = mozilla::Move(ent->mData);
136 
137   this->Remove(aKey);
138 }
139 
140 #endif // nsClassHashtable_h__
141