]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/include/bits/node_handle.h
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / include / bits / node_handle.h
1 // Node handles for containers -*- C++ -*-
2
3 // Copyright (C) 2016-2024 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 /** @file bits/node_handle.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly.
28 * @headername{map,set,unordered_map,unordered_set}
29 */
30
31 #ifndef _NODE_HANDLE
32 #define _NODE_HANDLE 1
33
34 #pragma GCC system_header
35
36 #include <bits/version.h>
37
38 #ifdef __glibcxx_node_extract // C++ >= 17 && HOSTED
39
40 #include <new>
41 #include <bits/alloc_traits.h>
42 #include <bits/ptr_traits.h>
43
44 namespace std _GLIBCXX_VISIBILITY(default)
45 {
46 _GLIBCXX_BEGIN_NAMESPACE_VERSION
47
48 /**
49 * @defgroup node_handles Node handles
50 * @ingroup associative_containers
51 * @since C++17
52 *
53 * The associative containers (`map`, `set`, `multimap` and `multiset`)
54 * support extracting and re-inserting nodes from the container. Those
55 * operations use the container's `node_handle` type, which is an alias
56 * for a `_Node_handle<...>` type. You should always use the container's
57 * `node_handle` type (e.g. `std::set<int>::node_handle`) to refer to
58 * these types, not the non-standard internal `_Node_handle` names.
59 *
60 * @{
61 */
62
63 /// Base class for node handle types of maps and sets.
64 template<typename _Val, typename _NodeAlloc>
65 class _Node_handle_common
66 {
67 using _AllocTraits = allocator_traits<_NodeAlloc>;
68
69 public:
70 using allocator_type = __alloc_rebind<_NodeAlloc, _Val>;
71
72 allocator_type
73 get_allocator() const noexcept
74 {
75 __glibcxx_assert(!this->empty());
76 return allocator_type(_M_alloc._M_alloc);
77 }
78
79 explicit operator bool() const noexcept { return _M_ptr != nullptr; }
80
81 [[nodiscard]] bool empty() const noexcept { return _M_ptr == nullptr; }
82
83 /// @cond undocumented
84 protected:
85 constexpr _Node_handle_common() noexcept : _M_ptr() { }
86
87 ~_Node_handle_common()
88 {
89 if (!empty())
90 _M_reset();
91 }
92
93 _Node_handle_common(_Node_handle_common&& __nh) noexcept
94 : _M_ptr(__nh._M_ptr)
95 {
96 if (_M_ptr)
97 _M_move(std::move(__nh));
98 }
99
100 _Node_handle_common&
101 operator=(_Node_handle_common&& __nh) noexcept
102 {
103 if (empty())
104 {
105 if (!__nh.empty())
106 _M_move(std::move(__nh));
107 }
108 else if (__nh.empty())
109 _M_reset();
110 else
111 {
112 // Free the current node before replacing the allocator.
113 _AllocTraits::destroy(*_M_alloc, _M_ptr->_M_valptr());
114 _AllocTraits::deallocate(*_M_alloc, _M_ptr, 1);
115
116 _M_alloc = __nh._M_alloc.release(); // assigns if POCMA
117 _M_ptr = __nh._M_ptr;
118 __nh._M_ptr = nullptr;
119 }
120 return *this;
121 }
122
123 _Node_handle_common(typename _AllocTraits::pointer __ptr,
124 const _NodeAlloc& __alloc)
125 : _M_ptr(__ptr), _M_alloc(__alloc)
126 {
127 __glibcxx_assert(__ptr != nullptr);
128 }
129
130 void
131 _M_swap(_Node_handle_common& __nh) noexcept
132 {
133 if (empty())
134 {
135 if (!__nh.empty())
136 _M_move(std::move(__nh));
137 }
138 else if (__nh.empty())
139 __nh._M_move(std::move(*this));
140 else
141 {
142 using std::swap;
143 swap(_M_ptr, __nh._M_ptr);
144 _M_alloc.swap(__nh._M_alloc); // swaps if POCS
145 }
146 }
147
148 private:
149 // Moves the pointer and allocator from __nh to *this.
150 // Precondition: empty() && !__nh.empty()
151 // Postcondition: !empty() && __nh.empty()
152 void
153 _M_move(_Node_handle_common&& __nh) noexcept
154 {
155 ::new (std::__addressof(_M_alloc)) _NodeAlloc(__nh._M_alloc.release());
156 _M_ptr = __nh._M_ptr;
157 __nh._M_ptr = nullptr;
158 }
159
160 // Deallocates the node, destroys the allocator.
161 // Precondition: !empty()
162 // Postcondition: empty()
163 void
164 _M_reset() noexcept
165 {
166 _NodeAlloc __alloc = _M_alloc.release();
167 _AllocTraits::destroy(__alloc, _M_ptr->_M_valptr());
168 _AllocTraits::deallocate(__alloc, _M_ptr, 1);
169 _M_ptr = nullptr;
170 }
171
172 protected:
173 typename _AllocTraits::pointer _M_ptr;
174
175 private:
176 // A simplified, non-copyable std::optional<_NodeAlloc>.
177 // Call release() before destruction iff the allocator member is active.
178 union _Optional_alloc
179 {
180 _Optional_alloc() { }
181 ~_Optional_alloc() { }
182
183 _Optional_alloc(_Optional_alloc&&) = delete;
184 _Optional_alloc& operator=(_Optional_alloc&&) = delete;
185
186 _Optional_alloc(const _NodeAlloc& __alloc) noexcept
187 : _M_alloc(__alloc)
188 { }
189
190 // Precondition: _M_alloc is the active member of the union.
191 void
192 operator=(_NodeAlloc&& __alloc) noexcept
193 {
194 using _ATr = _AllocTraits;
195 if constexpr (_ATr::propagate_on_container_move_assignment::value)
196 _M_alloc = std::move(__alloc);
197 else if constexpr (!_AllocTraits::is_always_equal::value)
198 __glibcxx_assert(_M_alloc == __alloc);
199 }
200
201 // Precondition: _M_alloc is the active member of both unions.
202 void
203 swap(_Optional_alloc& __other) noexcept
204 {
205 using std::swap;
206 if constexpr (_AllocTraits::propagate_on_container_swap::value)
207 swap(_M_alloc, __other._M_alloc);
208 else if constexpr (!_AllocTraits::is_always_equal::value)
209 __glibcxx_assert(_M_alloc == __other._M_alloc);
210 }
211
212 // Precondition: _M_alloc is the active member of the union.
213 _NodeAlloc& operator*() noexcept { return _M_alloc; }
214
215 // Precondition: _M_alloc is the active member of the union.
216 _NodeAlloc release() noexcept
217 {
218 _NodeAlloc __tmp = std::move(_M_alloc);
219 _M_alloc.~_NodeAlloc();
220 return __tmp;
221 }
222
223 struct _Empty { };
224
225 [[__no_unique_address__]] _Empty _M_empty;
226 [[__no_unique_address__]] _NodeAlloc _M_alloc;
227 };
228
229 [[__no_unique_address__]] _Optional_alloc _M_alloc;
230
231 template<typename _Key2, typename _Value2, typename _KeyOfValue,
232 typename _Compare, typename _ValueAlloc>
233 friend class _Rb_tree;
234
235 /// @endcond
236 };
237
238 /// Node handle type for maps.
239 template<typename _Key, typename _Value, typename _NodeAlloc>
240 class _Node_handle : public _Node_handle_common<_Value, _NodeAlloc>
241 {
242 public:
243 constexpr _Node_handle() noexcept = default;
244 ~_Node_handle() = default;
245 _Node_handle(_Node_handle&&) noexcept = default;
246
247 _Node_handle&
248 operator=(_Node_handle&&) noexcept = default;
249
250 using key_type = _Key;
251 using mapped_type = typename _Value::second_type;
252
253 key_type&
254 key() const noexcept
255 {
256 __glibcxx_assert(!this->empty());
257 return *_M_pkey;
258 }
259
260 mapped_type&
261 mapped() const noexcept
262 {
263 __glibcxx_assert(!this->empty());
264 return *_M_pmapped;
265 }
266
267 void
268 swap(_Node_handle& __nh) noexcept
269 {
270 this->_M_swap(__nh);
271 using std::swap;
272 swap(_M_pkey, __nh._M_pkey);
273 swap(_M_pmapped, __nh._M_pmapped);
274 }
275
276 friend void
277 swap(_Node_handle& __x, _Node_handle& __y)
278 noexcept(noexcept(__x.swap(__y)))
279 { __x.swap(__y); }
280
281 private:
282 using _AllocTraits = allocator_traits<_NodeAlloc>;
283
284 _Node_handle(typename _AllocTraits::pointer __ptr,
285 const _NodeAlloc& __alloc)
286 : _Node_handle_common<_Value, _NodeAlloc>(__ptr, __alloc)
287 {
288 if (__ptr)
289 {
290 auto& __key = const_cast<_Key&>(__ptr->_M_valptr()->first);
291 _M_pkey = _S_pointer_to(__key);
292 _M_pmapped = _S_pointer_to(__ptr->_M_valptr()->second);
293 }
294 else
295 {
296 _M_pkey = nullptr;
297 _M_pmapped = nullptr;
298 }
299 }
300
301 template<typename _Tp>
302 using __pointer
303 = __ptr_rebind<typename _AllocTraits::pointer,
304 remove_reference_t<_Tp>>;
305
306 __pointer<_Key> _M_pkey = nullptr;
307 __pointer<typename _Value::second_type> _M_pmapped = nullptr;
308
309 template<typename _Tp>
310 __pointer<_Tp>
311 _S_pointer_to(_Tp& __obj)
312 { return pointer_traits<__pointer<_Tp>>::pointer_to(__obj); }
313
314 const key_type&
315 _M_key() const noexcept { return key(); }
316
317 template<typename _Key2, typename _Value2, typename _KeyOfValue,
318 typename _Compare, typename _ValueAlloc>
319 friend class _Rb_tree;
320
321 template<typename _Key2, typename _Value2, typename _ValueAlloc,
322 typename _ExtractKey, typename _Equal,
323 typename _Hash, typename _RangeHash, typename _Unused,
324 typename _RehashPolicy, typename _Traits>
325 friend class _Hashtable;
326 };
327
328 /// Node handle type for sets.
329 template<typename _Value, typename _NodeAlloc>
330 class _Node_handle<_Value, _Value, _NodeAlloc>
331 : public _Node_handle_common<_Value, _NodeAlloc>
332 {
333 public:
334 constexpr _Node_handle() noexcept = default;
335 ~_Node_handle() = default;
336 _Node_handle(_Node_handle&&) noexcept = default;
337
338 _Node_handle&
339 operator=(_Node_handle&&) noexcept = default;
340
341 using value_type = _Value;
342
343 value_type&
344 value() const noexcept
345 {
346 __glibcxx_assert(!this->empty());
347 return *this->_M_ptr->_M_valptr();
348 }
349
350 void
351 swap(_Node_handle& __nh) noexcept
352 { this->_M_swap(__nh); }
353
354 friend void
355 swap(_Node_handle& __x, _Node_handle& __y)
356 noexcept(noexcept(__x.swap(__y)))
357 { __x.swap(__y); }
358
359 private:
360 using _AllocTraits = allocator_traits<_NodeAlloc>;
361
362 _Node_handle(typename _AllocTraits::pointer __ptr,
363 const _NodeAlloc& __alloc)
364 : _Node_handle_common<_Value, _NodeAlloc>(__ptr, __alloc) { }
365
366 const value_type&
367 _M_key() const noexcept { return value(); }
368
369 template<typename _Key, typename _Val, typename _KeyOfValue,
370 typename _Compare, typename _Alloc>
371 friend class _Rb_tree;
372
373 template<typename _Key2, typename _Value2, typename _ValueAlloc,
374 typename _ExtractKey, typename _Equal,
375 typename _Hash, typename _RangeHash, typename _Unused,
376 typename _RehashPolicy, typename _Traits>
377 friend class _Hashtable;
378 };
379
380 /// Return type of insert(node_handle&&) on unique maps/sets.
381 template<typename _Iterator, typename _NodeHandle>
382 struct _Node_insert_return
383 {
384 _Iterator position = _Iterator();
385 bool inserted = false;
386 _NodeHandle node;
387 };
388
389 /// @}
390
391 _GLIBCXX_END_NAMESPACE_VERSION
392 } // namespace std
393
394 #endif // __glibcxx_node_extract
395 #endif