1// Copyright 2017 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_TYPES_INTERNAL_OPTIONAL_H_
16#define ABSL_TYPES_INTERNAL_OPTIONAL_H_
17
18#include <functional>
19#include <new>
20#include <type_traits>
21#include <utility>
22
23#include "absl/base/internal/inline_variable.h"
24#include "absl/memory/memory.h"
25#include "absl/meta/type_traits.h"
26#include "absl/utility/utility.h"
27
28// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
29//
30// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015.
31// __cpp_inheriting_constructors is a predefined macro and a recommended way to
32// check for this language feature, but GCC doesn't support it until 5.0 and
33// Clang doesn't support it until 3.6.
34// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template
35// constructor. For example, the following code won't work on MSVC 2015 Update3:
36// struct Base {
37// int t;
38// template <typename T>
39// constexpr Base(T t_) : t(t_) {}
40// };
41// struct Foo : Base {
42// using Base::Base;
43// }
44// constexpr Foo foo(0); // doesn't work on MSVC 2015
45#if defined(__clang__)
46#if __has_feature(cxx_inheriting_constructors)
47#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
48#endif
49#elif (defined(__GNUC__) && \
50 (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
51 (__cpp_inheriting_constructors >= 200802) || \
52 (defined(_MSC_VER) && _MSC_VER >= 1910)
53#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
54#endif
55
56namespace absl {
57ABSL_NAMESPACE_BEGIN
58
59// Forward declaration
60template <typename T>
61class optional;
62
63namespace optional_internal {
64
65// This tag type is used as a constructor parameter type for `nullopt_t`.
66struct init_t {
67 explicit init_t() = default;
68};
69
70struct empty_struct {};
71
72// This class stores the data in optional<T>.
73// It is specialized based on whether T is trivially destructible.
74// This is the specialization for non trivially destructible type.
75template <typename T, bool unused = std::is_trivially_destructible<T>::value>
76class optional_data_dtor_base {
77 struct dummy_type {
78 static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
79 // Use an array to avoid GCC 6 placement-new warning.
80 empty_struct data[sizeof(T) / sizeof(empty_struct)];
81 };
82
83 protected:
84 // Whether there is data or not.
85 bool engaged_;
86 // Data storage
87 union {
88 T data_;
89 dummy_type dummy_;
90 };
91
92 void destruct() noexcept {
93 if (engaged_) {
94 // `data_` must be initialized if `engaged_` is true.
95#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
96#pragma GCC diagnostic push
97#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
98#endif
99 data_.~T();
100#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
101#pragma GCC diagnostic pop
102#endif
103 engaged_ = false;
104 }
105 }
106
107 // dummy_ must be initialized for constexpr constructor.
108 constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
109
110 template <typename... Args>
111 constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
112 : engaged_(true), data_(absl::forward<Args>(args)...) {}
113
114 ~optional_data_dtor_base() { destruct(); }
115};
116
117// Specialization for trivially destructible type.
118template <typename T>
119class optional_data_dtor_base<T, true> {
120 struct dummy_type {
121 static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
122 // Use array to avoid GCC 6 placement-new warning.
123 empty_struct data[sizeof(T) / sizeof(empty_struct)];
124 };
125
126 protected:
127 // Whether there is data or not.
128 bool engaged_;
129 // Data storage
130 union {
131 T data_;
132 dummy_type dummy_;
133 };
134 void destruct() noexcept { engaged_ = false; }
135
136 // dummy_ must be initialized for constexpr constructor.
137 constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
138
139 template <typename... Args>
140 constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
141 : engaged_(true), data_(absl::forward<Args>(args)...) {}
142};
143
144template <typename T>
145class optional_data_base : public optional_data_dtor_base<T> {
146 protected:
147 using base = optional_data_dtor_base<T>;
148#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
149 using base::base;
150#else
151 optional_data_base() = default;
152
153 template <typename... Args>
154 constexpr explicit optional_data_base(in_place_t t, Args&&... args)
155 : base(t, absl::forward<Args>(args)...) {}
156#endif
157
158 template <typename... Args>
159 void construct(Args&&... args) {
160 // Use dummy_'s address to work around casting cv-qualified T* to void*.
161 ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
162 this->engaged_ = true;
163 }
164
165 template <typename U>
166 void assign(U&& u) {
167 if (this->engaged_) {
168 this->data_ = std::forward<U>(u);
169 } else {
170 construct(std::forward<U>(u));
171 }
172 }
173};
174
175// TODO(absl-team): Add another class using
176// std::is_trivially_move_constructible trait when available to match
177// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
178// have trivial move but nontrivial copy.
179// Also, we should be checking is_trivially_copyable here, which is not
180// supported now, so we use is_trivially_* traits instead.
181template <typename T,
182 bool unused = absl::is_trivially_copy_constructible<T>::value&&
183 absl::is_trivially_copy_assignable<typename std::remove_cv<
184 T>::type>::value&& std::is_trivially_destructible<T>::value>
185class optional_data;
186
187// Trivially copyable types
188template <typename T>
189class optional_data<T, true> : public optional_data_base<T> {
190 protected:
191#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
192 using optional_data_base<T>::optional_data_base;
193#else
194 optional_data() = default;
195
196 template <typename... Args>
197 constexpr explicit optional_data(in_place_t t, Args&&... args)
198 : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
199#endif
200};
201
202template <typename T>
203class optional_data<T, false> : public optional_data_base<T> {
204 protected:
205#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
206 using optional_data_base<T>::optional_data_base;
207#else
208 template <typename... Args>
209 constexpr explicit optional_data(in_place_t t, Args&&... args)
210 : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
211#endif
212
213 optional_data() = default;
214
215 optional_data(const optional_data& rhs) : optional_data_base<T>() {
216 if (rhs.engaged_) {
217 this->construct(rhs.data_);
218 }
219 }
220
221 optional_data(optional_data&& rhs) noexcept(
222 absl::default_allocator_is_nothrow::value ||
223 std::is_nothrow_move_constructible<T>::value)
224 : optional_data_base<T>() {
225 if (rhs.engaged_) {
226 this->construct(std::move(rhs.data_));
227 }
228 }
229
230 optional_data& operator=(const optional_data& rhs) {
231 if (rhs.engaged_) {
232 this->assign(rhs.data_);
233 } else {
234 this->destruct();
235 }
236 return *this;
237 }
238
239 optional_data& operator=(optional_data&& rhs) noexcept(
240 std::is_nothrow_move_assignable<T>::value&&
241 std::is_nothrow_move_constructible<T>::value) {
242 if (rhs.engaged_) {
243 this->assign(std::move(rhs.data_));
244 } else {
245 this->destruct();
246 }
247 return *this;
248 }
249};
250
251// Ordered by level of restriction, from low to high.
252// Copyable implies movable.
253enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
254
255// Base class for enabling/disabling copy/move constructor.
256template <copy_traits>
257class optional_ctor_base;
258
259template <>
260class optional_ctor_base<copy_traits::copyable> {
261 public:
262 constexpr optional_ctor_base() = default;
263 optional_ctor_base(const optional_ctor_base&) = default;
264 optional_ctor_base(optional_ctor_base&&) = default;
265 optional_ctor_base& operator=(const optional_ctor_base&) = default;
266 optional_ctor_base& operator=(optional_ctor_base&&) = default;
267};
268
269template <>
270class optional_ctor_base<copy_traits::movable> {
271 public:
272 constexpr optional_ctor_base() = default;
273 optional_ctor_base(const optional_ctor_base&) = delete;
274 optional_ctor_base(optional_ctor_base&&) = default;
275 optional_ctor_base& operator=(const optional_ctor_base&) = default;
276 optional_ctor_base& operator=(optional_ctor_base&&) = default;
277};
278
279template <>
280class optional_ctor_base<copy_traits::non_movable> {
281 public:
282 constexpr optional_ctor_base() = default;
283 optional_ctor_base(const optional_ctor_base&) = delete;
284 optional_ctor_base(optional_ctor_base&&) = delete;
285 optional_ctor_base& operator=(const optional_ctor_base&) = default;
286 optional_ctor_base& operator=(optional_ctor_base&&) = default;
287};
288
289// Base class for enabling/disabling copy/move assignment.
290template <copy_traits>
291class optional_assign_base;
292
293template <>
294class optional_assign_base<copy_traits::copyable> {
295 public:
296 constexpr optional_assign_base() = default;
297 optional_assign_base(const optional_assign_base&) = default;
298 optional_assign_base(optional_assign_base&&) = default;
299 optional_assign_base& operator=(const optional_assign_base&) = default;
300 optional_assign_base& operator=(optional_assign_base&&) = default;
301};
302
303template <>
304class optional_assign_base<copy_traits::movable> {
305 public:
306 constexpr optional_assign_base() = default;
307 optional_assign_base(const optional_assign_base&) = default;
308 optional_assign_base(optional_assign_base&&) = default;
309 optional_assign_base& operator=(const optional_assign_base&) = delete;
310 optional_assign_base& operator=(optional_assign_base&&) = default;
311};
312
313template <>
314class optional_assign_base<copy_traits::non_movable> {
315 public:
316 constexpr optional_assign_base() = default;
317 optional_assign_base(const optional_assign_base&) = default;
318 optional_assign_base(optional_assign_base&&) = default;
319 optional_assign_base& operator=(const optional_assign_base&) = delete;
320 optional_assign_base& operator=(optional_assign_base&&) = delete;
321};
322
323template <typename T>
324struct ctor_copy_traits {
325 static constexpr copy_traits traits =
326 std::is_copy_constructible<T>::value
327 ? copy_traits::copyable
328 : std::is_move_constructible<T>::value ? copy_traits::movable
329 : copy_traits::non_movable;
330};
331
332template <typename T>
333struct assign_copy_traits {
334 static constexpr copy_traits traits =
335 absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
336 ? copy_traits::copyable
337 : absl::is_move_assignable<T>::value &&
338 std::is_move_constructible<T>::value
339 ? copy_traits::movable
340 : copy_traits::non_movable;
341};
342
343// Whether T is constructible or convertible from optional<U>.
344template <typename T, typename U>
345struct is_constructible_convertible_from_optional
346 : std::integral_constant<
347 bool, std::is_constructible<T, optional<U>&>::value ||
348 std::is_constructible<T, optional<U>&&>::value ||
349 std::is_constructible<T, const optional<U>&>::value ||
350 std::is_constructible<T, const optional<U>&&>::value ||
351 std::is_convertible<optional<U>&, T>::value ||
352 std::is_convertible<optional<U>&&, T>::value ||
353 std::is_convertible<const optional<U>&, T>::value ||
354 std::is_convertible<const optional<U>&&, T>::value> {};
355
356// Whether T is constructible or convertible or assignable from optional<U>.
357template <typename T, typename U>
358struct is_constructible_convertible_assignable_from_optional
359 : std::integral_constant<
360 bool, is_constructible_convertible_from_optional<T, U>::value ||
361 std::is_assignable<T&, optional<U>&>::value ||
362 std::is_assignable<T&, optional<U>&&>::value ||
363 std::is_assignable<T&, const optional<U>&>::value ||
364 std::is_assignable<T&, const optional<U>&&>::value> {};
365
366// Helper function used by [optional.relops], [optional.comp_with_t],
367// for checking whether an expression is convertible to bool.
368bool convertible_to_bool(bool);
369
370// Base class for std::hash<absl::optional<T>>:
371// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
372// compute the hash; Otherwise, it is disabled.
373// Reference N4659 23.14.15 [unord.hash].
374template <typename T, typename = size_t>
375struct optional_hash_base {
376 optional_hash_base() = delete;
377 optional_hash_base(const optional_hash_base&) = delete;
378 optional_hash_base(optional_hash_base&&) = delete;
379 optional_hash_base& operator=(const optional_hash_base&) = delete;
380 optional_hash_base& operator=(optional_hash_base&&) = delete;
381};
382
383template <typename T>
384struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
385 std::declval<absl::remove_const_t<T> >()))> {
386 using argument_type = absl::optional<T>;
387 using result_type = size_t;
388 size_t operator()(const absl::optional<T>& opt) const {
389 absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
390 if (opt) {
391 return std::hash<absl::remove_const_t<T> >()(*opt);
392 } else {
393 return static_cast<size_t>(0x297814aaad196e6dULL);
394 }
395 }
396};
397
398} // namespace optional_internal
399ABSL_NAMESPACE_END
400} // namespace absl
401
402#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
403
404#endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_
405

source code of include/absl/types/internal/optional.h