source: webkit/trunk/JavaScriptCore/wtf/HashMap.h@ 27710

Last change on this file since 27710 was 27710, checked in by Adam Roben, 18 years ago

Fix <rdar://5578982> ASSERT in HashTable::checkTableConsistencyExceptSize beneath WebNotificationCenter

The bug was due to a mismatch between HashMap::remove and
HashTable::checkTableConsistency. HashMap::remove can delete the value
stored in the HashTable (by derefing it), which is not normally
allowed by HashTable. It's OK in this case because the value is about
to be removed from the table, but HashTable wasn't aware of this.

HashMap::remove now performs the consistency check itself before
derefing the value.

Darin noticed that the same bug would occur in HashSet, so I've fixed
it there as well.

Reviewed by Darin.

  • wtf/HashMap.h: (WTF::HashMap::remove): Perform the HashTable consistency check manually before calling deref.
  • wtf/HashSet.h: (WTF::HashSet::remove): Ditto.
  • wtf/HashTable.h: Made checkTableConsistency public so that HashMap and HashSet can call it. (WTF::HashTable::removeAndInvalidateWithoutEntryConsistencyCheck): Added. (WTF::HashTable::removeAndInvalidate): Added. (WTF::HashTable::remove): (WTF::HashTable::removeWithoutEntryConsistencyCheck): Added.
  • Property svn:eol-style set to native
