/src/abseil-cpp/absl/container/internal/hash_policy_traits.h
Line  | Count  | Source  | 
1  |  | // Copyright 2018 The Abseil Authors.  | 
2  |  | //  | 
3  |  | // Licensed under the Apache License, Version 2.0 (the "License");  | 
4  |  | // you may not use this file except in compliance with the License.  | 
5  |  | // You may obtain a copy of the License at  | 
6  |  | //  | 
7  |  | //      https://www.apache.org/licenses/LICENSE-2.0  | 
8  |  | //  | 
9  |  | // Unless required by applicable law or agreed to in writing, software  | 
10  |  | // distributed under the License is distributed on an "AS IS" BASIS,  | 
11  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
12  |  | // See the License for the specific language governing permissions and  | 
13  |  | // limitations under the License.  | 
14  |  |  | 
15  |  | #ifndef ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_  | 
16  |  | #define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_  | 
17  |  |  | 
18  |  | #include <cstddef>  | 
19  |  | #include <memory>  | 
20  |  | #include <new>  | 
21  |  | #include <type_traits>  | 
22  |  | #include <utility>  | 
23  |  |  | 
24  |  | #include "absl/container/internal/common_policy_traits.h"  | 
25  |  | #include "absl/container/internal/container_memory.h"  | 
26  |  | #include "absl/meta/type_traits.h"  | 
27  |  |  | 
28  |  | namespace absl { | 
29  |  | ABSL_NAMESPACE_BEGIN  | 
30  |  | namespace container_internal { | 
31  |  |  | 
32  |  | // Defines how slots are initialized/destroyed/moved.  | 
33  |  | template <class Policy, class = void>  | 
34  |  | struct hash_policy_traits : common_policy_traits<Policy> { | 
35  |  |   // The type of the keys stored in the hashtable.  | 
36  |  |   using key_type = typename Policy::key_type;  | 
37  |  |  | 
38  |  |  private:  | 
39  |  |   struct ReturnKey { | 
40  |  |     template <class Key,  | 
41  |  |               absl::enable_if_t<std::is_lvalue_reference<Key>::value, int> = 0>  | 
42  |  |     static key_type& Impl(Key&& k, int) { | 
43  |  |       return *std::launder(  | 
44  |  |           const_cast<key_type*>(std::addressof(std::forward<Key>(k))));  | 
45  |  |     }  | 
46  |  |  | 
47  |  |     template <class Key>  | 
48  |  |     static Key Impl(Key&& k, char) { | 
49  |  |       return std::forward<Key>(k);  | 
50  |  |     }  | 
51  |  |  | 
52  |  |     // When Key=T&, we forward the lvalue reference.  | 
53  |  |     // When Key=T, we return by value to avoid a dangling reference.  | 
54  |  |     // eg, for string_hash_map.  | 
55  |  |     template <class Key, class... Args>  | 
56  |  |     auto operator()(Key&& k, const Args&...) const  | 
57  |  |         -> decltype(Impl(std::forward<Key>(k), 0)) { | 
58  |  |       return Impl(std::forward<Key>(k), 0);  | 
59  |  |     }  | 
60  |  |   };  | 
61  |  |  | 
62  |  |   template <class P = Policy, class = void>  | 
63  |  |   struct ConstantIteratorsImpl : std::false_type {}; | 
64  |  |  | 
65  |  |   template <class P>  | 
66  |  |   struct ConstantIteratorsImpl<P, absl::void_t<typename P::constant_iterators>>  | 
67  |  |       : P::constant_iterators {}; | 
68  |  |  | 
69  |  |  public:  | 
70  |  |   // The actual object stored in the hash table.  | 
71  |  |   using slot_type = typename Policy::slot_type;  | 
72  |  |  | 
73  |  |   // The argument type for insertions into the hashtable. This is different  | 
74  |  |   // from value_type for increased performance. See initializer_list constructor  | 
75  |  |   // and insert() member functions for more details.  | 
76  |  |   using init_type = typename Policy::init_type;  | 
77  |  |  | 
78  |  |   using reference = decltype(Policy::element(std::declval<slot_type*>()));  | 
79  |  |   using pointer = typename std::remove_reference<reference>::type*;  | 
80  |  |   using value_type = typename std::remove_reference<reference>::type;  | 
81  |  |  | 
82  |  |   // Policies can set this variable to tell raw_hash_set that all iterators  | 
83  |  |   // should be constant, even `iterator`. This is useful for set-like  | 
84  |  |   // containers.  | 
85  |  |   // Defaults to false if not provided by the policy.  | 
86  |  |   using constant_iterators = ConstantIteratorsImpl<>;  | 
87  |  |  | 
88  |  |   // Returns the amount of memory owned by `slot`, exclusive of `sizeof(*slot)`.  | 
89  |  |   //  | 
90  |  |   // If `slot` is nullptr, returns the constant amount of memory owned by any  | 
91  |  |   // full slot or -1 if slots own variable amounts of memory.  | 
92  |  |   //  | 
93  |  |   // PRECONDITION: `slot` is INITIALIZED or nullptr  | 
94  |  |   template <class P = Policy>  | 
95  |  |   static size_t space_used(const slot_type* slot) { | 
96  |  |     return P::space_used(slot);  | 
97  |  |   }  | 
98  |  |  | 
99  |  |   // Provides generalized access to the key for elements, both for elements in  | 
100  |  |   // the table and for elements that have not yet been inserted (or even  | 
101  |  |   // constructed).  We would like an API that allows us to say: `key(args...)`  | 
102  |  |   // but we cannot do that for all cases, so we use this more general API that  | 
103  |  |   // can be used for many things, including the following:  | 
104  |  |   //  | 
105  |  |   //   - Given an element in a table, get its key.  | 
106  |  |   //   - Given an element initializer, get its key.  | 
107  |  |   //   - Given `emplace()` arguments, get the element key.  | 
108  |  |   //  | 
109  |  |   // Implementations of this must adhere to a very strict technical  | 
110  |  |   // specification around aliasing and consuming arguments:  | 
111  |  |   //  | 
112  |  |   // Let `value_type` be the result type of `element()` without ref- and  | 
113  |  |   // cv-qualifiers. The first argument is a functor, the rest are constructor  | 
114  |  |   // arguments for `value_type`. Returns `std::forward<F>(f)(k, xs...)`, where  | 
115  |  |   // `k` is the element key, and `xs...` are the new constructor arguments for  | 
116  |  |   // `value_type`. It's allowed for `k` to alias `xs...`, and for both to alias  | 
117  |  |   // `ts...`. The key won't be touched once `xs...` are used to construct an  | 
118  |  |   // element; `ts...` won't be touched at all, which allows `apply()` to consume  | 
119  |  |   // any rvalues among them.  | 
120  |  |   //  | 
121  |  |   // If `value_type` is constructible from `Ts&&...`, `Policy::apply()` must not  | 
122  |  |   // trigger a hard compile error unless it originates from `f`. In other words,  | 
123  |  |   // `Policy::apply()` must be SFINAE-friendly. If `value_type` is not  | 
124  |  |   // constructible from `Ts&&...`, either SFINAE or a hard compile error is OK.  | 
125  |  |   //  | 
126  |  |   // If `Ts...` is `[cv] value_type[&]` or `[cv] init_type[&]`,  | 
127  |  |   // `Policy::apply()` must work. A compile error is not allowed, SFINAE or not.  | 
128  |  |   template <class F, class... Ts, class P = Policy>  | 
129  |  |   static auto apply(F&& f, Ts&&... ts)  | 
130  | 46  |       -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { | 
131  | 46  |     return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);  | 
132  | 46  |   } _ZN4absl18container_internal18hash_policy_traitsINS0_17FlatHashMapPolicyINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEPNS_15CommandLineFlagEEEvE5applyINS0_12EqualElementIS7_NS0_8StringEqEEEJRNS3_4pairIKS7_S9_EEESA_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSL_DpOSM_ Line  | Count  | Source  |  130  | 16  |       -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { |  131  | 16  |     return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);  |  132  | 16  |   }  |  
 _ZN4absl18container_internal18hash_policy_traitsINS0_17FlatHashMapPolicyINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEPNS_15CommandLineFlagEEEvE5applyINS0_12raw_hash_setISA_NS0_10StringHashENS0_8StringEqENS3_9allocatorINS3_4pairIKS7_S9_EEEEE19EmplaceDecomposableEJSJ_ESA_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSO_DpOSP_ Line  | Count  | Source  |  130  | 16  |       -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { |  131  | 16  |     return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);  |  132  | 16  |   }  |  
 Unexecuted instantiation: _ZN4absl18container_internal18hash_policy_traitsINS0_17FlatHashMapPolicyINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEPNS_15CommandLineFlagEEEvE5applyINS0_11HashElementINS0_10StringHashELb1EEEJRNS3_4pairIKS7_S9_EEESA_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSL_DpOSM_ _ZN4absl18container_internal18hash_policy_traitsINS0_17FlatHashMapPolicyINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEPNS_15CommandLineFlagEEEvE5applyINS0_12raw_hash_setISA_NS0_10StringHashENS0_8StringEqENS3_9allocatorINS3_4pairIKS7_S9_EEEEE11FindElementEJRSJ_ESA_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSP_DpOSQ_ Line  | Count  | Source  |  130  | 14  |       -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) { |  131  | 14  |     return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);  |  132  | 14  |   }  |  
 Unexecuted instantiation: _ZN4absl18container_internal18hash_policy_traitsINS0_17FlatHashMapPolicyINSt3__117basic_string_viewIcNS3_11char_traitsIcEEEEPNS_15CommandLineFlagEEEvE5applyINS0_12raw_hash_setISA_NS0_10StringHashENS0_8StringEqENS3_9allocatorINS3_4pairIKS7_S9_EEEEE19EmplaceDecomposableEJNSH_IS7_S9_EEESA_EEDTclsrT1_5applyclsr3stdE7forwardIT_Efp_Espclsr3stdE7forwardIT0_Efp0_EEEOSP_DpOSQ_  | 
