1 // Copyright 2017 The Abseil Authors.
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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.
15 #ifndef ABSL_TYPES_INTERNAL_OPTIONAL_H_
16 #define ABSL_TYPES_INTERNAL_OPTIONAL_H_
20 #include <type_traits>
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"
28 // ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
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:
38 // template <typename T>
39 // constexpr Base(T t_) : t(t_) {}
41 // struct Foo : Base {
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
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
58 // Forward declaration
62 namespace optional_internal {
64 // This tag type is used as a constructor parameter type for `nullopt_t`.
66 explicit init_t() = default;
69 struct empty_struct {};
71 // This class stores the data in optional<T>.
72 // It is specialized based on whether T is trivially destructible.
73 // This is the specialization for non trivially destructible type.
74 template <typename T, bool unused = std::is_trivially_destructible<T>::value>
75 class optional_data_dtor_base {
77 static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
78 // Use an array to avoid GCC 6 placement-new warning.
79 empty_struct data[sizeof(T) / sizeof(empty_struct)];
83 // Whether there is data or not.
91 void destruct() noexcept {
98 // dummy_ must be initialized for constexpr constructor.
99 constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
101 template <typename... Args>
102 constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
103 : engaged_(true), data_(absl::forward<Args>(args)...) {}
105 ~optional_data_dtor_base() { destruct(); }
108 // Specialization for trivially destructible type.
109 template <typename T>
110 class optional_data_dtor_base<T, true> {
112 static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
113 // Use array to avoid GCC 6 placement-new warning.
114 empty_struct data[sizeof(T) / sizeof(empty_struct)];
118 // Whether there is data or not.
125 void destruct() noexcept { engaged_ = false; }
127 // dummy_ must be initialized for constexpr constructor.
128 constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
130 template <typename... Args>
131 constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
132 : engaged_(true), data_(absl::forward<Args>(args)...) {}
135 template <typename T>
136 class optional_data_base : public optional_data_dtor_base<T> {
138 using base = optional_data_dtor_base<T>;
139 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
142 optional_data_base() = default;
144 template <typename... Args>
145 constexpr explicit optional_data_base(in_place_t t, Args&&... args)
146 : base(t, absl::forward<Args>(args)...) {}
149 template <typename... Args>
150 void construct(Args&&... args) {
151 // Use dummy_'s address to work around casting cv-qualified T* to void*.
152 ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
153 this->engaged_ = true;
156 template <typename U>
158 if (this->engaged_) {
159 this->data_ = std::forward<U>(u);
161 construct(std::forward<U>(u));
166 // TODO(absl-team): Add another class using
167 // std::is_trivially_move_constructible trait when available to match
168 // http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
169 // have trivial move but nontrivial copy.
170 // Also, we should be checking is_trivially_copyable here, which is not
171 // supported now, so we use is_trivially_* traits instead.
172 template <typename T,
173 bool unused = absl::is_trivially_copy_constructible<T>::value&&
174 absl::is_trivially_copy_assignable<typename std::remove_cv<
175 T>::type>::value&& std::is_trivially_destructible<T>::value>
178 // Trivially copyable types
179 template <typename T>
180 class optional_data<T, true> : public optional_data_base<T> {
182 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
183 using optional_data_base<T>::optional_data_base;
185 optional_data() = default;
187 template <typename... Args>
188 constexpr explicit optional_data(in_place_t t, Args&&... args)
189 : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
193 template <typename T>
194 class optional_data<T, false> : public optional_data_base<T> {
196 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
197 using optional_data_base<T>::optional_data_base;
199 template <typename... Args>
200 constexpr explicit optional_data(in_place_t t, Args&&... args)
201 : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
204 optional_data() = default;
206 optional_data(const optional_data& rhs) : optional_data_base<T>() {
208 this->construct(rhs.data_);
212 optional_data(optional_data&& rhs) noexcept(
213 absl::default_allocator_is_nothrow::value ||
214 std::is_nothrow_move_constructible<T>::value)
215 : optional_data_base<T>() {
217 this->construct(std::move(rhs.data_));
221 optional_data& operator=(const optional_data& rhs) {
223 this->assign(rhs.data_);
230 optional_data& operator=(optional_data&& rhs) noexcept(
231 std::is_nothrow_move_assignable<T>::value&&
232 std::is_nothrow_move_constructible<T>::value) {
234 this->assign(std::move(rhs.data_));
242 // Ordered by level of restriction, from low to high.
243 // Copyable implies movable.
244 enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
246 // Base class for enabling/disabling copy/move constructor.
247 template <copy_traits>
248 class optional_ctor_base;
251 class optional_ctor_base<copy_traits::copyable> {
253 constexpr optional_ctor_base() = default;
254 optional_ctor_base(const optional_ctor_base&) = default;
255 optional_ctor_base(optional_ctor_base&&) = default;
256 optional_ctor_base& operator=(const optional_ctor_base&) = default;
257 optional_ctor_base& operator=(optional_ctor_base&&) = default;
261 class optional_ctor_base<copy_traits::movable> {
263 constexpr optional_ctor_base() = default;
264 optional_ctor_base(const optional_ctor_base&) = delete;
265 optional_ctor_base(optional_ctor_base&&) = default;
266 optional_ctor_base& operator=(const optional_ctor_base&) = default;
267 optional_ctor_base& operator=(optional_ctor_base&&) = default;
271 class optional_ctor_base<copy_traits::non_movable> {
273 constexpr optional_ctor_base() = default;
274 optional_ctor_base(const optional_ctor_base&) = delete;
275 optional_ctor_base(optional_ctor_base&&) = delete;
276 optional_ctor_base& operator=(const optional_ctor_base&) = default;
277 optional_ctor_base& operator=(optional_ctor_base&&) = default;
280 // Base class for enabling/disabling copy/move assignment.
281 template <copy_traits>
282 class optional_assign_base;
285 class optional_assign_base<copy_traits::copyable> {
287 constexpr optional_assign_base() = default;
288 optional_assign_base(const optional_assign_base&) = default;
289 optional_assign_base(optional_assign_base&&) = default;
290 optional_assign_base& operator=(const optional_assign_base&) = default;
291 optional_assign_base& operator=(optional_assign_base&&) = default;
295 class optional_assign_base<copy_traits::movable> {
297 constexpr optional_assign_base() = default;
298 optional_assign_base(const optional_assign_base&) = default;
299 optional_assign_base(optional_assign_base&&) = default;
300 optional_assign_base& operator=(const optional_assign_base&) = delete;
301 optional_assign_base& operator=(optional_assign_base&&) = default;
305 class optional_assign_base<copy_traits::non_movable> {
307 constexpr optional_assign_base() = default;
308 optional_assign_base(const optional_assign_base&) = default;
309 optional_assign_base(optional_assign_base&&) = default;
310 optional_assign_base& operator=(const optional_assign_base&) = delete;
311 optional_assign_base& operator=(optional_assign_base&&) = delete;
314 template <typename T>
315 struct ctor_copy_traits {
316 static constexpr copy_traits traits =
317 std::is_copy_constructible<T>::value
318 ? copy_traits::copyable
319 : std::is_move_constructible<T>::value ? copy_traits::movable
320 : copy_traits::non_movable;
323 template <typename T>
324 struct assign_copy_traits {
325 static constexpr copy_traits traits =
326 absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
327 ? copy_traits::copyable
328 : absl::is_move_assignable<T>::value &&
329 std::is_move_constructible<T>::value
330 ? copy_traits::movable
331 : copy_traits::non_movable;
334 // Whether T is constructible or convertible from optional<U>.
335 template <typename T, typename U>
336 struct is_constructible_convertible_from_optional
337 : std::integral_constant<
338 bool, std::is_constructible<T, optional<U>&>::value ||
339 std::is_constructible<T, optional<U>&&>::value ||
340 std::is_constructible<T, const optional<U>&>::value ||
341 std::is_constructible<T, const optional<U>&&>::value ||
342 std::is_convertible<optional<U>&, T>::value ||
343 std::is_convertible<optional<U>&&, T>::value ||
344 std::is_convertible<const optional<U>&, T>::value ||
345 std::is_convertible<const optional<U>&&, T>::value> {};
347 // Whether T is constructible or convertible or assignable from optional<U>.
348 template <typename T, typename U>
349 struct is_constructible_convertible_assignable_from_optional
350 : std::integral_constant<
351 bool, is_constructible_convertible_from_optional<T, U>::value ||
352 std::is_assignable<T&, optional<U>&>::value ||
353 std::is_assignable<T&, optional<U>&&>::value ||
354 std::is_assignable<T&, const optional<U>&>::value ||
355 std::is_assignable<T&, const optional<U>&&>::value> {};
357 // Helper function used by [optional.relops], [optional.comp_with_t],
358 // for checking whether an expression is convertible to bool.
359 bool convertible_to_bool(bool);
361 // Base class for std::hash<absl::optional<T>>:
362 // If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
363 // compute the hash; Otherwise, it is disabled.
364 // Reference N4659 23.14.15 [unord.hash].
365 template <typename T, typename = size_t>
366 struct optional_hash_base {
367 optional_hash_base() = delete;
368 optional_hash_base(const optional_hash_base&) = delete;
369 optional_hash_base(optional_hash_base&&) = delete;
370 optional_hash_base& operator=(const optional_hash_base&) = delete;
371 optional_hash_base& operator=(optional_hash_base&&) = delete;
374 template <typename T>
375 struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
376 std::declval<absl::remove_const_t<T> >()))> {
377 using argument_type = absl::optional<T>;
378 using result_type = size_t;
379 size_t operator()(const absl::optional<T>& opt) const {
380 absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
382 return std::hash<absl::remove_const_t<T> >()(*opt);
384 return static_cast<size_t>(0x297814aaad196e6dULL);
389 } // namespace optional_internal
392 #undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
394 #endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_