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 destruct()92 void destruct() noexcept { 93 if (engaged_) { 94 data_.~T(); 95 engaged_ = false; 96 } 97 } 98 99 // dummy_ must be initialized for constexpr constructor. optional_data_dtor_base()100 constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} 101 102 template <typename... Args> optional_data_dtor_base(in_place_t,Args &&...args)103 constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) 104 : engaged_(true), data_(absl::forward<Args>(args)...) {} 105 ~optional_data_dtor_base()106 ~optional_data_dtor_base() { destruct(); } 107 }; 108 109 // Specialization for trivially destructible type. 110 template <typename T> 111 class optional_data_dtor_base<T, true> { 112 struct dummy_type { 113 static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); 114 // Use array to avoid GCC 6 placement-new warning. 115 empty_struct data[sizeof(T) / sizeof(empty_struct)]; 116 }; 117 118 protected: 119 // Whether there is data or not. 120 bool engaged_; 121 // Data storage 122 union { 123 T data_; 124 dummy_type dummy_; 125 }; destruct()126 void destruct() noexcept { engaged_ = false; } 127 128 // dummy_ must be initialized for constexpr constructor. optional_data_dtor_base()129 constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} 130 131 template <typename... Args> optional_data_dtor_base(in_place_t,Args &&...args)132 constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) 133 : engaged_(true), data_(absl::forward<Args>(args)...) {} 134 }; 135 136 template <typename T> 137 class optional_data_base : public optional_data_dtor_base<T> { 138 protected: 139 using base = optional_data_dtor_base<T>; 140 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 141 using base::base; 142 #else 143 optional_data_base() = default; 144 145 template <typename... Args> optional_data_base(in_place_t t,Args &&...args)146 constexpr explicit optional_data_base(in_place_t t, Args&&... args) 147 : base(t, absl::forward<Args>(args)...) {} 148 #endif 149 150 template <typename... Args> construct(Args &&...args)151 void construct(Args&&... args) { 152 // Use dummy_'s address to work around casting cv-qualified T* to void*. 153 ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...); 154 this->engaged_ = true; 155 } 156 157 template <typename U> assign(U && u)158 void assign(U&& u) { 159 if (this->engaged_) { 160 this->data_ = std::forward<U>(u); 161 } else { 162 construct(std::forward<U>(u)); 163 } 164 } 165 }; 166 167 // TODO(absl-team): Add another class using 168 // std::is_trivially_move_constructible trait when available to match 169 // http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that 170 // have trivial move but nontrivial copy. 171 // Also, we should be checking is_trivially_copyable here, which is not 172 // supported now, so we use is_trivially_* traits instead. 173 template <typename T, 174 bool unused = absl::is_trivially_copy_constructible<T>::value&& 175 absl::is_trivially_copy_assignable<typename std::remove_cv< 176 T>::type>::value&& std::is_trivially_destructible<T>::value> 177 class optional_data; 178 179 // Trivially copyable types 180 template <typename T> 181 class optional_data<T, true> : public optional_data_base<T> { 182 protected: 183 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 184 using optional_data_base<T>::optional_data_base; 185 #else 186 optional_data() = default; 187 188 template <typename... Args> 189 constexpr explicit optional_data(in_place_t t, Args&&... args) 190 : optional_data_base<T>(t, absl::forward<Args>(args)...) {} 191 #endif 192 }; 193 194 template <typename T> 195 class optional_data<T, false> : public optional_data_base<T> { 196 protected: 197 #ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 198 using optional_data_base<T>::optional_data_base; 199 #else 200 template <typename... Args> 201 constexpr explicit optional_data(in_place_t t, Args&&... args) 202 : optional_data_base<T>(t, absl::forward<Args>(args)...) {} 203 #endif 204 205 optional_data() = default; 206 optional_data(const optional_data & rhs)207 optional_data(const optional_data& rhs) : optional_data_base<T>() { 208 if (rhs.engaged_) { 209 this->construct(rhs.data_); 210 } 211 } 212 213 optional_data(optional_data&& rhs) noexcept( 214 absl::default_allocator_is_nothrow::value || 215 std::is_nothrow_move_constructible<T>::value) 216 : optional_data_base<T>() { 217 if (rhs.engaged_) { 218 this->construct(std::move(rhs.data_)); 219 } 220 } 221 222 optional_data& operator=(const optional_data& rhs) { 223 if (rhs.engaged_) { 224 this->assign(rhs.data_); 225 } else { 226 this->destruct(); 227 } 228 return *this; 229 } 230 noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value)231 optional_data& operator=(optional_data&& rhs) noexcept( 232 std::is_nothrow_move_assignable<T>::value&& 233 std::is_nothrow_move_constructible<T>::value) { 234 if (rhs.engaged_) { 235 this->assign(std::move(rhs.data_)); 236 } else { 237 this->destruct(); 238 } 239 return *this; 240 } 241 }; 242 243 // Ordered by level of restriction, from low to high. 244 // Copyable implies movable. 245 enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 }; 246 247 // Base class for enabling/disabling copy/move constructor. 248 template <copy_traits> 249 class optional_ctor_base; 250 251 template <> 252 class optional_ctor_base<copy_traits::copyable> { 253 public: 254 constexpr optional_ctor_base() = default; 255 optional_ctor_base(const optional_ctor_base&) = default; 256 optional_ctor_base(optional_ctor_base&&) = default; 257 optional_ctor_base& operator=(const optional_ctor_base&) = default; 258 optional_ctor_base& operator=(optional_ctor_base&&) = default; 259 }; 260 261 template <> 262 class optional_ctor_base<copy_traits::movable> { 263 public: 264 constexpr optional_ctor_base() = default; 265 optional_ctor_base(const optional_ctor_base&) = delete; 266 optional_ctor_base(optional_ctor_base&&) = default; 267 optional_ctor_base& operator=(const optional_ctor_base&) = default; 268 optional_ctor_base& operator=(optional_ctor_base&&) = default; 269 }; 270 271 template <> 272 class optional_ctor_base<copy_traits::non_movable> { 273 public: 274 constexpr optional_ctor_base() = default; 275 optional_ctor_base(const optional_ctor_base&) = delete; 276 optional_ctor_base(optional_ctor_base&&) = delete; 277 optional_ctor_base& operator=(const optional_ctor_base&) = default; 278 optional_ctor_base& operator=(optional_ctor_base&&) = default; 279 }; 280 281 // Base class for enabling/disabling copy/move assignment. 282 template <copy_traits> 283 class optional_assign_base; 284 285 template <> 286 class optional_assign_base<copy_traits::copyable> { 287 public: 288 constexpr optional_assign_base() = default; 289 optional_assign_base(const optional_assign_base&) = default; 290 optional_assign_base(optional_assign_base&&) = default; 291 optional_assign_base& operator=(const optional_assign_base&) = default; 292 optional_assign_base& operator=(optional_assign_base&&) = default; 293 }; 294 295 template <> 296 class optional_assign_base<copy_traits::movable> { 297 public: 298 constexpr optional_assign_base() = default; 299 optional_assign_base(const optional_assign_base&) = default; 300 optional_assign_base(optional_assign_base&&) = default; 301 optional_assign_base& operator=(const optional_assign_base&) = delete; 302 optional_assign_base& operator=(optional_assign_base&&) = default; 303 }; 304 305 template <> 306 class optional_assign_base<copy_traits::non_movable> { 307 public: 308 constexpr optional_assign_base() = default; 309 optional_assign_base(const optional_assign_base&) = default; 310 optional_assign_base(optional_assign_base&&) = default; 311 optional_assign_base& operator=(const optional_assign_base&) = delete; 312 optional_assign_base& operator=(optional_assign_base&&) = delete; 313 }; 314 315 template <typename T> 316 struct ctor_copy_traits { 317 static constexpr copy_traits traits = 318 std::is_copy_constructible<T>::value 319 ? copy_traits::copyable 320 : std::is_move_constructible<T>::value ? copy_traits::movable 321 : copy_traits::non_movable; 322 }; 323 324 template <typename T> 325 struct assign_copy_traits { 326 static constexpr copy_traits traits = 327 absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value 328 ? copy_traits::copyable 329 : absl::is_move_assignable<T>::value && 330 std::is_move_constructible<T>::value 331 ? copy_traits::movable 332 : copy_traits::non_movable; 333 }; 334 335 // Whether T is constructible or convertible from optional<U>. 336 template <typename T, typename U> 337 struct is_constructible_convertible_from_optional 338 : std::integral_constant< 339 bool, std::is_constructible<T, optional<U>&>::value || 340 std::is_constructible<T, optional<U>&&>::value || 341 std::is_constructible<T, const optional<U>&>::value || 342 std::is_constructible<T, const optional<U>&&>::value || 343 std::is_convertible<optional<U>&, T>::value || 344 std::is_convertible<optional<U>&&, T>::value || 345 std::is_convertible<const optional<U>&, T>::value || 346 std::is_convertible<const optional<U>&&, T>::value> {}; 347 348 // Whether T is constructible or convertible or assignable from optional<U>. 349 template <typename T, typename U> 350 struct is_constructible_convertible_assignable_from_optional 351 : std::integral_constant< 352 bool, is_constructible_convertible_from_optional<T, U>::value || 353 std::is_assignable<T&, optional<U>&>::value || 354 std::is_assignable<T&, optional<U>&&>::value || 355 std::is_assignable<T&, const optional<U>&>::value || 356 std::is_assignable<T&, const optional<U>&&>::value> {}; 357 358 // Helper function used by [optional.relops], [optional.comp_with_t], 359 // for checking whether an expression is convertible to bool. 360 bool convertible_to_bool(bool); 361 362 // Base class for std::hash<absl::optional<T>>: 363 // If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to 364 // compute the hash; Otherwise, it is disabled. 365 // Reference N4659 23.14.15 [unord.hash]. 366 template <typename T, typename = size_t> 367 struct optional_hash_base { 368 optional_hash_base() = delete; 369 optional_hash_base(const optional_hash_base&) = delete; 370 optional_hash_base(optional_hash_base&&) = delete; 371 optional_hash_base& operator=(const optional_hash_base&) = delete; 372 optional_hash_base& operator=(optional_hash_base&&) = delete; 373 }; 374 375 template <typename T> 376 struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()( 377 std::declval<absl::remove_const_t<T> >()))> { 378 using argument_type = absl::optional<T>; 379 using result_type = size_t; 380 size_t operator()(const absl::optional<T>& opt) const { 381 absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>(); 382 if (opt) { 383 return std::hash<absl::remove_const_t<T> >()(*opt); 384 } else { 385 return static_cast<size_t>(0x297814aaad196e6dULL); 386 } 387 } 388 }; 389 390 } // namespace optional_internal 391 ABSL_NAMESPACE_END 392 } // namespace absl 393 394 #undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 395 396 #endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_ 397