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