133  |  |  | 
134  |  |   // Returns the "key" portion of the slot.  | 
135  |  |   // Used for node handle manipulation.  | 
136  |  |   template <class P = Policy>  | 
137  |  |   static auto mutable_key(slot_type* slot)  | 
138  |  |       -> decltype(P::apply(ReturnKey(), hash_policy_traits::element(slot))) { | 
139  |  |     return P::apply(ReturnKey(), hash_policy_traits::element(slot));  | 
140  |  |   }  | 
141  |  |  | 
142  |  |   // Returns the "value" (as opposed to the "key") portion of the element. Used  | 
143  |  |   // by maps to implement `operator[]`, `at()` and `insert_or_assign()`.  | 
144  |  |   template <class T, class P = Policy>  | 
145  |  |   static auto value(T* elem) -> decltype(P::value(elem)) { | 
146  |  |     return P::value(elem);  | 
147  |  |   }  | 
148  |  |  | 
149  |  |   template <class Hash, bool kIsDefault>  | 
150  | 0  |   static constexpr HashSlotFn get_hash_slot_fn() { | 
151  | 0  | // get_hash_slot_fn may return nullptr to signal that non type erased function  | 
152  | 0  | // should be used. GCC warns against comparing function address with nullptr.  | 
153  | 0  | #if defined(__GNUC__) && !defined(__clang__)  | 
154  | 0  | #pragma GCC diagnostic push  | 
155  | 0  | // silent error: the address of * will never be NULL [-Werror=address]  | 
156  | 0  | #pragma GCC diagnostic ignored "-Waddress"  | 
157  | 0  | #endif  | 
158  | 0  |     return Policy::template get_hash_slot_fn<Hash, kIsDefault>() == nullptr  | 
159  | 0  |                ? &hash_slot_fn_non_type_erased<Hash, kIsDefault>  | 
160  | 0  |                : Policy::template get_hash_slot_fn<Hash, kIsDefault>();  | 
161  | 0  | #if defined(__GNUC__) && !defined(__clang__)  | 
162  | 0  | #pragma GCC diagnostic pop  | 
163  | 0  | #endif  | 
164  | 0  |   }  | 
165  |  |  | 
166  |  |   // Whether small object optimization is enabled. True by default.  | 
167  | 0  |   static constexpr bool soo_enabled() { return soo_enabled_impl(Rank1{}); } | 
168  |  |  | 
169  |  |  private:  | 
170  |  |   template <class Hash, bool kIsDefault>  | 
171  |  |   static size_t hash_slot_fn_non_type_erased(const void* hash_fn, void* slot,  | 
172  | 0  |                                              size_t seed) { | 
173  | 0  |     return Policy::apply(  | 
174  | 0  |         HashElement<Hash, kIsDefault>{*static_cast<const Hash*>(hash_fn), seed}, | 
175  | 0  |         Policy::element(static_cast<slot_type*>(slot)));  | 
176  | 0  |   }  | 
177  |  |  | 
178  |  |   // Use go/ranked-overloads for dispatching. Rank1 is preferred.  | 
179  |  |   struct Rank0 {}; | 
180  |  |   struct Rank1 : Rank0 {}; | 
181  |  |  | 
182  |  |   // Use auto -> decltype as an enabler.  | 
183  |  |   template <class P = Policy>  | 
184  |  |   static constexpr auto soo_enabled_impl(Rank1) -> decltype(P::soo_enabled()) { | 
185  |  |     return P::soo_enabled();  | 
186  |  |   }  | 
187  |  |  | 
188  | 0  |   static constexpr bool soo_enabled_impl(Rank0) { return true; } | 
189  |  | };  | 
190  |  |  | 
191  |  | }  // namespace container_internal  | 
192  |  | ABSL_NAMESPACE_END  | 
193  |  | }  // namespace absl  | 
194  |  |  | 
195  |  | #endif  // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_  |