| 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 | |
| 56 | namespace absl { |
| 57 | ABSL_NAMESPACE_BEGIN |
| 58 | |
| 59 | // Forward declaration |
| 60 | template <typename T> |
| 61 | class optional; |
| 62 | |
| 63 | namespace optional_internal { |
| 64 | |
| 65 | // This tag type is used as a constructor parameter type for `nullopt_t`. |
| 66 | struct init_t { |
| 67 | explicit init_t() = default; |
| 68 | }; |
| 69 | |
| 70 | struct 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. |
| 75 | template <typename T, bool unused = std::is_trivially_destructible<T>::value> |
| 76 | class 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. |
| 118 | template <typename T> |
| 119 | class 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 | |
| 144 | template <typename T> |
| 145 | class 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. |
| 181 | template <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> |
| 185 | class optional_data; |
| 186 | |
| 187 | // Trivially copyable types |
| 188 | template <typename T> |
| 189 | class 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 | |
| 202 | template <typename T> |
| 203 | class 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. |
| 253 | enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 }; |
| 254 | |
| 255 | // Base class for enabling/disabling copy/move constructor. |
| 256 | template <copy_traits> |
| 257 | class optional_ctor_base; |
| 258 | |
| 259 | template <> |
| 260 | class 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 | |
| 269 | template <> |
| 270 | class 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 | |
| 279 | template <> |
| 280 | class 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. |
| 290 | template <copy_traits> |
| 291 | class optional_assign_base; |
| 292 | |
| 293 | template <> |
| 294 | class 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 | |
| 303 | template <> |
| 304 | class 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 | |
| 313 | template <> |
| 314 | class 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 | |
| 323 | template <typename T> |
| 324 | struct 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 | |
| 332 | template <typename T> |
| 333 | struct 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>. |
| 344 | template <typename T, typename U> |
| 345 | struct 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>. |
| 357 | template <typename T, typename U> |
| 358 | struct 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. |
| 368 | bool 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]. |
| 374 | template <typename T, typename = size_t> |
| 375 | struct 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 | |
| 383 | template <typename T> |
| 384 | struct 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 |
| 399 | ABSL_NAMESPACE_END |
| 400 | } // namespace absl |
| 401 | |
| 402 | #undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS |
| 403 | |
| 404 | #endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_ |
| 405 | |