/src/parallel-hashmap/parallel_hashmap/phmap_base.h
Line | Count | Source (jump to first uncovered line) |
1 | | #if !defined(phmap_base_h_guard_) |
2 | | #define phmap_base_h_guard_ |
3 | | |
4 | | // --------------------------------------------------------------------------- |
5 | | // Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com |
6 | | // |
7 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | // you may not use this file except in compliance with the License. |
9 | | // You may obtain a copy of the License at |
10 | | // |
11 | | // https://www.apache.org/licenses/LICENSE-2.0 |
12 | | // |
13 | | // Unless required by applicable law or agreed to in writing, software |
14 | | // distributed under the License is distributed on an "AS IS" BASIS, |
15 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | // See the License for the specific language governing permissions and |
17 | | // limitations under the License. |
18 | | // |
19 | | // Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp) |
20 | | // with modifications. |
21 | | // |
22 | | // Copyright 2018 The Abseil Authors. |
23 | | // |
24 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
25 | | // you may not use this file except in compliance with the License. |
26 | | // You may obtain a copy of the License at |
27 | | // |
28 | | // https://www.apache.org/licenses/LICENSE-2.0 |
29 | | // |
30 | | // Unless required by applicable law or agreed to in writing, software |
31 | | // distributed under the License is distributed on an "AS IS" BASIS, |
32 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
33 | | // See the License for the specific language governing permissions and |
34 | | // limitations under the License. |
35 | | // --------------------------------------------------------------------------- |
36 | | |
37 | | #include <algorithm> |
38 | | #include <cassert> |
39 | | #include <cstddef> |
40 | | #include <initializer_list> |
41 | | #include <iterator> |
42 | | #include <string> |
43 | | #include <type_traits> |
44 | | #include <utility> |
45 | | #include <functional> |
46 | | #include <tuple> |
47 | | #include <utility> |
48 | | #include <memory> |
49 | | #include <mutex> // for std::lock |
50 | | |
51 | | #include "phmap_config.h" |
52 | | |
53 | | #ifdef PHMAP_HAVE_SHARED_MUTEX |
54 | | #include <shared_mutex> // after "phmap_config.h" |
55 | | #endif |
56 | | |
57 | | #ifdef _MSC_VER |
58 | | #pragma warning(push) |
59 | | #pragma warning(disable : 4514) // unreferenced inline function has been removed |
60 | | #pragma warning(disable : 4582) // constructor is not implicitly called |
61 | | #pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted |
62 | | #pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted |
63 | | #pragma warning(disable : 4710) // function not inlined |
64 | | #pragma warning(disable : 4711) // selected for automatic inline expansion |
65 | | #pragma warning(disable : 4820) // '6' bytes padding added after data member |
66 | | #endif // _MSC_VER |
67 | | |
68 | | namespace phmap { |
69 | | |
70 | | template <class T> using Allocator = typename std::allocator<T>; |
71 | | |
72 | | template<class T1, class T2> using Pair = typename std::pair<T1, T2>; |
73 | | |
74 | | template <class T> |
75 | | struct EqualTo |
76 | | { |
77 | | inline bool operator()(const T& a, const T& b) const |
78 | 10.4M | { |
79 | 10.4M | return std::equal_to<T>()(a, b); |
80 | 10.4M | } |
81 | | }; |
82 | | |
83 | | template <class T> |
84 | | struct Less |
85 | | { |
86 | | inline bool operator()(const T& a, const T& b) const |
87 | | { |
88 | | return std::less<T>()(a, b); |
89 | | } |
90 | | }; |
91 | | |
92 | | namespace type_traits_internal { |
93 | | |
94 | | template <typename... Ts> |
95 | | struct VoidTImpl { |
96 | | using type = void; |
97 | | }; |
98 | | |
99 | | // NOTE: The `is_detected` family of templates here differ from the library |
100 | | // fundamentals specification in that for library fundamentals, `Op<Args...>` is |
101 | | // evaluated as soon as the type `is_detected<Op, Args...>` undergoes |
102 | | // substitution, regardless of whether or not the `::value` is accessed. That |
103 | | // is inconsistent with all other standard traits and prevents lazy evaluation |
104 | | // in larger contexts (such as if the `is_detected` check is a trailing argument |
105 | | // of a `conjunction`. This implementation opts to instead be lazy in the same |
106 | | // way that the standard traits are (this "defect" of the detection idiom |
107 | | // specifications has been reported). |
108 | | // --------------------------------------------------------------------------- |
109 | | |
110 | | template <class Enabler, template <class...> class Op, class... Args> |
111 | | struct is_detected_impl { |
112 | | using type = std::false_type; |
113 | | }; |
114 | | |
115 | | template <template <class...> class Op, class... Args> |
116 | | struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> { |
117 | | using type = std::true_type; |
118 | | }; |
119 | | |
120 | | template <template <class...> class Op, class... Args> |
121 | | struct is_detected : is_detected_impl<void, Op, Args...>::type {}; |
122 | | |
123 | | template <class Enabler, class To, template <class...> class Op, class... Args> |
124 | | struct is_detected_convertible_impl { |
125 | | using type = std::false_type; |
126 | | }; |
127 | | |
128 | | template <class To, template <class...> class Op, class... Args> |
129 | | struct is_detected_convertible_impl< |
130 | | typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type, |
131 | | To, Op, Args...> { |
132 | | using type = std::true_type; |
133 | | }; |
134 | | |
135 | | template <class To, template <class...> class Op, class... Args> |
136 | | struct is_detected_convertible |
137 | | : is_detected_convertible_impl<void, To, Op, Args...>::type {}; |
138 | | |
139 | | template <typename T> |
140 | | using IsCopyAssignableImpl = |
141 | | decltype(std::declval<T&>() = std::declval<const T&>()); |
142 | | |
143 | | template <typename T> |
144 | | using IsMoveAssignableImpl = decltype(std::declval<T&>() = std::declval<T&&>()); |
145 | | |
146 | | } // namespace type_traits_internal |
147 | | |
148 | | template <typename T> |
149 | | struct is_copy_assignable : type_traits_internal::is_detected< |
150 | | type_traits_internal::IsCopyAssignableImpl, T> { |
151 | | }; |
152 | | |
153 | | template <typename T> |
154 | | struct is_move_assignable : type_traits_internal::is_detected< |
155 | | type_traits_internal::IsMoveAssignableImpl, T> { |
156 | | }; |
157 | | |
158 | | // --------------------------------------------------------------------------- |
159 | | // void_t() |
160 | | // |
161 | | // Ignores the type of any its arguments and returns `void`. In general, this |
162 | | // metafunction allows you to create a general case that maps to `void` while |
163 | | // allowing specializations that map to specific types. |
164 | | // |
165 | | // This metafunction is designed to be a drop-in replacement for the C++17 |
166 | | // `std::void_t` metafunction. |
167 | | // |
168 | | // NOTE: `phmap::void_t` does not use the standard-specified implementation so |
169 | | // that it can remain compatible with gcc < 5.1. This can introduce slightly |
170 | | // different behavior, such as when ordering partial specializations. |
171 | | // --------------------------------------------------------------------------- |
172 | | template <typename... Ts> |
173 | | using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type; |
174 | | |
175 | | // --------------------------------------------------------------------------- |
176 | | // conjunction |
177 | | // |
178 | | // Performs a compile-time logical AND operation on the passed types (which |
179 | | // must have `::value` members convertible to `bool`. Short-circuits if it |
180 | | // encounters any `false` members (and does not compare the `::value` members |
181 | | // of any remaining arguments). |
182 | | // |
183 | | // This metafunction is designed to be a drop-in replacement for the C++17 |
184 | | // `std::conjunction` metafunction. |
185 | | // --------------------------------------------------------------------------- |
186 | | template <typename... Ts> |
187 | | struct conjunction; |
188 | | |
189 | | template <typename T, typename... Ts> |
190 | | struct conjunction<T, Ts...> |
191 | | : std::conditional<T::value, conjunction<Ts...>, T>::type {}; |
192 | | |
193 | | template <typename T> |
194 | | struct conjunction<T> : T {}; |
195 | | |
196 | | template <> |
197 | | struct conjunction<> : std::true_type {}; |
198 | | |
199 | | // --------------------------------------------------------------------------- |
200 | | // disjunction |
201 | | // |
202 | | // Performs a compile-time logical OR operation on the passed types (which |
203 | | // must have `::value` members convertible to `bool`. Short-circuits if it |
204 | | // encounters any `true` members (and does not compare the `::value` members |
205 | | // of any remaining arguments). |
206 | | // |
207 | | // This metafunction is designed to be a drop-in replacement for the C++17 |
208 | | // `std::disjunction` metafunction. |
209 | | // --------------------------------------------------------------------------- |
210 | | template <typename... Ts> |
211 | | struct disjunction; |
212 | | |
213 | | template <typename T, typename... Ts> |
214 | | struct disjunction<T, Ts...> : |
215 | | std::conditional<T::value, T, disjunction<Ts...>>::type {}; |
216 | | |
217 | | template <typename T> |
218 | | struct disjunction<T> : T {}; |
219 | | |
220 | | template <> |
221 | | struct disjunction<> : std::false_type {}; |
222 | | |
223 | | template <typename T> |
224 | | struct negation : std::integral_constant<bool, !T::value> {}; |
225 | | |
226 | | // ----------------------------------------------------------------------------- |
227 | | // C++14 "_t" trait aliases |
228 | | // ----------------------------------------------------------------------------- |
229 | | |
230 | | template <typename T> |
231 | | using remove_cv_t = typename std::remove_cv<T>::type; |
232 | | |
233 | | template <typename T> |
234 | | using remove_const_t = typename std::remove_const<T>::type; |
235 | | |
236 | | template <typename T> |
237 | | using remove_volatile_t = typename std::remove_volatile<T>::type; |
238 | | |
239 | | template <typename T> |
240 | | using add_cv_t = typename std::add_cv<T>::type; |
241 | | |
242 | | template <typename T> |
243 | | using add_const_t = typename std::add_const<T>::type; |
244 | | |
245 | | template <typename T> |
246 | | using add_volatile_t = typename std::add_volatile<T>::type; |
247 | | |
248 | | template <typename T> |
249 | | using remove_reference_t = typename std::remove_reference<T>::type; |
250 | | |
251 | | template <typename T> |
252 | | using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type; |
253 | | |
254 | | template <typename T> |
255 | | using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type; |
256 | | |
257 | | template <typename T> |
258 | | using remove_pointer_t = typename std::remove_pointer<T>::type; |
259 | | |
260 | | template <typename T> |
261 | | using add_pointer_t = typename std::add_pointer<T>::type; |
262 | | |
263 | | template <typename T> |
264 | | using make_signed_t = typename std::make_signed<T>::type; |
265 | | |
266 | | template <typename T> |
267 | | using make_unsigned_t = typename std::make_unsigned<T>::type; |
268 | | |
269 | | template <typename T> |
270 | | using remove_extent_t = typename std::remove_extent<T>::type; |
271 | | |
272 | | template <typename T> |
273 | | using remove_all_extents_t = typename std::remove_all_extents<T>::type; |
274 | | |
275 | | template<std::size_t Len, std::size_t Align> |
276 | | struct aligned_storage { |
277 | | struct type { |
278 | | alignas(Align) unsigned char data[Len]; |
279 | | }; |
280 | | }; |
281 | | |
282 | | template< std::size_t Len, std::size_t Align> |
283 | | using aligned_storage_t = typename aligned_storage<Len, Align>::type; |
284 | | |
285 | | template <typename T> |
286 | | using decay_t = typename std::decay<T>::type; |
287 | | |
288 | | template <bool B, typename T = void> |
289 | | using enable_if_t = typename std::enable_if<B, T>::type; |
290 | | |
291 | | template <bool B, typename T, typename F> |
292 | | using conditional_t = typename std::conditional<B, T, F>::type; |
293 | | |
294 | | |
295 | | template <typename... T> |
296 | | using common_type_t = typename std::common_type<T...>::type; |
297 | | |
298 | | template <typename T> |
299 | | using underlying_type_t = typename std::underlying_type<T>::type; |
300 | | |
301 | | template< class F, class... ArgTypes> |
302 | | #if PHMAP_HAVE_CC17 && defined(__cpp_lib_result_of_sfinae) |
303 | | using invoke_result_t = typename std::invoke_result_t<F, ArgTypes...>; |
304 | | #else |
305 | | using invoke_result_t = typename std::result_of<F(ArgTypes...)>::type; |
306 | | #endif |
307 | | |
308 | | namespace type_traits_internal { |
309 | | |
310 | | // ---------------------------------------------------------------------- |
311 | | // In MSVC we can't probe std::hash or stdext::hash because it triggers a |
312 | | // static_assert instead of failing substitution. Libc++ prior to 4.0 |
313 | | // also used a static_assert. |
314 | | // ---------------------------------------------------------------------- |
315 | | #if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \ |
316 | | _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11) |
317 | | #define PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0 |
318 | | #else |
319 | | #define PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1 |
320 | | #endif |
321 | | |
322 | | #if !PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ |
323 | | template <typename Key, typename = size_t> |
324 | | struct IsHashable : std::true_type {}; |
325 | | #else // PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ |
326 | | template <typename Key, typename = void> |
327 | | struct IsHashable : std::false_type {}; |
328 | | |
329 | | template <typename Key> |
330 | | struct IsHashable<Key, |
331 | | phmap::enable_if_t<std::is_convertible< |
332 | | decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())), |
333 | | std::size_t>::value>> : std::true_type {}; |
334 | | #endif |
335 | | |
336 | | struct AssertHashEnabledHelper |
337 | | { |
338 | | private: |
339 | 0 | static void Sink(...) {} |
340 | | struct NAT {}; |
341 | | |
342 | | template <class Key> |
343 | | static auto GetReturnType(int) |
344 | | -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>())); |
345 | | template <class Key> |
346 | | static NAT GetReturnType(...); |
347 | | |
348 | | template <class Key> |
349 | | static std::nullptr_t DoIt() { |
350 | | static_assert(IsHashable<Key>::value, |
351 | | "std::hash<Key> does not provide a call operator"); |
352 | | static_assert( |
353 | | std::is_default_constructible<std::hash<Key>>::value, |
354 | | "std::hash<Key> must be default constructible when it is enabled"); |
355 | | static_assert( |
356 | | std::is_copy_constructible<std::hash<Key>>::value, |
357 | | "std::hash<Key> must be copy constructible when it is enabled"); |
358 | | static_assert(phmap::is_copy_assignable<std::hash<Key>>::value, |
359 | | "std::hash<Key> must be copy assignable when it is enabled"); |
360 | | // is_destructible is unchecked as it's implied by each of the |
361 | | // is_constructible checks. |
362 | | using ReturnType = decltype(GetReturnType<Key>(0)); |
363 | | static_assert(std::is_same<ReturnType, NAT>::value || |
364 | | std::is_same<ReturnType, size_t>::value, |
365 | | "std::hash<Key> must return size_t"); |
366 | | return nullptr; |
367 | | } |
368 | | |
369 | | template <class... Ts> |
370 | | friend void AssertHashEnabled(); |
371 | | }; |
372 | | |
373 | | template <class... Ts> |
374 | | inline void AssertHashEnabled |
375 | | () |
376 | | { |
377 | | using Helper = AssertHashEnabledHelper; |
378 | | Helper::Sink(Helper::DoIt<Ts>()...); |
379 | | } |
380 | | |
381 | | } // namespace type_traits_internal |
382 | | |
383 | | } // namespace phmap |
384 | | |
385 | | |
386 | | // ----------------------------------------------------------------------------- |
387 | | // hash_policy_traits |
388 | | // ----------------------------------------------------------------------------- |
389 | | namespace phmap { |
390 | | namespace priv { |
391 | | |
392 | | // Defines how slots are initialized/destroyed/moved. |
393 | | template <class Policy, class = void> |
394 | | struct hash_policy_traits |
395 | | { |
396 | | private: |
397 | | struct ReturnKey |
398 | | { |
399 | | // We return `Key` here. |
400 | | // When Key=T&, we forward the lvalue reference. |
401 | | // When Key=T, we return by value to avoid a dangling reference. |
402 | | // eg, for string_hash_map. |
403 | | template <class Key, class... Args> |
404 | | Key operator()(Key&& k, const Args&...) const { |
405 | | return std::forward<Key>(k); |
406 | | } |
407 | | }; |
408 | | |
409 | | template <class P = Policy, class = void> |
410 | | struct ConstantIteratorsImpl : std::false_type {}; |
411 | | |
412 | | template <class P> |
413 | | struct ConstantIteratorsImpl<P, phmap::void_t<typename P::constant_iterators>> |
414 | | : P::constant_iterators {}; |
415 | | |
416 | | public: |
417 | | // The actual object stored in the hash table. |
418 | | using slot_type = typename Policy::slot_type; |
419 | | |
420 | | // The type of the keys stored in the hashtable. |
421 | | using key_type = typename Policy::key_type; |
422 | | |
423 | | // The argument type for insertions into the hashtable. This is different |
424 | | // from value_type for increased performance. See initializer_list constructor |
425 | | // and insert() member functions for more details. |
426 | | using init_type = typename Policy::init_type; |
427 | | |
428 | | using reference = decltype(Policy::element(std::declval<slot_type*>())); |
429 | | using pointer = typename std::remove_reference<reference>::type*; |
430 | | using value_type = typename std::remove_reference<reference>::type; |
431 | | |
432 | | // Policies can set this variable to tell raw_hash_set that all iterators |
433 | | // should be constant, even `iterator`. This is useful for set-like |
434 | | // containers. |
435 | | // Defaults to false if not provided by the policy. |
436 | | using constant_iterators = ConstantIteratorsImpl<>; |
437 | | |
438 | | // PRECONDITION: `slot` is UNINITIALIZED |
439 | | // POSTCONDITION: `slot` is INITIALIZED |
440 | | template <class Alloc, class... Args> |
441 | 591k | static void construct(Alloc* alloc, slot_type* slot, Args&&... args) { |
442 | 591k | Policy::construct(alloc, slot, std::forward<Args>(args)...); |
443 | 591k | } |
444 | | |
445 | | // PRECONDITION: `slot` is INITIALIZED |
446 | | // POSTCONDITION: `slot` is UNINITIALIZED |
447 | | template <class Alloc> |
448 | 1.17M | static void destroy(Alloc* alloc, slot_type* slot) { |
449 | 1.17M | Policy::destroy(alloc, slot); |
450 | 1.17M | } void phmap::priv::hash_policy_traits<phmap::priv::FlatHashMapPolicy<unsigned int, int>, void>::destroy<std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, phmap::priv::map_slot_type<unsigned int, int>*) Line | Count | Source | 448 | 1.17M | static void destroy(Alloc* alloc, slot_type* slot) { | 449 | 1.17M | Policy::destroy(alloc, slot); | 450 | 1.17M | } |
Unexecuted instantiation: void phmap::priv::hash_policy_traits<phmap::priv::FlatHashMapPolicy<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, void>::destroy<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >*) |
451 | | |
452 | | // Transfers the `old_slot` to `new_slot`. Any memory allocated by the |
453 | | // allocator inside `old_slot` to `new_slot` can be transferred. |
454 | | // |
455 | | // OPTIONAL: defaults to: |
456 | | // |
457 | | // clone(new_slot, std::move(*old_slot)); |
458 | | // destroy(old_slot); |
459 | | // |
460 | | // PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED |
461 | | // POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is |
462 | | // UNINITIALIZED |
463 | | template <class Alloc> |
464 | 1.04M | static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) { |
465 | 1.04M | transfer_impl(alloc, new_slot, old_slot, 0); |
466 | 1.04M | } |
467 | | |
468 | | // PRECONDITION: `slot` is INITIALIZED |
469 | | // POSTCONDITION: `slot` is INITIALIZED |
470 | | template <class P = Policy> |
471 | 12.6M | static auto element(slot_type* slot) -> decltype(P::element(slot)) { |
472 | 12.6M | return P::element(slot); |
473 | 12.6M | } decltype (phmap::priv::FlatHashMapPolicy<unsigned int, int>::element({parm#1})) phmap::priv::hash_policy_traits<phmap::priv::FlatHashMapPolicy<unsigned int, int>, void>::element<phmap::priv::FlatHashMapPolicy<unsigned int, int> >(phmap::priv::map_slot_type<unsigned int, int>*) Line | Count | Source | 471 | 12.6M | static auto element(slot_type* slot) -> decltype(P::element(slot)) { | 472 | 12.6M | return P::element(slot); | 473 | 12.6M | } |
Unexecuted instantiation: decltype (phmap::priv::FlatHashMapPolicy<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::element({parm#1})) phmap::priv::hash_policy_traits<phmap::priv::FlatHashMapPolicy<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, void>::element<phmap::priv::FlatHashMapPolicy<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >*) |
474 | | |
475 | | // Returns the amount of memory owned by `slot`, exclusive of `sizeof(*slot)`. |
476 | | // |
477 | | // If `slot` is nullptr, returns the constant amount of memory owned by any |
478 | | // full slot or -1 if slots own variable amounts of memory. |
479 | | // |
480 | | // PRECONDITION: `slot` is INITIALIZED or nullptr |
481 | | template <class P = Policy> |
482 | | static size_t space_used(const slot_type* slot) { |
483 | | return P::space_used(slot); |
484 | | } |
485 | | |
486 | | // Provides generalized access to the key for elements, both for elements in |
487 | | // the table and for elements that have not yet been inserted (or even |
488 | | // constructed). We would like an API that allows us to say: `key(args...)` |
489 | | // but we cannot do that for all cases, so we use this more general API that |
490 | | // can be used for many things, including the following: |
491 | | // |
492 | | // - Given an element in a table, get its key. |
493 | | // - Given an element initializer, get its key. |
494 | | // - Given `emplace()` arguments, get the element key. |
495 | | // |
496 | | // Implementations of this must adhere to a very strict technical |
497 | | // specification around aliasing and consuming arguments: |
498 | | // |
499 | | // Let `value_type` be the result type of `element()` without ref- and |
500 | | // cv-qualifiers. The first argument is a functor, the rest are constructor |
501 | | // arguments for `value_type`. Returns `std::forward<F>(f)(k, xs...)`, where |
502 | | // `k` is the element key, and `xs...` are the new constructor arguments for |
503 | | // `value_type`. It's allowed for `k` to alias `xs...`, and for both to alias |
504 | | // `ts...`. The key won't be touched once `xs...` are used to construct an |
505 | | // element; `ts...` won't be touched at all, which allows `apply()` to consume |
506 | | // any rvalues among them. |
507 | | // |
508 | | // If `value_type` is constructible from `Ts&&...`, `Policy::apply()` must not |
509 | | // trigger a hard compile error unless it originates from `f`. In other words, |
510 | | // `Policy::apply()` must be SFINAE-friendly. If `value_type` is not |
511 | | // constructible from `Ts&&...`, either SFINAE or a hard compile error is OK. |
512 | | // |
513 | | // If `Ts...` is `[cv] value_type[&]` or `[cv] init_type[&]`, |
514 | | // `Policy::apply()` must work. A compile error is not allowed, SFINAE or not. |
515 | | template <class F, class... Ts, class P = Policy> |
516 | | static auto apply(F&& f, Ts&&... ts) |
517 | 20.7M | -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { |
518 | 20.7M | return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...); |
519 | 20.7M | } _ZN5phmap4priv18hash_policy_traitsINS0_17FlatHashMapPolicyIjiEEvE5applyINS0_12raw_hash_setIS3_NS_4HashIjEENS_7EqualToIjEENSt3__19allocatorINSB_4pairIKjiEEEEE19EmplaceDecomposableEJSF_ES3_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSK_DpOSL_ Line | Count | Source | 517 | 8.71M | -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { | 518 | 8.71M | return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...); | 519 | 8.71M | } |
_ZN5phmap4priv18hash_policy_traitsINS0_17FlatHashMapPolicyIjiEEvE5applyINS0_12raw_hash_setIS3_NS_4HashIjEENS_7EqualToIjEENSt3__19allocatorINSB_4pairIKjiEEEEE12EqualElementIjEEJRSF_ES3_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSM_DpOSN_ Line | Count | Source | 517 | 10.4M | -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { | 518 | 10.4M | return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...); | 519 | 10.4M | } |
_ZN5phmap4priv18hash_policy_traitsINS0_17FlatHashMapPolicyIjiEEvE5applyINS0_12raw_hash_setIS3_NS_4HashIjEENS_7EqualToIjEENSt3__19allocatorINSB_4pairIKjiEEEEE11HashElementEJRSF_ES3_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSL_DpOSM_ Line | Count | Source | 517 | 1.04M | -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { | 518 | 1.04M | return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...); | 519 | 1.04M | } |
_ZN5phmap4priv18hash_policy_traitsINS0_17FlatHashMapPolicyIjiEEvE5applyINS0_12raw_hash_setIS3_NS_4HashIjEENS_7EqualToIjEENSt3__19allocatorINSB_4pairIKjiEEEEE11HashElementEJRKSF_ES3_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSM_DpOSN_ Line | Count | Source | 517 | 578k | -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { | 518 | 578k | return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...); | 519 | 578k | } |
|
520 | | |
521 | | // Returns the "key" portion of the slot. |
522 | | // Used for node handle manipulation. |
523 | | template <class P = Policy> |
524 | | static auto key(slot_type* slot) |
525 | | -> decltype(P::apply(ReturnKey(), element(slot))) { |
526 | | return P::apply(ReturnKey(), element(slot)); |
527 | | } |
528 | | |
529 | | // Returns the "value" (as opposed to the "key") portion of the element. Used |
530 | | // by maps to implement `operator[]`, `at()` and `insert_or_assign()`. |
531 | | template <class T, class P = Policy> |
532 | | static auto value(T* elem) -> decltype(P::value(elem)) { |
533 | | return P::value(elem); |
534 | | } |
535 | | |
536 | | private: |
537 | | |
538 | | // Use auto -> decltype as an enabler. |
539 | | template <class Alloc, class P = Policy> |
540 | | static auto transfer_impl(Alloc* alloc, slot_type* new_slot, |
541 | | slot_type* old_slot, int) |
542 | 1.04M | -> decltype((void)P::transfer(alloc, new_slot, old_slot)) { |
543 | 1.04M | P::transfer(alloc, new_slot, old_slot); |
544 | 1.04M | } |
545 | | |
546 | | template <class Alloc> |
547 | | static void transfer_impl(Alloc* alloc, slot_type* new_slot, |
548 | | slot_type* old_slot, char) { |
549 | | construct(alloc, new_slot, std::move(element(old_slot))); |
550 | | destroy(alloc, old_slot); |
551 | | } |
552 | | }; |
553 | | |
554 | | } // namespace priv |
555 | | } // namespace phmap |
556 | | |
557 | | // ----------------------------------------------------------------------------- |
558 | | // file utility.h |
559 | | // ----------------------------------------------------------------------------- |
560 | | |
561 | | // --------- identity.h |
562 | | namespace phmap { |
563 | | namespace internal { |
564 | | |
565 | | template <typename T> |
566 | | struct identity { |
567 | | typedef T type; |
568 | | }; |
569 | | |
570 | | template <typename T> |
571 | | using identity_t = typename identity<T>::type; |
572 | | |
573 | | } // namespace internal |
574 | | } // namespace phmap |
575 | | |
576 | | |
577 | | // --------- inline_variable.h |
578 | | |
579 | | #ifdef __cpp_inline_variables |
580 | | |
581 | | #if defined(__clang__) |
582 | | #define PHMAP_INTERNAL_EXTERN_DECL(type, name) \ |
583 | | extern const ::phmap::internal::identity_t<type> name; |
584 | | #else // Otherwise, just define the macro to do nothing. |
585 | | #define PHMAP_INTERNAL_EXTERN_DECL(type, name) |
586 | | #endif // defined(__clang__) |
587 | | |
588 | | // See above comment at top of file for details. |
589 | | #define PHMAP_INTERNAL_INLINE_CONSTEXPR(type, name, init) \ |
590 | | PHMAP_INTERNAL_EXTERN_DECL(type, name) \ |
591 | | inline constexpr ::phmap::internal::identity_t<type> name = init |
592 | | |
593 | | #else |
594 | | |
595 | | // See above comment at top of file for details. |
596 | | // |
597 | | // Note: |
598 | | // identity_t is used here so that the const and name are in the |
599 | | // appropriate place for pointer types, reference types, function pointer |
600 | | // types, etc.. |
601 | | #define PHMAP_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \ |
602 | | template <class /*PhmapInternalDummy*/ = void> \ |
603 | | struct PhmapInternalInlineVariableHolder##name { \ |
604 | | static constexpr ::phmap::internal::identity_t<var_type> kInstance = init; \ |
605 | | }; \ |
606 | | \ |
607 | | template <class PhmapInternalDummy> \ |
608 | | constexpr ::phmap::internal::identity_t<var_type> \ |
609 | | PhmapInternalInlineVariableHolder##name<PhmapInternalDummy>::kInstance; \ |
610 | | \ |
611 | | static constexpr const ::phmap::internal::identity_t<var_type>& \ |
612 | | name = /* NOLINT */ \ |
613 | | PhmapInternalInlineVariableHolder##name<>::kInstance; \ |
614 | | static_assert(sizeof(void (*)(decltype(name))) != 0, \ |
615 | | "Silence unused variable warnings.") |
616 | | |
617 | | #endif // __cpp_inline_variables |
618 | | |
619 | | // ----------- throw_delegate |
620 | | |
621 | | namespace phmap { |
622 | | namespace base_internal { |
623 | | |
624 | | namespace { |
625 | | |
626 | | #ifdef PHMAP_HAVE_EXCEPTIONS |
627 | | #define PHMAP_THROW_IMPL(e) throw e |
628 | | #else |
629 | | #define PHMAP_THROW_IMPL(e) do { (void)(e); std::abort(); } while(0) |
630 | | #endif |
631 | | } // namespace |
632 | | |
633 | 0 | static inline void ThrowStdLogicError(const std::string& what_arg) { |
634 | 0 | PHMAP_THROW_IMPL(std::logic_error(what_arg)); |
635 | 0 | } |
636 | 0 | static inline void ThrowStdLogicError(const char* what_arg) { |
637 | 0 | PHMAP_THROW_IMPL(std::logic_error(what_arg)); |
638 | 0 | } |
639 | 0 | static inline void ThrowStdInvalidArgument(const std::string& what_arg) { |
640 | 0 | PHMAP_THROW_IMPL(std::invalid_argument(what_arg)); |
641 | 0 | } |
642 | 0 | static inline void ThrowStdInvalidArgument(const char* what_arg) { |
643 | 0 | PHMAP_THROW_IMPL(std::invalid_argument(what_arg)); |
644 | 0 | } |
645 | | |
646 | 0 | static inline void ThrowStdDomainError(const std::string& what_arg) { |
647 | 0 | PHMAP_THROW_IMPL(std::domain_error(what_arg)); |
648 | 0 | } |
649 | 0 | static inline void ThrowStdDomainError(const char* what_arg) { |
650 | 0 | PHMAP_THROW_IMPL(std::domain_error(what_arg)); |
651 | 0 | } |
652 | | |
653 | 0 | static inline void ThrowStdLengthError(const std::string& what_arg) { |
654 | 0 | PHMAP_THROW_IMPL(std::length_error(what_arg)); |
655 | 0 | } |
656 | 0 | static inline void ThrowStdLengthError(const char* what_arg) { |
657 | 0 | PHMAP_THROW_IMPL(std::length_error(what_arg)); |
658 | 0 | } |
659 | | |
660 | 0 | static inline void ThrowStdOutOfRange(const std::string& what_arg) { |
661 | 0 | PHMAP_THROW_IMPL(std::out_of_range(what_arg)); |
662 | 0 | } |
663 | 0 | static inline void ThrowStdOutOfRange(const char* what_arg) { |
664 | 0 | PHMAP_THROW_IMPL(std::out_of_range(what_arg)); |
665 | 0 | } |
666 | | |
667 | 0 | static inline void ThrowStdRuntimeError(const std::string& what_arg) { |
668 | 0 | PHMAP_THROW_IMPL(std::runtime_error(what_arg)); |
669 | 0 | } |
670 | 0 | static inline void ThrowStdRuntimeError(const char* what_arg) { |
671 | 0 | PHMAP_THROW_IMPL(std::runtime_error(what_arg)); |
672 | 0 | } |
673 | | |
674 | 0 | static inline void ThrowStdRangeError(const std::string& what_arg) { |
675 | 0 | PHMAP_THROW_IMPL(std::range_error(what_arg)); |
676 | 0 | } |
677 | 0 | static inline void ThrowStdRangeError(const char* what_arg) { |
678 | 0 | PHMAP_THROW_IMPL(std::range_error(what_arg)); |
679 | 0 | } |
680 | | |
681 | 0 | static inline void ThrowStdOverflowError(const std::string& what_arg) { |
682 | 0 | PHMAP_THROW_IMPL(std::overflow_error(what_arg)); |
683 | 0 | } |
684 | | |
685 | 0 | static inline void ThrowStdOverflowError(const char* what_arg) { |
686 | 0 | PHMAP_THROW_IMPL(std::overflow_error(what_arg)); |
687 | 0 | } |
688 | | |
689 | 0 | static inline void ThrowStdUnderflowError(const std::string& what_arg) { |
690 | 0 | PHMAP_THROW_IMPL(std::underflow_error(what_arg)); |
691 | 0 | } |
692 | | |
693 | 0 | static inline void ThrowStdUnderflowError(const char* what_arg) { |
694 | 0 | PHMAP_THROW_IMPL(std::underflow_error(what_arg)); |
695 | 0 | } |
696 | | |
697 | 0 | static inline void ThrowStdBadFunctionCall() { |
698 | 0 | PHMAP_THROW_IMPL(std::bad_function_call()); |
699 | 0 | } |
700 | | |
701 | 0 | static inline void ThrowStdBadAlloc() { |
702 | 0 | PHMAP_THROW_IMPL(std::bad_alloc()); |
703 | 0 | } |
704 | | |
705 | | } // namespace base_internal |
706 | | } // namespace phmap |
707 | | |
708 | | // ----------- invoke.h |
709 | | |
710 | | namespace phmap { |
711 | | namespace base_internal { |
712 | | |
713 | | template <typename Derived> |
714 | | struct StrippedAccept |
715 | | { |
716 | | template <typename... Args> |
717 | | struct Accept : Derived::template AcceptImpl<typename std::remove_cv< |
718 | | typename std::remove_reference<Args>::type>::type...> {}; |
719 | | }; |
720 | | |
721 | | // (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T |
722 | | // and t1 is an object of type T or a reference to an object of type T or a |
723 | | // reference to an object of a type derived from T. |
724 | | struct MemFunAndRef : StrippedAccept<MemFunAndRef> |
725 | | { |
726 | | template <typename... Args> |
727 | | struct AcceptImpl : std::false_type {}; |
728 | | |
729 | | template <typename R, typename C, typename... Params, typename Obj, |
730 | | typename... Args> |
731 | | struct AcceptImpl<R (C::*)(Params...), Obj, Args...> |
732 | | : std::is_base_of<C, Obj> {}; |
733 | | |
734 | | template <typename R, typename C, typename... Params, typename Obj, |
735 | | typename... Args> |
736 | | struct AcceptImpl<R (C::*)(Params...) const, Obj, Args...> |
737 | | : std::is_base_of<C, Obj> {}; |
738 | | |
739 | | template <typename MemFun, typename Obj, typename... Args> |
740 | | static decltype((std::declval<Obj>().* |
741 | | std::declval<MemFun>())(std::declval<Args>()...)) |
742 | | Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) { |
743 | | return (std::forward<Obj>(obj).* |
744 | | std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...); |
745 | | } |
746 | | }; |
747 | | |
748 | | // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a |
749 | | // class T and t1 is not one of the types described in the previous item. |
750 | | struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> |
751 | | { |
752 | | template <typename... Args> |
753 | | struct AcceptImpl : std::false_type {}; |
754 | | |
755 | | template <typename R, typename C, typename... Params, typename Ptr, |
756 | | typename... Args> |
757 | | struct AcceptImpl<R (C::*)(Params...), Ptr, Args...> |
758 | | : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {}; |
759 | | |
760 | | template <typename R, typename C, typename... Params, typename Ptr, |
761 | | typename... Args> |
762 | | struct AcceptImpl<R (C::*)(Params...) const, Ptr, Args...> |
763 | | : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {}; |
764 | | |
765 | | template <typename MemFun, typename Ptr, typename... Args> |
766 | | static decltype(((*std::declval<Ptr>()).* |
767 | | std::declval<MemFun>())(std::declval<Args>()...)) |
768 | | Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) { |
769 | | return ((*std::forward<Ptr>(ptr)).* |
770 | | std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...); |
771 | | } |
772 | | }; |
773 | | |
774 | | // t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is |
775 | | // an object of type T or a reference to an object of type T or a reference |
776 | | // to an object of a type derived from T. |
777 | | struct DataMemAndRef : StrippedAccept<DataMemAndRef> |
778 | | { |
779 | | template <typename... Args> |
780 | | struct AcceptImpl : std::false_type {}; |
781 | | |
782 | | template <typename R, typename C, typename Obj> |
783 | | struct AcceptImpl<R C::*, Obj> : std::is_base_of<C, Obj> {}; |
784 | | |
785 | | template <typename DataMem, typename Ref> |
786 | | static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke( |
787 | | DataMem&& data_mem, Ref&& ref) { |
788 | | return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem); |
789 | | } |
790 | | }; |
791 | | |
792 | | // (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 |
793 | | // is not one of the types described in the previous item. |
794 | | struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> |
795 | | { |
796 | | template <typename... Args> |
797 | | struct AcceptImpl : std::false_type {}; |
798 | | |
799 | | template <typename R, typename C, typename Ptr> |
800 | | struct AcceptImpl<R C::*, Ptr> |
801 | | : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {}; |
802 | | |
803 | | template <typename DataMem, typename Ptr> |
804 | | static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke( |
805 | | DataMem&& data_mem, Ptr&& ptr) { |
806 | | return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem); |
807 | | } |
808 | | }; |
809 | | |
810 | | // f(t1, t2, ..., tN) in all other cases. |
811 | | struct Callable |
812 | | { |
813 | | // Callable doesn't have Accept because it's the last clause that gets picked |
814 | | // when none of the previous clauses are applicable. |
815 | | template <typename F, typename... Args> |
816 | | static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke( |
817 | | F&& f, Args&&... args) { |
818 | | return std::forward<F>(f)(std::forward<Args>(args)...); |
819 | | } |
820 | | }; |
821 | | |
822 | | // Resolves to the first matching clause. |
823 | | template <typename... Args> |
824 | | struct Invoker |
825 | | { |
826 | | typedef typename std::conditional< |
827 | | MemFunAndRef::Accept<Args...>::value, MemFunAndRef, |
828 | | typename std::conditional< |
829 | | MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr, |
830 | | typename std::conditional< |
831 | | DataMemAndRef::Accept<Args...>::value, DataMemAndRef, |
832 | | typename std::conditional<DataMemAndPtr::Accept<Args...>::value, |
833 | | DataMemAndPtr, Callable>::type>::type>:: |
834 | | type>::type type; |
835 | | }; |
836 | | |
837 | | // The result type of Invoke<F, Args...>. |
838 | | template <typename F, typename... Args> |
839 | | using InvokeT = decltype(Invoker<F, Args...>::type::Invoke( |
840 | | std::declval<F>(), std::declval<Args>()...)); |
841 | | |
842 | | // Invoke(f, args...) is an implementation of INVOKE(f, args...) from section |
843 | | // [func.require] of the C++ standard. |
844 | | template <typename F, typename... Args> |
845 | | InvokeT<F, Args...> Invoke(F&& f, Args&&... args) { |
846 | | return Invoker<F, Args...>::type::Invoke(std::forward<F>(f), |
847 | | std::forward<Args>(args)...); |
848 | | } |
849 | | } // namespace base_internal |
850 | | } // namespace phmap |
851 | | |
852 | | |
853 | | // ----------- utility.h |
854 | | |
855 | | namespace phmap { |
856 | | |
857 | | // integer_sequence |
858 | | // |
859 | | // Class template representing a compile-time integer sequence. An instantiation |
860 | | // of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its |
861 | | // type through its template arguments (which is a common need when |
862 | | // working with C++11 variadic templates). `phmap::integer_sequence` is designed |
863 | | // to be a drop-in replacement for C++14's `std::integer_sequence`. |
864 | | // |
865 | | // Example: |
866 | | // |
867 | | // template< class T, T... Ints > |
868 | | // void user_function(integer_sequence<T, Ints...>); |
869 | | // |
870 | | // int main() |
871 | | // { |
872 | | // // user_function's `T` will be deduced to `int` and `Ints...` |
873 | | // // will be deduced to `0, 1, 2, 3, 4`. |
874 | | // user_function(make_integer_sequence<int, 5>()); |
875 | | // } |
876 | | template <typename T, T... Ints> |
877 | | struct integer_sequence |
878 | | { |
879 | | using value_type = T; |
880 | | static constexpr size_t size() noexcept { return sizeof...(Ints); } |
881 | | }; |
882 | | |
883 | | // index_sequence |
884 | | // |
885 | | // A helper template for an `integer_sequence` of `size_t`, |
886 | | // `phmap::index_sequence` is designed to be a drop-in replacement for C++14's |
887 | | // `std::index_sequence`. |
888 | | template <size_t... Ints> |
889 | | using index_sequence = integer_sequence<size_t, Ints...>; |
890 | | |
891 | | namespace utility_internal { |
892 | | |
893 | | template <typename Seq, size_t SeqSize, size_t Rem> |
894 | | struct Extend; |
895 | | |
896 | | // Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. |
897 | | template <typename T, T... Ints, size_t SeqSize> |
898 | | struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> { |
899 | | using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>; |
900 | | }; |
901 | | |
902 | | template <typename T, T... Ints, size_t SeqSize> |
903 | | struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> { |
904 | | using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>; |
905 | | }; |
906 | | |
907 | | // Recursion helper for 'make_integer_sequence<T, N>'. |
908 | | // 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'. |
909 | | template <typename T, size_t N> |
910 | | struct Gen { |
911 | | using type = |
912 | | typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type; |
913 | | }; |
914 | | |
915 | | template <typename T> |
916 | | struct Gen<T, 0> { |
917 | | using type = integer_sequence<T>; |
918 | | }; |
919 | | |
920 | | } // namespace utility_internal |
921 | | |
922 | | // Compile-time sequences of integers |
923 | | |
924 | | // make_integer_sequence |
925 | | // |
926 | | // This template alias is equivalent to |
927 | | // `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in |
928 | | // replacement for C++14's `std::make_integer_sequence`. |
929 | | template <typename T, T N> |
930 | | using make_integer_sequence = typename utility_internal::Gen<T, N>::type; |
931 | | |
932 | | // make_index_sequence |
933 | | // |
934 | | // This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, |
935 | | // and is designed to be a drop-in replacement for C++14's |
936 | | // `std::make_index_sequence`. |
937 | | template <size_t N> |
938 | | using make_index_sequence = make_integer_sequence<size_t, N>; |
939 | | |
940 | | // index_sequence_for |
941 | | // |
942 | | // Converts a typename pack into an index sequence of the same length, and |
943 | | // is designed to be a drop-in replacement for C++14's |
944 | | // `std::index_sequence_for()` |
945 | | template <typename... Ts> |
946 | | using index_sequence_for = make_index_sequence<sizeof...(Ts)>; |
947 | | |
948 | | // Tag types |
949 | | |
950 | | #ifdef PHMAP_HAVE_STD_OPTIONAL |
951 | | |
952 | | using std::in_place_t; |
953 | | using std::in_place; |
954 | | |
955 | | #else // PHMAP_HAVE_STD_OPTIONAL |
956 | | |
957 | | // in_place_t |
958 | | // |
959 | | // Tag type used to specify in-place construction, such as with |
960 | | // `phmap::optional`, designed to be a drop-in replacement for C++17's |
961 | | // `std::in_place_t`. |
962 | | struct in_place_t {}; |
963 | | |
964 | | PHMAP_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {}); |
965 | | |
966 | | #endif // PHMAP_HAVE_STD_OPTIONAL |
967 | | |
968 | | #if defined(PHMAP_HAVE_STD_ANY) || defined(PHMAP_HAVE_STD_VARIANT) |
969 | | using std::in_place_type_t; |
970 | | #else |
971 | | |
972 | | // in_place_type_t |
973 | | // |
974 | | // Tag type used for in-place construction when the type to construct needs to |
975 | | // be specified, such as with `phmap::any`, designed to be a drop-in replacement |
976 | | // for C++17's `std::in_place_type_t`. |
977 | | template <typename T> |
978 | | struct in_place_type_t {}; |
979 | | #endif // PHMAP_HAVE_STD_ANY || PHMAP_HAVE_STD_VARIANT |
980 | | |
981 | | #ifdef PHMAP_HAVE_STD_VARIANT |
982 | | using std::in_place_index_t; |
983 | | #else |
984 | | |
985 | | // in_place_index_t |
986 | | // |
987 | | // Tag type used for in-place construction when the type to construct needs to |
988 | | // be specified, such as with `phmap::any`, designed to be a drop-in replacement |
989 | | // for C++17's `std::in_place_index_t`. |
990 | | template <size_t I> |
991 | | struct in_place_index_t {}; |
992 | | #endif // PHMAP_HAVE_STD_VARIANT |
993 | | |
994 | | // Constexpr move and forward |
995 | | |
996 | | // move() |
997 | | // |
998 | | // A constexpr version of `std::move()`, designed to be a drop-in replacement |
999 | | // for C++14's `std::move()`. |
1000 | | template <typename T> |
1001 | | constexpr phmap::remove_reference_t<T>&& move(T&& t) noexcept { |
1002 | | return static_cast<phmap::remove_reference_t<T>&&>(t); |
1003 | | } |
1004 | | |
1005 | | // forward() |
1006 | | // |
1007 | | // A constexpr version of `std::forward()`, designed to be a drop-in replacement |
1008 | | // for C++14's `std::forward()`. |
1009 | | template <typename T> |
1010 | | constexpr T&& forward( |
1011 | | phmap::remove_reference_t<T>& t) noexcept { // NOLINT(runtime/references) |
1012 | | return static_cast<T&&>(t); |
1013 | | } |
1014 | | |
1015 | | namespace utility_internal { |
1016 | | // Helper method for expanding tuple into a called method. |
1017 | | template <typename Functor, typename Tuple, std::size_t... Indexes> |
1018 | | auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>) |
1019 | | -> decltype(phmap::base_internal::Invoke( |
1020 | | phmap::forward<Functor>(functor), |
1021 | | std::get<Indexes>(phmap::forward<Tuple>(t))...)) { |
1022 | | return phmap::base_internal::Invoke( |
1023 | | phmap::forward<Functor>(functor), |
1024 | | std::get<Indexes>(phmap::forward<Tuple>(t))...); |
1025 | | } |
1026 | | |
1027 | | } // namespace utility_internal |
1028 | | |
1029 | | // apply |
1030 | | // |
1031 | | // Invokes a Callable using elements of a tuple as its arguments. |
1032 | | // Each element of the tuple corresponds to an argument of the call (in order). |
1033 | | // Both the Callable argument and the tuple argument are perfect-forwarded. |
1034 | | // For member-function Callables, the first tuple element acts as the `this` |
1035 | | // pointer. `phmap::apply` is designed to be a drop-in replacement for C++17's |
1036 | | // `std::apply`. Unlike C++17's `std::apply`, this is not currently `constexpr`. |
1037 | | // |
1038 | | // Example: |
1039 | | // |
1040 | | // class Foo { |
1041 | | // public: |
1042 | | // void Bar(int); |
1043 | | // }; |
1044 | | // void user_function1(int, std::string); |
1045 | | // void user_function2(std::unique_ptr<Foo>); |
1046 | | // auto user_lambda = [](int, int) {}; |
1047 | | // |
1048 | | // int main() |
1049 | | // { |
1050 | | // std::tuple<int, std::string> tuple1(42, "bar"); |
1051 | | // // Invokes the first user function on int, std::string. |
1052 | | // phmap::apply(&user_function1, tuple1); |
1053 | | // |
1054 | | // std::tuple<std::unique_ptr<Foo>> tuple2(phmap::make_unique<Foo>()); |
1055 | | // // Invokes the user function that takes ownership of the unique |
1056 | | // // pointer. |
1057 | | // phmap::apply(&user_function2, std::move(tuple2)); |
1058 | | // |
1059 | | // auto foo = phmap::make_unique<Foo>(); |
1060 | | // std::tuple<Foo*, int> tuple3(foo.get(), 42); |
1061 | | // // Invokes the method Bar on foo with one argument, 42. |
1062 | | // phmap::apply(&Foo::Bar, tuple3); |
1063 | | // |
1064 | | // std::tuple<int, int> tuple4(8, 9); |
1065 | | // // Invokes a lambda. |
1066 | | // phmap::apply(user_lambda, tuple4); |
1067 | | // } |
1068 | | template <typename Functor, typename Tuple> |
1069 | | auto apply(Functor&& functor, Tuple&& t) |
1070 | | -> decltype(utility_internal::apply_helper( |
1071 | | phmap::forward<Functor>(functor), phmap::forward<Tuple>(t), |
1072 | | phmap::make_index_sequence<std::tuple_size< |
1073 | | typename std::remove_reference<Tuple>::type>::value>{})) { |
1074 | | return utility_internal::apply_helper( |
1075 | | phmap::forward<Functor>(functor), phmap::forward<Tuple>(t), |
1076 | | phmap::make_index_sequence<std::tuple_size< |
1077 | | typename std::remove_reference<Tuple>::type>::value>{}); |
1078 | | } |
1079 | | |
1080 | | #ifdef _MSC_VER |
1081 | | #pragma warning(push) |
1082 | | #pragma warning(disable : 4365) // '=': conversion from 'T' to 'T', signed/unsigned mismatch |
1083 | | #endif // _MSC_VER |
1084 | | |
1085 | | // exchange |
1086 | | // |
1087 | | // Replaces the value of `obj` with `new_value` and returns the old value of |
1088 | | // `obj`. `phmap::exchange` is designed to be a drop-in replacement for C++14's |
1089 | | // `std::exchange`. |
1090 | | // |
1091 | | // Example: |
1092 | | // |
1093 | | // Foo& operator=(Foo&& other) { |
1094 | | // ptr1_ = phmap::exchange(other.ptr1_, nullptr); |
1095 | | // int1_ = phmap::exchange(other.int1_, -1); |
1096 | | // return *this; |
1097 | | // } |
1098 | | template <typename T, typename U = T> |
1099 | | T exchange(T& obj, U&& new_value) |
1100 | | { |
1101 | | T old_value = phmap::move(obj); |
1102 | | obj = phmap::forward<U>(new_value); |
1103 | | return old_value; |
1104 | | } |
1105 | | |
1106 | | #ifdef _MSC_VER |
1107 | | #pragma warning(pop) |
1108 | | #endif // _MSC_VER |
1109 | | |
1110 | | |
1111 | | } // namespace phmap |
1112 | | |
1113 | | // ----------------------------------------------------------------------------- |
1114 | | // memory.h |
1115 | | // ----------------------------------------------------------------------------- |
1116 | | |
1117 | | namespace phmap { |
1118 | | |
1119 | | template <typename T> |
1120 | | std::unique_ptr<T> WrapUnique(T* ptr) |
1121 | | { |
1122 | | static_assert(!std::is_array<T>::value, "array types are unsupported"); |
1123 | | static_assert(std::is_object<T>::value, "non-object types are unsupported"); |
1124 | | return std::unique_ptr<T>(ptr); |
1125 | | } |
1126 | | |
1127 | | namespace memory_internal { |
1128 | | |
1129 | | // Traits to select proper overload and return type for `phmap::make_unique<>`. |
1130 | | template <typename T> |
1131 | | struct MakeUniqueResult { |
1132 | | using scalar = std::unique_ptr<T>; |
1133 | | }; |
1134 | | template <typename T> |
1135 | | struct MakeUniqueResult<T[]> { |
1136 | | using array = std::unique_ptr<T[]>; |
1137 | | }; |
1138 | | template <typename T, size_t N> |
1139 | | struct MakeUniqueResult<T[N]> { |
1140 | | using invalid = void; |
1141 | | }; |
1142 | | |
1143 | | } // namespace memory_internal |
1144 | | |
1145 | | #if (__cplusplus > 201103L || defined(_MSC_VER)) && \ |
1146 | | !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8) |
1147 | | using std::make_unique; |
1148 | | #else |
1149 | | |
1150 | | template <typename T, typename... Args> |
1151 | | typename memory_internal::MakeUniqueResult<T>::scalar make_unique( |
1152 | | Args&&... args) { |
1153 | | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
1154 | | } |
1155 | | |
1156 | | template <typename T> |
1157 | | typename memory_internal::MakeUniqueResult<T>::array make_unique(size_t n) { |
1158 | | return std::unique_ptr<T>(new typename phmap::remove_extent_t<T>[n]()); |
1159 | | } |
1160 | | |
1161 | | template <typename T, typename... Args> |
1162 | | typename memory_internal::MakeUniqueResult<T>::invalid make_unique( |
1163 | | Args&&... /* args */) = delete; |
1164 | | #endif |
1165 | | |
1166 | | template <typename T> |
1167 | | auto RawPtr(T&& ptr) -> decltype(std::addressof(*ptr)) |
1168 | | { |
1169 | | // ptr is a forwarding reference to support Ts with non-const operators. |
1170 | | return (ptr != nullptr) ? std::addressof(*ptr) : nullptr; |
1171 | | } |
1172 | | |
1173 | 0 | inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; } |
1174 | | |
1175 | | template <typename T, typename D> |
1176 | | std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) { |
1177 | | return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>(); |
1178 | | } |
1179 | | |
1180 | | template <typename T> |
1181 | | std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) { |
1182 | | return std::weak_ptr<T>(ptr); |
1183 | | } |
1184 | | |
1185 | | namespace memory_internal { |
1186 | | |
1187 | | // ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D. |
1188 | | template <template <typename> class Extract, typename Obj, typename Default, |
1189 | | typename> |
1190 | | struct ExtractOr { |
1191 | | using type = Default; |
1192 | | }; |
1193 | | |
1194 | | template <template <typename> class Extract, typename Obj, typename Default> |
1195 | | struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> { |
1196 | | using type = Extract<Obj>; |
1197 | | }; |
1198 | | |
1199 | | template <template <typename> class Extract, typename Obj, typename Default> |
1200 | | using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type; |
1201 | | |
1202 | | // Extractors for the features of allocators. |
1203 | | template <typename T> |
1204 | | using GetPointer = typename T::pointer; |
1205 | | |
1206 | | template <typename T> |
1207 | | using GetConstPointer = typename T::const_pointer; |
1208 | | |
1209 | | template <typename T> |
1210 | | using GetVoidPointer = typename T::void_pointer; |
1211 | | |
1212 | | template <typename T> |
1213 | | using GetConstVoidPointer = typename T::const_void_pointer; |
1214 | | |
1215 | | template <typename T> |
1216 | | using GetDifferenceType = typename T::difference_type; |
1217 | | |
1218 | | template <typename T> |
1219 | | using GetSizeType = typename T::size_type; |
1220 | | |
1221 | | template <typename T> |
1222 | | using GetPropagateOnContainerCopyAssignment = |
1223 | | typename T::propagate_on_container_copy_assignment; |
1224 | | |
1225 | | template <typename T> |
1226 | | using GetPropagateOnContainerMoveAssignment = |
1227 | | typename T::propagate_on_container_move_assignment; |
1228 | | |
1229 | | template <typename T> |
1230 | | using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap; |
1231 | | |
1232 | | template <typename T> |
1233 | | using GetIsAlwaysEqual = typename T::is_always_equal; |
1234 | | |
1235 | | template <typename T> |
1236 | | struct GetFirstArg; |
1237 | | |
1238 | | template <template <typename...> class Class, typename T, typename... Args> |
1239 | | struct GetFirstArg<Class<T, Args...>> { |
1240 | | using type = T; |
1241 | | }; |
1242 | | |
1243 | | template <typename Ptr, typename = void> |
1244 | | struct ElementType { |
1245 | | using type = typename GetFirstArg<Ptr>::type; |
1246 | | }; |
1247 | | |
1248 | | template <typename T> |
1249 | | struct ElementType<T, void_t<typename T::element_type>> { |
1250 | | using type = typename T::element_type; |
1251 | | }; |
1252 | | |
1253 | | template <typename T, typename U> |
1254 | | struct RebindFirstArg; |
1255 | | |
1256 | | template <template <typename...> class Class, typename T, typename... Args, |
1257 | | typename U> |
1258 | | struct RebindFirstArg<Class<T, Args...>, U> { |
1259 | | using type = Class<U, Args...>; |
1260 | | }; |
1261 | | |
1262 | | template <typename T, typename U, typename = void> |
1263 | | struct RebindPtr { |
1264 | | using type = typename RebindFirstArg<T, U>::type; |
1265 | | }; |
1266 | | |
1267 | | template <typename T, typename U> |
1268 | | struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> { |
1269 | | using type = typename T::template rebind<U>; |
1270 | | }; |
1271 | | |
1272 | | template <typename T, typename U> |
1273 | | constexpr bool HasRebindAlloc(...) { |
1274 | | return false; |
1275 | | } |
1276 | | |
1277 | | template <typename T, typename U> |
1278 | 0 | constexpr bool HasRebindAlloc(typename std::allocator_traits<T>::template rebind_alloc<U>*) { |
1279 | 0 | return true; |
1280 | 0 | } Unexecuted instantiation: bool phmap::memory_internal::HasRebindAlloc<std::__1::allocator<std::__1::pair<unsigned int const, int> >, std::__1::pair<unsigned int const, int> >(std::__1::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::rebind_alloc<std::__1::pair<unsigned int const, int> >*) Unexecuted instantiation: bool phmap::memory_internal::HasRebindAlloc<std::__1::allocator<std::__1::pair<unsigned int const, int> >, phmap::priv::map_slot_type<unsigned int, int> >(std::__1::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::rebind_alloc<phmap::priv::map_slot_type<unsigned int, int> >*) Unexecuted instantiation: bool phmap::memory_internal::HasRebindAlloc<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::allocator_traits<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >::rebind_alloc<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*) Unexecuted instantiation: bool phmap::memory_internal::HasRebindAlloc<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::allocator_traits<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >::rebind_alloc<phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*) Unexecuted instantiation: bool phmap::memory_internal::HasRebindAlloc<std::__1::allocator<std::__1::pair<unsigned int const, int> >, phmap::priv::Deallocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, void*, unsigned long)::M>(std::__1::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::rebind_alloc<phmap::priv::Deallocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, void*, unsigned long)::M>*) Unexecuted instantiation: bool phmap::memory_internal::HasRebindAlloc<std::__1::allocator<std::__1::pair<unsigned int const, int> >, phmap::priv::Allocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, unsigned long)::M>(std::__1::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::rebind_alloc<phmap::priv::Allocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, unsigned long)::M>*) Unexecuted instantiation: bool phmap::memory_internal::HasRebindAlloc<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, phmap::priv::Deallocate<8ul, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, void*, unsigned long)::M>(std::__1::allocator_traits<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >::rebind_alloc<phmap::priv::Deallocate<8ul, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, void*, unsigned long)::M>*) |
1281 | | |
1282 | | template <typename T, typename U, bool = HasRebindAlloc<T, U>(nullptr)> |
1283 | | struct RebindAlloc { |
1284 | | using type = typename RebindFirstArg<T, U>::type; |
1285 | | }; |
1286 | | |
1287 | | template <typename A, typename U> |
1288 | | struct RebindAlloc<A, U, true> { |
1289 | | using type = typename std::allocator_traits<A>::template rebind_alloc<U>; |
1290 | | }; |
1291 | | |
1292 | | |
1293 | | } // namespace memory_internal |
1294 | | |
1295 | | template <typename Ptr> |
1296 | | struct pointer_traits |
1297 | | { |
1298 | | using pointer = Ptr; |
1299 | | |
1300 | | // element_type: |
1301 | | // Ptr::element_type if present. Otherwise T if Ptr is a template |
1302 | | // instantiation Template<T, Args...> |
1303 | | using element_type = typename memory_internal::ElementType<Ptr>::type; |
1304 | | |
1305 | | // difference_type: |
1306 | | // Ptr::difference_type if present, otherwise std::ptrdiff_t |
1307 | | using difference_type = |
1308 | | memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr, |
1309 | | std::ptrdiff_t>; |
1310 | | |
1311 | | // rebind: |
1312 | | // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a |
1313 | | // template instantiation Template<T, Args...> |
1314 | | template <typename U> |
1315 | | using rebind = typename memory_internal::RebindPtr<Ptr, U>::type; |
1316 | | |
1317 | | // pointer_to: |
1318 | | // Calls Ptr::pointer_to(r) |
1319 | | static pointer pointer_to(element_type& r) { // NOLINT(runtime/references) |
1320 | | return Ptr::pointer_to(r); |
1321 | | } |
1322 | | }; |
1323 | | |
1324 | | // Specialization for T*. |
1325 | | template <typename T> |
1326 | | struct pointer_traits<T*> |
1327 | | { |
1328 | | using pointer = T*; |
1329 | | using element_type = T; |
1330 | | using difference_type = std::ptrdiff_t; |
1331 | | |
1332 | | template <typename U> |
1333 | | using rebind = U*; |
1334 | | |
1335 | | // pointer_to: |
1336 | | // Calls std::addressof(r) |
1337 | | static pointer pointer_to( |
1338 | | element_type& r) noexcept { // NOLINT(runtime/references) |
1339 | | return std::addressof(r); |
1340 | | } |
1341 | | }; |
1342 | | |
1343 | | // ----------------------------------------------------------------------------- |
1344 | | // Class Template: allocator_traits |
1345 | | // ----------------------------------------------------------------------------- |
1346 | | // |
1347 | | // A C++11 compatible implementation of C++17's std::allocator_traits. |
1348 | | // |
1349 | | template <typename Alloc> |
1350 | | struct allocator_traits |
1351 | | { |
1352 | | using allocator_type = Alloc; |
1353 | | |
1354 | | // value_type: |
1355 | | // Alloc::value_type |
1356 | | using value_type = typename Alloc::value_type; |
1357 | | |
1358 | | // pointer: |
1359 | | // Alloc::pointer if present, otherwise value_type* |
1360 | | using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer, |
1361 | | Alloc, value_type*>; |
1362 | | |
1363 | | // const_pointer: |
1364 | | // Alloc::const_pointer if present, otherwise |
1365 | | // phmap::pointer_traits<pointer>::rebind<const value_type> |
1366 | | using const_pointer = |
1367 | | memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc, |
1368 | | typename phmap::pointer_traits<pointer>:: |
1369 | | template rebind<const value_type>>; |
1370 | | |
1371 | | // void_pointer: |
1372 | | // Alloc::void_pointer if present, otherwise |
1373 | | // phmap::pointer_traits<pointer>::rebind<void> |
1374 | | using void_pointer = memory_internal::ExtractOrT< |
1375 | | memory_internal::GetVoidPointer, Alloc, |
1376 | | typename phmap::pointer_traits<pointer>::template rebind<void>>; |
1377 | | |
1378 | | // const_void_pointer: |
1379 | | // Alloc::const_void_pointer if present, otherwise |
1380 | | // phmap::pointer_traits<pointer>::rebind<const void> |
1381 | | using const_void_pointer = memory_internal::ExtractOrT< |
1382 | | memory_internal::GetConstVoidPointer, Alloc, |
1383 | | typename phmap::pointer_traits<pointer>::template rebind<const void>>; |
1384 | | |
1385 | | // difference_type: |
1386 | | // Alloc::difference_type if present, otherwise |
1387 | | // phmap::pointer_traits<pointer>::difference_type |
1388 | | using difference_type = memory_internal::ExtractOrT< |
1389 | | memory_internal::GetDifferenceType, Alloc, |
1390 | | typename phmap::pointer_traits<pointer>::difference_type>; |
1391 | | |
1392 | | // size_type: |
1393 | | // Alloc::size_type if present, otherwise |
1394 | | // std::make_unsigned<difference_type>::type |
1395 | | using size_type = memory_internal::ExtractOrT< |
1396 | | memory_internal::GetSizeType, Alloc, |
1397 | | typename std::make_unsigned<difference_type>::type>; |
1398 | | |
1399 | | // propagate_on_container_copy_assignment: |
1400 | | // Alloc::propagate_on_container_copy_assignment if present, otherwise |
1401 | | // std::false_type |
1402 | | using propagate_on_container_copy_assignment = memory_internal::ExtractOrT< |
1403 | | memory_internal::GetPropagateOnContainerCopyAssignment, Alloc, |
1404 | | std::false_type>; |
1405 | | |
1406 | | // propagate_on_container_move_assignment: |
1407 | | // Alloc::propagate_on_container_move_assignment if present, otherwise |
1408 | | // std::false_type |
1409 | | using propagate_on_container_move_assignment = memory_internal::ExtractOrT< |
1410 | | memory_internal::GetPropagateOnContainerMoveAssignment, Alloc, |
1411 | | std::false_type>; |
1412 | | |
1413 | | // propagate_on_container_swap: |
1414 | | // Alloc::propagate_on_container_swap if present, otherwise std::false_type |
1415 | | using propagate_on_container_swap = |
1416 | | memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap, |
1417 | | Alloc, std::false_type>; |
1418 | | |
1419 | | // is_always_equal: |
1420 | | // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type |
1421 | | using is_always_equal = |
1422 | | memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc, |
1423 | | typename std::is_empty<Alloc>::type>; |
1424 | | |
1425 | | // rebind_alloc: |
1426 | | // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc |
1427 | | // is Alloc<U, Args> |
1428 | | template <typename T> |
1429 | | using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type; |
1430 | | |
1431 | | // rebind_traits: |
1432 | | // phmap::allocator_traits<rebind_alloc<T>> |
1433 | | template <typename T> |
1434 | | using rebind_traits = phmap::allocator_traits<rebind_alloc<T>>; |
1435 | | |
1436 | | // allocate(Alloc& a, size_type n): |
1437 | | // Calls a.allocate(n) |
1438 | | static pointer allocate(Alloc& a, // NOLINT(runtime/references) |
1439 | 2.79k | size_type n) { |
1440 | 2.79k | return a.allocate(n); |
1441 | 2.79k | } |
1442 | | |
1443 | | // allocate(Alloc& a, size_type n, const_void_pointer hint): |
1444 | | // Calls a.allocate(n, hint) if possible. |
1445 | | // If not possible, calls a.allocate(n) |
1446 | | static pointer allocate(Alloc& a, size_type n, // NOLINT(runtime/references) |
1447 | | const_void_pointer hint) { |
1448 | | return allocate_impl(0, a, n, hint); |
1449 | | } |
1450 | | |
1451 | | // deallocate(Alloc& a, pointer p, size_type n): |
1452 | | // Calls a.deallocate(p, n) |
1453 | | static void deallocate(Alloc& a, pointer p, // NOLINT(runtime/references) |
1454 | 2.79k | size_type n) { |
1455 | 2.79k | a.deallocate(p, n); |
1456 | 2.79k | } phmap::allocator_traits<std::__1::allocator<phmap::priv::Deallocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, void*, unsigned long)::M> >::deallocate(std::__1::allocator<phmap::priv::Deallocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, void*, unsigned long)::M>&, phmap::priv::Deallocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, void*, unsigned long)::M*, unsigned long) Line | Count | Source | 1454 | 2.79k | size_type n) { | 1455 | 2.79k | a.deallocate(p, n); | 1456 | 2.79k | } |
Unexecuted instantiation: phmap::allocator_traits<std::__1::allocator<phmap::priv::Deallocate<8ul, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, void*, unsigned long)::M> >::deallocate(std::__1::allocator<phmap::priv::Deallocate<8ul, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, void*, unsigned long)::M>&, phmap::priv::Deallocate<8ul, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, void*, unsigned long)::M*, unsigned long) |
1457 | | |
1458 | | // construct(Alloc& a, T* p, Args&&... args): |
1459 | | // Calls a.construct(p, std::forward<Args>(args)...) if possible. |
1460 | | // If not possible, calls |
1461 | | // ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...) |
1462 | | template <typename T, typename... Args> |
1463 | | static void construct(Alloc& a, T* p, // NOLINT(runtime/references) |
1464 | 1.63M | Args&&... args) { |
1465 | 1.63M | construct_impl(0, a, p, std::forward<Args>(args)...); |
1466 | 1.63M | } void phmap::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::construct<std::__1::pair<unsigned int, int>, std::__1::pair<unsigned int, int> >(std::__1::allocator<std::__1::pair<unsigned int const, int> >&, std::__1::pair<unsigned int, int>*, std::__1::pair<unsigned int, int>&&) Line | Count | Source | 1464 | 1.04M | Args&&... args) { | 1465 | 1.04M | construct_impl(0, a, p, std::forward<Args>(args)...); | 1466 | 1.04M | } |
void phmap::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::construct<std::__1::pair<unsigned int, int>, std::__1::piecewise_construct_t const&, std::__1::tuple<unsigned int const&&>, std::__1::tuple<int&&> >(std::__1::allocator<std::__1::pair<unsigned int const, int> >&, std::__1::pair<unsigned int, int>*, std::__1::piecewise_construct_t const&, std::__1::tuple<unsigned int const&&>&&, std::__1::tuple<int&&>&&) Line | Count | Source | 1464 | 591k | Args&&... args) { | 1465 | 591k | construct_impl(0, a, p, std::forward<Args>(args)...); | 1466 | 591k | } |
Unexecuted instantiation: void phmap::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::construct<std::__1::pair<unsigned int const, int>, std::__1::pair<unsigned int const, int> >(std::__1::allocator<std::__1::pair<unsigned int const, int> >&, std::__1::pair<unsigned int const, int>*, std::__1::pair<unsigned int const, int>&&) Unexecuted instantiation: void phmap::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::construct<std::__1::pair<unsigned int const, int>, std::__1::piecewise_construct_t const&, std::__1::tuple<unsigned int const&&>, std::__1::tuple<int&&> >(std::__1::allocator<std::__1::pair<unsigned int const, int> >&, std::__1::pair<unsigned int const, int>*, std::__1::piecewise_construct_t const&, std::__1::tuple<unsigned int const&&>&&, std::__1::tuple<int&&>&&) |
1467 | | |
1468 | | // destroy(Alloc& a, T* p): |
1469 | | // Calls a.destroy(p) if possible. If not possible, calls p->~T(). |
1470 | | template <typename T> |
1471 | 2.21M | static void destroy(Alloc& a, T* p) { // NOLINT(runtime/references) |
1472 | 2.21M | destroy_impl(0, a, p); |
1473 | 2.21M | } void phmap::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::destroy<std::__1::pair<unsigned int, int> >(std::__1::allocator<std::__1::pair<unsigned int const, int> >&, std::__1::pair<unsigned int, int>*) Line | Count | Source | 1471 | 2.21M | static void destroy(Alloc& a, T* p) { // NOLINT(runtime/references) | 1472 | 2.21M | destroy_impl(0, a, p); | 1473 | 2.21M | } |
Unexecuted instantiation: void phmap::allocator_traits<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >::destroy<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >*) Unexecuted instantiation: void phmap::allocator_traits<std::__1::allocator<std::__1::pair<unsigned int const, int> > >::destroy<std::__1::pair<unsigned int const, int> >(std::__1::allocator<std::__1::pair<unsigned int const, int> >&, std::__1::pair<unsigned int const, int>*) Unexecuted instantiation: void phmap::allocator_traits<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >::destroy<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >*) |
1474 | | |
1475 | | // max_size(const Alloc& a): |
1476 | | // Returns a.max_size() if possible. If not possible, returns |
1477 | | // std::numeric_limits<size_type>::max() / sizeof(value_type) |
1478 | | static size_type max_size(const Alloc& a) { return max_size_impl(0, a); } |
1479 | | |
1480 | | // select_on_container_copy_construction(const Alloc& a): |
1481 | | // Returns a.select_on_container_copy_construction() if possible. |
1482 | | // If not possible, returns a. |
1483 | | static Alloc select_on_container_copy_construction(const Alloc& a) { |
1484 | | return select_on_container_copy_construction_impl(0, a); |
1485 | | } |
1486 | | |
1487 | | private: |
1488 | | template <typename A> |
1489 | | static auto allocate_impl(int, A& a, // NOLINT(runtime/references) |
1490 | | size_type n, const_void_pointer hint) |
1491 | | -> decltype(a.allocate(n, hint)) { |
1492 | | return a.allocate(n, hint); |
1493 | | } |
1494 | | static pointer allocate_impl(char, Alloc& a, // NOLINT(runtime/references) |
1495 | | size_type n, const_void_pointer) { |
1496 | | return a.allocate(n); |
1497 | | } |
1498 | | |
1499 | | template <typename A, typename... Args> |
1500 | | static auto construct_impl(int, A& a, // NOLINT(runtime/references) |
1501 | | Args&&... args) |
1502 | 1.63M | -> decltype(std::allocator_traits<A>::construct(a, std::forward<Args>(args)...)) { |
1503 | 1.63M | std::allocator_traits<A>::construct(a, std::forward<Args>(args)...); |
1504 | 1.63M | } _ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKjiEEEEE14construct_implIS6_JRPNS3_IjiEES9_EEEDTclsr3std16allocator_traitsIT_EE9constructfp0_spclsr3stdE7forwardIT0_Efp1_EEEiRSC_DpOSD_ Line | Count | Source | 1502 | 1.04M | -> decltype(std::allocator_traits<A>::construct(a, std::forward<Args>(args)...)) { | 1503 | 1.04M | std::allocator_traits<A>::construct(a, std::forward<Args>(args)...); | 1504 | 1.04M | } |
_ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKjiEEEEE14construct_implIS6_JRPNS3_IjiEERKNS1_21piecewise_construct_tENS1_5tupleIJOS4_EEENSF_IJOiEEEEEEDTclsr3std16allocator_traitsIT_EE9constructfp0_spclsr3stdE7forwardIT0_Efp1_EEEiRSK_DpOSL_ Line | Count | Source | 1502 | 591k | -> decltype(std::allocator_traits<A>::construct(a, std::forward<Args>(args)...)) { | 1503 | 591k | std::allocator_traits<A>::construct(a, std::forward<Args>(args)...); | 1504 | 591k | } |
Unexecuted instantiation: _ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKjiEEEEE14construct_implIS6_JRPS5_S5_EEEDTclsr3std16allocator_traitsIT_EE9constructfp0_spclsr3stdE7forwardIT0_Efp1_EEEiRSB_DpOSC_ Unexecuted instantiation: _ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKjiEEEEE14construct_implIS6_JRPS5_RKNS1_21piecewise_construct_tENS1_5tupleIJOS4_EEENSE_IJOiEEEEEEDTclsr3std16allocator_traitsIT_EE9constructfp0_spclsr3stdE7forwardIT0_Efp1_EEEiRSJ_DpOSK_ |
1505 | | |
1506 | | template <typename T, typename... Args> |
1507 | | static void construct_impl(char, Alloc&, T* p, Args&&... args) { |
1508 | | ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...); |
1509 | | } |
1510 | | |
1511 | | template <typename A, typename T> |
1512 | | static auto destroy_impl(int, A& a, // NOLINT(runtime/references) |
1513 | 2.21M | T* p) -> decltype(std::allocator_traits<A>::destroy(a, p)) { |
1514 | 2.21M | std::allocator_traits<A>::destroy(a, p); |
1515 | 2.21M | } _ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKjiEEEEE12destroy_implIS6_NS3_IjiEEEEDTclsr3std16allocator_traitsIT_EE7destroyfp0_fp1_EEiRSA_PT0_ Line | Count | Source | 1513 | 2.21M | T* p) -> decltype(std::allocator_traits<A>::destroy(a, p)) { | 1514 | 2.21M | std::allocator_traits<A>::destroy(a, p); | 1515 | 2.21M | } |
Unexecuted instantiation: _ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKNS1_12basic_stringIcNS1_11char_traitsIcEENS2_IcEEEES8_EEEEE12destroy_implISB_NS3_IS8_S8_EEEEDTclsr3std16allocator_traitsIT_EE7destroyfp0_fp1_EEiRSF_PT0_ Unexecuted instantiation: _ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKjiEEEEE12destroy_implIS6_S5_EEDTclsr3std16allocator_traitsIT_EE7destroyfp0_fp1_EEiRS9_PT0_ Unexecuted instantiation: _ZN5phmap16allocator_traitsINSt3__19allocatorINS1_4pairIKNS1_12basic_stringIcNS1_11char_traitsIcEENS2_IcEEEES8_EEEEE12destroy_implISB_SA_EEDTclsr3std16allocator_traitsIT_EE7destroyfp0_fp1_EEiRSE_PT0_ |
1516 | | template <typename T> |
1517 | | static void destroy_impl(char, Alloc&, T* p) { |
1518 | | p->~T(); |
1519 | | } |
1520 | | |
1521 | | template <typename A> |
1522 | | static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) { |
1523 | | return a.max_size(); |
1524 | | } |
1525 | | static size_type max_size_impl(char, const Alloc&) { |
1526 | | return (std::numeric_limits<size_type>::max)() / sizeof(value_type); |
1527 | | } |
1528 | | |
1529 | | template <typename A> |
1530 | | static auto select_on_container_copy_construction_impl(int, const A& a) |
1531 | | -> decltype(a.select_on_container_copy_construction()) { |
1532 | | return a.select_on_container_copy_construction(); |
1533 | | } |
1534 | | static Alloc select_on_container_copy_construction_impl(char, |
1535 | | const Alloc& a) { |
1536 | | return a; |
1537 | | } |
1538 | | }; |
1539 | | |
1540 | | namespace memory_internal { |
1541 | | |
1542 | | // This template alias transforms Alloc::is_nothrow into a metafunction with |
1543 | | // Alloc as a parameter so it can be used with ExtractOrT<>. |
1544 | | template <typename Alloc> |
1545 | | using GetIsNothrow = typename Alloc::is_nothrow; |
1546 | | |
1547 | | } // namespace memory_internal |
1548 | | |
1549 | | // PHMAP_ALLOCATOR_NOTHROW is a build time configuration macro for user to |
1550 | | // specify whether the default allocation function can throw or never throws. |
1551 | | // If the allocation function never throws, user should define it to a non-zero |
1552 | | // value (e.g. via `-DPHMAP_ALLOCATOR_NOTHROW`). |
1553 | | // If the allocation function can throw, user should leave it undefined or |
1554 | | // define it to zero. |
1555 | | // |
1556 | | // allocator_is_nothrow<Alloc> is a traits class that derives from |
1557 | | // Alloc::is_nothrow if present, otherwise std::false_type. It's specialized |
1558 | | // for Alloc = std::allocator<T> for any type T according to the state of |
1559 | | // PHMAP_ALLOCATOR_NOTHROW. |
1560 | | // |
1561 | | // default_allocator_is_nothrow is a class that derives from std::true_type |
1562 | | // when the default allocator (global operator new) never throws, and |
1563 | | // std::false_type when it can throw. It is a convenience shorthand for writing |
1564 | | // allocator_is_nothrow<std::allocator<T>> (T can be any type). |
1565 | | // NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from |
1566 | | // the same type for all T, because users should specialize neither |
1567 | | // allocator_is_nothrow nor std::allocator. |
1568 | | template <typename Alloc> |
1569 | | struct allocator_is_nothrow |
1570 | | : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc, |
1571 | | std::false_type> {}; |
1572 | | |
1573 | | #if defined(PHMAP_ALLOCATOR_NOTHROW) && PHMAP_ALLOCATOR_NOTHROW |
1574 | | template <typename T> |
1575 | | struct allocator_is_nothrow<std::allocator<T>> : std::true_type {}; |
1576 | | struct default_allocator_is_nothrow : std::true_type {}; |
1577 | | #else |
1578 | | struct default_allocator_is_nothrow : std::false_type {}; |
1579 | | #endif |
1580 | | |
1581 | | namespace memory_internal { |
1582 | | template <typename Allocator, typename Iterator, typename... Args> |
1583 | | void ConstructRange(Allocator& alloc, Iterator first, Iterator last, |
1584 | | const Args&... args) |
1585 | | { |
1586 | | for (Iterator cur = first; cur != last; ++cur) { |
1587 | | PHMAP_INTERNAL_TRY { |
1588 | | std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), |
1589 | | args...); |
1590 | | } |
1591 | | PHMAP_INTERNAL_CATCH_ANY { |
1592 | | while (cur != first) { |
1593 | | --cur; |
1594 | | std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); |
1595 | | } |
1596 | | PHMAP_INTERNAL_RETHROW; |
1597 | | } |
1598 | | } |
1599 | | } |
1600 | | |
1601 | | template <typename Allocator, typename Iterator, typename InputIterator> |
1602 | | void CopyRange(Allocator& alloc, Iterator destination, InputIterator first, |
1603 | | InputIterator last) |
1604 | | { |
1605 | | for (Iterator cur = destination; first != last; |
1606 | | static_cast<void>(++cur), static_cast<void>(++first)) { |
1607 | | PHMAP_INTERNAL_TRY { |
1608 | | std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur), |
1609 | | *first); |
1610 | | } |
1611 | | PHMAP_INTERNAL_CATCH_ANY { |
1612 | | while (cur != destination) { |
1613 | | --cur; |
1614 | | std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur)); |
1615 | | } |
1616 | | PHMAP_INTERNAL_RETHROW; |
1617 | | } |
1618 | | } |
1619 | | } |
1620 | | } // namespace memory_internal |
1621 | | } // namespace phmap |
1622 | | |
1623 | | |
1624 | | // ----------------------------------------------------------------------------- |
1625 | | // optional.h |
1626 | | // ----------------------------------------------------------------------------- |
1627 | | #ifdef PHMAP_HAVE_STD_OPTIONAL |
1628 | | |
1629 | | #include <optional> // IWYU pragma: export |
1630 | | |
1631 | | namespace phmap { |
1632 | | using std::bad_optional_access; |
1633 | | using std::optional; |
1634 | | using std::make_optional; |
1635 | | using std::nullopt_t; |
1636 | | using std::nullopt; |
1637 | | } // namespace phmap |
1638 | | |
1639 | | #else |
1640 | | |
1641 | | #if defined(__clang__) |
1642 | | #if __has_feature(cxx_inheriting_constructors) |
1643 | | #define PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 |
1644 | | #endif |
1645 | | #elif (defined(__GNUC__) && \ |
1646 | | (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \ |
1647 | | (__cpp_inheriting_constructors >= 200802) || \ |
1648 | | (defined(_MSC_VER) && _MSC_VER >= 1910) |
1649 | | |
1650 | | #define PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 |
1651 | | #endif |
1652 | | |
1653 | | namespace phmap { |
1654 | | |
1655 | | class bad_optional_access : public std::exception |
1656 | | { |
1657 | | public: |
1658 | | bad_optional_access() = default; |
1659 | | ~bad_optional_access() override; |
1660 | | const char* what() const noexcept override; |
1661 | | }; |
1662 | | |
1663 | | template <typename T> |
1664 | | class optional; |
1665 | | |
1666 | | // -------------------------------- |
1667 | | struct nullopt_t |
1668 | | { |
1669 | | struct init_t {}; |
1670 | | static init_t init; |
1671 | | |
1672 | 0 | explicit constexpr nullopt_t(init_t& /*unused*/) {} |
1673 | | }; |
1674 | | |
1675 | | constexpr nullopt_t nullopt(nullopt_t::init); |
1676 | | |
1677 | | namespace optional_internal { |
1678 | | |
1679 | | // throw delegator |
1680 | | [[noreturn]] void throw_bad_optional_access(); |
1681 | | |
1682 | | |
1683 | | struct empty_struct {}; |
1684 | | |
1685 | | // This class stores the data in optional<T>. |
1686 | | // It is specialized based on whether T is trivially destructible. |
1687 | | // This is the specialization for non trivially destructible type. |
1688 | | template <typename T, bool unused = std::is_trivially_destructible<T>::value> |
1689 | | class optional_data_dtor_base |
1690 | | { |
1691 | | struct dummy_type { |
1692 | | static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); |
1693 | | // Use an array to avoid GCC 6 placement-new warning. |
1694 | | empty_struct data[sizeof(T) / sizeof(empty_struct)]; |
1695 | | }; |
1696 | | |
1697 | | protected: |
1698 | | // Whether there is data or not. |
1699 | | bool engaged_; |
1700 | | // Data storage |
1701 | | union { |
1702 | | dummy_type dummy_; |
1703 | | T data_; |
1704 | | }; |
1705 | | |
1706 | | void destruct() noexcept { |
1707 | | if (engaged_) { |
1708 | | data_.~T(); |
1709 | | engaged_ = false; |
1710 | | } |
1711 | | } |
1712 | | |
1713 | | // dummy_ must be initialized for constexpr constructor. |
1714 | | constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} |
1715 | | |
1716 | | template <typename... Args> |
1717 | | constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) |
1718 | | : engaged_(true), data_(phmap::forward<Args>(args)...) {} |
1719 | | |
1720 | | ~optional_data_dtor_base() { destruct(); } |
1721 | | }; |
1722 | | |
1723 | | // Specialization for trivially destructible type. |
1724 | | template <typename T> |
1725 | | class optional_data_dtor_base<T, true> |
1726 | | { |
1727 | | struct dummy_type { |
1728 | | static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); |
1729 | | // Use array to avoid GCC 6 placement-new warning. |
1730 | | empty_struct data[sizeof(T) / sizeof(empty_struct)]; |
1731 | | }; |
1732 | | |
1733 | | protected: |
1734 | | // Whether there is data or not. |
1735 | | bool engaged_; |
1736 | | // Data storage |
1737 | | union { |
1738 | | dummy_type dummy_; |
1739 | | T data_; |
1740 | | }; |
1741 | | void destruct() noexcept { engaged_ = false; } |
1742 | | |
1743 | | // dummy_ must be initialized for constexpr constructor. |
1744 | | constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} |
1745 | | |
1746 | | template <typename... Args> |
1747 | | constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) |
1748 | | : engaged_(true), data_(phmap::forward<Args>(args)...) {} |
1749 | | }; |
1750 | | |
1751 | | template <typename T> |
1752 | | class optional_data_base : public optional_data_dtor_base<T> |
1753 | | { |
1754 | | protected: |
1755 | | using base = optional_data_dtor_base<T>; |
1756 | | #if PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS |
1757 | | using base::base; |
1758 | | #else |
1759 | | optional_data_base() = default; |
1760 | | |
1761 | | template <typename... Args> |
1762 | | constexpr explicit optional_data_base(in_place_t t, Args&&... args) |
1763 | | : base(t, phmap::forward<Args>(args)...) {} |
1764 | | #endif |
1765 | | |
1766 | | template <typename... Args> |
1767 | | void construct(Args&&... args) { |
1768 | | // Use dummy_'s address to work around casting cv-qualified T* to void*. |
1769 | | ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...); |
1770 | | this->engaged_ = true; |
1771 | | } |
1772 | | |
1773 | | template <typename U> |
1774 | | void assign(U&& u) { |
1775 | | if (this->engaged_) { |
1776 | | this->data_ = std::forward<U>(u); |
1777 | | } else { |
1778 | | construct(std::forward<U>(u)); |
1779 | | } |
1780 | | } |
1781 | | }; |
1782 | | |
1783 | | // TODO: Add another class using |
1784 | | // std::is_trivially_move_constructible trait when available to match |
1785 | | // http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that |
1786 | | // have trivial move but nontrivial copy. |
1787 | | // Also, we should be checking is_trivially_copyable here, which is not |
1788 | | // supported now, so we use is_trivially_* traits instead. |
1789 | | template <typename T, |
1790 | | bool unused = |
1791 | | std::is_trivially_copy_constructible<T>::value && |
1792 | | std::is_trivially_copy_assignable<typename std::remove_cv<T>::type>::value && |
1793 | | std::is_trivially_destructible<T>::value> |
1794 | | class optional_data; |
1795 | | |
1796 | | // Trivially copyable types |
1797 | | template <typename T> |
1798 | | class optional_data<T, true> : public optional_data_base<T> |
1799 | | { |
1800 | | protected: |
1801 | | #if PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS |
1802 | | using optional_data_base<T>::optional_data_base; |
1803 | | #else |
1804 | | optional_data() = default; |
1805 | | |
1806 | | template <typename... Args> |
1807 | | constexpr explicit optional_data(in_place_t t, Args&&... args) |
1808 | | : optional_data_base<T>(t, phmap::forward<Args>(args)...) {} |
1809 | | #endif |
1810 | | }; |
1811 | | |
1812 | | template <typename T> |
1813 | | class optional_data<T, false> : public optional_data_base<T> |
1814 | | { |
1815 | | protected: |
1816 | | #if PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS |
1817 | | using optional_data_base<T>::optional_data_base; |
1818 | | #else |
1819 | | template <typename... Args> |
1820 | | constexpr explicit optional_data(in_place_t t, Args&&... args) |
1821 | | : optional_data_base<T>(t, phmap::forward<Args>(args)...) {} |
1822 | | #endif |
1823 | | |
1824 | | optional_data() = default; |
1825 | | |
1826 | | optional_data(const optional_data& rhs) : optional_data_base<T>() { |
1827 | | if (rhs.engaged_) { |
1828 | | this->construct(rhs.data_); |
1829 | | } |
1830 | | } |
1831 | | |
1832 | | optional_data(optional_data&& rhs) noexcept( |
1833 | | phmap::default_allocator_is_nothrow::value || |
1834 | | std::is_nothrow_move_constructible<T>::value) |
1835 | | : optional_data_base<T>() { |
1836 | | if (rhs.engaged_) { |
1837 | | this->construct(std::move(rhs.data_)); |
1838 | | } |
1839 | | } |
1840 | | |
1841 | | optional_data& operator=(const optional_data& rhs) { |
1842 | | if (rhs.engaged_) { |
1843 | | this->assign(rhs.data_); |
1844 | | } else { |
1845 | | this->destruct(); |
1846 | | } |
1847 | | return *this; |
1848 | | } |
1849 | | |
1850 | | optional_data& operator=(optional_data&& rhs) noexcept( |
1851 | | std::is_nothrow_move_assignable<T>::value&& |
1852 | | std::is_nothrow_move_constructible<T>::value) { |
1853 | | if (rhs.engaged_) { |
1854 | | this->assign(std::move(rhs.data_)); |
1855 | | } else { |
1856 | | this->destruct(); |
1857 | | } |
1858 | | return *this; |
1859 | | } |
1860 | | }; |
1861 | | |
1862 | | // Ordered by level of restriction, from low to high. |
1863 | | // Copyable implies movable. |
1864 | | enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 }; |
1865 | | |
1866 | | // Base class for enabling/disabling copy/move constructor. |
1867 | | template <copy_traits> |
1868 | | class optional_ctor_base; |
1869 | | |
1870 | | template <> |
1871 | | class optional_ctor_base<copy_traits::copyable> |
1872 | | { |
1873 | | public: |
1874 | | constexpr optional_ctor_base() = default; |
1875 | | optional_ctor_base(const optional_ctor_base&) = default; |
1876 | | optional_ctor_base(optional_ctor_base&&) = default; |
1877 | | optional_ctor_base& operator=(const optional_ctor_base&) = default; |
1878 | | optional_ctor_base& operator=(optional_ctor_base&&) = default; |
1879 | | }; |
1880 | | |
1881 | | template <> |
1882 | | class optional_ctor_base<copy_traits::movable> |
1883 | | { |
1884 | | public: |
1885 | | constexpr optional_ctor_base() = default; |
1886 | | optional_ctor_base(const optional_ctor_base&) = delete; |
1887 | | optional_ctor_base(optional_ctor_base&&) = default; |
1888 | | optional_ctor_base& operator=(const optional_ctor_base&) = default; |
1889 | | optional_ctor_base& operator=(optional_ctor_base&&) = default; |
1890 | | }; |
1891 | | |
1892 | | template <> |
1893 | | class optional_ctor_base<copy_traits::non_movable> |
1894 | | { |
1895 | | public: |
1896 | | constexpr optional_ctor_base() = default; |
1897 | | optional_ctor_base(const optional_ctor_base&) = delete; |
1898 | | optional_ctor_base(optional_ctor_base&&) = delete; |
1899 | | optional_ctor_base& operator=(const optional_ctor_base&) = default; |
1900 | | optional_ctor_base& operator=(optional_ctor_base&&) = default; |
1901 | | }; |
1902 | | |
1903 | | // Base class for enabling/disabling copy/move assignment. |
1904 | | template <copy_traits> |
1905 | | class optional_assign_base; |
1906 | | |
1907 | | template <> |
1908 | | class optional_assign_base<copy_traits::copyable> |
1909 | | { |
1910 | | public: |
1911 | | constexpr optional_assign_base() = default; |
1912 | | optional_assign_base(const optional_assign_base&) = default; |
1913 | | optional_assign_base(optional_assign_base&&) = default; |
1914 | | optional_assign_base& operator=(const optional_assign_base&) = default; |
1915 | | optional_assign_base& operator=(optional_assign_base&&) = default; |
1916 | | }; |
1917 | | |
1918 | | template <> |
1919 | | class optional_assign_base<copy_traits::movable> |
1920 | | { |
1921 | | public: |
1922 | | constexpr optional_assign_base() = default; |
1923 | | optional_assign_base(const optional_assign_base&) = default; |
1924 | | optional_assign_base(optional_assign_base&&) = default; |
1925 | | optional_assign_base& operator=(const optional_assign_base&) = delete; |
1926 | | optional_assign_base& operator=(optional_assign_base&&) = default; |
1927 | | }; |
1928 | | |
1929 | | template <> |
1930 | | class optional_assign_base<copy_traits::non_movable> |
1931 | | { |
1932 | | public: |
1933 | | constexpr optional_assign_base() = default; |
1934 | | optional_assign_base(const optional_assign_base&) = default; |
1935 | | optional_assign_base(optional_assign_base&&) = default; |
1936 | | optional_assign_base& operator=(const optional_assign_base&) = delete; |
1937 | | optional_assign_base& operator=(optional_assign_base&&) = delete; |
1938 | | }; |
1939 | | |
1940 | | template <typename T> |
1941 | | constexpr copy_traits get_ctor_copy_traits() |
1942 | 0 | { |
1943 | 0 | return std::is_copy_constructible<T>::value |
1944 | 0 | ? copy_traits::copyable |
1945 | 0 | : std::is_move_constructible<T>::value ? copy_traits::movable |
1946 | 0 | : copy_traits::non_movable; |
1947 | 0 | } |
1948 | | |
1949 | | template <typename T> |
1950 | | constexpr copy_traits get_assign_copy_traits() |
1951 | 0 | { |
1952 | 0 | return phmap::is_copy_assignable<T>::value && |
1953 | 0 | std::is_copy_constructible<T>::value |
1954 | 0 | ? copy_traits::copyable |
1955 | 0 | : phmap::is_move_assignable<T>::value && |
1956 | 0 | std::is_move_constructible<T>::value |
1957 | 0 | ? copy_traits::movable |
1958 | 0 | : copy_traits::non_movable; |
1959 | 0 | } |
1960 | | |
1961 | | // Whether T is constructible or convertible from optional<U>. |
1962 | | template <typename T, typename U> |
1963 | | struct is_constructible_convertible_from_optional |
1964 | | : std::integral_constant< |
1965 | | bool, std::is_constructible<T, optional<U>&>::value || |
1966 | | std::is_constructible<T, optional<U>&&>::value || |
1967 | | std::is_constructible<T, const optional<U>&>::value || |
1968 | | std::is_constructible<T, const optional<U>&&>::value || |
1969 | | std::is_convertible<optional<U>&, T>::value || |
1970 | | std::is_convertible<optional<U>&&, T>::value || |
1971 | | std::is_convertible<const optional<U>&, T>::value || |
1972 | | std::is_convertible<const optional<U>&&, T>::value> {}; |
1973 | | |
1974 | | // Whether T is constructible or convertible or assignable from optional<U>. |
1975 | | template <typename T, typename U> |
1976 | | struct is_constructible_convertible_assignable_from_optional |
1977 | | : std::integral_constant< |
1978 | | bool, is_constructible_convertible_from_optional<T, U>::value || |
1979 | | std::is_assignable<T&, optional<U>&>::value || |
1980 | | std::is_assignable<T&, optional<U>&&>::value || |
1981 | | std::is_assignable<T&, const optional<U>&>::value || |
1982 | | std::is_assignable<T&, const optional<U>&&>::value> {}; |
1983 | | |
1984 | | // Helper function used by [optional.relops], [optional.comp_with_t], |
1985 | | // for checking whether an expression is convertible to bool. |
1986 | | bool convertible_to_bool(bool); |
1987 | | |
1988 | | // Base class for std::hash<phmap::optional<T>>: |
1989 | | // If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to |
1990 | | // compute the hash; Otherwise, it is disabled. |
1991 | | // Reference N4659 23.14.15 [unord.hash]. |
1992 | | template <typename T, typename = size_t> |
1993 | | struct optional_hash_base |
1994 | | { |
1995 | | optional_hash_base() = delete; |
1996 | | optional_hash_base(const optional_hash_base&) = delete; |
1997 | | optional_hash_base(optional_hash_base&&) = delete; |
1998 | | optional_hash_base& operator=(const optional_hash_base&) = delete; |
1999 | | optional_hash_base& operator=(optional_hash_base&&) = delete; |
2000 | | }; |
2001 | | |
2002 | | template <typename T> |
2003 | | struct optional_hash_base<T, decltype(std::hash<phmap::remove_const_t<T> >()( |
2004 | | std::declval<phmap::remove_const_t<T> >()))> |
2005 | | { |
2006 | | using argument_type = phmap::optional<T>; |
2007 | | using result_type = size_t; |
2008 | | size_t operator()(const phmap::optional<T>& opt) const { |
2009 | | phmap::type_traits_internal::AssertHashEnabled<phmap::remove_const_t<T>>(); |
2010 | | if (opt) { |
2011 | | return std::hash<phmap::remove_const_t<T> >()(*opt); |
2012 | | } else { |
2013 | | return static_cast<size_t>(0x297814aaad196e6dULL); |
2014 | | } |
2015 | | } |
2016 | | }; |
2017 | | |
2018 | | } // namespace optional_internal |
2019 | | |
2020 | | |
2021 | | // ----------------------------------------------------------------------------- |
2022 | | // phmap::optional class definition |
2023 | | // ----------------------------------------------------------------------------- |
2024 | | |
2025 | | template <typename T> |
2026 | | class optional : private optional_internal::optional_data<T>, |
2027 | | private optional_internal::optional_ctor_base< |
2028 | | optional_internal::get_ctor_copy_traits<T>()>, |
2029 | | private optional_internal::optional_assign_base< |
2030 | | optional_internal::get_assign_copy_traits<T>()> |
2031 | | { |
2032 | | using data_base = optional_internal::optional_data<T>; |
2033 | | |
2034 | | public: |
2035 | | typedef T value_type; |
2036 | | |
2037 | | // Constructors |
2038 | | |
2039 | | // Constructs an `optional` holding an empty value, NOT a default constructed |
2040 | | // `T`. |
2041 | | constexpr optional() noexcept {} |
2042 | | |
2043 | | // Constructs an `optional` initialized with `nullopt` to hold an empty value. |
2044 | | constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit) |
2045 | | |
2046 | | // Copy constructor, standard semantics |
2047 | | optional(const optional& src) = default; |
2048 | | |
2049 | | // Move constructor, standard semantics |
2050 | | optional(optional&& src) noexcept = default; |
2051 | | |
2052 | | // Constructs a non-empty `optional` direct-initialized value of type `T` from |
2053 | | // the arguments `std::forward<Args>(args)...` within the `optional`. |
2054 | | // (The `in_place_t` is a tag used to indicate that the contained object |
2055 | | // should be constructed in-place.) |
2056 | | template <typename InPlaceT, typename... Args, |
2057 | | phmap::enable_if_t<phmap::conjunction< |
2058 | | std::is_same<InPlaceT, in_place_t>, |
2059 | | std::is_constructible<T, Args&&...> >::value>* = nullptr> |
2060 | | constexpr explicit optional(InPlaceT, Args&&... args) |
2061 | | : data_base(in_place_t(), phmap::forward<Args>(args)...) {} |
2062 | | |
2063 | | // Constructs a non-empty `optional` direct-initialized value of type `T` from |
2064 | | // the arguments of an initializer_list and `std::forward<Args>(args)...`. |
2065 | | // (The `in_place_t` is a tag used to indicate that the contained object |
2066 | | // should be constructed in-place.) |
2067 | | template <typename U, typename... Args, |
2068 | | typename = typename std::enable_if<std::is_constructible< |
2069 | | T, std::initializer_list<U>&, Args&&...>::value>::type> |
2070 | | constexpr explicit optional(in_place_t, std::initializer_list<U> il, |
2071 | | Args&&... args) |
2072 | | : data_base(in_place_t(), il, phmap::forward<Args>(args)...) { |
2073 | | } |
2074 | | |
2075 | | // Value constructor (implicit) |
2076 | | template < |
2077 | | typename U = T, |
2078 | | typename std::enable_if< |
2079 | | phmap::conjunction<phmap::negation<std::is_same< |
2080 | | in_place_t, typename std::decay<U>::type> >, |
2081 | | phmap::negation<std::is_same< |
2082 | | optional<T>, typename std::decay<U>::type> >, |
2083 | | std::is_convertible<U&&, T>, |
2084 | | std::is_constructible<T, U&&> >::value, |
2085 | | bool>::type = false> |
2086 | | constexpr optional(U&& v) : data_base(in_place_t(), phmap::forward<U>(v)) {} |
2087 | | |
2088 | | // Value constructor (explicit) |
2089 | | template < |
2090 | | typename U = T, |
2091 | | typename std::enable_if< |
2092 | | phmap::conjunction<phmap::negation<std::is_same< |
2093 | | in_place_t, typename std::decay<U>::type>>, |
2094 | | phmap::negation<std::is_same< |
2095 | | optional<T>, typename std::decay<U>::type>>, |
2096 | | phmap::negation<std::is_convertible<U&&, T>>, |
2097 | | std::is_constructible<T, U&&>>::value, |
2098 | | bool>::type = false> |
2099 | | explicit constexpr optional(U&& v) |
2100 | | : data_base(in_place_t(), phmap::forward<U>(v)) {} |
2101 | | |
2102 | | // Converting copy constructor (implicit) |
2103 | | template <typename U, |
2104 | | typename std::enable_if< |
2105 | | phmap::conjunction< |
2106 | | phmap::negation<std::is_same<T, U> >, |
2107 | | std::is_constructible<T, const U&>, |
2108 | | phmap::negation< |
2109 | | optional_internal:: |
2110 | | is_constructible_convertible_from_optional<T, U> >, |
2111 | | std::is_convertible<const U&, T> >::value, |
2112 | | bool>::type = false> |
2113 | | optional(const optional<U>& rhs) { |
2114 | | if (rhs) { |
2115 | | this->construct(*rhs); |
2116 | | } |
2117 | | } |
2118 | | |
2119 | | // Converting copy constructor (explicit) |
2120 | | template <typename U, |
2121 | | typename std::enable_if< |
2122 | | phmap::conjunction< |
2123 | | phmap::negation<std::is_same<T, U>>, |
2124 | | std::is_constructible<T, const U&>, |
2125 | | phmap::negation< |
2126 | | optional_internal:: |
2127 | | is_constructible_convertible_from_optional<T, U>>, |
2128 | | phmap::negation<std::is_convertible<const U&, T>>>::value, |
2129 | | bool>::type = false> |
2130 | | explicit optional(const optional<U>& rhs) { |
2131 | | if (rhs) { |
2132 | | this->construct(*rhs); |
2133 | | } |
2134 | | } |
2135 | | |
2136 | | // Converting move constructor (implicit) |
2137 | | template <typename U, |
2138 | | typename std::enable_if< |
2139 | | phmap::conjunction< |
2140 | | phmap::negation<std::is_same<T, U> >, |
2141 | | std::is_constructible<T, U&&>, |
2142 | | phmap::negation< |
2143 | | optional_internal:: |
2144 | | is_constructible_convertible_from_optional<T, U> >, |
2145 | | std::is_convertible<U&&, T> >::value, |
2146 | | bool>::type = false> |
2147 | | optional(optional<U>&& rhs) { |
2148 | | if (rhs) { |
2149 | | this->construct(std::move(*rhs)); |
2150 | | } |
2151 | | } |
2152 | | |
2153 | | // Converting move constructor (explicit) |
2154 | | template < |
2155 | | typename U, |
2156 | | typename std::enable_if< |
2157 | | phmap::conjunction< |
2158 | | phmap::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, |
2159 | | phmap::negation< |
2160 | | optional_internal::is_constructible_convertible_from_optional< |
2161 | | T, U>>, |
2162 | | phmap::negation<std::is_convertible<U&&, T>>>::value, |
2163 | | bool>::type = false> |
2164 | | explicit optional(optional<U>&& rhs) { |
2165 | | if (rhs) { |
2166 | | this->construct(std::move(*rhs)); |
2167 | | } |
2168 | | } |
2169 | | |
2170 | | // Destructor. Trivial if `T` is trivially destructible. |
2171 | | ~optional() = default; |
2172 | | |
2173 | | // Assignment Operators |
2174 | | |
2175 | | // Assignment from `nullopt` |
2176 | | // |
2177 | | // Example: |
2178 | | // |
2179 | | // struct S { int value; }; |
2180 | | // optional<S> opt = phmap::nullopt; // Could also use opt = { }; |
2181 | | optional& operator=(nullopt_t) noexcept { |
2182 | | this->destruct(); |
2183 | | return *this; |
2184 | | } |
2185 | | |
2186 | | // Copy assignment operator, standard semantics |
2187 | | optional& operator=(const optional& src) = default; |
2188 | | |
2189 | | // Move assignment operator, standard semantics |
2190 | | optional& operator=(optional&& src) noexcept = default; |
2191 | | |
2192 | | // Value assignment operators |
2193 | | template < |
2194 | | typename U = T, |
2195 | | typename = typename std::enable_if<phmap::conjunction< |
2196 | | phmap::negation< |
2197 | | std::is_same<optional<T>, typename std::decay<U>::type>>, |
2198 | | phmap::negation< |
2199 | | phmap::conjunction<std::is_scalar<T>, |
2200 | | std::is_same<T, typename std::decay<U>::type>>>, |
2201 | | std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type> |
2202 | | optional& operator=(U&& v) { |
2203 | | this->assign(std::forward<U>(v)); |
2204 | | return *this; |
2205 | | } |
2206 | | |
2207 | | template < |
2208 | | typename U, |
2209 | | typename = typename std::enable_if<phmap::conjunction< |
2210 | | phmap::negation<std::is_same<T, U>>, |
2211 | | std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>, |
2212 | | phmap::negation< |
2213 | | optional_internal:: |
2214 | | is_constructible_convertible_assignable_from_optional< |
2215 | | T, U>>>::value>::type> |
2216 | | optional& operator=(const optional<U>& rhs) { |
2217 | | if (rhs) { |
2218 | | this->assign(*rhs); |
2219 | | } else { |
2220 | | this->destruct(); |
2221 | | } |
2222 | | return *this; |
2223 | | } |
2224 | | |
2225 | | template <typename U, |
2226 | | typename = typename std::enable_if<phmap::conjunction< |
2227 | | phmap::negation<std::is_same<T, U>>, std::is_constructible<T, U>, |
2228 | | std::is_assignable<T&, U>, |
2229 | | phmap::negation< |
2230 | | optional_internal:: |
2231 | | is_constructible_convertible_assignable_from_optional< |
2232 | | T, U>>>::value>::type> |
2233 | | optional& operator=(optional<U>&& rhs) { |
2234 | | if (rhs) { |
2235 | | this->assign(std::move(*rhs)); |
2236 | | } else { |
2237 | | this->destruct(); |
2238 | | } |
2239 | | return *this; |
2240 | | } |
2241 | | |
2242 | | // Modifiers |
2243 | | |
2244 | | // optional::reset() |
2245 | | // |
2246 | | // Destroys the inner `T` value of an `phmap::optional` if one is present. |
2247 | | PHMAP_ATTRIBUTE_REINITIALIZES void reset() noexcept { this->destruct(); } |
2248 | | |
2249 | | // optional::emplace() |
2250 | | // |
2251 | | // (Re)constructs the underlying `T` in-place with the given forwarded |
2252 | | // arguments. |
2253 | | // |
2254 | | // Example: |
2255 | | // |
2256 | | // optional<Foo> opt; |
2257 | | // opt.emplace(arg1,arg2,arg3); // Constructs Foo(arg1,arg2,arg3) |
2258 | | // |
2259 | | // If the optional is non-empty, and the `args` refer to subobjects of the |
2260 | | // current object, then behaviour is undefined, because the current object |
2261 | | // will be destructed before the new object is constructed with `args`. |
2262 | | template <typename... Args, |
2263 | | typename = typename std::enable_if< |
2264 | | std::is_constructible<T, Args&&...>::value>::type> |
2265 | | T& emplace(Args&&... args) { |
2266 | | this->destruct(); |
2267 | | this->construct(std::forward<Args>(args)...); |
2268 | | return reference(); |
2269 | | } |
2270 | | |
2271 | | // Emplace reconstruction overload for an initializer list and the given |
2272 | | // forwarded arguments. |
2273 | | // |
2274 | | // Example: |
2275 | | // |
2276 | | // struct Foo { |
2277 | | // Foo(std::initializer_list<int>); |
2278 | | // }; |
2279 | | // |
2280 | | // optional<Foo> opt; |
2281 | | // opt.emplace({1,2,3}); // Constructs Foo({1,2,3}) |
2282 | | template <typename U, typename... Args, |
2283 | | typename = typename std::enable_if<std::is_constructible< |
2284 | | T, std::initializer_list<U>&, Args&&...>::value>::type> |
2285 | | T& emplace(std::initializer_list<U> il, Args&&... args) { |
2286 | | this->destruct(); |
2287 | | this->construct(il, std::forward<Args>(args)...); |
2288 | | return reference(); |
2289 | | } |
2290 | | |
2291 | | // Swaps |
2292 | | |
2293 | | // Swap, standard semantics |
2294 | | void swap(optional& rhs) noexcept( |
2295 | | std::is_nothrow_move_constructible<T>::value&& |
2296 | | std::is_trivial<T>::value) { |
2297 | | if (*this) { |
2298 | | if (rhs) { |
2299 | | using std::swap; |
2300 | | swap(**this, *rhs); |
2301 | | } else { |
2302 | | rhs.construct(std::move(**this)); |
2303 | | this->destruct(); |
2304 | | } |
2305 | | } else { |
2306 | | if (rhs) { |
2307 | | this->construct(std::move(*rhs)); |
2308 | | rhs.destruct(); |
2309 | | } else { |
2310 | | // No effect (swap(disengaged, disengaged)). |
2311 | | } |
2312 | | } |
2313 | | } |
2314 | | |
2315 | | // Observers |
2316 | | |
2317 | | // optional::operator->() |
2318 | | // |
2319 | | // Accesses the underlying `T` value's member `m` of an `optional`. If the |
2320 | | // `optional` is empty, behavior is undefined. |
2321 | | // |
2322 | | // If you need myOpt->foo in constexpr, use (*myOpt).foo instead. |
2323 | | const T* operator->() const { |
2324 | | assert(this->engaged_); |
2325 | | return std::addressof(this->data_); |
2326 | | } |
2327 | | T* operator->() { |
2328 | | assert(this->engaged_); |
2329 | | return std::addressof(this->data_); |
2330 | | } |
2331 | | |
2332 | | // optional::operator*() |
2333 | | // |
2334 | | // Accesses the underlying `T` value of an `optional`. If the `optional` is |
2335 | | // empty, behavior is undefined. |
2336 | | constexpr const T& operator*() const & { return reference(); } |
2337 | | T& operator*() & { |
2338 | | assert(this->engaged_); |
2339 | | return reference(); |
2340 | | } |
2341 | | constexpr const T&& operator*() const && { |
2342 | | return phmap::move(reference()); |
2343 | | } |
2344 | | T&& operator*() && { |
2345 | | assert(this->engaged_); |
2346 | | return std::move(reference()); |
2347 | | } |
2348 | | |
2349 | | // optional::operator bool() |
2350 | | // |
2351 | | // Returns false if and only if the `optional` is empty. |
2352 | | // |
2353 | | // if (opt) { |
2354 | | // // do something with opt.value(); |
2355 | | // } else { |
2356 | | // // opt is empty. |
2357 | | // } |
2358 | | // |
2359 | | constexpr explicit operator bool() const noexcept { return this->engaged_; } |
2360 | | |
2361 | | // optional::has_value() |
2362 | | // |
2363 | | // Determines whether the `optional` contains a value. Returns `false` if and |
2364 | | // only if `*this` is empty. |
2365 | | constexpr bool has_value() const noexcept { return this->engaged_; } |
2366 | | |
2367 | | // Suppress bogus warning on MSVC: MSVC complains call to reference() after |
2368 | | // throw_bad_optional_access() is unreachable. |
2369 | | #ifdef _MSC_VER |
2370 | | #pragma warning(push) |
2371 | | #pragma warning(disable : 4702) |
2372 | | #endif // _MSC_VER |
2373 | | // optional::value() |
2374 | | // |
2375 | | // Returns a reference to an `optional`s underlying value. The constness |
2376 | | // and lvalue/rvalue-ness of the `optional` is preserved to the view of |
2377 | | // the `T` sub-object. Throws `phmap::bad_optional_access` when the `optional` |
2378 | | // is empty. |
2379 | | constexpr const T& value() const & { |
2380 | | return static_cast<bool>(*this) |
2381 | | ? reference() |
2382 | | : (optional_internal::throw_bad_optional_access(), reference()); |
2383 | | } |
2384 | | T& value() & { |
2385 | | return static_cast<bool>(*this) |
2386 | | ? reference() |
2387 | | : (optional_internal::throw_bad_optional_access(), reference()); |
2388 | | } |
2389 | | T&& value() && { // NOLINT(build/c++11) |
2390 | | return std::move( |
2391 | | static_cast<bool>(*this) |
2392 | | ? reference() |
2393 | | : (optional_internal::throw_bad_optional_access(), reference())); |
2394 | | } |
2395 | | constexpr const T&& value() const && { // NOLINT(build/c++11) |
2396 | | return phmap::move( |
2397 | | static_cast<bool>(*this) |
2398 | | ? reference() |
2399 | | : (optional_internal::throw_bad_optional_access(), reference())); |
2400 | | } |
2401 | | #ifdef _MSC_VER |
2402 | | #pragma warning(pop) |
2403 | | #endif // _MSC_VER |
2404 | | |
2405 | | // optional::value_or() |
2406 | | // |
2407 | | // Returns either the value of `T` or a passed default `v` if the `optional` |
2408 | | // is empty. |
2409 | | template <typename U> |
2410 | | constexpr T value_or(U&& v) const& { |
2411 | | static_assert(std::is_copy_constructible<value_type>::value, |
2412 | | "optional<T>::value_or: T must by copy constructible"); |
2413 | | static_assert(std::is_convertible<U&&, value_type>::value, |
2414 | | "optional<T>::value_or: U must be convertible to T"); |
2415 | | return static_cast<bool>(*this) |
2416 | | ? **this |
2417 | | : static_cast<T>(phmap::forward<U>(v)); |
2418 | | } |
2419 | | template <typename U> |
2420 | | T value_or(U&& v) && { // NOLINT(build/c++11) |
2421 | | static_assert(std::is_move_constructible<value_type>::value, |
2422 | | "optional<T>::value_or: T must by move constructible"); |
2423 | | static_assert(std::is_convertible<U&&, value_type>::value, |
2424 | | "optional<T>::value_or: U must be convertible to T"); |
2425 | | return static_cast<bool>(*this) ? std::move(**this) |
2426 | | : static_cast<T>(std::forward<U>(v)); |
2427 | | } |
2428 | | |
2429 | | private: |
2430 | | // Private accessors for internal storage viewed as reference to T. |
2431 | | constexpr const T& reference() const { return this->data_; } |
2432 | | T& reference() { return this->data_; } |
2433 | | |
2434 | | // T constraint checks. You can't have an optional of nullopt_t, in_place_t |
2435 | | // or a reference. |
2436 | | static_assert( |
2437 | | !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value, |
2438 | | "optional<nullopt_t> is not allowed."); |
2439 | | static_assert( |
2440 | | !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value, |
2441 | | "optional<in_place_t> is not allowed."); |
2442 | | static_assert(!std::is_reference<T>::value, |
2443 | | "optional<reference> is not allowed."); |
2444 | | }; |
2445 | | |
2446 | | // Non-member functions |
2447 | | |
2448 | | // swap() |
2449 | | // |
2450 | | // Performs a swap between two `phmap::optional` objects, using standard |
2451 | | // semantics. |
2452 | | // |
2453 | | // NOTE: we assume `is_swappable()` is always `true`. A compile error will |
2454 | | // result if this is not the case. |
2455 | | template <typename T, |
2456 | | typename std::enable_if<std::is_move_constructible<T>::value, |
2457 | | bool>::type = false> |
2458 | | void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) { |
2459 | | a.swap(b); |
2460 | | } |
2461 | | |
2462 | | // make_optional() |
2463 | | // |
2464 | | // Creates a non-empty `optional<T>` where the type of `T` is deduced. An |
2465 | | // `phmap::optional` can also be explicitly instantiated with |
2466 | | // `make_optional<T>(v)`. |
2467 | | // |
2468 | | // Note: `make_optional()` constructions may be declared `constexpr` for |
2469 | | // trivially copyable types `T`. Non-trivial types require copy elision |
2470 | | // support in C++17 for `make_optional` to support `constexpr` on such |
2471 | | // non-trivial types. |
2472 | | // |
2473 | | // Example: |
2474 | | // |
2475 | | // constexpr phmap::optional<int> opt = phmap::make_optional(1); |
2476 | | // static_assert(opt.value() == 1, ""); |
2477 | | template <typename T> |
2478 | | constexpr optional<typename std::decay<T>::type> make_optional(T&& v) { |
2479 | | return optional<typename std::decay<T>::type>(phmap::forward<T>(v)); |
2480 | | } |
2481 | | |
2482 | | template <typename T, typename... Args> |
2483 | | constexpr optional<T> make_optional(Args&&... args) { |
2484 | | return optional<T>(in_place_t(), phmap::forward<Args>(args)...); |
2485 | | } |
2486 | | |
2487 | | template <typename T, typename U, typename... Args> |
2488 | | constexpr optional<T> make_optional(std::initializer_list<U> il, |
2489 | | Args&&... args) { |
2490 | | return optional<T>(in_place_t(), il, |
2491 | | phmap::forward<Args>(args)...); |
2492 | | } |
2493 | | |
2494 | | // Relational operators [optional.relops] |
2495 | | |
2496 | | // Empty optionals are considered equal to each other and less than non-empty |
2497 | | // optionals. Supports relations between optional<T> and optional<U>, between |
2498 | | // optional<T> and U, and between optional<T> and nullopt. |
2499 | | // |
2500 | | // Note: We're careful to support T having non-bool relationals. |
2501 | | |
2502 | | // Requires: The expression, e.g. "*x == *y" shall be well-formed and its result |
2503 | | // shall be convertible to bool. |
2504 | | // The C++17 (N4606) "Returns:" statements are translated into |
2505 | | // code in an obvious way here, and the original text retained as function docs. |
2506 | | // Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true; |
2507 | | // otherwise *x == *y. |
2508 | | template <typename T, typename U> |
2509 | | constexpr auto operator==(const optional<T>& x, const optional<U>& y) |
2510 | | -> decltype(optional_internal::convertible_to_bool(*x == *y)) { |
2511 | | return static_cast<bool>(x) != static_cast<bool>(y) |
2512 | | ? false |
2513 | | : static_cast<bool>(x) == false ? true |
2514 | | : static_cast<bool>(*x == *y); |
2515 | | } |
2516 | | |
2517 | | // Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false; |
2518 | | // otherwise *x != *y. |
2519 | | template <typename T, typename U> |
2520 | | constexpr auto operator!=(const optional<T>& x, const optional<U>& y) |
2521 | | -> decltype(optional_internal::convertible_to_bool(*x != *y)) { |
2522 | | return static_cast<bool>(x) != static_cast<bool>(y) |
2523 | | ? true |
2524 | | : static_cast<bool>(x) == false ? false |
2525 | | : static_cast<bool>(*x != *y); |
2526 | | } |
2527 | | // Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y. |
2528 | | template <typename T, typename U> |
2529 | | constexpr auto operator<(const optional<T>& x, const optional<U>& y) |
2530 | | -> decltype(optional_internal::convertible_to_bool(*x < *y)) { |
2531 | | return !y ? false : !x ? true : static_cast<bool>(*x < *y); |
2532 | | } |
2533 | | // Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y. |
2534 | | template <typename T, typename U> |
2535 | | constexpr auto operator>(const optional<T>& x, const optional<U>& y) |
2536 | | -> decltype(optional_internal::convertible_to_bool(*x > *y)) { |
2537 | | return !x ? false : !y ? true : static_cast<bool>(*x > *y); |
2538 | | } |
2539 | | // Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y. |
2540 | | template <typename T, typename U> |
2541 | | constexpr auto operator<=(const optional<T>& x, const optional<U>& y) |
2542 | | -> decltype(optional_internal::convertible_to_bool(*x <= *y)) { |
2543 | | return !x ? true : !y ? false : static_cast<bool>(*x <= *y); |
2544 | | } |
2545 | | // Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y. |
2546 | | template <typename T, typename U> |
2547 | | constexpr auto operator>=(const optional<T>& x, const optional<U>& y) |
2548 | | -> decltype(optional_internal::convertible_to_bool(*x >= *y)) { |
2549 | | return !y ? true : !x ? false : static_cast<bool>(*x >= *y); |
2550 | | } |
2551 | | |
2552 | | // Comparison with nullopt [optional.nullops] |
2553 | | // The C++17 (N4606) "Returns:" statements are used directly here. |
2554 | | template <typename T> |
2555 | | constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept { |
2556 | | return !x; |
2557 | | } |
2558 | | template <typename T> |
2559 | | constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept { |
2560 | | return !x; |
2561 | | } |
2562 | | template <typename T> |
2563 | | constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept { |
2564 | | return static_cast<bool>(x); |
2565 | | } |
2566 | | template <typename T> |
2567 | | constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept { |
2568 | | return static_cast<bool>(x); |
2569 | | } |
2570 | | template <typename T> |
2571 | | constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { |
2572 | | return false; |
2573 | | } |
2574 | | template <typename T> |
2575 | | constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept { |
2576 | | return static_cast<bool>(x); |
2577 | | } |
2578 | | template <typename T> |
2579 | | constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept { |
2580 | | return !x; |
2581 | | } |
2582 | | template <typename T> |
2583 | | constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { |
2584 | | return true; |
2585 | | } |
2586 | | template <typename T> |
2587 | | constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept { |
2588 | | return static_cast<bool>(x); |
2589 | | } |
2590 | | template <typename T> |
2591 | | constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { |
2592 | | return false; |
2593 | | } |
2594 | | template <typename T> |
2595 | | constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { |
2596 | | return true; |
2597 | | } |
2598 | | template <typename T> |
2599 | | constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept { |
2600 | | return !x; |
2601 | | } |
2602 | | |
2603 | | // Comparison with T [optional.comp_with_t] |
2604 | | |
2605 | | // Requires: The expression, e.g. "*x == v" shall be well-formed and its result |
2606 | | // shall be convertible to bool. |
2607 | | // The C++17 (N4606) "Equivalent to:" statements are used directly here. |
2608 | | template <typename T, typename U> |
2609 | | constexpr auto operator==(const optional<T>& x, const U& v) |
2610 | | -> decltype(optional_internal::convertible_to_bool(*x == v)) { |
2611 | | return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false; |
2612 | | } |
2613 | | template <typename T, typename U> |
2614 | | constexpr auto operator==(const U& v, const optional<T>& x) |
2615 | | -> decltype(optional_internal::convertible_to_bool(v == *x)) { |
2616 | | return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false; |
2617 | | } |
2618 | | template <typename T, typename U> |
2619 | | constexpr auto operator!=(const optional<T>& x, const U& v) |
2620 | | -> decltype(optional_internal::convertible_to_bool(*x != v)) { |
2621 | | return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true; |
2622 | | } |
2623 | | template <typename T, typename U> |
2624 | | constexpr auto operator!=(const U& v, const optional<T>& x) |
2625 | | -> decltype(optional_internal::convertible_to_bool(v != *x)) { |
2626 | | return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true; |
2627 | | } |
2628 | | template <typename T, typename U> |
2629 | | constexpr auto operator<(const optional<T>& x, const U& v) |
2630 | | -> decltype(optional_internal::convertible_to_bool(*x < v)) { |
2631 | | return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true; |
2632 | | } |
2633 | | template <typename T, typename U> |
2634 | | constexpr auto operator<(const U& v, const optional<T>& x) |
2635 | | -> decltype(optional_internal::convertible_to_bool(v < *x)) { |
2636 | | return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false; |
2637 | | } |
2638 | | template <typename T, typename U> |
2639 | | constexpr auto operator<=(const optional<T>& x, const U& v) |
2640 | | -> decltype(optional_internal::convertible_to_bool(*x <= v)) { |
2641 | | return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true; |
2642 | | } |
2643 | | template <typename T, typename U> |
2644 | | constexpr auto operator<=(const U& v, const optional<T>& x) |
2645 | | -> decltype(optional_internal::convertible_to_bool(v <= *x)) { |
2646 | | return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false; |
2647 | | } |
2648 | | template <typename T, typename U> |
2649 | | constexpr auto operator>(const optional<T>& x, const U& v) |
2650 | | -> decltype(optional_internal::convertible_to_bool(*x > v)) { |
2651 | | return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false; |
2652 | | } |
2653 | | template <typename T, typename U> |
2654 | | constexpr auto operator>(const U& v, const optional<T>& x) |
2655 | | -> decltype(optional_internal::convertible_to_bool(v > *x)) { |
2656 | | return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true; |
2657 | | } |
2658 | | template <typename T, typename U> |
2659 | | constexpr auto operator>=(const optional<T>& x, const U& v) |
2660 | | -> decltype(optional_internal::convertible_to_bool(*x >= v)) { |
2661 | | return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false; |
2662 | | } |
2663 | | template <typename T, typename U> |
2664 | | constexpr auto operator>=(const U& v, const optional<T>& x) |
2665 | | -> decltype(optional_internal::convertible_to_bool(v >= *x)) { |
2666 | | return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true; |
2667 | | } |
2668 | | |
2669 | | } // namespace phmap |
2670 | | |
2671 | | namespace std { |
2672 | | |
2673 | | // std::hash specialization for phmap::optional. |
2674 | | template <typename T> |
2675 | | struct hash<phmap::optional<T> > |
2676 | | : phmap::optional_internal::optional_hash_base<T> {}; |
2677 | | |
2678 | | } // namespace std |
2679 | | |
2680 | | #endif |
2681 | | |
2682 | | // ----------------------------------------------------------------------------- |
2683 | | // common.h |
2684 | | // ----------------------------------------------------------------------------- |
2685 | | namespace phmap { |
2686 | | namespace priv { |
2687 | | |
2688 | | template <class, class = void> |
2689 | | struct IsTransparent : std::false_type {}; |
2690 | | template <class T> |
2691 | | struct IsTransparent<T, phmap::void_t<typename T::is_transparent>> |
2692 | | : std::true_type {}; |
2693 | | |
2694 | | template <bool is_transparent> |
2695 | | struct KeyArg |
2696 | | { |
2697 | | // Transparent. Forward `K`. |
2698 | | template <typename K, typename key_type> |
2699 | | using type = K; |
2700 | | }; |
2701 | | |
2702 | | template <> |
2703 | | struct KeyArg<false> |
2704 | | { |
2705 | | // Not transparent. Always use `key_type`. |
2706 | | template <typename K, typename key_type> |
2707 | | using type = key_type; |
2708 | | }; |
2709 | | |
2710 | | #ifdef _MSC_VER |
2711 | | #pragma warning(push) |
2712 | | // warning C4820: '6' bytes padding added after data member |
2713 | | #pragma warning(disable : 4820) |
2714 | | #endif |
2715 | | |
2716 | | // The node_handle concept from C++17. |
2717 | | // We specialize node_handle for sets and maps. node_handle_base holds the |
2718 | | // common API of both. |
2719 | | // ----------------------------------------------------------------------- |
2720 | | template <typename PolicyTraits, typename Alloc> |
2721 | | class node_handle_base |
2722 | | { |
2723 | | protected: |
2724 | | using slot_type = typename PolicyTraits::slot_type; |
2725 | | |
2726 | | public: |
2727 | | using allocator_type = Alloc; |
2728 | | |
2729 | | constexpr node_handle_base() {} |
2730 | | |
2731 | | node_handle_base(node_handle_base&& other) noexcept { |
2732 | | *this = std::move(other); |
2733 | | } |
2734 | | |
2735 | | ~node_handle_base() { destroy(); } |
2736 | | |
2737 | | node_handle_base& operator=(node_handle_base&& other) noexcept { |
2738 | | destroy(); |
2739 | | if (!other.empty()) { |
2740 | | alloc_ = other.alloc_; |
2741 | | PolicyTraits::transfer(alloc(), slot(), other.slot()); |
2742 | | other.reset(); |
2743 | | } |
2744 | | return *this; |
2745 | | } |
2746 | | |
2747 | | bool empty() const noexcept { return !alloc_; } |
2748 | | explicit operator bool() const noexcept { return !empty(); } |
2749 | | allocator_type get_allocator() const { return *alloc_; } |
2750 | | |
2751 | | protected: |
2752 | | friend struct CommonAccess; |
2753 | | |
2754 | | struct transfer_tag_t {}; |
2755 | | node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s) |
2756 | | : alloc_(a) { |
2757 | | PolicyTraits::transfer(alloc(), slot(), s); |
2758 | | } |
2759 | | |
2760 | | struct move_tag_t {}; |
2761 | | node_handle_base(move_tag_t, const allocator_type& a, slot_type* s) |
2762 | | : alloc_(a) { |
2763 | | PolicyTraits::construct(alloc(), slot(), s); |
2764 | | } |
2765 | | |
2766 | | node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) { |
2767 | | PolicyTraits::transfer(alloc(), slot(), s); |
2768 | | } |
2769 | | |
2770 | | //node_handle_base(const node_handle_base&) = delete; |
2771 | | //node_handle_base& operator=(const node_handle_base&) = delete; |
2772 | | |
2773 | | void destroy() { |
2774 | | if (!empty()) { |
2775 | | PolicyTraits::destroy(alloc(), slot()); |
2776 | | reset(); |
2777 | | } |
2778 | | } |
2779 | | |
2780 | | void reset() { |
2781 | | assert(alloc_.has_value()); |
2782 | | alloc_ = phmap::nullopt; |
2783 | | } |
2784 | | |
2785 | | slot_type* slot() const { |
2786 | | assert(!empty()); |
2787 | | return reinterpret_cast<slot_type*>(std::addressof(slot_space_)); |
2788 | | } |
2789 | | |
2790 | | allocator_type* alloc() { return std::addressof(*alloc_); } |
2791 | | |
2792 | | private: |
2793 | | phmap::optional<allocator_type> alloc_; |
2794 | | mutable phmap::aligned_storage_t<sizeof(slot_type), alignof(slot_type)> slot_space_; |
2795 | | }; |
2796 | | |
2797 | | #ifdef _MSC_VER |
2798 | | #pragma warning(pop) |
2799 | | #endif |
2800 | | |
2801 | | // For sets. |
2802 | | // --------- |
2803 | | template <typename Policy, typename PolicyTraits, typename Alloc, |
2804 | | typename = void> |
2805 | | class node_handle : public node_handle_base<PolicyTraits, Alloc> |
2806 | | { |
2807 | | using Base = node_handle_base<PolicyTraits, Alloc>; |
2808 | | |
2809 | | public: |
2810 | | using value_type = typename PolicyTraits::value_type; |
2811 | | |
2812 | | constexpr node_handle() {} |
2813 | | |
2814 | | value_type& value() const { return PolicyTraits::element(this->slot()); } |
2815 | | |
2816 | | value_type& key() const { return PolicyTraits::element(this->slot()); } |
2817 | | |
2818 | | private: |
2819 | | friend struct CommonAccess; |
2820 | | |
2821 | | using Base::Base; |
2822 | | }; |
2823 | | |
2824 | | // For maps. |
2825 | | // --------- |
2826 | | template <typename Policy, typename PolicyTraits, typename Alloc> |
2827 | | class node_handle<Policy, PolicyTraits, Alloc, |
2828 | | phmap::void_t<typename Policy::mapped_type>> |
2829 | | : public node_handle_base<PolicyTraits, Alloc> |
2830 | | { |
2831 | | using Base = node_handle_base<PolicyTraits, Alloc>; |
2832 | | using slot_type = typename PolicyTraits::slot_type; |
2833 | | |
2834 | | public: |
2835 | | using key_type = typename Policy::key_type; |
2836 | | using mapped_type = typename Policy::mapped_type; |
2837 | | |
2838 | | constexpr node_handle() {} |
2839 | | |
2840 | | auto key() const -> decltype(PolicyTraits::key(this->slot())) { |
2841 | | return PolicyTraits::key(this->slot()); |
2842 | | } |
2843 | | |
2844 | | mapped_type& mapped() const { |
2845 | | return PolicyTraits::value(&PolicyTraits::element(this->slot())); |
2846 | | } |
2847 | | |
2848 | | private: |
2849 | | friend struct CommonAccess; |
2850 | | |
2851 | | using Base::Base; |
2852 | | }; |
2853 | | |
2854 | | // Provide access to non-public node-handle functions. |
2855 | | struct CommonAccess |
2856 | | { |
2857 | | template <typename Node> |
2858 | | static auto GetSlot(const Node& node) -> decltype(node.slot()) { |
2859 | | return node.slot(); |
2860 | | } |
2861 | | |
2862 | | template <typename Node> |
2863 | | static void Destroy(Node* node) { |
2864 | | node->destroy(); |
2865 | | } |
2866 | | |
2867 | | template <typename Node> |
2868 | | static void Reset(Node* node) { |
2869 | | node->reset(); |
2870 | | } |
2871 | | |
2872 | | template <typename T, typename... Args> |
2873 | | static T Make(Args&&... args) { |
2874 | | return T(std::forward<Args>(args)...); |
2875 | | } |
2876 | | |
2877 | | template <typename T, typename... Args> |
2878 | | static T Transfer(Args&&... args) { |
2879 | | return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...); |
2880 | | } |
2881 | | |
2882 | | template <typename T, typename... Args> |
2883 | | static T Move(Args&&... args) { |
2884 | | return T(typename T::move_tag_t{}, std::forward<Args>(args)...); |
2885 | | } |
2886 | | }; |
2887 | | |
2888 | | // Implement the insert_return_type<> concept of C++17. |
2889 | | template <class Iterator, class NodeType> |
2890 | | struct InsertReturnType |
2891 | | { |
2892 | | Iterator position; |
2893 | | bool inserted; |
2894 | | NodeType node; |
2895 | | }; |
2896 | | |
2897 | | } // namespace priv |
2898 | | } // namespace phmap |
2899 | | |
2900 | | |
2901 | | #ifdef ADDRESS_SANITIZER |
2902 | | #include <sanitizer/asan_interface.h> |
2903 | | #endif |
2904 | | |
2905 | | // --------------------------------------------------------------------------- |
2906 | | // span.h |
2907 | | // --------------------------------------------------------------------------- |
2908 | | |
2909 | | namespace phmap { |
2910 | | |
2911 | | template <typename T> |
2912 | | class Span; |
2913 | | |
2914 | | namespace span_internal { |
2915 | | // A constexpr min function |
2916 | 0 | constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; } |
2917 | | |
2918 | | // Wrappers for access to container data pointers. |
2919 | | template <typename C> |
2920 | | constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references) |
2921 | | -> decltype(c.data()) { |
2922 | | return c.data(); |
2923 | | } |
2924 | | |
2925 | | // Before C++17, std::string::data returns a const char* in all cases. |
2926 | | inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references) |
2927 | 0 | int) noexcept { |
2928 | 0 | return &s[0]; |
2929 | 0 | } |
2930 | | |
2931 | | template <typename C> |
2932 | | constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references) |
2933 | | -> decltype(GetDataImpl(c, 0)) { |
2934 | | return GetDataImpl(c, 0); |
2935 | | } |
2936 | | |
2937 | | // Detection idioms for size() and data(). |
2938 | | template <typename C> |
2939 | | using HasSize = |
2940 | | std::is_integral<phmap::decay_t<decltype(std::declval<C&>().size())>>; |
2941 | | |
2942 | | // We want to enable conversion from vector<T*> to Span<const T* const> but |
2943 | | // disable conversion from vector<Derived> to Span<Base>. Here we use |
2944 | | // the fact that U** is convertible to Q* const* if and only if Q is the same |
2945 | | // type or a more cv-qualified version of U. We also decay the result type of |
2946 | | // data() to avoid problems with classes which have a member function data() |
2947 | | // which returns a reference. |
2948 | | template <typename T, typename C> |
2949 | | using HasData = |
2950 | | std::is_convertible<phmap::decay_t<decltype(GetData(std::declval<C&>()))>*, |
2951 | | T* const*>; |
2952 | | |
2953 | | // Extracts value type from a Container |
2954 | | template <typename C> |
2955 | | struct ElementType { |
2956 | | using type = typename phmap::remove_reference_t<C>::value_type; |
2957 | | }; |
2958 | | |
2959 | | template <typename T, size_t N> |
2960 | | struct ElementType<T (&)[N]> { |
2961 | | using type = T; |
2962 | | }; |
2963 | | |
2964 | | template <typename C> |
2965 | | using ElementT = typename ElementType<C>::type; |
2966 | | |
2967 | | template <typename T> |
2968 | | using EnableIfMutable = |
2969 | | typename std::enable_if<!std::is_const<T>::value, int>::type; |
2970 | | |
2971 | | template <typename T> |
2972 | | bool EqualImpl(Span<T> a, Span<T> b) { |
2973 | | static_assert(std::is_const<T>::value, ""); |
2974 | | return std::equal(a.begin(), a.end(), b.begin(), b.end()); |
2975 | | } |
2976 | | |
2977 | | template <typename T> |
2978 | | bool LessThanImpl(Span<T> a, Span<T> b) { |
2979 | | static_assert(std::is_const<T>::value, ""); |
2980 | | return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); |
2981 | | } |
2982 | | |
2983 | | // The `IsConvertible` classes here are needed because of the |
2984 | | // `std::is_convertible` bug in libcxx when compiled with GCC. This build |
2985 | | // configuration is used by Android NDK toolchain. Reference link: |
2986 | | // https://bugs.llvm.org/show_bug.cgi?id=27538. |
2987 | | template <typename From, typename To> |
2988 | | struct IsConvertibleHelper { |
2989 | | static std::true_type testval(To); |
2990 | | static std::false_type testval(...); |
2991 | | |
2992 | | using type = decltype(testval(std::declval<From>())); |
2993 | | }; |
2994 | | |
2995 | | template <typename From, typename To> |
2996 | | struct IsConvertible : IsConvertibleHelper<From, To>::type {}; |
2997 | | |
2998 | | // TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the |
2999 | | // older version of libcxx is not supported. |
3000 | | template <typename From, typename To> |
3001 | | using EnableIfConvertibleToSpanConst = |
3002 | | typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type; |
3003 | | } // namespace span_internal |
3004 | | |
3005 | | //------------------------------------------------------------------------------ |
3006 | | // Span |
3007 | | //------------------------------------------------------------------------------ |
3008 | | // |
3009 | | // A `Span` is an "array view" type for holding a view of a contiguous data |
3010 | | // array; the `Span` object does not and cannot own such data itself. A span |
3011 | | // provides an easy way to provide overloads for anything operating on |
3012 | | // contiguous sequences without needing to manage pointers and array lengths |
3013 | | // manually. |
3014 | | |
3015 | | // A span is conceptually a pointer (ptr) and a length (size) into an already |
3016 | | // existing array of contiguous memory; the array it represents references the |
3017 | | // elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span` |
3018 | | // instead of raw pointers avoids many issues related to index out of bounds |
3019 | | // errors. |
3020 | | // |
3021 | | // Spans may also be constructed from containers holding contiguous sequences. |
3022 | | // Such containers must supply `data()` and `size() const` methods (e.g |
3023 | | // `std::vector<T>`, `phmap::InlinedVector<T, N>`). All implicit conversions to |
3024 | | // `phmap::Span` from such containers will create spans of type `const T`; |
3025 | | // spans which can mutate their values (of type `T`) must use explicit |
3026 | | // constructors. |
3027 | | // |
3028 | | // A `Span<T>` is somewhat analogous to an `phmap::string_view`, but for an array |
3029 | | // of elements of type `T`. A user of `Span` must ensure that the data being |
3030 | | // pointed to outlives the `Span` itself. |
3031 | | // |
3032 | | // You can construct a `Span<T>` in several ways: |
3033 | | // |
3034 | | // * Explicitly from a reference to a container type |
3035 | | // * Explicitly from a pointer and size |
3036 | | // * Implicitly from a container type (but only for spans of type `const T`) |
3037 | | // * Using the `MakeSpan()` or `MakeConstSpan()` factory functions. |
3038 | | // |
3039 | | // Examples: |
3040 | | // |
3041 | | // // Construct a Span explicitly from a container: |
3042 | | // std::vector<int> v = {1, 2, 3, 4, 5}; |
3043 | | // auto span = phmap::Span<const int>(v); |
3044 | | // |
3045 | | // // Construct a Span explicitly from a C-style array: |
3046 | | // int a[5] = {1, 2, 3, 4, 5}; |
3047 | | // auto span = phmap::Span<const int>(a); |
3048 | | // |
3049 | | // // Construct a Span implicitly from a container |
3050 | | // void MyRoutine(phmap::Span<const int> a) { |
3051 | | // ... |
3052 | | // } |
3053 | | // std::vector v = {1,2,3,4,5}; |
3054 | | // MyRoutine(v) // convert to Span<const T> |
3055 | | // |
3056 | | // Note that `Span` objects, in addition to requiring that the memory they |
3057 | | // point to remains alive, must also ensure that such memory does not get |
3058 | | // reallocated. Therefore, to avoid undefined behavior, containers with |
3059 | | // associated span views should not invoke operations that may reallocate memory |
3060 | | // (such as resizing) or invalidate iterators into the container. |
3061 | | // |
3062 | | // One common use for a `Span` is when passing arguments to a routine that can |
3063 | | // accept a variety of array types (e.g. a `std::vector`, `phmap::InlinedVector`, |
3064 | | // a C-style array, etc.). Instead of creating overloads for each case, you |
3065 | | // can simply specify a `Span` as the argument to such a routine. |
3066 | | // |
3067 | | // Example: |
3068 | | // |
3069 | | // void MyRoutine(phmap::Span<const int> a) { |
3070 | | // ... |
3071 | | // } |
3072 | | // |
3073 | | // std::vector v = {1,2,3,4,5}; |
3074 | | // MyRoutine(v); |
3075 | | // |
3076 | | // phmap::InlinedVector<int, 4> my_inline_vector; |
3077 | | // MyRoutine(my_inline_vector); |
3078 | | // |
3079 | | // // Explicit constructor from pointer,size |
3080 | | // int* my_array = new int[10]; |
3081 | | // MyRoutine(phmap::Span<const int>(my_array, 10)); |
3082 | | template <typename T> |
3083 | | class Span |
3084 | | { |
3085 | | private: |
3086 | | // Used to determine whether a Span can be constructed from a container of |
3087 | | // type C. |
3088 | | template <typename C> |
3089 | | using EnableIfConvertibleFrom = |
3090 | | typename std::enable_if<span_internal::HasData<T, C>::value && |
3091 | | span_internal::HasSize<C>::value>::type; |
3092 | | |
3093 | | // Used to SFINAE-enable a function when the slice elements are const. |
3094 | | template <typename U> |
3095 | | using EnableIfConstView = |
3096 | | typename std::enable_if<std::is_const<T>::value, U>::type; |
3097 | | |
3098 | | // Used to SFINAE-enable a function when the slice elements are mutable. |
3099 | | template <typename U> |
3100 | | using EnableIfMutableView = |
3101 | | typename std::enable_if<!std::is_const<T>::value, U>::type; |
3102 | | |
3103 | | public: |
3104 | | using value_type = phmap::remove_cv_t<T>; |
3105 | | using pointer = T*; |
3106 | | using const_pointer = const T*; |
3107 | | using reference = T&; |
3108 | | using const_reference = const T&; |
3109 | | using iterator = pointer; |
3110 | | using const_iterator = const_pointer; |
3111 | | using reverse_iterator = std::reverse_iterator<iterator>; |
3112 | | using const_reverse_iterator = std::reverse_iterator<const_iterator>; |
3113 | | using size_type = size_t; |
3114 | | using difference_type = ptrdiff_t; |
3115 | | |
3116 | | static const size_type npos = ~(size_type(0)); |
3117 | | |
3118 | | constexpr Span() noexcept : Span(nullptr, 0) {} |
3119 | | constexpr Span(pointer array, size_type lgth) noexcept |
3120 | | : ptr_(array), len_(lgth) {} |
3121 | | |
3122 | | // Implicit conversion constructors |
3123 | | template <size_t N> |
3124 | | constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit) |
3125 | | : Span(a, N) {} |
3126 | | |
3127 | | // Explicit reference constructor for a mutable `Span<T>` type. Can be |
3128 | | // replaced with MakeSpan() to infer the type parameter. |
3129 | | template <typename V, typename = EnableIfConvertibleFrom<V>, |
3130 | | typename = EnableIfMutableView<V>> |
3131 | | explicit Span(V& v) noexcept // NOLINT(runtime/references) |
3132 | | : Span(span_internal::GetData(v), v.size()) {} |
3133 | | |
3134 | | // Implicit reference constructor for a read-only `Span<const T>` type |
3135 | | template <typename V, typename = EnableIfConvertibleFrom<V>, |
3136 | | typename = EnableIfConstView<V>> |
3137 | | constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit) |
3138 | | : Span(span_internal::GetData(v), v.size()) {} |
3139 | | |
3140 | | // Implicit constructor from an initializer list, making it possible to pass a |
3141 | | // brace-enclosed initializer list to a function expecting a `Span`. Such |
3142 | | // spans constructed from an initializer list must be of type `Span<const T>`. |
3143 | | // |
3144 | | // void Process(phmap::Span<const int> x); |
3145 | | // Process({1, 2, 3}); |
3146 | | // |
3147 | | // Note that as always the array referenced by the span must outlive the span. |
3148 | | // Since an initializer list constructor acts as if it is fed a temporary |
3149 | | // array (cf. C++ standard [dcl.init.list]/5), it's safe to use this |
3150 | | // constructor only when the `std::initializer_list` itself outlives the span. |
3151 | | // In order to meet this requirement it's sufficient to ensure that neither |
3152 | | // the span nor a copy of it is used outside of the expression in which it's |
3153 | | // created: |
3154 | | // |
3155 | | // // Assume that this function uses the array directly, not retaining any |
3156 | | // // copy of the span or pointer to any of its elements. |
3157 | | // void Process(phmap::Span<const int> ints); |
3158 | | // |
3159 | | // // Okay: the std::initializer_list<int> will reference a temporary array |
3160 | | // // that isn't destroyed until after the call to Process returns. |
3161 | | // Process({ 17, 19 }); |
3162 | | // |
3163 | | // // Not okay: the storage used by the std::initializer_list<int> is not |
3164 | | // // allowed to be referenced after the first line. |
3165 | | // phmap::Span<const int> ints = { 17, 19 }; |
3166 | | // Process(ints); |
3167 | | // |
3168 | | // // Not okay for the same reason as above: even when the elements of the |
3169 | | // // initializer list expression are not temporaries the underlying array |
3170 | | // // is, so the initializer list must still outlive the span. |
3171 | | // const int foo = 17; |
3172 | | // phmap::Span<const int> ints = { foo }; |
3173 | | // Process(ints); |
3174 | | // |
3175 | | template <typename LazyT = T, |
3176 | | typename = EnableIfConstView<LazyT>> |
3177 | | Span( |
3178 | | std::initializer_list<value_type> v) noexcept // NOLINT(runtime/explicit) |
3179 | | : Span(v.begin(), v.size()) {} |
3180 | | |
3181 | | // Accessors |
3182 | | |
3183 | | // Span::data() |
3184 | | // |
3185 | | // Returns a pointer to the span's underlying array of data (which is held |
3186 | | // outside the span). |
3187 | | constexpr pointer data() const noexcept { return ptr_; } |
3188 | | |
3189 | | // Span::size() |
3190 | | // |
3191 | | // Returns the size of this span. |
3192 | | constexpr size_type size() const noexcept { return len_; } |
3193 | | |
3194 | | // Span::length() |
3195 | | // |
3196 | | // Returns the length (size) of this span. |
3197 | | constexpr size_type length() const noexcept { return size(); } |
3198 | | |
3199 | | // Span::empty() |
3200 | | // |
3201 | | // Returns a boolean indicating whether or not this span is considered empty. |
3202 | | constexpr bool empty() const noexcept { return size() == 0; } |
3203 | | |
3204 | | // Span::operator[] |
3205 | | // |
3206 | | // Returns a reference to the i'th element of this span. |
3207 | | constexpr reference operator[](size_type i) const noexcept { |
3208 | | // MSVC 2015 accepts this as constexpr, but not ptr_[i] |
3209 | | return *(data() + i); |
3210 | | } |
3211 | | |
3212 | | // Span::at() |
3213 | | // |
3214 | | // Returns a reference to the i'th element of this span. |
3215 | | constexpr reference at(size_type i) const { |
3216 | | return PHMAP_PREDICT_TRUE(i < size()) // |
3217 | | ? *(data() + i) |
3218 | | : (base_internal::ThrowStdOutOfRange( |
3219 | | "Span::at failed bounds check"), |
3220 | | *(data() + i)); |
3221 | | } |
3222 | | |
3223 | | // Span::front() |
3224 | | // |
3225 | | // Returns a reference to the first element of this span. |
3226 | | constexpr reference front() const noexcept { |
3227 | | return PHMAP_ASSERT(size() > 0), *data(); |
3228 | | } |
3229 | | |
3230 | | // Span::back() |
3231 | | // |
3232 | | // Returns a reference to the last element of this span. |
3233 | | constexpr reference back() const noexcept { |
3234 | | return PHMAP_ASSERT(size() > 0), *(data() + size() - 1); |
3235 | | } |
3236 | | |
3237 | | // Span::begin() |
3238 | | // |
3239 | | // Returns an iterator to the first element of this span. |
3240 | | constexpr iterator begin() const noexcept { return data(); } |
3241 | | |
3242 | | // Span::cbegin() |
3243 | | // |
3244 | | // Returns a const iterator to the first element of this span. |
3245 | | constexpr const_iterator cbegin() const noexcept { return begin(); } |
3246 | | |
3247 | | // Span::end() |
3248 | | // |
3249 | | // Returns an iterator to the last element of this span. |
3250 | | constexpr iterator end() const noexcept { return data() + size(); } |
3251 | | |
3252 | | // Span::cend() |
3253 | | // |
3254 | | // Returns a const iterator to the last element of this span. |
3255 | | constexpr const_iterator cend() const noexcept { return end(); } |
3256 | | |
3257 | | // Span::rbegin() |
3258 | | // |
3259 | | // Returns a reverse iterator starting at the last element of this span. |
3260 | | constexpr reverse_iterator rbegin() const noexcept { |
3261 | | return reverse_iterator(end()); |
3262 | | } |
3263 | | |
3264 | | // Span::crbegin() |
3265 | | // |
3266 | | // Returns a reverse const iterator starting at the last element of this span. |
3267 | | constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } |
3268 | | |
3269 | | // Span::rend() |
3270 | | // |
3271 | | // Returns a reverse iterator starting at the first element of this span. |
3272 | | constexpr reverse_iterator rend() const noexcept { |
3273 | | return reverse_iterator(begin()); |
3274 | | } |
3275 | | |
3276 | | // Span::crend() |
3277 | | // |
3278 | | // Returns a reverse iterator starting at the first element of this span. |
3279 | | constexpr const_reverse_iterator crend() const noexcept { return rend(); } |
3280 | | |
3281 | | // Span mutations |
3282 | | |
3283 | | // Span::remove_prefix() |
3284 | | // |
3285 | | // Removes the first `n` elements from the span. |
3286 | | void remove_prefix(size_type n) noexcept { |
3287 | | assert(size() >= n); |
3288 | | ptr_ += n; |
3289 | | len_ -= n; |
3290 | | } |
3291 | | |
3292 | | // Span::remove_suffix() |
3293 | | // |
3294 | | // Removes the last `n` elements from the span. |
3295 | | void remove_suffix(size_type n) noexcept { |
3296 | | assert(size() >= n); |
3297 | | len_ -= n; |
3298 | | } |
3299 | | |
3300 | | // Span::subspan() |
3301 | | // |
3302 | | // Returns a `Span` starting at element `pos` and of length `len`. Both `pos` |
3303 | | // and `len` are of type `size_type` and thus non-negative. Parameter `pos` |
3304 | | // must be <= size(). Any `len` value that points past the end of the span |
3305 | | // will be trimmed to at most size() - `pos`. A default `len` value of `npos` |
3306 | | // ensures the returned subspan continues until the end of the span. |
3307 | | // |
3308 | | // Examples: |
3309 | | // |
3310 | | // std::vector<int> vec = {10, 11, 12, 13}; |
3311 | | // phmap::MakeSpan(vec).subspan(1, 2); // {11, 12} |
3312 | | // phmap::MakeSpan(vec).subspan(2, 8); // {12, 13} |
3313 | | // phmap::MakeSpan(vec).subspan(1); // {11, 12, 13} |
3314 | | // phmap::MakeSpan(vec).subspan(4); // {} |
3315 | | // phmap::MakeSpan(vec).subspan(5); // throws std::out_of_range |
3316 | | constexpr Span subspan(size_type pos = 0, size_type len = npos) const { |
3317 | | return (pos <= size()) |
3318 | | ? Span(data() + pos, span_internal::Min(size() - pos, len)) |
3319 | | : (base_internal::ThrowStdOutOfRange("pos > size()"), Span()); |
3320 | | } |
3321 | | |
3322 | | // Span::first() |
3323 | | // |
3324 | | // Returns a `Span` containing first `len` elements. Parameter `len` is of |
3325 | | // type `size_type` and thus non-negative. `len` value must be <= size(). |
3326 | | // |
3327 | | // Examples: |
3328 | | // |
3329 | | // std::vector<int> vec = {10, 11, 12, 13}; |
3330 | | // phmap::MakeSpan(vec).first(1); // {10} |
3331 | | // phmap::MakeSpan(vec).first(3); // {10, 11, 12} |
3332 | | // phmap::MakeSpan(vec).first(5); // throws std::out_of_range |
3333 | | constexpr Span first(size_type len) const { |
3334 | | return (len <= size()) |
3335 | | ? Span(data(), len) |
3336 | | : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); |
3337 | | } |
3338 | | |
3339 | | // Span::last() |
3340 | | // |
3341 | | // Returns a `Span` containing last `len` elements. Parameter `len` is of |
3342 | | // type `size_type` and thus non-negative. `len` value must be <= size(). |
3343 | | // |
3344 | | // Examples: |
3345 | | // |
3346 | | // std::vector<int> vec = {10, 11, 12, 13}; |
3347 | | // phmap::MakeSpan(vec).last(1); // {13} |
3348 | | // phmap::MakeSpan(vec).last(3); // {11, 12, 13} |
3349 | | // phmap::MakeSpan(vec).last(5); // throws std::out_of_range |
3350 | | constexpr Span last(size_type len) const { |
3351 | | return (len <= size()) |
3352 | | ? Span(size() - len + data(), len) |
3353 | | : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); |
3354 | | } |
3355 | | |
3356 | | // Support for phmap::Hash. |
3357 | | template <typename H> |
3358 | | friend H AbslHashValue(H h, Span v) { |
3359 | | return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()), |
3360 | | v.size()); |
3361 | | } |
3362 | | |
3363 | | private: |
3364 | | pointer ptr_; |
3365 | | size_type len_; |
3366 | | }; |
3367 | | |
3368 | | template <typename T> |
3369 | | const typename Span<T>::size_type Span<T>::npos; |
3370 | | |
3371 | | // Span relationals |
3372 | | |
3373 | | // Equality is compared element-by-element, while ordering is lexicographical. |
3374 | | // We provide three overloads for each operator to cover any combination on the |
3375 | | // left or right hand side of mutable Span<T>, read-only Span<const T>, and |
3376 | | // convertible-to-read-only Span<T>. |
3377 | | // TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering |
3378 | | // template functions, 5 overloads per operator is needed as a workaround. We |
3379 | | // should update them to 3 overloads per operator using non-deduced context like |
3380 | | // string_view, i.e. |
3381 | | // - (Span<T>, Span<T>) |
3382 | | // - (Span<T>, non_deduced<Span<const T>>) |
3383 | | // - (non_deduced<Span<const T>>, Span<T>) |
3384 | | |
3385 | | // operator== |
3386 | | template <typename T> |
3387 | | bool operator==(Span<T> a, Span<T> b) { |
3388 | | return span_internal::EqualImpl<const T>(a, b); |
3389 | | } |
3390 | | |
3391 | | template <typename T> |
3392 | | bool operator==(Span<const T> a, Span<T> b) { |
3393 | | return span_internal::EqualImpl<const T>(a, b); |
3394 | | } |
3395 | | |
3396 | | template <typename T> |
3397 | | bool operator==(Span<T> a, Span<const T> b) { |
3398 | | return span_internal::EqualImpl<const T>(a, b); |
3399 | | } |
3400 | | |
3401 | | template <typename T, typename U, |
3402 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3403 | | bool operator==(const U& a, Span<T> b) { |
3404 | | return span_internal::EqualImpl<const T>(a, b); |
3405 | | } |
3406 | | |
3407 | | template <typename T, typename U, |
3408 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3409 | | bool operator==(Span<T> a, const U& b) { |
3410 | | return span_internal::EqualImpl<const T>(a, b); |
3411 | | } |
3412 | | |
3413 | | // operator!= |
3414 | | template <typename T> |
3415 | | bool operator!=(Span<T> a, Span<T> b) { |
3416 | | return !(a == b); |
3417 | | } |
3418 | | |
3419 | | template <typename T> |
3420 | | bool operator!=(Span<const T> a, Span<T> b) { |
3421 | | return !(a == b); |
3422 | | } |
3423 | | |
3424 | | template <typename T> |
3425 | | bool operator!=(Span<T> a, Span<const T> b) { |
3426 | | return !(a == b); |
3427 | | } |
3428 | | |
3429 | | template <typename T, typename U, |
3430 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3431 | | bool operator!=(const U& a, Span<T> b) { |
3432 | | return !(a == b); |
3433 | | } |
3434 | | |
3435 | | template <typename T, typename U, |
3436 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3437 | | bool operator!=(Span<T> a, const U& b) { |
3438 | | return !(a == b); |
3439 | | } |
3440 | | |
3441 | | // operator< |
3442 | | template <typename T> |
3443 | | bool operator<(Span<T> a, Span<T> b) { |
3444 | | return span_internal::LessThanImpl<const T>(a, b); |
3445 | | } |
3446 | | |
3447 | | template <typename T> |
3448 | | bool operator<(Span<const T> a, Span<T> b) { |
3449 | | return span_internal::LessThanImpl<const T>(a, b); |
3450 | | } |
3451 | | |
3452 | | template <typename T> |
3453 | | bool operator<(Span<T> a, Span<const T> b) { |
3454 | | return span_internal::LessThanImpl<const T>(a, b); |
3455 | | } |
3456 | | |
3457 | | template <typename T, typename U, |
3458 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3459 | | bool operator<(const U& a, Span<T> b) { |
3460 | | return span_internal::LessThanImpl<const T>(a, b); |
3461 | | } |
3462 | | |
3463 | | template <typename T, typename U, |
3464 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3465 | | bool operator<(Span<T> a, const U& b) { |
3466 | | return span_internal::LessThanImpl<const T>(a, b); |
3467 | | } |
3468 | | |
3469 | | // operator> |
3470 | | template <typename T> |
3471 | | bool operator>(Span<T> a, Span<T> b) { |
3472 | | return b < a; |
3473 | | } |
3474 | | |
3475 | | template <typename T> |
3476 | | bool operator>(Span<const T> a, Span<T> b) { |
3477 | | return b < a; |
3478 | | } |
3479 | | |
3480 | | template <typename T> |
3481 | | bool operator>(Span<T> a, Span<const T> b) { |
3482 | | return b < a; |
3483 | | } |
3484 | | |
3485 | | template <typename T, typename U, |
3486 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3487 | | bool operator>(const U& a, Span<T> b) { |
3488 | | return b < a; |
3489 | | } |
3490 | | |
3491 | | template <typename T, typename U, |
3492 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3493 | | bool operator>(Span<T> a, const U& b) { |
3494 | | return b < a; |
3495 | | } |
3496 | | |
3497 | | // operator<= |
3498 | | template <typename T> |
3499 | | bool operator<=(Span<T> a, Span<T> b) { |
3500 | | return !(b < a); |
3501 | | } |
3502 | | |
3503 | | template <typename T> |
3504 | | bool operator<=(Span<const T> a, Span<T> b) { |
3505 | | return !(b < a); |
3506 | | } |
3507 | | |
3508 | | template <typename T> |
3509 | | bool operator<=(Span<T> a, Span<const T> b) { |
3510 | | return !(b < a); |
3511 | | } |
3512 | | |
3513 | | template <typename T, typename U, |
3514 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3515 | | bool operator<=(const U& a, Span<T> b) { |
3516 | | return !(b < a); |
3517 | | } |
3518 | | |
3519 | | template <typename T, typename U, |
3520 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3521 | | bool operator<=(Span<T> a, const U& b) { |
3522 | | return !(b < a); |
3523 | | } |
3524 | | |
3525 | | // operator>= |
3526 | | template <typename T> |
3527 | | bool operator>=(Span<T> a, Span<T> b) { |
3528 | | return !(a < b); |
3529 | | } |
3530 | | |
3531 | | template <typename T> |
3532 | | bool operator>=(Span<const T> a, Span<T> b) { |
3533 | | return !(a < b); |
3534 | | } |
3535 | | |
3536 | | template <typename T> |
3537 | | bool operator>=(Span<T> a, Span<const T> b) { |
3538 | | return !(a < b); |
3539 | | } |
3540 | | |
3541 | | template <typename T, typename U, |
3542 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3543 | | bool operator>=(const U& a, Span<T> b) { |
3544 | | return !(a < b); |
3545 | | } |
3546 | | |
3547 | | template <typename T, typename U, |
3548 | | typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> |
3549 | | bool operator>=(Span<T> a, const U& b) { |
3550 | | return !(a < b); |
3551 | | } |
3552 | | |
3553 | | // MakeSpan() |
3554 | | // |
3555 | | // Constructs a mutable `Span<T>`, deducing `T` automatically from either a |
3556 | | // container or pointer+size. |
3557 | | // |
3558 | | // Because a read-only `Span<const T>` is implicitly constructed from container |
3559 | | // types regardless of whether the container itself is a const container, |
3560 | | // constructing mutable spans of type `Span<T>` from containers requires |
3561 | | // explicit constructors. The container-accepting version of `MakeSpan()` |
3562 | | // deduces the type of `T` by the constness of the pointer received from the |
3563 | | // container's `data()` member. Similarly, the pointer-accepting version returns |
3564 | | // a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise. |
3565 | | // |
3566 | | // Examples: |
3567 | | // |
3568 | | // void MyRoutine(phmap::Span<MyComplicatedType> a) { |
3569 | | // ... |
3570 | | // }; |
3571 | | // // my_vector is a container of non-const types |
3572 | | // std::vector<MyComplicatedType> my_vector; |
3573 | | // |
3574 | | // // Constructing a Span implicitly attempts to create a Span of type |
3575 | | // // `Span<const T>` |
3576 | | // MyRoutine(my_vector); // error, type mismatch |
3577 | | // |
3578 | | // // Explicitly constructing the Span is verbose |
3579 | | // MyRoutine(phmap::Span<MyComplicatedType>(my_vector)); |
3580 | | // |
3581 | | // // Use MakeSpan() to make an phmap::Span<T> |
3582 | | // MyRoutine(phmap::MakeSpan(my_vector)); |
3583 | | // |
3584 | | // // Construct a span from an array ptr+size |
3585 | | // phmap::Span<T> my_span() { |
3586 | | // return phmap::MakeSpan(&array[0], num_elements_); |
3587 | | // } |
3588 | | // |
3589 | | template <int&... ExplicitArgumentBarrier, typename T> |
3590 | | constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept { |
3591 | | return Span<T>(ptr, size); |
3592 | | } |
3593 | | |
3594 | | template <int&... ExplicitArgumentBarrier, typename T> |
3595 | | Span<T> MakeSpan(T* begin, T* end) noexcept { |
3596 | | return PHMAP_ASSERT(begin <= end), Span<T>(begin, end - begin); |
3597 | | } |
3598 | | |
3599 | | template <int&... ExplicitArgumentBarrier, typename C> |
3600 | | constexpr auto MakeSpan(C& c) noexcept // NOLINT(runtime/references) |
3601 | | -> decltype(phmap::MakeSpan(span_internal::GetData(c), c.size())) { |
3602 | | return MakeSpan(span_internal::GetData(c), c.size()); |
3603 | | } |
3604 | | |
3605 | | template <int&... ExplicitArgumentBarrier, typename T, size_t N> |
3606 | | constexpr Span<T> MakeSpan(T (&array)[N]) noexcept { |
3607 | | return Span<T>(array, N); |
3608 | | } |
3609 | | |
3610 | | // MakeConstSpan() |
3611 | | // |
3612 | | // Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically, |
3613 | | // but always returning a `Span<const T>`. |
3614 | | // |
3615 | | // Examples: |
3616 | | // |
3617 | | // void ProcessInts(phmap::Span<const int> some_ints); |
3618 | | // |
3619 | | // // Call with a pointer and size. |
3620 | | // int array[3] = { 0, 0, 0 }; |
3621 | | // ProcessInts(phmap::MakeConstSpan(&array[0], 3)); |
3622 | | // |
3623 | | // // Call with a [begin, end) pair. |
3624 | | // ProcessInts(phmap::MakeConstSpan(&array[0], &array[3])); |
3625 | | // |
3626 | | // // Call directly with an array. |
3627 | | // ProcessInts(phmap::MakeConstSpan(array)); |
3628 | | // |
3629 | | // // Call with a contiguous container. |
3630 | | // std::vector<int> some_ints = ...; |
3631 | | // ProcessInts(phmap::MakeConstSpan(some_ints)); |
3632 | | // ProcessInts(phmap::MakeConstSpan(std::vector<int>{ 0, 0, 0 })); |
3633 | | // |
3634 | | template <int&... ExplicitArgumentBarrier, typename T> |
3635 | | constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept { |
3636 | | return Span<const T>(ptr, size); |
3637 | | } |
3638 | | |
3639 | | template <int&... ExplicitArgumentBarrier, typename T> |
3640 | | Span<const T> MakeConstSpan(T* begin, T* end) noexcept { |
3641 | | return PHMAP_ASSERT(begin <= end), Span<const T>(begin, end - begin); |
3642 | | } |
3643 | | |
3644 | | template <int&... ExplicitArgumentBarrier, typename C> |
3645 | | constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) { |
3646 | | return MakeSpan(c); |
3647 | | } |
3648 | | |
3649 | | template <int&... ExplicitArgumentBarrier, typename T, size_t N> |
3650 | | constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept { |
3651 | | return Span<const T>(array, N); |
3652 | | } |
3653 | | } // namespace phmap |
3654 | | |
3655 | | // --------------------------------------------------------------------------- |
3656 | | // layout.h |
3657 | | // --------------------------------------------------------------------------- |
3658 | | namespace phmap { |
3659 | | namespace priv { |
3660 | | |
3661 | | // A type wrapper that instructs `Layout` to use the specific alignment for the |
3662 | | // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API |
3663 | | // and behavior as `Layout<..., T, ...>` except that the first element of the |
3664 | | // array of `T` is aligned to `N` (the rest of the elements follow without |
3665 | | // padding). |
3666 | | // |
3667 | | // Requires: `N >= alignof(T)` and `N` is a power of 2. |
3668 | | template <class T, size_t N> |
3669 | | struct Aligned; |
3670 | | |
3671 | | namespace internal_layout { |
3672 | | |
3673 | | template <class T> |
3674 | | struct NotAligned {}; |
3675 | | |
3676 | | template <class T, size_t N> |
3677 | | struct NotAligned<const Aligned<T, N>> { |
3678 | | static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified"); |
3679 | | }; |
3680 | | |
3681 | | template <size_t> |
3682 | | using IntToSize = size_t; |
3683 | | |
3684 | | template <class> |
3685 | | using TypeToSize = size_t; |
3686 | | |
3687 | | template <class T> |
3688 | | struct Type : NotAligned<T> { |
3689 | | using type = T; |
3690 | | }; |
3691 | | |
3692 | | template <class T, size_t N> |
3693 | | struct Type<Aligned<T, N>> { |
3694 | | using type = T; |
3695 | | }; |
3696 | | |
3697 | | template <class T> |
3698 | | struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {}; |
3699 | | |
3700 | | template <class T, size_t N> |
3701 | | struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {}; |
3702 | | |
3703 | | // Note: workaround for https://gcc.gnu.org/PR88115 |
3704 | | template <class T> |
3705 | | struct AlignOf : NotAligned<T> { |
3706 | | static constexpr size_t value = alignof(T); |
3707 | | }; |
3708 | | |
3709 | | template <class T, size_t N> |
3710 | | struct AlignOf<Aligned<T, N>> { |
3711 | | static_assert(N % alignof(T) == 0, |
3712 | | "Custom alignment can't be lower than the type's alignment"); |
3713 | | static constexpr size_t value = N; |
3714 | | }; |
3715 | | |
3716 | | // Does `Ts...` contain `T`? |
3717 | | template <class T, class... Ts> |
3718 | | using Contains = phmap::disjunction<std::is_same<T, Ts>...>; |
3719 | | |
3720 | | template <class From, class To> |
3721 | | using CopyConst = |
3722 | | typename std::conditional<std::is_const<From>::value, const To, To>::type; |
3723 | | |
3724 | | // Note: We're not qualifying this with phmap:: because it doesn't compile under |
3725 | | // MSVC. |
3726 | | template <class T> |
3727 | | using SliceType = Span<T>; |
3728 | | |
3729 | | // This namespace contains no types. It prevents functions defined in it from |
3730 | | // being found by ADL. |
3731 | | namespace adl_barrier { |
3732 | | |
3733 | | template <class Needle, class... Ts> |
3734 | | constexpr size_t Find(Needle, Needle, Ts...) { |
3735 | | static_assert(!Contains<Needle, Ts...>(), "Duplicate element type"); |
3736 | | return 0; |
3737 | | } |
3738 | | |
3739 | | template <class Needle, class T, class... Ts> |
3740 | | constexpr size_t Find(Needle, T, Ts...) { |
3741 | | return adl_barrier::Find(Needle(), Ts()...) + 1; |
3742 | | } |
3743 | | |
3744 | 0 | constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); } |
3745 | | |
3746 | | // Returns `q * m` for the smallest `q` such that `q * m >= n`. |
3747 | | // Requires: `m` is a power of two. It's enforced by IsLegalElementType below. |
3748 | 8.38k | constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); } |
3749 | | |
3750 | 0 | constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; } |
3751 | | |
3752 | 0 | constexpr size_t Max(size_t a) { return a; } |
3753 | | |
3754 | | template <class... Ts> |
3755 | 0 | constexpr size_t Max(size_t a, size_t b, Ts... rest) { |
3756 | 0 | return adl_barrier::Max(b < a ? a : b, rest...); |
3757 | 0 | } |
3758 | | |
3759 | | } // namespace adl_barrier |
3760 | | |
3761 | | template <bool C> |
3762 | | using EnableIf = typename std::enable_if<C, int>::type; |
3763 | | |
3764 | | // Can `T` be a template argument of `Layout`? |
3765 | | // --------------------------------------------------------------------------- |
3766 | | template <class T> |
3767 | | using IsLegalElementType = std::integral_constant< |
3768 | | bool, !std::is_reference<T>::value && !std::is_volatile<T>::value && |
3769 | | !std::is_reference<typename Type<T>::type>::value && |
3770 | | !std::is_volatile<typename Type<T>::type>::value && |
3771 | | adl_barrier::IsPow2(AlignOf<T>::value)>; |
3772 | | |
3773 | | template <class Elements, class SizeSeq, class OffsetSeq> |
3774 | | class LayoutImpl; |
3775 | | |
3776 | | // --------------------------------------------------------------------------- |
3777 | | // Public base class of `Layout` and the result type of `Layout::Partial()`. |
3778 | | // |
3779 | | // `Elements...` contains all template arguments of `Layout` that created this |
3780 | | // instance. |
3781 | | // |
3782 | | // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments |
3783 | | // passed to `Layout::Partial()` or `Layout::Layout()`. |
3784 | | // |
3785 | | // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is |
3786 | | // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we |
3787 | | // can compute offsets). |
3788 | | // --------------------------------------------------------------------------- |
3789 | | template <class... Elements, size_t... SizeSeq, size_t... OffsetSeq> |
3790 | | class LayoutImpl<std::tuple<Elements...>, phmap::index_sequence<SizeSeq...>, |
3791 | | phmap::index_sequence<OffsetSeq...>> |
3792 | | { |
3793 | | private: |
3794 | | static_assert(sizeof...(Elements) > 0, "At least one field is required"); |
3795 | | static_assert(phmap::conjunction<IsLegalElementType<Elements>...>::value, |
3796 | | "Invalid element type (see IsLegalElementType)"); |
3797 | | |
3798 | | enum { |
3799 | | NumTypes = sizeof...(Elements), |
3800 | | NumSizes = sizeof...(SizeSeq), |
3801 | | NumOffsets = sizeof...(OffsetSeq), |
3802 | | }; |
3803 | | |
3804 | | // These are guaranteed by `Layout`. |
3805 | | static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1), |
3806 | | "Internal error"); |
3807 | | static_assert(NumTypes > 0, "Internal error"); |
3808 | | |
3809 | | // Returns the index of `T` in `Elements...`. Results in a compilation error |
3810 | | // if `Elements...` doesn't contain exactly one instance of `T`. |
3811 | | template <class T> |
3812 | | static constexpr size_t ElementIndex() { |
3813 | | static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(), |
3814 | | "Type not found"); |
3815 | | return adl_barrier::Find(Type<T>(), |
3816 | | Type<typename Type<Elements>::type>()...); |
3817 | | } |
3818 | | |
3819 | | template <size_t N> |
3820 | | using ElementAlignment = |
3821 | | AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>; |
3822 | | |
3823 | | public: |
3824 | | // Element types of all arrays packed in a tuple. |
3825 | | using ElementTypes = std::tuple<typename Type<Elements>::type...>; |
3826 | | |
3827 | | // Element type of the Nth array. |
3828 | | template <size_t N> |
3829 | | using ElementType = typename std::tuple_element<N, ElementTypes>::type; |
3830 | | |
3831 | | constexpr explicit LayoutImpl(IntToSize<SizeSeq>... sizes) |
3832 | 5.58k | : size_{sizes...} {} phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<unsigned int, int> >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::LayoutImpl(unsigned long, unsigned long) Line | Count | Source | 3832 | 5.58k | : size_{sizes...} {} |
Unexecuted instantiation: phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::LayoutImpl(unsigned long, unsigned long) |
3833 | | |
3834 | | // Alignment of the layout, equal to the strictest alignment of all elements. |
3835 | | // All pointers passed to the methods of layout must be aligned to this value. |
3836 | 0 | static constexpr size_t Alignment() { |
3837 | 0 | return adl_barrier::Max(AlignOf<Elements>::value...); |
3838 | 0 | } Unexecuted instantiation: phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<unsigned int, int> >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::Alignment() Unexecuted instantiation: phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::Alignment() |
3839 | | |
3840 | | // Offset in bytes of the Nth array. |
3841 | | // |
3842 | | // // int[3], 4 bytes of padding, double[4]. |
3843 | | // Layout<int, double> x(3, 4); |
3844 | | // assert(x.Offset<0>() == 0); // The ints starts from 0. |
3845 | | // assert(x.Offset<1>() == 16); // The doubles starts from 16. |
3846 | | // |
3847 | | // Requires: `N <= NumSizes && N < sizeof...(Ts)`. |
3848 | | template <size_t N, EnableIf<N == 0> = 0> |
3849 | 11.1k | constexpr size_t Offset() const { |
3850 | 11.1k | return 0; |
3851 | 11.1k | } unsigned long phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<unsigned int, int> >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::Offset<0ul, 0>() const Line | Count | Source | 3849 | 11.1k | constexpr size_t Offset() const { | 3850 | 11.1k | return 0; | 3851 | 11.1k | } |
Unexecuted instantiation: unsigned long phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::Offset<0ul, 0>() const |
3852 | | |
3853 | | template <size_t N, EnableIf<N != 0> = 0> |
3854 | 8.38k | constexpr size_t Offset() const { |
3855 | 8.38k | static_assert(N < NumOffsets, "Index out of bounds"); |
3856 | 8.38k | return adl_barrier::Align( |
3857 | 8.38k | Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1], |
3858 | 8.38k | ElementAlignment<N>::value); |
3859 | 8.38k | } unsigned long phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<unsigned int, int> >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::Offset<1ul, 0>() const Line | Count | Source | 3854 | 8.38k | constexpr size_t Offset() const { | 3855 | 8.38k | static_assert(N < NumOffsets, "Index out of bounds"); | 3856 | 8.38k | return adl_barrier::Align( | 3857 | 8.38k | Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1], | 3858 | 8.38k | ElementAlignment<N>::value); | 3859 | 8.38k | } |
Unexecuted instantiation: unsigned long phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::Offset<1ul, 0>() const |
3860 | | |
3861 | | // Offset in bytes of the array with the specified element type. There must |
3862 | | // be exactly one such array and its zero-based index must be at most |
3863 | | // `NumSizes`. |
3864 | | // |
3865 | | // // int[3], 4 bytes of padding, double[4]. |
3866 | | // Layout<int, double> x(3, 4); |
3867 | | // assert(x.Offset<int>() == 0); // The ints starts from 0. |
3868 | | // assert(x.Offset<double>() == 16); // The doubles starts from 16. |
3869 | | template <class T> |
3870 | | constexpr size_t Offset() const { |
3871 | | return Offset<ElementIndex<T>()>(); |
3872 | | } |
3873 | | |
3874 | | // Offsets in bytes of all arrays for which the offsets are known. |
3875 | | constexpr std::array<size_t, NumOffsets> Offsets() const { |
3876 | | return {{Offset<OffsetSeq>()...}}; |
3877 | | } |
3878 | | |
3879 | | // The number of elements in the Nth array. This is the Nth argument of |
3880 | | // `Layout::Partial()` or `Layout::Layout()` (zero-based). |
3881 | | // |
3882 | | // // int[3], 4 bytes of padding, double[4]. |
3883 | | // Layout<int, double> x(3, 4); |
3884 | | // assert(x.Size<0>() == 3); |
3885 | | // assert(x.Size<1>() == 4); |
3886 | | // |
3887 | | // Requires: `N < NumSizes`. |
3888 | | template <size_t N> |
3889 | | constexpr size_t Size() const { |
3890 | | static_assert(N < NumSizes, "Index out of bounds"); |
3891 | | return size_[N]; |
3892 | | } |
3893 | | |
3894 | | // The number of elements in the array with the specified element type. |
3895 | | // There must be exactly one such array and its zero-based index must be |
3896 | | // at most `NumSizes`. |
3897 | | // |
3898 | | // // int[3], 4 bytes of padding, double[4]. |
3899 | | // Layout<int, double> x(3, 4); |
3900 | | // assert(x.Size<int>() == 3); |
3901 | | // assert(x.Size<double>() == 4); |
3902 | | template <class T> |
3903 | | constexpr size_t Size() const { |
3904 | | return Size<ElementIndex<T>()>(); |
3905 | | } |
3906 | | |
3907 | | // The number of elements of all arrays for which they are known. |
3908 | | constexpr std::array<size_t, NumSizes> Sizes() const { |
3909 | | return {{Size<SizeSeq>()...}}; |
3910 | | } |
3911 | | |
3912 | | // Pointer to the beginning of the Nth array. |
3913 | | // |
3914 | | // `Char` must be `[const] [signed|unsigned] char`. |
3915 | | // |
3916 | | // // int[3], 4 bytes of padding, double[4]. |
3917 | | // Layout<int, double> x(3, 4); |
3918 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
3919 | | // int* ints = x.Pointer<0>(p); |
3920 | | // double* doubles = x.Pointer<1>(p); |
3921 | | // |
3922 | | // Requires: `N <= NumSizes && N < sizeof...(Ts)`. |
3923 | | // Requires: `p` is aligned to `Alignment()`. |
3924 | | template <size_t N, class Char> |
3925 | 5.58k | CopyConst<Char, ElementType<N>>* Pointer(Char* p) const { |
3926 | 5.58k | using C = typename std::remove_const<Char>::type; |
3927 | 5.58k | static_assert( |
3928 | 5.58k | std::is_same<C, char>() || std::is_same<C, unsigned char>() || |
3929 | 5.58k | std::is_same<C, signed char>(), |
3930 | 5.58k | "The argument must be a pointer to [const] [signed|unsigned] char"); |
3931 | 5.58k | constexpr size_t alignment = Alignment(); |
3932 | 5.58k | (void)alignment; |
3933 | 5.58k | assert(reinterpret_cast<uintptr_t>(p) % alignment == 0); |
3934 | 0 | return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>()); |
3935 | 5.58k | } _ZNK5phmap4priv15internal_layout10LayoutImplINSt3__15tupleIJaNS0_13map_slot_typeIjiEEEEENS_16integer_sequenceImJLm0ELm1EEEES9_E7PointerILm0EcEEPNS3_11conditionalIXsr3std8is_constIT0_EE5valueEKNS3_13tuple_elementIXT_ES7_E4typeESG_E4typeEPSD_ Line | Count | Source | 3925 | 2.79k | CopyConst<Char, ElementType<N>>* Pointer(Char* p) const { | 3926 | 2.79k | using C = typename std::remove_const<Char>::type; | 3927 | 2.79k | static_assert( | 3928 | 2.79k | std::is_same<C, char>() || std::is_same<C, unsigned char>() || | 3929 | 2.79k | std::is_same<C, signed char>(), | 3930 | 2.79k | "The argument must be a pointer to [const] [signed|unsigned] char"); | 3931 | 2.79k | constexpr size_t alignment = Alignment(); | 3932 | 2.79k | (void)alignment; | 3933 | 2.79k | assert(reinterpret_cast<uintptr_t>(p) % alignment == 0); | 3934 | 0 | return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>()); | 3935 | 2.79k | } |
_ZNK5phmap4priv15internal_layout10LayoutImplINSt3__15tupleIJaNS0_13map_slot_typeIjiEEEEENS_16integer_sequenceImJLm0ELm1EEEES9_E7PointerILm1EcEEPNS3_11conditionalIXsr3std8is_constIT0_EE5valueEKNS3_13tuple_elementIXT_ES7_E4typeESG_E4typeEPSD_ Line | Count | Source | 3925 | 2.79k | CopyConst<Char, ElementType<N>>* Pointer(Char* p) const { | 3926 | 2.79k | using C = typename std::remove_const<Char>::type; | 3927 | 2.79k | static_assert( | 3928 | 2.79k | std::is_same<C, char>() || std::is_same<C, unsigned char>() || | 3929 | 2.79k | std::is_same<C, signed char>(), | 3930 | 2.79k | "The argument must be a pointer to [const] [signed|unsigned] char"); | 3931 | 2.79k | constexpr size_t alignment = Alignment(); | 3932 | 2.79k | (void)alignment; | 3933 | 2.79k | assert(reinterpret_cast<uintptr_t>(p) % alignment == 0); | 3934 | 0 | return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>()); | 3935 | 2.79k | } |
|
3936 | | |
3937 | | // Pointer to the beginning of the array with the specified element type. |
3938 | | // There must be exactly one such array and its zero-based index must be at |
3939 | | // most `NumSizes`. |
3940 | | // |
3941 | | // `Char` must be `[const] [signed|unsigned] char`. |
3942 | | // |
3943 | | // // int[3], 4 bytes of padding, double[4]. |
3944 | | // Layout<int, double> x(3, 4); |
3945 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
3946 | | // int* ints = x.Pointer<int>(p); |
3947 | | // double* doubles = x.Pointer<double>(p); |
3948 | | // |
3949 | | // Requires: `p` is aligned to `Alignment()`. |
3950 | | template <class T, class Char> |
3951 | | CopyConst<Char, T>* Pointer(Char* p) const { |
3952 | | return Pointer<ElementIndex<T>()>(p); |
3953 | | } |
3954 | | |
3955 | | // Pointers to all arrays for which pointers are known. |
3956 | | // |
3957 | | // `Char` must be `[const] [signed|unsigned] char`. |
3958 | | // |
3959 | | // // int[3], 4 bytes of padding, double[4]. |
3960 | | // Layout<int, double> x(3, 4); |
3961 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
3962 | | // |
3963 | | // int* ints; |
3964 | | // double* doubles; |
3965 | | // std::tie(ints, doubles) = x.Pointers(p); |
3966 | | // |
3967 | | // Requires: `p` is aligned to `Alignment()`. |
3968 | | // |
3969 | | // Note: We're not using ElementType alias here because it does not compile |
3970 | | // under MSVC. |
3971 | | template <class Char> |
3972 | | std::tuple<CopyConst< |
3973 | | Char, typename std::tuple_element<OffsetSeq, ElementTypes>::type>*...> |
3974 | | Pointers(Char* p) const { |
3975 | | return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>( |
3976 | | Pointer<OffsetSeq>(p)...); |
3977 | | } |
3978 | | |
3979 | | // The Nth array. |
3980 | | // |
3981 | | // `Char` must be `[const] [signed|unsigned] char`. |
3982 | | // |
3983 | | // // int[3], 4 bytes of padding, double[4]. |
3984 | | // Layout<int, double> x(3, 4); |
3985 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
3986 | | // Span<int> ints = x.Slice<0>(p); |
3987 | | // Span<double> doubles = x.Slice<1>(p); |
3988 | | // |
3989 | | // Requires: `N < NumSizes`. |
3990 | | // Requires: `p` is aligned to `Alignment()`. |
3991 | | template <size_t N, class Char> |
3992 | | SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const { |
3993 | | return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>()); |
3994 | | } |
3995 | | |
3996 | | // The array with the specified element type. There must be exactly one |
3997 | | // such array and its zero-based index must be less than `NumSizes`. |
3998 | | // |
3999 | | // `Char` must be `[const] [signed|unsigned] char`. |
4000 | | // |
4001 | | // // int[3], 4 bytes of padding, double[4]. |
4002 | | // Layout<int, double> x(3, 4); |
4003 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
4004 | | // Span<int> ints = x.Slice<int>(p); |
4005 | | // Span<double> doubles = x.Slice<double>(p); |
4006 | | // |
4007 | | // Requires: `p` is aligned to `Alignment()`. |
4008 | | template <class T, class Char> |
4009 | | SliceType<CopyConst<Char, T>> Slice(Char* p) const { |
4010 | | return Slice<ElementIndex<T>()>(p); |
4011 | | } |
4012 | | |
4013 | | // All arrays with known sizes. |
4014 | | // |
4015 | | // `Char` must be `[const] [signed|unsigned] char`. |
4016 | | // |
4017 | | // // int[3], 4 bytes of padding, double[4]. |
4018 | | // Layout<int, double> x(3, 4); |
4019 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
4020 | | // |
4021 | | // Span<int> ints; |
4022 | | // Span<double> doubles; |
4023 | | // std::tie(ints, doubles) = x.Slices(p); |
4024 | | // |
4025 | | // Requires: `p` is aligned to `Alignment()`. |
4026 | | // |
4027 | | // Note: We're not using ElementType alias here because it does not compile |
4028 | | // under MSVC. |
4029 | | template <class Char> |
4030 | | std::tuple<SliceType<CopyConst< |
4031 | | Char, typename std::tuple_element<SizeSeq, ElementTypes>::type>>...> |
4032 | | Slices(Char* p) const { |
4033 | | // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed |
4034 | | // in 6.1). |
4035 | | (void)p; |
4036 | | return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>( |
4037 | | Slice<SizeSeq>(p)...); |
4038 | | } |
4039 | | |
4040 | | // The size of the allocation that fits all arrays. |
4041 | | // |
4042 | | // // int[3], 4 bytes of padding, double[4]. |
4043 | | // Layout<int, double> x(3, 4); |
4044 | | // unsigned char* p = new unsigned char[x.AllocSize()]; // 48 bytes |
4045 | | // |
4046 | | // Requires: `NumSizes == sizeof...(Ts)`. |
4047 | 5.58k | constexpr size_t AllocSize() const { |
4048 | 5.58k | static_assert(NumTypes == NumSizes, "You must specify sizes of all fields"); |
4049 | 5.58k | return Offset<NumTypes - 1>() + |
4050 | 5.58k | SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1]; |
4051 | 5.58k | } phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<unsigned int, int> >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::AllocSize() const Line | Count | Source | 4047 | 5.58k | constexpr size_t AllocSize() const { | 4048 | 5.58k | static_assert(NumTypes == NumSizes, "You must specify sizes of all fields"); | 4049 | 5.58k | return Offset<NumTypes - 1>() + | 4050 | 5.58k | SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1]; | 4051 | 5.58k | } |
Unexecuted instantiation: phmap::priv::internal_layout::LayoutImpl<std::__1::tuple<signed char, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, phmap::integer_sequence<unsigned long, 0ul, 1ul>, phmap::integer_sequence<unsigned long, 0ul, 1ul> >::AllocSize() const |
4052 | | |
4053 | | // If built with --config=asan, poisons padding bytes (if any) in the |
4054 | | // allocation. The pointer must point to a memory block at least |
4055 | | // `AllocSize()` bytes in length. |
4056 | | // |
4057 | | // `Char` must be `[const] [signed|unsigned] char`. |
4058 | | // |
4059 | | // Requires: `p` is aligned to `Alignment()`. |
4060 | | template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0> |
4061 | | void PoisonPadding(const Char* p) const { |
4062 | | Pointer<0>(p); // verify the requirements on `Char` and `p` |
4063 | | } |
4064 | | |
4065 | | template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0> |
4066 | | void PoisonPadding(const Char* p) const { |
4067 | | static_assert(N < NumOffsets, "Index out of bounds"); |
4068 | | (void)p; |
4069 | | #ifdef ADDRESS_SANITIZER |
4070 | | PoisonPadding<Char, N - 1>(p); |
4071 | | // The `if` is an optimization. It doesn't affect the observable behaviour. |
4072 | | if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) { |
4073 | | size_t start = |
4074 | | Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1]; |
4075 | | ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start); |
4076 | | } |
4077 | | #endif |
4078 | | } |
4079 | | |
4080 | | private: |
4081 | | // Arguments of `Layout::Partial()` or `Layout::Layout()`. |
4082 | | size_t size_[NumSizes > 0 ? NumSizes : 1]; |
4083 | | }; |
4084 | | |
4085 | | template <size_t NumSizes, class... Ts> |
4086 | | using LayoutType = LayoutImpl< |
4087 | | std::tuple<Ts...>, phmap::make_index_sequence<NumSizes>, |
4088 | | phmap::make_index_sequence<adl_barrier::Min(sizeof...(Ts), NumSizes + 1)>>; |
4089 | | |
4090 | | } // namespace internal_layout |
4091 | | |
4092 | | // --------------------------------------------------------------------------- |
4093 | | // Descriptor of arrays of various types and sizes laid out in memory one after |
4094 | | // another. See the top of the file for documentation. |
4095 | | // |
4096 | | // Check out the public API of internal_layout::LayoutImpl above. The type is |
4097 | | // internal to the library but its methods are public, and they are inherited |
4098 | | // by `Layout`. |
4099 | | // --------------------------------------------------------------------------- |
4100 | | template <class... Ts> |
4101 | | class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...> |
4102 | | { |
4103 | | public: |
4104 | | static_assert(sizeof...(Ts) > 0, "At least one field is required"); |
4105 | | static_assert( |
4106 | | phmap::conjunction<internal_layout::IsLegalElementType<Ts>...>::value, |
4107 | | "Invalid element type (see IsLegalElementType)"); |
4108 | | |
4109 | | template <size_t NumSizes> |
4110 | | using PartialType = internal_layout::LayoutType<NumSizes, Ts...>; |
4111 | | |
4112 | | template <class... Sizes> |
4113 | | static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) { |
4114 | | static_assert(sizeof...(Sizes) <= sizeof...(Ts), ""); |
4115 | | return PartialType<sizeof...(Sizes)>(phmap::forward<Sizes>(sizes)...); |
4116 | | } |
4117 | | |
4118 | | // Creates a layout with the sizes of all arrays specified. If you know |
4119 | | // only the sizes of the first N arrays (where N can be zero), you can use |
4120 | | // `Partial()` defined above. The constructor is essentially equivalent to |
4121 | | // calling `Partial()` and passing in all array sizes; the constructor is |
4122 | | // provided as a convenient abbreviation. |
4123 | | // |
4124 | | // Note: The sizes of the arrays must be specified in number of elements, |
4125 | | // not in bytes. |
4126 | | constexpr explicit Layout(internal_layout::TypeToSize<Ts>... sizes) |
4127 | 5.58k | : internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...) {} phmap::priv::Layout<signed char, phmap::priv::map_slot_type<unsigned int, int> >::Layout(unsigned long, unsigned long) Line | Count | Source | 4127 | 5.58k | : internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...) {} |
Unexecuted instantiation: phmap::priv::Layout<signed char, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >::Layout(unsigned long, unsigned long) |
4128 | | }; |
4129 | | |
4130 | | |
4131 | | #ifdef _MSC_VER |
4132 | | #pragma warning(push) |
4133 | | // warning warning C4324: structure was padded due to alignment specifier |
4134 | | #pragma warning(disable : 4324) |
4135 | | #endif |
4136 | | |
4137 | | |
4138 | | // ---------------------------------------------------------------------------- |
4139 | | // Allocates at least n bytes aligned to the specified alignment. |
4140 | | // Alignment must be a power of 2. It must be positive. |
4141 | | // |
4142 | | // Note that many allocators don't honor alignment requirements above certain |
4143 | | // threshold (usually either alignof(std::max_align_t) or alignof(void*)). |
4144 | | // Allocate() doesn't apply alignment corrections. If the underlying allocator |
4145 | | // returns insufficiently alignment pointer, that's what you are going to get. |
4146 | | // ---------------------------------------------------------------------------- |
4147 | | template <size_t Alignment, class Alloc> |
4148 | 2.79k | void* Allocate(Alloc* alloc, size_t n) { |
4149 | 2.79k | static_assert(Alignment > 0, ""); |
4150 | 2.79k | assert(n && "n must be positive"); |
4151 | 0 | struct alignas(Alignment) M {}; |
4152 | 2.79k | using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>; |
4153 | 2.79k | using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>; |
4154 | 2.79k | A mem_alloc(*alloc); |
4155 | 2.79k | void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M)); |
4156 | 2.79k | assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 && |
4157 | 2.79k | "allocator does not respect alignment"); |
4158 | 0 | return p; |
4159 | 2.79k | } |
4160 | | |
4161 | | // ---------------------------------------------------------------------------- |
4162 | | // The pointer must have been previously obtained by calling |
4163 | | // Allocate<Alignment>(alloc, n). |
4164 | | // ---------------------------------------------------------------------------- |
4165 | | template <size_t Alignment, class Alloc> |
4166 | 2.79k | void Deallocate(Alloc* alloc, void* p, size_t n) { |
4167 | 2.79k | static_assert(Alignment > 0, ""); |
4168 | 2.79k | assert(n && "n must be positive"); |
4169 | 0 | struct alignas(Alignment) M {}; |
4170 | 2.79k | using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>; |
4171 | 2.79k | using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>; |
4172 | 2.79k | A mem_alloc(*alloc); |
4173 | 2.79k | AT::deallocate(mem_alloc, static_cast<M*>(p), |
4174 | 2.79k | (n + sizeof(M) - 1) / sizeof(M)); |
4175 | 2.79k | } void phmap::priv::Deallocate<4ul, std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, void*, unsigned long) Line | Count | Source | 4166 | 2.79k | void Deallocate(Alloc* alloc, void* p, size_t n) { | 4167 | 2.79k | static_assert(Alignment > 0, ""); | 4168 | 2.79k | assert(n && "n must be positive"); | 4169 | 0 | struct alignas(Alignment) M {}; | 4170 | 2.79k | using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>; | 4171 | 2.79k | using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>; | 4172 | 2.79k | A mem_alloc(*alloc); | 4173 | 2.79k | AT::deallocate(mem_alloc, static_cast<M*>(p), | 4174 | 2.79k | (n + sizeof(M) - 1) / sizeof(M)); | 4175 | 2.79k | } |
Unexecuted instantiation: void phmap::priv::Deallocate<8ul, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, void*, unsigned long) |
4176 | | |
4177 | | #ifdef _MSC_VER |
4178 | | #pragma warning(pop) |
4179 | | #endif |
4180 | | |
4181 | | // Helper functions for asan and msan. |
4182 | | // ---------------------------------------------------------------------------- |
4183 | 2.79k | inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) { |
4184 | | #ifdef ADDRESS_SANITIZER |
4185 | | ASAN_POISON_MEMORY_REGION(m, s); |
4186 | | #endif |
4187 | | #ifdef MEMORY_SANITIZER |
4188 | | __msan_poison(m, s); |
4189 | | #endif |
4190 | 2.79k | (void)m; |
4191 | 2.79k | (void)s; |
4192 | 2.79k | } |
4193 | | |
4194 | 1.63M | inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) { |
4195 | | #ifdef ADDRESS_SANITIZER |
4196 | | ASAN_UNPOISON_MEMORY_REGION(m, s); |
4197 | | #endif |
4198 | | #ifdef MEMORY_SANITIZER |
4199 | | __msan_unpoison(m, s); |
4200 | | #endif |
4201 | 1.63M | (void)m; |
4202 | 1.63M | (void)s; |
4203 | 1.63M | } |
4204 | | |
4205 | | template <typename T> |
4206 | 0 | inline void SanitizerPoisonObject(const T* object) { |
4207 | 0 | SanitizerPoisonMemoryRegion(object, sizeof(T)); |
4208 | 0 | } |
4209 | | |
4210 | | template <typename T> |
4211 | 1.63M | inline void SanitizerUnpoisonObject(const T* object) { |
4212 | 1.63M | SanitizerUnpoisonMemoryRegion(object, sizeof(T)); |
4213 | 1.63M | } |
4214 | | |
4215 | | } // namespace priv |
4216 | | } // namespace phmap |
4217 | | |
4218 | | |
4219 | | // --------------------------------------------------------------------------- |
4220 | | // thread_annotations.h |
4221 | | // --------------------------------------------------------------------------- |
4222 | | |
4223 | | #if defined(__clang__) |
4224 | | #define PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) |
4225 | | #else |
4226 | | #define PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op |
4227 | | #endif |
4228 | | |
4229 | | #define PHMAP_GUARDED_BY(x) PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) |
4230 | | #define PHMAP_PT_GUARDED_BY(x) PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) |
4231 | | |
4232 | | #define PHMAP_ACQUIRED_AFTER(...) \ |
4233 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) |
4234 | | |
4235 | | #define PHMAP_ACQUIRED_BEFORE(...) \ |
4236 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) |
4237 | | |
4238 | | #define PHMAP_EXCLUSIVE_LOCKS_REQUIRED(...) \ |
4239 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) |
4240 | | |
4241 | | #define PHMAP_SHARED_LOCKS_REQUIRED(...) \ |
4242 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) |
4243 | | |
4244 | | #define PHMAP_LOCKS_EXCLUDED(...) \ |
4245 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) |
4246 | | |
4247 | | #define PHMAP_LOCK_RETURNED(x) \ |
4248 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) |
4249 | | |
4250 | | #define PHMAP_LOCKABLE \ |
4251 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(lockable) |
4252 | | |
4253 | | #define PHMAP_SCOPED_LOCKABLE \ |
4254 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) |
4255 | | |
4256 | | #define PHMAP_EXCLUSIVE_LOCK_FUNCTION(...) \ |
4257 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) |
4258 | | |
4259 | | #define PHMAP_SHARED_LOCK_FUNCTION(...) \ |
4260 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) |
4261 | | |
4262 | | #define PHMAP_UNLOCK_FUNCTION(...) \ |
4263 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) |
4264 | | |
4265 | | #define PHMAP_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ |
4266 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) |
4267 | | |
4268 | | #define PHMAP_SHARED_TRYLOCK_FUNCTION(...) \ |
4269 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) |
4270 | | |
4271 | | #define PHMAP_ASSERT_EXCLUSIVE_LOCK(...) \ |
4272 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) |
4273 | | |
4274 | | #define PHMAP_ASSERT_SHARED_LOCK(...) \ |
4275 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) |
4276 | | |
4277 | | #define PHMAP_NO_THREAD_SAFETY_ANALYSIS \ |
4278 | | PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) |
4279 | | |
4280 | | //------------------------------------------------------------------------------ |
4281 | | // Tool-Supplied Annotations |
4282 | | //------------------------------------------------------------------------------ |
4283 | | |
4284 | | // TS_UNCHECKED should be placed around lock expressions that are not valid |
4285 | | // C++ syntax, but which are present for documentation purposes. These |
4286 | | // annotations will be ignored by the analysis. |
4287 | | #define PHMAP_TS_UNCHECKED(x) "" |
4288 | | |
4289 | | // TS_FIXME is used to mark lock expressions that are not valid C++ syntax. |
4290 | | // It is used by automated tools to mark and disable invalid expressions. |
4291 | | // The annotation should either be fixed, or changed to TS_UNCHECKED. |
4292 | | #define PHMAP_TS_FIXME(x) "" |
4293 | | |
4294 | | // Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of |
4295 | | // a particular function. However, this attribute is used to mark functions |
4296 | | // that are incorrect and need to be fixed. It is used by automated tools to |
4297 | | // avoid breaking the build when the analysis is updated. |
4298 | | // Code owners are expected to eventually fix the routine. |
4299 | | #define PHMAP_NO_THREAD_SAFETY_ANALYSIS_FIXME PHMAP_NO_THREAD_SAFETY_ANALYSIS |
4300 | | |
4301 | | // Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY |
4302 | | // annotation that needs to be fixed, because it is producing thread safety |
4303 | | // warning. It disables the GUARDED_BY. |
4304 | | #define PHMAP_GUARDED_BY_FIXME(x) |
4305 | | |
4306 | | // Disables warnings for a single read operation. This can be used to avoid |
4307 | | // warnings when it is known that the read is not actually involved in a race, |
4308 | | // but the compiler cannot confirm that. |
4309 | | #define PHMAP_TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x) |
4310 | | |
4311 | | |
4312 | | namespace phmap { |
4313 | | namespace thread_safety_analysis { |
4314 | | |
4315 | | // Takes a reference to a guarded data member, and returns an unguarded |
4316 | | // reference. |
4317 | | template <typename T> |
4318 | | inline const T& ts_unchecked_read(const T& v) PHMAP_NO_THREAD_SAFETY_ANALYSIS { |
4319 | | return v; |
4320 | | } |
4321 | | |
4322 | | template <typename T> |
4323 | | inline T& ts_unchecked_read(T& v) PHMAP_NO_THREAD_SAFETY_ANALYSIS { |
4324 | | return v; |
4325 | | } |
4326 | | |
4327 | | } // namespace thread_safety_analysis |
4328 | | |
4329 | | namespace priv { |
4330 | | |
4331 | | namespace memory_internal { |
4332 | | |
4333 | | // ---------------------------------------------------------------------------- |
4334 | | // If Pair is a standard-layout type, OffsetOf<Pair>::kFirst and |
4335 | | // OffsetOf<Pair>::kSecond are equivalent to offsetof(Pair, first) and |
4336 | | // offsetof(Pair, second) respectively. Otherwise they are -1. |
4337 | | // |
4338 | | // The purpose of OffsetOf is to avoid calling offsetof() on non-standard-layout |
4339 | | // type, which is non-portable. |
4340 | | // ---------------------------------------------------------------------------- |
4341 | | template <class Pair, class = std::true_type> |
4342 | | struct OffsetOf { |
4343 | | static constexpr size_t kFirst = (size_t)-1; |
4344 | | static constexpr size_t kSecond = (size_t)-1; |
4345 | | }; |
4346 | | |
4347 | | template <class Pair> |
4348 | | struct OffsetOf<Pair, typename std::is_standard_layout<Pair>::type> |
4349 | | { |
4350 | | static constexpr size_t kFirst = offsetof(Pair, first); |
4351 | | static constexpr size_t kSecond = offsetof(Pair, second); |
4352 | | }; |
4353 | | |
4354 | | // ---------------------------------------------------------------------------- |
4355 | | template <class K, class V> |
4356 | | struct IsLayoutCompatible |
4357 | | { |
4358 | | private: |
4359 | | struct Pair { |
4360 | | K first; |
4361 | | V second; |
4362 | | }; |
4363 | | |
4364 | | // Is P layout-compatible with Pair? |
4365 | | template <class P> |
4366 | 0 | static constexpr bool LayoutCompatible() { |
4367 | 0 | return std::is_standard_layout<P>() && sizeof(P) == sizeof(Pair) && |
4368 | 0 | alignof(P) == alignof(Pair) && |
4369 | 0 | memory_internal::OffsetOf<P>::kFirst == |
4370 | 0 | memory_internal::OffsetOf<Pair>::kFirst && |
4371 | 0 | memory_internal::OffsetOf<P>::kSecond == |
4372 | 0 | memory_internal::OffsetOf<Pair>::kSecond; |
4373 | 0 | } Unexecuted instantiation: bool phmap::priv::memory_internal::IsLayoutCompatible<unsigned int, int>::LayoutCompatible<std::__1::pair<unsigned int, int> >() Unexecuted instantiation: bool phmap::priv::memory_internal::IsLayoutCompatible<unsigned int, int>::LayoutCompatible<std::__1::pair<unsigned int const, int> >() Unexecuted instantiation: bool phmap::priv::memory_internal::IsLayoutCompatible<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::LayoutCompatible<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >() Unexecuted instantiation: bool phmap::priv::memory_internal::IsLayoutCompatible<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::LayoutCompatible<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >() |
4374 | | |
4375 | | public: |
4376 | | // Whether pair<const K, V> and pair<K, V> are layout-compatible. If they are, |
4377 | | // then it is safe to store them in a union and read from either. |
4378 | | static constexpr bool value = std::is_standard_layout<K>() && |
4379 | | std::is_standard_layout<Pair>() && |
4380 | | memory_internal::OffsetOf<Pair>::kFirst == 0 && |
4381 | | LayoutCompatible<std::pair<K, V>>() && |
4382 | | LayoutCompatible<std::pair<const K, V>>(); |
4383 | | }; |
4384 | | |
4385 | | } // namespace memory_internal |
4386 | | |
4387 | | // ---------------------------------------------------------------------------- |
4388 | | // The internal storage type for key-value containers like flat_hash_map. |
4389 | | // |
4390 | | // It is convenient for the value_type of a flat_hash_map<K, V> to be |
4391 | | // pair<const K, V>; the "const K" prevents accidental modification of the key |
4392 | | // when dealing with the reference returned from find() and similar methods. |
4393 | | // However, this creates other problems; we want to be able to emplace(K, V) |
4394 | | // efficiently with move operations, and similarly be able to move a |
4395 | | // pair<K, V> in insert(). |
4396 | | // |
4397 | | // The solution is this union, which aliases the const and non-const versions |
4398 | | // of the pair. This also allows flat_hash_map<const K, V> to work, even though |
4399 | | // that has the same efficiency issues with move in emplace() and insert() - |
4400 | | // but people do it anyway. |
4401 | | // |
4402 | | // If kMutableKeys is false, only the value member can be accessed. |
4403 | | // |
4404 | | // If kMutableKeys is true, key can be accessed through all slots while value |
4405 | | // and mutable_value must be accessed only via INITIALIZED slots. Slots are |
4406 | | // created and destroyed via mutable_value so that the key can be moved later. |
4407 | | // |
4408 | | // Accessing one of the union fields while the other is active is safe as |
4409 | | // long as they are layout-compatible, which is guaranteed by the definition of |
4410 | | // kMutableKeys. For C++11, the relevant section of the standard is |
4411 | | // https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19) |
4412 | | // ---------------------------------------------------------------------------- |
4413 | | template <class K, class V> |
4414 | | union map_slot_type |
4415 | | { |
4416 | 1.63M | map_slot_type() {} |
4417 | | ~map_slot_type() = delete; |
4418 | | map_slot_type(const map_slot_type&) = delete; |
4419 | | map_slot_type& operator=(const map_slot_type&) = delete; |
4420 | | |
4421 | | using value_type = std::pair<const K, V>; |
4422 | | using mutable_value_type = std::pair<K, V>; |
4423 | | |
4424 | | value_type value; |
4425 | | mutable_value_type mutable_value; |
4426 | | K key; |
4427 | | }; |
4428 | | |
4429 | | // ---------------------------------------------------------------------------- |
4430 | | // ---------------------------------------------------------------------------- |
4431 | | template <class K, class V> |
4432 | | struct map_slot_policy |
4433 | | { |
4434 | | using slot_type = map_slot_type<K, V>; |
4435 | | using value_type = std::pair<const K, V>; |
4436 | | using mutable_value_type = std::pair<K, V>; |
4437 | | |
4438 | | private: |
4439 | 1.63M | static void emplace(slot_type* slot) { |
4440 | | // The construction of union doesn't do anything at runtime but it allows us |
4441 | | // to access its members without violating aliasing rules. |
4442 | 1.63M | new (slot) slot_type; |
4443 | 1.63M | } |
4444 | | // If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one |
4445 | | // or the other via slot_type. We are also free to access the key via |
4446 | | // slot_type::key in this case. |
4447 | | using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>; |
4448 | | |
4449 | | public: |
4450 | | static value_type& element(slot_type* slot) { return slot->value; } |
4451 | | static const value_type& element(const slot_type* slot) { |
4452 | | return slot->value; |
4453 | | } |
4454 | | |
4455 | | static const K& key(const slot_type* slot) { |
4456 | | return kMutableKeys::value ? slot->key : slot->value.first; |
4457 | | } |
4458 | | |
4459 | | template <class Allocator, class... Args> |
4460 | 591k | static void construct(Allocator* alloc, slot_type* slot, Args&&... args) { |
4461 | 591k | emplace(slot); |
4462 | 591k | if (kMutableKeys::value) { |
4463 | 591k | phmap::allocator_traits<Allocator>::construct(*alloc, &slot->mutable_value, |
4464 | 591k | std::forward<Args>(args)...); |
4465 | 591k | } else { |
4466 | 0 | phmap::allocator_traits<Allocator>::construct(*alloc, &slot->value, |
4467 | 0 | std::forward<Args>(args)...); |
4468 | 0 | } |
4469 | 591k | } |
4470 | | |
4471 | | // Construct this slot by moving from another slot. |
4472 | | template <class Allocator> |
4473 | | static void construct(Allocator* alloc, slot_type* slot, slot_type* other) { |
4474 | | emplace(slot); |
4475 | | if (kMutableKeys::value) { |
4476 | | phmap::allocator_traits<Allocator>::construct( |
4477 | | *alloc, &slot->mutable_value, std::move(other->mutable_value)); |
4478 | | } else { |
4479 | | phmap::allocator_traits<Allocator>::construct(*alloc, &slot->value, |
4480 | | std::move(other->value)); |
4481 | | } |
4482 | | } |
4483 | | |
4484 | | template <class Allocator> |
4485 | 2.21M | static void destroy(Allocator* alloc, slot_type* slot) { |
4486 | 2.21M | if (kMutableKeys::value) { |
4487 | 2.21M | phmap::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value); |
4488 | 2.21M | } else { |
4489 | 0 | phmap::allocator_traits<Allocator>::destroy(*alloc, &slot->value); |
4490 | 0 | } |
4491 | 2.21M | } void phmap::priv::map_slot_policy<unsigned int, int>::destroy<std::__1::allocator<std::__1::pair<unsigned int const, int> > >(std::__1::allocator<std::__1::pair<unsigned int const, int> >*, phmap::priv::map_slot_type<unsigned int, int>*) Line | Count | Source | 4485 | 2.21M | static void destroy(Allocator* alloc, slot_type* slot) { | 4486 | 2.21M | if (kMutableKeys::value) { | 4487 | 2.21M | phmap::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value); | 4488 | 2.21M | } else { | 4489 | 0 | phmap::allocator_traits<Allocator>::destroy(*alloc, &slot->value); | 4490 | 0 | } | 4491 | 2.21M | } |
Unexecuted instantiation: void phmap::priv::map_slot_policy<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::destroy<std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >*, phmap::priv::map_slot_type<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >*) |
4492 | | |
4493 | | template <class Allocator> |
4494 | | static void transfer(Allocator* alloc, slot_type* new_slot, |
4495 | 1.04M | slot_type* old_slot) { |
4496 | 1.04M | emplace(new_slot); |
4497 | 1.04M | if (kMutableKeys::value) { |
4498 | 1.04M | phmap::allocator_traits<Allocator>::construct( |
4499 | 1.04M | *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value)); |
4500 | 1.04M | } else { |
4501 | 0 | phmap::allocator_traits<Allocator>::construct(*alloc, &new_slot->value, |
4502 | 0 | std::move(old_slot->value)); |
4503 | 0 | } |
4504 | 1.04M | destroy(alloc, old_slot); |
4505 | 1.04M | } |
4506 | | |
4507 | | template <class Allocator> |
4508 | | static void swap(Allocator* alloc, slot_type* a, slot_type* b) { |
4509 | | if (kMutableKeys::value) { |
4510 | | using std::swap; |
4511 | | swap(a->mutable_value, b->mutable_value); |
4512 | | } else { |
4513 | | value_type tmp = std::move(a->value); |
4514 | | phmap::allocator_traits<Allocator>::destroy(*alloc, &a->value); |
4515 | | phmap::allocator_traits<Allocator>::construct(*alloc, &a->value, |
4516 | | std::move(b->value)); |
4517 | | phmap::allocator_traits<Allocator>::destroy(*alloc, &b->value); |
4518 | | phmap::allocator_traits<Allocator>::construct(*alloc, &b->value, |
4519 | | std::move(tmp)); |
4520 | | } |
4521 | | } |
4522 | | |
4523 | | template <class Allocator> |
4524 | | static void move(Allocator* alloc, slot_type* src, slot_type* dest) { |
4525 | | if (kMutableKeys::value) { |
4526 | | dest->mutable_value = std::move(src->mutable_value); |
4527 | | } else { |
4528 | | phmap::allocator_traits<Allocator>::destroy(*alloc, &dest->value); |
4529 | | phmap::allocator_traits<Allocator>::construct(*alloc, &dest->value, |
4530 | | std::move(src->value)); |
4531 | | } |
4532 | | } |
4533 | | |
4534 | | template <class Allocator> |
4535 | | static void move(Allocator* alloc, slot_type* first, slot_type* last, |
4536 | | slot_type* result) { |
4537 | | for (slot_type *src = first, *dest = result; src != last; ++src, ++dest) |
4538 | | move(alloc, src, dest); |
4539 | | } |
4540 | | }; |
4541 | | |
4542 | | } // namespace priv |
4543 | | } // phmap |
4544 | | |
4545 | | |
4546 | | namespace phmap { |
4547 | | |
4548 | | #ifdef BOOST_THREAD_LOCK_OPTIONS_HPP |
4549 | | using defer_lock_t = boost::defer_lock_t; |
4550 | | using try_to_lock_t = boost::try_to_lock_t; |
4551 | | using adopt_lock_t = boost::adopt_lock_t; |
4552 | | #else |
4553 | | struct adopt_lock_t { explicit adopt_lock_t() = default; }; |
4554 | | struct defer_lock_t { explicit defer_lock_t() = default; }; |
4555 | | struct try_to_lock_t { explicit try_to_lock_t() = default; }; |
4556 | | #endif |
4557 | | |
4558 | | // ----------------------------------------------------------------------------- |
4559 | | // NullMutex |
4560 | | // ----------------------------------------------------------------------------- |
4561 | | // A class that implements the Mutex interface, but does nothing. This is to be |
4562 | | // used as a default template parameters for classes who provide optional |
4563 | | // internal locking (like phmap::parallel_flat_hash_map). |
4564 | | // ----------------------------------------------------------------------------- |
4565 | | class NullMutex { |
4566 | | public: |
4567 | 0 | NullMutex() {} |
4568 | 0 | ~NullMutex() {} |
4569 | 0 | void lock() {} |
4570 | 0 | void unlock() {} |
4571 | 0 | bool try_lock() { return true; } |
4572 | 0 | void lock_shared() {} |
4573 | 0 | void unlock_shared() {} |
4574 | 0 | bool try_lock_shared() { return true; } |
4575 | | }; |
4576 | | |
4577 | | // ------------------------ lockable object used internally ------------------------- |
4578 | | template <class MutexType> |
4579 | | class LockableBaseImpl |
4580 | | { |
4581 | | public: |
4582 | | // ---------------------------------------------------- |
4583 | | struct DoNothing |
4584 | | { |
4585 | | using mutex_type = MutexType; |
4586 | | DoNothing() noexcept {} |
4587 | | explicit DoNothing(mutex_type& ) noexcept {} |
4588 | | explicit DoNothing(mutex_type& , mutex_type&) noexcept {} |
4589 | | DoNothing(mutex_type&, phmap::adopt_lock_t) noexcept {} |
4590 | | DoNothing(mutex_type&, phmap::defer_lock_t) noexcept {} |
4591 | | DoNothing(mutex_type&, phmap::try_to_lock_t) {} |
4592 | | template<class T> explicit DoNothing(T&&) {} |
4593 | | DoNothing& operator=(const DoNothing&) { return *this; } |
4594 | | DoNothing& operator=(DoNothing&&) noexcept { return *this; } |
4595 | | void swap(DoNothing &) {} |
4596 | | bool owns_lock() const noexcept { return true; } |
4597 | | }; |
4598 | | |
4599 | | // ---------------------------------------------------- |
4600 | | class WriteLock |
4601 | | { |
4602 | | public: |
4603 | | using mutex_type = MutexType; |
4604 | | |
4605 | | WriteLock() : m_(nullptr), locked_(false) {} |
4606 | | |
4607 | | explicit WriteLock(mutex_type &m) : m_(&m) { |
4608 | | m_->lock(); |
4609 | | locked_ = true; |
4610 | | } |
4611 | | |
4612 | | WriteLock(mutex_type& m, adopt_lock_t) noexcept : |
4613 | | m_(&m), locked_(true) |
4614 | | {} |
4615 | | |
4616 | | WriteLock(mutex_type& m, defer_lock_t) noexcept : |
4617 | | m_(&m), locked_(false) |
4618 | | {} |
4619 | | |
4620 | | WriteLock(mutex_type& m, try_to_lock_t) : |
4621 | | m_(&m), locked_(false) { |
4622 | | m_->try_lock(); |
4623 | | } |
4624 | | |
4625 | | WriteLock(WriteLock &&o) noexcept : |
4626 | | m_(std::move(o.m_)), locked_(std::move(o.locked_)) { |
4627 | | o.locked_ = false; |
4628 | | o.m_ = nullptr; |
4629 | | } |
4630 | | |
4631 | | WriteLock& operator=(WriteLock&& other) noexcept { |
4632 | | WriteLock temp(std::move(other)); |
4633 | | swap(temp); |
4634 | | return *this; |
4635 | | } |
4636 | | |
4637 | | ~WriteLock() { |
4638 | | if (locked_) |
4639 | | m_->unlock(); |
4640 | | } |
4641 | | |
4642 | | void lock() { |
4643 | | if (!locked_) { |
4644 | | m_->lock(); |
4645 | | locked_ = true; |
4646 | | } |
4647 | | } |
4648 | | |
4649 | | void unlock() { |
4650 | | if (locked_) { |
4651 | | m_->unlock(); |
4652 | | locked_ = false; |
4653 | | } |
4654 | | } |
4655 | | |
4656 | | bool try_lock() { |
4657 | | if (locked_) |
4658 | | return true; |
4659 | | locked_ = m_->try_lock(); |
4660 | | return locked_; |
4661 | | } |
4662 | | |
4663 | | bool owns_lock() const noexcept { return locked_; } |
4664 | | |
4665 | | void swap(WriteLock &o) noexcept { |
4666 | | std::swap(m_, o.m_); |
4667 | | std::swap(locked_, o.locked_); |
4668 | | } |
4669 | | |
4670 | | mutex_type *mutex() const noexcept { return m_; } |
4671 | | |
4672 | | private: |
4673 | | mutex_type *m_; |
4674 | | bool locked_; |
4675 | | }; |
4676 | | |
4677 | | // ---------------------------------------------------- |
4678 | | class ReadLock |
4679 | | { |
4680 | | public: |
4681 | | using mutex_type = MutexType; |
4682 | | |
4683 | | ReadLock() : m_(nullptr), locked_(false) {} |
4684 | | |
4685 | | explicit ReadLock(mutex_type &m) : m_(&m) { |
4686 | | m_->lock_shared(); |
4687 | | locked_ = true; |
4688 | | } |
4689 | | |
4690 | | ReadLock(mutex_type& m, adopt_lock_t) noexcept : |
4691 | | m_(&m), locked_(true) |
4692 | | {} |
4693 | | |
4694 | | ReadLock(mutex_type& m, defer_lock_t) noexcept : |
4695 | | m_(&m), locked_(false) |
4696 | | {} |
4697 | | |
4698 | | ReadLock(mutex_type& m, try_to_lock_t) : |
4699 | | m_(&m), locked_(false) { |
4700 | | m_->try_lock_shared(); |
4701 | | } |
4702 | | |
4703 | | ReadLock(ReadLock &&o) noexcept : |
4704 | | m_(std::move(o.m_)), locked_(std::move(o.locked_)) { |
4705 | | o.locked_ = false; |
4706 | | o.m_ = nullptr; |
4707 | | } |
4708 | | |
4709 | | ReadLock& operator=(ReadLock&& other) noexcept { |
4710 | | ReadLock temp(std::move(other)); |
4711 | | swap(temp); |
4712 | | return *this; |
4713 | | } |
4714 | | |
4715 | | ~ReadLock() { |
4716 | | if (locked_) |
4717 | | m_->unlock_shared(); |
4718 | | } |
4719 | | |
4720 | | void lock() { |
4721 | | if (!locked_) { |
4722 | | m_->lock_shared(); |
4723 | | locked_ = true; |
4724 | | } |
4725 | | } |
4726 | | |
4727 | | void unlock() { |
4728 | | if (locked_) { |
4729 | | m_->unlock_shared(); |
4730 | | locked_ = false; |
4731 | | } |
4732 | | } |
4733 | | |
4734 | | bool try_lock() { |
4735 | | if (locked_) |
4736 | | return true; |
4737 | | locked_ = m_->try_lock_shared(); |
4738 | | return locked_; |
4739 | | } |
4740 | | |
4741 | | bool owns_lock() const noexcept { return locked_; } |
4742 | | |
4743 | | void swap(ReadLock &o) noexcept { |
4744 | | std::swap(m_, o.m_); |
4745 | | std::swap(locked_, o.locked_); |
4746 | | } |
4747 | | |
4748 | | mutex_type *mutex() const noexcept { return m_; } |
4749 | | |
4750 | | private: |
4751 | | mutex_type *m_; |
4752 | | bool locked_; |
4753 | | }; |
4754 | | |
4755 | | // ---------------------------------------------------- |
4756 | | class WriteLocks |
4757 | | { |
4758 | | public: |
4759 | | using mutex_type = MutexType; |
4760 | | |
4761 | | explicit WriteLocks(mutex_type& m1, mutex_type& m2) : |
4762 | | _m1(m1), _m2(m2) |
4763 | | { |
4764 | | std::lock(m1, m2); |
4765 | | } |
4766 | | |
4767 | | WriteLocks(adopt_lock_t, mutex_type& m1, mutex_type& m2) : |
4768 | | _m1(m1), _m2(m2) |
4769 | | { // adopt means we already own the mutexes |
4770 | | } |
4771 | | |
4772 | | ~WriteLocks() |
4773 | | { |
4774 | | _m1.unlock(); |
4775 | | _m2.unlock(); |
4776 | | } |
4777 | | |
4778 | | WriteLocks(WriteLocks const&) = delete; |
4779 | | WriteLocks& operator=(WriteLocks const&) = delete; |
4780 | | private: |
4781 | | mutex_type& _m1; |
4782 | | mutex_type& _m2; |
4783 | | }; |
4784 | | |
4785 | | // ---------------------------------------------------- |
4786 | | class ReadLocks |
4787 | | { |
4788 | | public: |
4789 | | using mutex_type = MutexType; |
4790 | | |
4791 | | explicit ReadLocks(mutex_type& m1, mutex_type& m2) : |
4792 | | _m1(m1), _m2(m2) |
4793 | | { |
4794 | | _m1.lock_shared(); |
4795 | | _m2.lock_shared(); |
4796 | | } |
4797 | | |
4798 | | ReadLocks(adopt_lock_t, mutex_type& m1, mutex_type& m2) : |
4799 | | _m1(m1), _m2(m2) |
4800 | | { // adopt means we already own the mutexes |
4801 | | } |
4802 | | |
4803 | | ~ReadLocks() |
4804 | | { |
4805 | | _m1.unlock_shared(); |
4806 | | _m2.unlock_shared(); |
4807 | | } |
4808 | | |
4809 | | ReadLocks(ReadLocks const&) = delete; |
4810 | | ReadLocks& operator=(ReadLocks const&) = delete; |
4811 | | private: |
4812 | | mutex_type& _m1; |
4813 | | mutex_type& _m2; |
4814 | | }; |
4815 | | }; |
4816 | | |
4817 | | // ------------------------ holds a mutex ------------------------------------ |
4818 | | // Default implementation for Lockable, should work fine for std::mutex |
4819 | | // ----------------------------------- |
4820 | | // use as: |
4821 | | // using Lockable = phmap::LockableImpl<mutex_type>; |
4822 | | // Lockable m; |
4823 | | // |
4824 | | // Lockable::UpgradeLock read_lock(m); // take a upgradable lock |
4825 | | // |
4826 | | // { |
4827 | | // Lockable::UpgradeToUnique unique_lock(read_lock); |
4828 | | // // now locked for write |
4829 | | // } |
4830 | | // |
4831 | | // --------------------------------------------------------------------------- |
4832 | | // Generic mutex support (always write locks) |
4833 | | // -------------------------------------------------------------------------- |
4834 | | template <class Mtx_> |
4835 | | class LockableImpl : public Mtx_ |
4836 | | { |
4837 | | public: |
4838 | | using mutex_type = Mtx_; |
4839 | | using Base = LockableBaseImpl<Mtx_>; |
4840 | | using SharedLock = typename Base::WriteLock; |
4841 | | using UpgradeLock = typename Base::WriteLock; |
4842 | | using UniqueLock = typename Base::WriteLock; |
4843 | | using SharedLocks = typename Base::WriteLocks; |
4844 | | using UniqueLocks = typename Base::WriteLocks; |
4845 | | using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership |
4846 | | }; |
4847 | | |
4848 | | // --------------------------------------------------------------------------- |
4849 | | // Null mutex (no-op) - when we don't want internal synchronization |
4850 | | // --------------------------------------------------------------------------- |
4851 | | template <> |
4852 | | class LockableImpl<phmap::NullMutex>: public phmap::NullMutex |
4853 | | { |
4854 | | public: |
4855 | | using mutex_type = phmap::NullMutex; |
4856 | | using Base = LockableBaseImpl<phmap::NullMutex>; |
4857 | | using SharedLock = typename Base::DoNothing; |
4858 | | using UpgradeLock = typename Base::DoNothing; |
4859 | | using UniqueLock = typename Base::DoNothing; |
4860 | | using UpgradeToUnique = typename Base::DoNothing; |
4861 | | using SharedLocks = typename Base::DoNothing; |
4862 | | using UniqueLocks = typename Base::DoNothing; |
4863 | | }; |
4864 | | |
4865 | | // -------------------------------------------------------------------------- |
4866 | | // Abseil Mutex support (read and write lock support) |
4867 | | // -------------------------------------------------------------------------- |
4868 | | #ifdef ABSL_SYNCHRONIZATION_MUTEX_H_ |
4869 | | |
4870 | | struct AbslMutex : protected absl::Mutex |
4871 | | { |
4872 | | void lock() { this->Lock(); } |
4873 | | void unlock() { this->Unlock(); } |
4874 | | void try_lock() { this->TryLock(); } |
4875 | | void lock_shared() { this->ReaderLock(); } |
4876 | | void unlock_shared() { this->ReaderUnlock(); } |
4877 | | void try_lock_shared() { this->ReaderTryLock(); } |
4878 | | }; |
4879 | | |
4880 | | template <> |
4881 | | class LockableImpl<absl::Mutex> : public AbslMutex |
4882 | | { |
4883 | | public: |
4884 | | using mutex_type = phmap::AbslMutex; |
4885 | | using Base = LockableBaseImpl<phmap::AbslMutex>; |
4886 | | using SharedLock = typename Base::ReadLock; |
4887 | | using UpgradeLock = typename Base::WriteLock; |
4888 | | using UniqueLock = typename Base::WriteLock; |
4889 | | using SharedLocks = typename Base::ReadLocks; |
4890 | | using UniqueLocks = typename Base::WriteLocks; |
4891 | | using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership |
4892 | | }; |
4893 | | |
4894 | | #endif |
4895 | | |
4896 | | // -------------------------------------------------------------------------- |
4897 | | // Boost shared_mutex support (read and write lock support) |
4898 | | // -------------------------------------------------------------------------- |
4899 | | #ifdef BOOST_THREAD_SHARED_MUTEX_HPP |
4900 | | |
4901 | | #if 1 |
4902 | | // --------------------------------------------------------------------------- |
4903 | | template <> |
4904 | | class LockableImpl<boost::shared_mutex> : public boost::shared_mutex |
4905 | | { |
4906 | | public: |
4907 | | using mutex_type = boost::shared_mutex; |
4908 | | using Base = LockableBaseImpl<boost::shared_mutex>; |
4909 | | using SharedLock = boost::shared_lock<mutex_type>; |
4910 | | using UpgradeLock = boost::unique_lock<mutex_type>; // assume can't upgrade |
4911 | | using UniqueLock = boost::unique_lock<mutex_type>; |
4912 | | using SharedLocks = typename Base::ReadLocks; |
4913 | | using UniqueLocks = typename Base::WriteLocks; |
4914 | | using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership |
4915 | | }; |
4916 | | #else |
4917 | | // --------------------------------------------------------------------------- |
4918 | | template <> |
4919 | | class LockableImpl<boost::upgrade_mutex> : public boost::upgrade_mutex |
4920 | | { |
4921 | | public: |
4922 | | using mutex_type = boost::upgrade_mutex; |
4923 | | using SharedLock = boost::shared_lock<mutex_type>; |
4924 | | using UpgradeLock = boost::upgrade_lock<mutex_type>; |
4925 | | using UniqueLock = boost::unique_lock<mutex_type>; |
4926 | | using SharedLocks = typename Base::ReadLocks; |
4927 | | using UniqueLocks = typename Base::WriteLocks; |
4928 | | using UpgradeToUnique = boost::upgrade_to_unique_lock<mutex_type>; |
4929 | | }; |
4930 | | #endif |
4931 | | |
4932 | | #endif // BOOST_THREAD_SHARED_MUTEX_HPP |
4933 | | |
4934 | | // -------------------------------------------------------------------------- |
4935 | | // std::shared_mutex support (read and write lock support) |
4936 | | // -------------------------------------------------------------------------- |
4937 | | #ifdef PHMAP_HAVE_SHARED_MUTEX |
4938 | | |
4939 | | // --------------------------------------------------------------------------- |
4940 | | template <> |
4941 | | class LockableImpl<std::shared_mutex> : public std::shared_mutex |
4942 | | { |
4943 | | public: |
4944 | | using mutex_type = std::shared_mutex; |
4945 | | using Base = LockableBaseImpl<std::shared_mutex>; |
4946 | | using SharedLock = std::shared_lock<mutex_type>; |
4947 | | using UpgradeLock = std::unique_lock<mutex_type>; // assume can't upgrade |
4948 | | using UniqueLock = std::unique_lock<mutex_type>; |
4949 | | using SharedLocks = typename Base::ReadLocks; |
4950 | | using UniqueLocks = typename Base::WriteLocks; |
4951 | | using UpgradeToUnique = typename Base::DoNothing; // we already have unique ownership |
4952 | | }; |
4953 | | #endif // PHMAP_HAVE_SHARED_MUTEX |
4954 | | |
4955 | | |
4956 | | } // phmap |
4957 | | |
4958 | | #ifdef _MSC_VER |
4959 | | #pragma warning(pop) |
4960 | | #endif |
4961 | | |
4962 | | |
4963 | | #endif // phmap_base_h_guard_ |