OLD | NEW |
1 /* | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights | 2 // Use of this source code is governed by a BSD-style license that can be |
3 * reserved. | 3 // found in the LICENSE file. |
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 | 4 |
22 #ifndef WTF_HashTraits_h | 5 #include "platform/wtf/HashTraits.h" |
23 #define WTF_HashTraits_h | |
24 | 6 |
25 #include "wtf/Forward.h" | 7 // The contents of this header was moved to platform/wtf as part of |
26 #include "wtf/HashFunctions.h" | 8 // WTF migration project. See the following post for details: |
27 #include "wtf/HashTableDeletedValueType.h" | 9 // https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gY
CAAJ |
28 #include "wtf/StdLibExtras.h" | |
29 #include "wtf/TypeTraits.h" | |
30 #include <limits> | |
31 #include <memory> | |
32 #include <string.h> // For memset. | |
33 #include <type_traits> | |
34 #include <utility> | |
35 | |
36 namespace WTF { | |
37 | |
38 template <bool isInteger, typename T> | |
39 struct GenericHashTraitsBase; | |
40 template <typename T> | |
41 struct HashTraits; | |
42 | |
43 enum ShouldWeakPointersBeMarkedStrongly { | |
44 WeakPointersActStrong, | |
45 WeakPointersActWeak | |
46 }; | |
47 | |
48 template <typename T> | |
49 struct GenericHashTraitsBase<false, T> { | |
50 // The emptyValueIsZero flag is used to optimize allocation of empty hash | |
51 // tables with zeroed memory. | |
52 static const bool emptyValueIsZero = false; | |
53 | |
54 // The hasIsEmptyValueFunction flag allows the hash table to automatically | |
55 // generate code to check for the empty value when it can be done with the | |
56 // equality operator, but allows custom functions for cases like String that | |
57 // need them. | |
58 static const bool hasIsEmptyValueFunction = false; | |
59 | |
60 // The starting table size. Can be overridden when we know beforehand that a | |
61 // hash table will have at least N entries. | |
62 #if defined(MEMORY_SANITIZER_INITIAL_SIZE) | |
63 static const unsigned minimumTableSize = 1; | |
64 #else | |
65 static const unsigned minimumTableSize = 8; | |
66 #endif | |
67 | |
68 // When a hash table backing store is traced, its elements will be | |
69 // traced if their class type has a trace method. However, weak-referenced | |
70 // elements should not be traced then, but handled by the weak processing | |
71 // phase that follows. | |
72 template <typename U = void> | |
73 struct IsTraceableInCollection { | |
74 static const bool value = IsTraceable<T>::value && !IsWeak<T>::value; | |
75 }; | |
76 | |
77 // The NeedsToForbidGCOnMove flag is used to make the hash table move | |
78 // operations safe when GC is enabled: if a move constructor invokes | |
79 // an allocation triggering the GC then it should be invoked within GC | |
80 // forbidden scope. | |
81 template <typename U = void> | |
82 struct NeedsToForbidGCOnMove { | |
83 // TODO(yutak): Consider using of std:::is_trivially_move_constructible | |
84 // when it is accessible. | |
85 static const bool value = !std::is_pod<T>::value; | |
86 }; | |
87 | |
88 static const WeakHandlingFlag weakHandlingFlag = | |
89 IsWeak<T>::value ? WeakHandlingInCollections | |
90 : NoWeakHandlingInCollections; | |
91 }; | |
92 | |
93 // Default integer traits disallow both 0 and -1 as keys (max value instead of | |
94 // -1 for unsigned). | |
95 template <typename T> | |
96 struct GenericHashTraitsBase<true, T> : GenericHashTraitsBase<false, T> { | |
97 static const bool emptyValueIsZero = true; | |
98 static void constructDeletedValue(T& slot, bool) { | |
99 slot = static_cast<T>(-1); | |
100 } | |
101 static bool isDeletedValue(T value) { return value == static_cast<T>(-1); } | |
102 }; | |
103 | |
104 template <typename T> | |
105 struct GenericHashTraits | |
106 : GenericHashTraitsBase<std::is_integral<T>::value, T> { | |
107 typedef T TraitType; | |
108 typedef T EmptyValueType; | |
109 | |
110 static T emptyValue() { return T(); } | |
111 | |
112 // Type for functions that do not take ownership, such as contains. | |
113 typedef const T& PeekInType; | |
114 typedef T* IteratorGetType; | |
115 typedef const T* IteratorConstGetType; | |
116 typedef T& IteratorReferenceType; | |
117 typedef const T& IteratorConstReferenceType; | |
118 static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { | |
119 return *x; | |
120 } | |
121 static IteratorConstReferenceType getToReferenceConstConversion( | |
122 IteratorConstGetType x) { | |
123 return *x; | |
124 } | |
125 | |
126 template <typename IncomingValueType> | |
127 static void store(IncomingValueType&& value, T& storage) { | |
128 storage = std::forward<IncomingValueType>(value); | |
129 } | |
130 | |
131 // Type for return value of functions that do not transfer ownership, such | |
132 // as get. | |
133 // FIXME: We could change this type to const T& for better performance if we | |
134 // figured out a way to handle the return value from emptyValue, which is a | |
135 // temporary. | |
136 typedef T PeekOutType; | |
137 static const T& peek(const T& value) { return value; } | |
138 }; | |
139 | |
140 template <typename T> | |
141 struct HashTraits : GenericHashTraits<T> {}; | |
142 | |
143 template <typename T> | |
144 struct FloatHashTraits : GenericHashTraits<T> { | |
145 static T emptyValue() { return std::numeric_limits<T>::infinity(); } | |
146 static void constructDeletedValue(T& slot, bool) { | |
147 slot = -std::numeric_limits<T>::infinity(); | |
148 } | |
149 static bool isDeletedValue(T value) { | |
150 return value == -std::numeric_limits<T>::infinity(); | |
151 } | |
152 }; | |
153 | |
154 template <> | |
155 struct HashTraits<float> : FloatHashTraits<float> {}; | |
156 template <> | |
157 struct HashTraits<double> : FloatHashTraits<double> {}; | |
158 | |
159 // Default unsigned traits disallow both 0 and max as keys -- use these traits | |
160 // to allow zero and disallow max - 1. | |
161 template <typename T> | |
162 struct UnsignedWithZeroKeyHashTraits : GenericHashTraits<T> { | |
163 static const bool emptyValueIsZero = false; | |
164 static T emptyValue() { return std::numeric_limits<T>::max(); } | |
165 static void constructDeletedValue(T& slot, bool) { | |
166 slot = std::numeric_limits<T>::max() - 1; | |
167 } | |
168 static bool isDeletedValue(T value) { | |
169 return value == std::numeric_limits<T>::max() - 1; | |
170 } | |
171 }; | |
172 | |
173 template <typename P> | |
174 struct HashTraits<P*> : GenericHashTraits<P*> { | |
175 static const bool emptyValueIsZero = true; | |
176 static void constructDeletedValue(P*& slot, bool) { | |
177 slot = reinterpret_cast<P*>(-1); | |
178 } | |
179 static bool isDeletedValue(P* value) { | |
180 return value == reinterpret_cast<P*>(-1); | |
181 } | |
182 }; | |
183 | |
184 template <typename T> | |
185 struct SimpleClassHashTraits : GenericHashTraits<T> { | |
186 static const bool emptyValueIsZero = true; | |
187 template <typename U = void> | |
188 struct NeedsToForbidGCOnMove { | |
189 static const bool value = false; | |
190 }; | |
191 static void constructDeletedValue(T& slot, bool) { | |
192 new (NotNull, &slot) T(HashTableDeletedValue); | |
193 } | |
194 static bool isDeletedValue(const T& value) { | |
195 return value.isHashTableDeletedValue(); | |
196 } | |
197 }; | |
198 | |
199 template <typename P> | |
200 struct HashTraits<RefPtr<P>> : SimpleClassHashTraits<RefPtr<P>> { | |
201 typedef std::nullptr_t EmptyValueType; | |
202 static EmptyValueType emptyValue() { return nullptr; } | |
203 | |
204 static const bool hasIsEmptyValueFunction = true; | |
205 static bool isEmptyValue(const RefPtr<P>& value) { return !value; } | |
206 | |
207 typedef RefPtrValuePeeker<P> PeekInType; | |
208 typedef RefPtr<P>* IteratorGetType; | |
209 typedef const RefPtr<P>* IteratorConstGetType; | |
210 typedef RefPtr<P>& IteratorReferenceType; | |
211 typedef const RefPtr<P>& IteratorConstReferenceType; | |
212 static IteratorReferenceType getToReferenceConversion(IteratorGetType x) { | |
213 return *x; | |
214 } | |
215 static IteratorConstReferenceType getToReferenceConstConversion( | |
216 IteratorConstGetType x) { | |
217 return *x; | |
218 } | |
219 | |
220 static void store(PassRefPtr<P> value, RefPtr<P>& storage) { | |
221 storage = std::move(value); | |
222 } | |
223 | |
224 typedef P* PeekOutType; | |
225 static PeekOutType peek(const RefPtr<P>& value) { return value.get(); } | |
226 static PeekOutType peek(std::nullptr_t) { return 0; } | |
227 }; | |
228 | |
229 template <typename T> | |
230 struct HashTraits<std::unique_ptr<T>> | |
231 : SimpleClassHashTraits<std::unique_ptr<T>> { | |
232 using EmptyValueType = std::nullptr_t; | |
233 static EmptyValueType emptyValue() { return nullptr; } | |
234 | |
235 static const bool hasIsEmptyValueFunction = true; | |
236 static bool isEmptyValue(const std::unique_ptr<T>& value) { return !value; } | |
237 | |
238 using PeekInType = T*; | |
239 | |
240 static void store(std::unique_ptr<T>&& value, std::unique_ptr<T>& storage) { | |
241 storage = std::move(value); | |
242 } | |
243 | |
244 using PeekOutType = T*; | |
245 static PeekOutType peek(const std::unique_ptr<T>& value) { | |
246 return value.get(); | |
247 } | |
248 static PeekOutType peek(std::nullptr_t) { return nullptr; } | |
249 | |
250 static void constructDeletedValue(std::unique_ptr<T>& slot, bool) { | |
251 // Dirty trick: implant an invalid pointer to unique_ptr. Destructor isn't | |
252 // called for deleted buckets, so this is okay. | |
253 new (NotNull, &slot) std::unique_ptr<T>(reinterpret_cast<T*>(1u)); | |
254 } | |
255 static bool isDeletedValue(const std::unique_ptr<T>& value) { | |
256 return value.get() == reinterpret_cast<T*>(1u); | |
257 } | |
258 }; | |
259 | |
260 template <> | |
261 struct HashTraits<String> : SimpleClassHashTraits<String> { | |
262 static const bool hasIsEmptyValueFunction = true; | |
263 static bool isEmptyValue(const String&); | |
264 }; | |
265 | |
266 // This struct template is an implementation detail of the | |
267 // isHashTraitsEmptyValue function, which selects either the emptyValue function | |
268 // or the isEmptyValue function to check for empty values. | |
269 template <typename Traits, bool hasEmptyValueFunction> | |
270 struct HashTraitsEmptyValueChecker; | |
271 template <typename Traits> | |
272 struct HashTraitsEmptyValueChecker<Traits, true> { | |
273 template <typename T> | |
274 static bool isEmptyValue(const T& value) { | |
275 return Traits::isEmptyValue(value); | |
276 } | |
277 }; | |
278 template <typename Traits> | |
279 struct HashTraitsEmptyValueChecker<Traits, false> { | |
280 template <typename T> | |
281 static bool isEmptyValue(const T& value) { | |
282 return value == Traits::emptyValue(); | |
283 } | |
284 }; | |
285 template <typename Traits, typename T> | |
286 inline bool isHashTraitsEmptyValue(const T& value) { | |
287 return HashTraitsEmptyValueChecker< | |
288 Traits, Traits::hasIsEmptyValueFunction>::isEmptyValue(value); | |
289 } | |
290 | |
291 template <typename FirstTraitsArg, typename SecondTraitsArg> | |
292 struct PairHashTraits | |
293 : GenericHashTraits<std::pair<typename FirstTraitsArg::TraitType, | |
294 typename SecondTraitsArg::TraitType>> { | |
295 typedef FirstTraitsArg FirstTraits; | |
296 typedef SecondTraitsArg SecondTraits; | |
297 typedef std::pair<typename FirstTraits::TraitType, | |
298 typename SecondTraits::TraitType> | |
299 TraitType; | |
300 typedef std::pair<typename FirstTraits::EmptyValueType, | |
301 typename SecondTraits::EmptyValueType> | |
302 EmptyValueType; | |
303 | |
304 static const bool emptyValueIsZero = | |
305 FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; | |
306 static EmptyValueType emptyValue() { | |
307 return std::make_pair(FirstTraits::emptyValue(), | |
308 SecondTraits::emptyValue()); | |
309 } | |
310 | |
311 static const bool hasIsEmptyValueFunction = | |
312 FirstTraits::hasIsEmptyValueFunction || | |
313 SecondTraits::hasIsEmptyValueFunction; | |
314 static bool isEmptyValue(const TraitType& value) { | |
315 return isHashTraitsEmptyValue<FirstTraits>(value.first) && | |
316 isHashTraitsEmptyValue<SecondTraits>(value.second); | |
317 } | |
318 | |
319 static const unsigned minimumTableSize = FirstTraits::minimumTableSize; | |
320 | |
321 static void constructDeletedValue(TraitType& slot, bool zeroValue) { | |
322 FirstTraits::constructDeletedValue(slot.first, zeroValue); | |
323 // For GC collections the memory for the backing is zeroed when it is | |
324 // allocated, and the constructors may take advantage of that, | |
325 // especially if a GC occurs during insertion of an entry into the | |
326 // table. This slot is being marked deleted, but If the slot is reused | |
327 // at a later point, the same assumptions around memory zeroing must | |
328 // hold as they did at the initial allocation. Therefore we zero the | |
329 // value part of the slot here for GC collections. | |
330 if (zeroValue) | |
331 memset(reinterpret_cast<void*>(&slot.second), 0, sizeof(slot.second)); | |
332 } | |
333 static bool isDeletedValue(const TraitType& value) { | |
334 return FirstTraits::isDeletedValue(value.first); | |
335 } | |
336 }; | |
337 | |
338 template <typename First, typename Second> | |
339 struct HashTraits<std::pair<First, Second>> | |
340 : public PairHashTraits<HashTraits<First>, HashTraits<Second>> {}; | |
341 | |
342 template <typename KeyTypeArg, typename ValueTypeArg> | |
343 struct KeyValuePair { | |
344 typedef KeyTypeArg KeyType; | |
345 | |
346 template <typename IncomingKeyType, typename IncomingValueType> | |
347 KeyValuePair(IncomingKeyType&& key, IncomingValueType&& value) | |
348 : key(std::forward<IncomingKeyType>(key)), | |
349 value(std::forward<IncomingValueType>(value)) {} | |
350 | |
351 template <typename OtherKeyType, typename OtherValueType> | |
352 KeyValuePair(KeyValuePair<OtherKeyType, OtherValueType>&& other) | |
353 : key(std::move(other.key)), value(std::move(other.value)) {} | |
354 | |
355 KeyTypeArg key; | |
356 ValueTypeArg value; | |
357 }; | |
358 | |
359 template <typename KeyTraitsArg, typename ValueTraitsArg> | |
360 struct KeyValuePairHashTraits | |
361 : GenericHashTraits<KeyValuePair<typename KeyTraitsArg::TraitType, | |
362 typename ValueTraitsArg::TraitType>> { | |
363 typedef KeyTraitsArg KeyTraits; | |
364 typedef ValueTraitsArg ValueTraits; | |
365 typedef KeyValuePair<typename KeyTraits::TraitType, | |
366 typename ValueTraits::TraitType> | |
367 TraitType; | |
368 typedef KeyValuePair<typename KeyTraits::EmptyValueType, | |
369 typename ValueTraits::EmptyValueType> | |
370 EmptyValueType; | |
371 | |
372 static const bool emptyValueIsZero = | |
373 KeyTraits::emptyValueIsZero && ValueTraits::emptyValueIsZero; | |
374 static EmptyValueType emptyValue() { | |
375 return KeyValuePair<typename KeyTraits::EmptyValueType, | |
376 typename ValueTraits::EmptyValueType>( | |
377 KeyTraits::emptyValue(), ValueTraits::emptyValue()); | |
378 } | |
379 | |
380 template <typename U = void> | |
381 struct IsTraceableInCollection { | |
382 static const bool value = IsTraceableInCollectionTrait<KeyTraits>::value || | |
383 IsTraceableInCollectionTrait<ValueTraits>::value; | |
384 }; | |
385 | |
386 template <typename U = void> | |
387 struct NeedsToForbidGCOnMove { | |
388 static const bool value = | |
389 KeyTraits::template NeedsToForbidGCOnMove<>::value || | |
390 ValueTraits::template NeedsToForbidGCOnMove<>::value; | |
391 }; | |
392 | |
393 static const WeakHandlingFlag weakHandlingFlag = | |
394 (KeyTraits::weakHandlingFlag == WeakHandlingInCollections || | |
395 ValueTraits::weakHandlingFlag == WeakHandlingInCollections) | |
396 ? WeakHandlingInCollections | |
397 : NoWeakHandlingInCollections; | |
398 | |
399 static const unsigned minimumTableSize = KeyTraits::minimumTableSize; | |
400 | |
401 static void constructDeletedValue(TraitType& slot, bool zeroValue) { | |
402 KeyTraits::constructDeletedValue(slot.key, zeroValue); | |
403 // See similar code in this file for why we need to do this. | |
404 if (zeroValue) | |
405 memset(reinterpret_cast<void*>(&slot.value), 0, sizeof(slot.value)); | |
406 } | |
407 static bool isDeletedValue(const TraitType& value) { | |
408 return KeyTraits::isDeletedValue(value.key); | |
409 } | |
410 }; | |
411 | |
412 template <typename Key, typename Value> | |
413 struct HashTraits<KeyValuePair<Key, Value>> | |
414 : public KeyValuePairHashTraits<HashTraits<Key>, HashTraits<Value>> {}; | |
415 | |
416 template <typename T> | |
417 struct NullableHashTraits : public HashTraits<T> { | |
418 static const bool emptyValueIsZero = false; | |
419 static T emptyValue() { return reinterpret_cast<T>(1); } | |
420 }; | |
421 | |
422 } // namespace WTF | |
423 | |
424 using WTF::HashTraits; | |
425 using WTF::PairHashTraits; | |
426 using WTF::NullableHashTraits; | |
427 using WTF::SimpleClassHashTraits; | |
428 | |
429 #endif // WTF_HashTraits_h | |
OLD | NEW |