• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_COMMON_H_
16 #define ABSL_CONTAINER_INTERNAL_COMMON_H_
17 
18 #include <cassert>
19 #include <type_traits>
20 
21 #include "absl/meta/type_traits.h"
22 #include "absl/types/optional.h"
23 
24 // TODO(b/402804213): Clean up these macros when no longer needed.
25 #define ABSL_INTERNAL_SINGLE_ARG(...) __VA_ARGS__
26 
27 #define ABSL_INTERNAL_IF_true(if_satisfied, ...) if_satisfied
28 #define ABSL_INTERNAL_IF_false(if_satisfied, ...) __VA_ARGS__
29 
30 #define ABSL_INTERNAL_IF_true_AND_true ABSL_INTERNAL_IF_true
31 #define ABSL_INTERNAL_IF_false_AND_false ABSL_INTERNAL_IF_false
32 #define ABSL_INTERNAL_IF_true_AND_false ABSL_INTERNAL_IF_false_AND_false
33 #define ABSL_INTERNAL_IF_false_AND_true ABSL_INTERNAL_IF_false_AND_false
34 
35 #define ABSL_INTERNAL_IF_true_OR_true ABSL_INTERNAL_IF_true
36 #define ABSL_INTERNAL_IF_false_OR_false ABSL_INTERNAL_IF_false
37 #define ABSL_INTERNAL_IF_true_OR_false ABSL_INTERNAL_IF_true_OR_true
38 #define ABSL_INTERNAL_IF_false_OR_true ABSL_INTERNAL_IF_true_OR_true
39 
40 #define ABSL_INTERNAL_IF_true_NOR_true ABSL_INTERNAL_IF_false_AND_false
41 #define ABSL_INTERNAL_IF_false_NOR_false ABSL_INTERNAL_IF_true_AND_true
42 #define ABSL_INTERNAL_IF_true_NOR_false ABSL_INTERNAL_IF_false_AND_true
43 #define ABSL_INTERNAL_IF_false_NOR_true ABSL_INTERNAL_IF_true_AND_false
44 
45 #define ABSL_INTERNAL_COMMA ,
46 
47 namespace absl {
48 ABSL_NAMESPACE_BEGIN
49 namespace container_internal {
50 
51 // TODO(b/402804213): Clean up these traits when no longer needed or
52 // deduplicate them with absl::functional_internal::EnableIf.
53 template <class Cond>
54 using EnableIf = std::enable_if_t<Cond::value, int>;
55 
56 template <bool Value, class T>
57 using HasValue = std::conditional_t<Value, T, absl::negation<T>>;
58 
59 template <class T>
60 struct IfRRef {
61   template <class Other>
62   using AddPtr = Other;
63 };
64 
65 template <class T>
66 struct IfRRef<T&&> {
67   template <class Other>
68   using AddPtr = Other*;
69 };
70 
71 template <class, class = void>
72 struct IsTransparent : std::false_type {};
73 template <class T>
74 struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
75     : std::true_type {};
76 
77 template <bool is_transparent>
78 struct KeyArg {
79   // Transparent. Forward `K`.
80   template <typename K, typename key_type>
81   using type = K;
82 };
83 
84 template <>
85 struct KeyArg<false> {
86   // Not transparent. Always use `key_type`.
87   template <typename K, typename key_type>
88   using type = key_type;
89 };
90 
91 // The node_handle concept from C++17.
92 // We specialize node_handle for sets and maps. node_handle_base holds the
93 // common API of both.
94 template <typename PolicyTraits, typename Alloc>
95 class node_handle_base {
96  protected:
97   using slot_type = typename PolicyTraits::slot_type;
98 
99  public:
100   using allocator_type = Alloc;
101 
102   constexpr node_handle_base() = default;
103   node_handle_base(node_handle_base&& other) noexcept {
104     *this = std::move(other);
105   }
106   ~node_handle_base() { destroy(); }
107   node_handle_base& operator=(node_handle_base&& other) noexcept {
108     destroy();
109     if (!other.empty()) {
110       alloc_ = other.alloc_;
111       PolicyTraits::transfer(alloc(), slot(), other.slot());
112       other.reset();
113     }
114     return *this;
115   }
116 
117   bool empty() const noexcept { return !alloc_; }
118   explicit operator bool() const noexcept { return !empty(); }
119   allocator_type get_allocator() const { return *alloc_; }
120 
121  protected:
122   friend struct CommonAccess;
123 
124   struct transfer_tag_t {};
125   node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s)
126       : alloc_(a) {
127     PolicyTraits::transfer(alloc(), slot(), s);
128   }
129 
130   struct construct_tag_t {};
131   template <typename... Args>
132   node_handle_base(construct_tag_t, const allocator_type& a, Args&&... args)
133       : alloc_(a) {
134     PolicyTraits::construct(alloc(), slot(), std::forward<Args>(args)...);
135   }
136 
137   void destroy() {
138     if (!empty()) {
139       PolicyTraits::destroy(alloc(), slot());
140       reset();
141     }
142   }
143 
144   void reset() {
145     assert(alloc_.has_value());
146     alloc_ = absl::nullopt;
147   }
148 
149   slot_type* slot() const {
150     assert(!empty());
151     return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
152   }
153   allocator_type* alloc() { return std::addressof(*alloc_); }
154 
155  private:
156   absl::optional<allocator_type> alloc_ = {};
157   alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
158 };
159 
160 // For sets.
161 template <typename Policy, typename PolicyTraits, typename Alloc,
162           typename = void>
163 class node_handle : public node_handle_base<PolicyTraits, Alloc> {
164   using Base = node_handle_base<PolicyTraits, Alloc>;
165 
166  public:
167   using value_type = typename PolicyTraits::value_type;
168 
169   constexpr node_handle() {}
170 
171   value_type& value() const { return PolicyTraits::element(this->slot()); }
172 
173  private:
174   friend struct CommonAccess;
175 
176   using Base::Base;
177 };
178 
179 // For maps.
180 template <typename Policy, typename PolicyTraits, typename Alloc>
181 class node_handle<Policy, PolicyTraits, Alloc,
182                   absl::void_t<typename Policy::mapped_type>>
183     : public node_handle_base<PolicyTraits, Alloc> {
184   using Base = node_handle_base<PolicyTraits, Alloc>;
185   using slot_type = typename PolicyTraits::slot_type;
186 
187  public:
188   using key_type = typename Policy::key_type;
189   using mapped_type = typename Policy::mapped_type;
190 
191   constexpr node_handle() {}
192 
193   // When C++17 is available, we can use std::launder to provide mutable
194   // access to the key. Otherwise, we provide const access.
195   auto key() const
196       -> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) {
197     return PolicyTraits::mutable_key(this->slot());
198   }
199 
200   mapped_type& mapped() const {
201     return PolicyTraits::value(&PolicyTraits::element(this->slot()));
202   }
203 
204  private:
205   friend struct CommonAccess;
206 
207   using Base::Base;
208 };
209 
210 // Provide access to non-public node-handle functions.
211 struct CommonAccess {
212   template <typename Node>
213   static auto GetSlot(const Node& node) -> decltype(node.slot()) {
214     return node.slot();
215   }
216 
217   template <typename Node>
218   static void Destroy(Node* node) {
219     node->destroy();
220   }
221 
222   template <typename Node>
223   static void Reset(Node* node) {
224     node->reset();
225   }
226 
227   template <typename T, typename... Args>
228   static T Transfer(Args&&... args) {
229     return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
230   }
231 
232   template <typename T, typename... Args>
233   static T Construct(Args&&... args) {
234     return T(typename T::construct_tag_t{}, std::forward<Args>(args)...);
235   }
236 };
237 
238 // Implement the insert_return_type<> concept of C++17.
239 template <class Iterator, class NodeType>
240 struct InsertReturnType {
241   Iterator position;
242   bool inserted;
243   NodeType node;
244 };
245 
246 }  // namespace container_internal
247 ABSL_NAMESPACE_END
248 }  // namespace absl
249 
250 #endif  // ABSL_CONTAINER_INTERNAL_COMMON_H_
251