blob: 591d3ea11fa25f197e12db98cb00ff26b7fd2a6b [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// 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_CONTAINER_H_
16#define ABSL_CONTAINER_INTERNAL_CONTAINER_H_
17
18#include <cassert>
19#include <type_traits>
20
21#include "absl/meta/type_traits.h"
22#include "absl/types/optional.h"
23
24namespace absl {
25namespace container_internal {
26
27template <class, class = void>
28struct IsTransparent : std::false_type {};
29template <class T>
30struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
31 : std::true_type {};
32
33template <bool is_transparent>
34struct KeyArg {
35 // Transparent. Forward `K`.
36 template <typename K, typename key_type>
37 using type = K;
38};
39
40template <>
41struct KeyArg<false> {
42 // Not transparent. Always use `key_type`.
43 template <typename K, typename key_type>
44 using type = key_type;
45};
46
47// The node_handle concept from C++17.
48// We specialize node_handle for sets and maps. node_handle_base holds the
49// common API of both.
50template <typename PolicyTraits, typename Alloc>
51class node_handle_base {
52 protected:
53 using slot_type = typename PolicyTraits::slot_type;
54
55 public:
56 using allocator_type = Alloc;
57
58 constexpr node_handle_base() {}
59 node_handle_base(node_handle_base&& other) noexcept {
60 *this = std::move(other);
61 }
62 ~node_handle_base() { destroy(); }
63 node_handle_base& operator=(node_handle_base&& other) noexcept {
64 destroy();
65 if (!other.empty()) {
66 alloc_ = other.alloc_;
67 PolicyTraits::transfer(alloc(), slot(), other.slot());
68 other.reset();
69 }
70 return *this;
71 }
72
73 bool empty() const noexcept { return !alloc_; }
74 explicit operator bool() const noexcept { return !empty(); }
75 allocator_type get_allocator() const { return *alloc_; }
76
77 protected:
78 friend struct CommonAccess;
79
80 struct transfer_tag_t {};
81 node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s)
82 : alloc_(a) {
83 PolicyTraits::transfer(alloc(), slot(), s);
84 }
85
86 struct move_tag_t {};
87 node_handle_base(move_tag_t, const allocator_type& a, slot_type* s)
88 : alloc_(a) {
89 PolicyTraits::construct(alloc(), slot(), s);
90 }
91
92 void destroy() {
93 if (!empty()) {
94 PolicyTraits::destroy(alloc(), slot());
95 reset();
96 }
97 }
98
99 void reset() {
100 assert(alloc_.has_value());
101 alloc_ = absl::nullopt;
102 }
103
104 slot_type* slot() const {
105 assert(!empty());
106 return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
107 }
108 allocator_type* alloc() { return std::addressof(*alloc_); }
109
110 private:
111 absl::optional<allocator_type> alloc_;
112 mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
113 slot_space_;
114};
115
116// For sets.
117template <typename Policy, typename PolicyTraits, typename Alloc,
118 typename = void>
119class node_handle : public node_handle_base<PolicyTraits, Alloc> {
120 using Base = typename node_handle::node_handle_base;
121
122 public:
123 using value_type = typename PolicyTraits::value_type;
124
125 constexpr node_handle() {}
126
127 value_type& value() const { return PolicyTraits::element(this->slot()); }
128
129 private:
130 friend struct CommonAccess;
131
132 using Base::Base;
133};
134
135// For maps.
136template <typename Policy, typename PolicyTraits, typename Alloc>
137class node_handle<Policy, PolicyTraits, Alloc,
138 absl::void_t<typename Policy::mapped_type>>
139 : public node_handle_base<PolicyTraits, Alloc> {
140 using Base = typename node_handle::node_handle_base;
141
142 public:
143 using key_type = typename Policy::key_type;
144 using mapped_type = typename Policy::mapped_type;
145
146 constexpr node_handle() {}
147
148 auto key() const -> decltype(PolicyTraits::key(this->slot())) {
149 return PolicyTraits::key(this->slot());
150 }
151
152 mapped_type& mapped() const {
153 return PolicyTraits::value(&PolicyTraits::element(this->slot()));
154 }
155
156 private:
157 friend struct CommonAccess;
158
159 using Base::Base;
160};
161
162// Provide access to non-public node-handle functions.
163struct CommonAccess {
164 template <typename Node>
165 static auto GetSlot(const Node& node) -> decltype(node.slot()) {
166 return node.slot();
167 }
168
169 template <typename Node>
170 static void Reset(Node* node) {
171 node->reset();
172 }
173
174 template <typename T, typename... Args>
175 static T Transfer(Args&&... args) {
176 return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
177 }
178
179 template <typename T, typename... Args>
180 static T Move(Args&&... args) {
181 return T(typename T::move_tag_t{}, std::forward<Args>(args)...);
182 }
183};
184
185// Implement the insert_return_type<> concept of C++17.
186template <class Iterator, class NodeType>
187struct InsertReturnType {
188 Iterator position;
189 bool inserted;
190 NodeType node;
191};
192
193} // namespace container_internal
194} // namespace absl
195
196#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_