File size: 16.1 KB
Line 
1// -*- mode: c++; c-basic-offset: 4 -*-
2/*
3 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#ifndef WTF_HashMap_h
23#define WTF_HashMap_h
24
25#include "HashTable.h"
26#include "Vector.h"
27
28namespace WTF {
29
30 template<typename PairType> struct PairFirstExtractor;
31
32 template<typename KeyArg, typename MappedArg, typename HashArg = typename DefaultHash<KeyArg>::Hash,
33 typename KeyTraitsArg = HashTraits<KeyArg>, typename MappedTraitsArg = HashTraits<MappedArg> >
34 class HashMap {
35 private:
36 typedef KeyTraitsArg KeyTraits;
37 typedef MappedTraitsArg MappedTraits;
38 typedef PairBaseHashTraits<KeyTraits, MappedTraits> ValueTraits;
39
40 public:
41 typedef typename KeyTraits::TraitType KeyType;
42 typedef typename MappedTraits::TraitType MappedType;
43 typedef typename ValueTraits::TraitType ValueType;
44
45 private:
46 typedef HashArg HashFunctions;
47
48 typedef typename HashKeyStorageTraits<HashFunctions, KeyTraits>::Hash StorageHashFunctions;
49
50 typedef typename HashKeyStorageTraits<HashFunctions, KeyTraits>::Traits KeyStorageTraits;
51 typedef typename MappedTraits::StorageTraits MappedStorageTraits;
52 typedef PairHashTraits<KeyStorageTraits, MappedStorageTraits> ValueStorageTraits;
53
54 typedef typename KeyStorageTraits::TraitType KeyStorageType;
55 typedef typename MappedStorageTraits::TraitType MappedStorageType;
56 typedef typename ValueStorageTraits::TraitType ValueStorageType;
57
58 typedef HashTable<KeyStorageType, ValueStorageType, PairFirstExtractor<ValueStorageType>,
59 StorageHashFunctions, ValueStorageTraits, KeyStorageTraits> HashTableType;
60
61 public:
62 typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator;
63 typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
64
65 HashMap();
66 HashMap(const HashMap&);
67 HashMap& operator=(const HashMap&);
68 ~HashMap();
69
70 void swap(HashMap&);
71
72 int size() const;
73 int capacity() const;
74 bool isEmpty() const;
75
76 // iterators iterate over pairs of keys and values
77 iterator begin();
78 iterator end();
79 const_iterator begin() const;
80 const_iterator end() const;
81
82 iterator find(const KeyType&);
83 const_iterator find(const KeyType&) const;
84 bool contains(const KeyType&) const;
85 MappedType get(const KeyType&) const;
86
87 // replaces value but not key if key is already present
88 // return value is a pair of the iterator to the key location,
89 // and a boolean that's true if a new value was actually added
90 pair<iterator, bool> set(const KeyType&, const MappedType&);
91
92 // does nothing if key is already present
93 // return value is a pair of the iterator to the key location,
94 // and a boolean that's true if a new value was actually added
95 pair<iterator, bool> add(const KeyType&, const MappedType&);
96
97 void remove(const KeyType&);
98 void remove(iterator);
99 void clear();
100
101 MappedType take(const KeyType&); // efficient combination of get with remove
102
103 private:
104 pair<iterator, bool> inlineAdd(const KeyType&, const MappedType&);
105 void refAll();
106 void derefAll();
107
108 HashTableType m_impl;
109 };
110
111 template<typename PairType> struct PairFirstExtractor {
112 static const typename PairType::first_type& extract(const PairType& p) { return p.first; }
113 };
114
115 template<bool canReplaceDeletedKey, typename ValueType, typename ValueTraits, typename ValueStorageTraits, typename HashFunctions>
116 struct HashMapTranslator;
117
118 template<typename ValueType, typename ValueTraits, typename ValueStorageTraits, typename HashFunctions>
119 struct HashMapTranslator<true, ValueType, ValueTraits, ValueStorageTraits, HashFunctions> {
120 typedef typename ValueType::first_type KeyType;
121 typedef typename ValueType::second_type MappedType;
122 typedef typename ValueStorageTraits::TraitType ValueStorageType;
123 typedef typename ValueStorageTraits::FirstTraits KeyStorageTraits;
124 typedef typename KeyStorageTraits::TraitType KeyStorageType;
125 typedef typename ValueStorageTraits::SecondTraits MappedStorageTraits;
126 typedef typename MappedStorageTraits::TraitType MappedStorageType;
127 typedef typename ValueTraits::FirstTraits KeyTraits;
128 typedef typename ValueTraits::SecondTraits MappedTraits;
129
130 static unsigned hash(const KeyType& key) { return HashFunctions::hash(key); }
131 static bool equal(const KeyStorageType& a, const KeyType& b) { return HashFunctions::equal(*(KeyType*)&a, b); }
132 static void translate(ValueStorageType& location, const KeyType& key, const MappedType& mapped)
133 {
134 Assigner<KeyTraits::needsRef, KeyType, KeyStorageType, KeyTraits>::assign(key, location.first);
135 Assigner<MappedTraits::needsRef, MappedType, MappedStorageType, MappedTraits>::assign(mapped, location.second);
136 }
137 };
138
139 template<typename ValueType, typename ValueTraits, typename ValueStorageTraits, typename HashFunctions>
140 struct HashMapTranslator<false, ValueType, ValueTraits, ValueStorageTraits, HashFunctions> {
141 typedef typename ValueType::first_type KeyType;
142 typedef typename ValueType::second_type MappedType;
143 typedef typename ValueStorageTraits::TraitType ValueStorageType;
144 typedef typename ValueStorageTraits::FirstTraits KeyStorageTraits;
145 typedef typename KeyStorageTraits::TraitType KeyStorageType;
146 typedef typename ValueStorageTraits::SecondTraits MappedStorageTraits;
147 typedef typename MappedStorageTraits::TraitType MappedStorageType;
148 typedef typename ValueTraits::FirstTraits KeyTraits;
149 typedef typename ValueTraits::SecondTraits MappedTraits;
150
151 static unsigned hash(const KeyType& key) { return HashFunctions::hash(key); }
152 static bool equal(const KeyStorageType& a, const KeyType& b) { return HashFunctions::equal(*(KeyType*)&a, b); }
153 static void translate(ValueStorageType& location, const KeyType& key, const MappedType& mapped)
154 {
155 if (location.first == KeyStorageTraits::deletedValue())
156 location.first = KeyStorageTraits::emptyValue();
157 Assigner<KeyTraits::needsRef, KeyType, KeyStorageType, KeyTraits>::assign(key, location.first);
158 Assigner<MappedTraits::needsRef, MappedType, MappedStorageType, MappedTraits>::assign(mapped, location.second);
159 }
160 };
161
162 template<typename T, typename U, typename V, typename W, typename X>
163 inline void HashMap<T, U, V, W, X>::refAll()
164 {
165 HashTableRefCounter<HashTableType, ValueTraits>::refAll(m_impl);
166 }
167
168 template<typename T, typename U, typename V, typename W, typename X>
169 inline void HashMap<T, U, V, W, X>::derefAll()
170 {
171 HashTableRefCounter<HashTableType, ValueTraits>::derefAll(m_impl);
172 }
173
174 template<typename T, typename U, typename V, typename W, typename X>
175 inline HashMap<T, U, V, W, X>::HashMap()
176 {
177 }
178
179 template<typename T, typename U, typename V, typename W, typename X>
180 inline HashMap<T, U, V, W, X>::HashMap(const HashMap& other)
181 : m_impl(other.m_impl)
182 {
183 refAll();
184 }
185
186 template<typename T, typename U, typename V, typename W, typename X>
187 inline HashMap<T, U, V, W, X>& HashMap<T, U, V, W, X>::operator=(const HashMap& other)
188 {
189 HashMap tmp(other);
190 swap(tmp);
191 return *this;
192 }
193
194 template<typename T, typename U, typename V, typename W, typename X>
195 inline void HashMap<T, U, V, W, X>::swap(HashMap& other)
196 {
197 m_impl.swap(other.m_impl);
198 }
199
200 template<typename T, typename U, typename V, typename W, typename X>
201 inline HashMap<T, U, V, W, X>::~HashMap()
202 {
203 derefAll();
204 }
205
206 template<typename T, typename U, typename V, typename W, typename X>
207 inline int HashMap<T, U, V, W, X>::size() const
208 {
209 return m_impl.size();
210 }
211
212 template<typename T, typename U, typename V, typename W, typename X>
213 inline int HashMap<T, U, V, W, X>::capacity() const
214 {
215 return m_impl.capacity();
216 }
217
218 template<typename T, typename U, typename V, typename W, typename X>
219 inline bool HashMap<T, U, V, W, X>::isEmpty() const
220 {
221 return m_impl.isEmpty();
222 }
223
224 template<typename T, typename U, typename V, typename W, typename X>
225 inline typename HashMap<T, U, V, W, X>::iterator HashMap<T, U, V, W, X>::begin()
226 {
227 return m_impl.begin();
228 }
229
230 template<typename T, typename U, typename V, typename W, typename X>
231 inline typename HashMap<T, U, V, W, X>::iterator HashMap<T, U, V, W, X>::end()
232 {
233 return m_impl.end();
234 }
235
236 template<typename T, typename U, typename V, typename W, typename X>
237 inline typename HashMap<T, U, V, W, X>::const_iterator HashMap<T, U, V, W, X>::begin() const
238 {
239 return m_impl.begin();
240 }
241
242 template<typename T, typename U, typename V, typename W, typename X>
243 inline typename HashMap<T, U, V, W, X>::const_iterator HashMap<T, U, V, W, X>::end() const
244 {
245 return m_impl.end();
246 }
247
248 template<typename T, typename U, typename V, typename W, typename X>
249 inline typename HashMap<T, U, V, W, X>::iterator HashMap<T, U, V, W, X>::find(const KeyType& key)
250 {
251 return m_impl.find(*(const KeyStorageType*)&key);
252 }
253
254 template<typename T, typename U, typename V, typename W, typename X>
255 inline typename HashMap<T, U, V, W, X>::const_iterator HashMap<T, U, V, W, X>::find(const KeyType& key) const
256 {
257 return m_impl.find(*(const KeyStorageType*)&key);
258 }
259
260 template<typename T, typename U, typename V, typename W, typename X>
261 inline bool HashMap<T, U, V, W, X>::contains(const KeyType& key) const
262 {
263 return m_impl.contains(*(const KeyStorageType*)&key);
264 }
265
266 template<typename T, typename U, typename V, typename W, typename X>
267 inline pair<typename HashMap<T, U, V, W, X>::iterator, bool>
268 HashMap<T, U, V, W, X>::inlineAdd(const KeyType& key, const MappedType& mapped)
269 {
270 const bool canReplaceDeletedKey = !KeyTraits::needsDestruction || KeyStorageTraits::needsDestruction;
271 typedef HashMapTranslator<canReplaceDeletedKey, ValueType, ValueTraits, ValueStorageTraits, HashFunctions> TranslatorType;
272 return m_impl.template add<KeyType, MappedType, TranslatorType>(key, mapped);
273 }
274
275 template<typename T, typename U, typename V, typename W, typename X>
276 pair<typename HashMap<T, U, V, W, X>::iterator, bool>
277 HashMap<T, U, V, W, X>::set(const KeyType& key, const MappedType& mapped)
278 {
279 pair<iterator, bool> result = inlineAdd(key, mapped);
280 if (!result.second)
281 // add call above didn't change anything, so set the mapped value
282 result.first->second = mapped;
283 return result;
284 }
285
286 template<typename T, typename U, typename V, typename W, typename X>
287 pair<typename HashMap<T, U, V, W, X>::iterator, bool>
288 HashMap<T, U, V, W, X>::add(const KeyType& key, const MappedType& mapped)
289 {
290 return inlineAdd(key, mapped);
291 }
292
293 template<typename T, typename U, typename V, typename W, typename MappedTraits>
294 typename HashMap<T, U, V, W, MappedTraits>::MappedType
295 HashMap<T, U, V, W, MappedTraits>::get(const KeyType& key) const
296 {
297 if (m_impl.isEmpty())
298 return MappedTraits::emptyValue();
299 ValueStorageType* entry = const_cast<HashTableType&>(m_impl).lookup(*(const KeyStorageType*)&key);
300 if (!entry)
301 return MappedTraits::emptyValue();
302 return ((ValueType *)entry)->second;
303 }
304
305 template<typename T, typename U, typename V, typename W, typename X>
306 inline void HashMap<T, U, V, W, X>::remove(iterator it)
307 {
308 if (it.m_impl == m_impl.end())
309 return;
310 m_impl.checkTableConsistency();
311 RefCounter<ValueTraits, ValueStorageTraits>::deref(*it.m_impl);
312 m_impl.removeWithoutEntryConsistencyCheck(it.m_impl);
313 }
314
315 template<typename T, typename U, typename V, typename W, typename X>
316 inline void HashMap<T, U, V, W, X>::remove(const KeyType& key)
317 {
318 remove(find(key));
319 }
320
321 template<typename T, typename U, typename V, typename W, typename X>
322 inline void HashMap<T, U, V, W, X>::clear()
323 {
324 derefAll();
325 m_impl.clear();
326 }
327
328 template<typename T, typename U, typename V, typename W, typename MappedTraits>
329 typename HashMap<T, U, V, W, MappedTraits>::MappedType
330 HashMap<T, U, V, W, MappedTraits>::take(const KeyType& key)
331 {
332 // This can probably be made more efficient to avoid ref/deref churn.
333 iterator it = find(key);
334 if (it == end())
335 return MappedTraits::emptyValue();
336 typename HashMap<T, U, V, W, MappedTraits>::MappedType result = it->second;
337 remove(it);
338 return result;
339 }
340
341 template<typename T, typename U, typename V, typename W, typename X>
342 bool operator==(const HashMap<T, U, V, W, X>& a, const HashMap<T, U, V, W, X>& b)
343 {
344 if (a.size() != b.size())
345 return false;
346
347 typedef typename HashMap<T, U, V, W, X>::const_iterator const_iterator;
348
349 const_iterator end = a.end();
350 const_iterator notFound = b.end();
351 for (const_iterator it = a.begin(); it != end; ++it) {
352 const_iterator bPos = b.find(it->first);
353 if (bPos == notFound || it->second != bPos->second)
354 return false;
355 }
356
357 return true;
358 }
359
360 template<typename T, typename U, typename V, typename W, typename X>
361 inline bool operator!=(const HashMap<T, U, V, W, X>& a, const HashMap<T, U, V, W, X>& b)
362 {
363 return !(a == b);
364 }
365
366 template<typename MappedType, typename HashTableType>
367 void deleteAllPairSeconds(HashTableType& collection)
368 {
369 typedef typename HashTableType::const_iterator iterator;
370 iterator end = collection.end();
371 for (iterator it = collection.begin(); it != end; ++it)
372 delete *(MappedType*)&it->second;
373 }
374
375 template<typename T, typename U, typename V, typename W, typename X>
376 inline void deleteAllValues(const HashMap<T, U, V, W, X>& collection)
377 {
378 deleteAllPairSeconds<typename HashMap<T, U, V, W, X>::MappedType>(collection);
379 }
380
381 template<typename KeyType, typename HashTableType>
382 void deleteAllPairFirsts(HashTableType& collection)
383 {
384 typedef typename HashTableType::const_iterator iterator;
385 iterator end = collection.end();
386 for (iterator it = collection.begin(); it != end; ++it)
387 delete *(KeyType*)&it->first;
388 }
389
390 template<typename T, typename U, typename V, typename W, typename X>
391 inline void deleteAllKeys(const HashMap<T, U, V, W, X>& collection)
392 {
393 deleteAllPairFirsts<typename HashMap<T, U, V, W, X>::KeyType>(collection);
394 }
395
396 template<typename T, typename U, typename V, typename W, typename X>
397 inline void copyValuesToVector(const HashMap<T, U, V, W, X>& collection, Vector<U>& vector)
398 {
399 typedef typename HashMap<T, U, V, W, X>::const_iterator iterator;
400
401 vector.resize(collection.size());
402
403 iterator it = collection.begin();
404 iterator end = collection.end();
405 for (unsigned i = 0; it != end; ++it, ++i)
406 vector[i] = (*it).second;
407 }
408
409} // namespace WTF
410
411using WTF::HashMap;
412
413#endif /* WTF_HashMap_h */
Note: See TracBrowser for help on using the repository browser.