1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is dual licensed under the MIT and the University of Illinois Open
7// Source Licenses. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#ifndef _LIBCPP___NODE_HANDLE
12#define _LIBCPP___NODE_HANDLE
13
14#include <__config>
15#include <memory>
16#include <optional>
17
18#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19#pragma GCC system_header
20#endif
21
22_LIBCPP_PUSH_MACROS
23#include <__undef_macros>
24
25_LIBCPP_BEGIN_NAMESPACE_STD
26
27#if _LIBCPP_STD_VER > 14
28
29#define __cpp_lib_node_extract 201606L
30
31// Specialized in __tree & __hash_table for their _NodeType.
32template <class _NodeType, class _Alloc>
33struct __generic_container_node_destructor;
34
35template <class _NodeType, class _Alloc,
36          template <class, class> class _MapOrSetSpecifics>
37class _LIBCPP_TEMPLATE_VIS __basic_node_handle
38    : public _MapOrSetSpecifics<
39          _NodeType,
40          __basic_node_handle<_NodeType, _Alloc, _MapOrSetSpecifics>>
41{
42    template <class _Tp, class _Compare, class _Allocator>
43        friend class __tree;
44    template <class _Tp, class _Hash, class _Equal, class _Allocator>
45        friend class __hash_table;
46    friend struct _MapOrSetSpecifics<
47        _NodeType, __basic_node_handle<_NodeType, _Alloc, _MapOrSetSpecifics>>;
48
49    typedef allocator_traits<_Alloc> __alloc_traits;
50    typedef typename __rebind_pointer<typename __alloc_traits::void_pointer,
51                                      _NodeType>::type
52        __node_pointer_type;
53
54public:
55    typedef _Alloc allocator_type;
56
57private:
58    __node_pointer_type __ptr_ = nullptr;
59    optional<allocator_type> __alloc_;
60
61    _LIBCPP_INLINE_VISIBILITY
62    void __release()
63    {
64        __ptr_ = nullptr;
65        __alloc_ = _VSTD::nullopt;
66    }
67
68    _LIBCPP_INLINE_VISIBILITY
69    void __destroy_node_pointer()
70    {
71        if (__ptr_ != nullptr)
72        {
73            typedef typename __allocator_traits_rebind<
74                allocator_type, _NodeType>::type __node_alloc_type;
75            __node_alloc_type __alloc(*__alloc_);
76            __generic_container_node_destructor<_NodeType, __node_alloc_type>(
77                __alloc, true)(__ptr_);
78            __ptr_ = nullptr;
79        }
80    }
81
82    _LIBCPP_INLINE_VISIBILITY
83    __basic_node_handle(__node_pointer_type __ptr,
84                        allocator_type const& __alloc)
85            : __ptr_(__ptr), __alloc_(__alloc)
86    {
87    }
88
89public:
90    _LIBCPP_INLINE_VISIBILITY
91    __basic_node_handle() = default;
92
93    _LIBCPP_INLINE_VISIBILITY
94    __basic_node_handle(__basic_node_handle&& __other) noexcept
95            : __ptr_(__other.__ptr_),
96              __alloc_(_VSTD::move(__other.__alloc_))
97    {
98        __other.__ptr_ = nullptr;
99        __other.__alloc_ = _VSTD::nullopt;
100    }
101
102    _LIBCPP_INLINE_VISIBILITY
103    __basic_node_handle& operator=(__basic_node_handle&& __other)
104    {
105        _LIBCPP_ASSERT(
106            __alloc_ == _VSTD::nullopt ||
107            __alloc_traits::propagate_on_container_move_assignment::value ||
108            __alloc_ == __other.__alloc_,
109            "node_type with incompatible allocator passed to "
110            "node_type::operator=(node_type&&)");
111
112        __destroy_node_pointer();
113        __ptr_ = __other.__ptr_;
114
115        if (__alloc_traits::propagate_on_container_move_assignment::value ||
116            __alloc_ == _VSTD::nullopt)
117            __alloc_ = _VSTD::move(__other.__alloc_);
118
119        __other.__ptr_ = nullptr;
120        __other.__alloc_ = _VSTD::nullopt;
121
122        return *this;
123    }
124
125    _LIBCPP_INLINE_VISIBILITY
126    allocator_type get_allocator() const { return *__alloc_; }
127
128    _LIBCPP_INLINE_VISIBILITY
129    explicit operator bool() const { return __ptr_ != nullptr; }
130
131    _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
132    bool empty() const { return __ptr_ == nullptr; }
133
134    _LIBCPP_INLINE_VISIBILITY
135    void swap(__basic_node_handle& __other) noexcept(
136        __alloc_traits::propagate_on_container_swap::value ||
137        __alloc_traits::is_always_equal::value)
138    {
139        using _VSTD::swap;
140        swap(__ptr_, __other.__ptr_);
141        if (__alloc_traits::propagate_on_container_swap::value ||
142            __alloc_ == _VSTD::nullopt || __other.__alloc_ == _VSTD::nullopt)
143            swap(__alloc_, __other.__alloc_);
144    }
145
146    _LIBCPP_INLINE_VISIBILITY
147    friend void swap(__basic_node_handle& __a, __basic_node_handle& __b)
148        noexcept(noexcept(__a.swap(__b))) { __a.swap(__b); }
149
150    _LIBCPP_INLINE_VISIBILITY
151    ~__basic_node_handle()
152    {
153        __destroy_node_pointer();
154    }
155};
156
157template <class _NodeType, class _Derived>
158struct __set_node_handle_specifics
159{
160    typedef typename _NodeType::__node_value_type value_type;
161
162    _LIBCPP_INLINE_VISIBILITY
163    value_type& value() const
164    {
165        return static_cast<_Derived const*>(this)->__ptr_->__value_;
166    }
167};
168
169template <class _NodeType, class _Derived>
170struct __map_node_handle_specifics
171{
172    typedef typename _NodeType::__node_value_type::key_type key_type;
173    typedef typename _NodeType::__node_value_type::mapped_type mapped_type;
174
175    _LIBCPP_INLINE_VISIBILITY
176    key_type& key() const
177    {
178        return static_cast<_Derived const*>(this)->
179            __ptr_->__value_.__ref().first;
180    }
181
182    _LIBCPP_INLINE_VISIBILITY
183    mapped_type& mapped() const
184    {
185        return static_cast<_Derived const*>(this)->
186            __ptr_->__value_.__ref().second;
187    }
188};
189
190template <class _NodeType, class _Alloc>
191using __set_node_handle =
192    __basic_node_handle< _NodeType, _Alloc, __set_node_handle_specifics>;
193
194template <class _NodeType, class _Alloc>
195using __map_node_handle =
196    __basic_node_handle< _NodeType, _Alloc, __map_node_handle_specifics>;
197
198template <class _Iterator, class _NodeType>
199_LIBCPP_TEMPLATE_VIS
200struct __insert_return_type
201{
202    _Iterator position;
203    bool inserted;
204    _NodeType node;
205};
206
207#endif // _LIBCPP_STD_VER > 14
208
209_LIBCPP_END_NAMESPACE_STD
210_LIBCPP_POP_MACROS
211
212#endif
213