140 KiB
140 KiB
<html lang="en">
<head>
</head>
</html>
LCOV - code coverage report | ||||||||||||||||||||||
![]() | ||||||||||||||||||||||
|
||||||||||||||||||||||
![]() |
Line data Source code 1 : // Copyright (C) 2011 - 2012 Andrzej Krzemienski. 2 : // 3 : // Use, modification, and distribution is subject to the Boost Software 4 : // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 5 : // http://www.boost.org/LICENSE_1_0.txt) 6 : // 7 : // The idea and interface is based on Boost.Optional library 8 : // authored by Fernando Luis Cacciola Carballal 9 : // 10 : // From https://github.com/akrzemi1/Optional 11 : // 12 : // C10 13 : // - Move file to `c10` namespace. 14 : // - Remove macro use in line 478 because the nvcc device compiler cannot handle 15 : // it. 16 : // - Revise constructor logic so that it is 1) consistent with c++ 17 standard 17 : // documented here in (8): 18 : // https://en.cppreference.com/w/cpp/utility/optional/optional, and 2) able to 19 : // support initialization of optionals from convertible type U. 20 : // - Remove the constructors for `optional(const T&)` and `optional(T&&)`, as 21 : // they can be handled by the template<U=T> case with the default template 22 : // argument. 23 : // - Move `constexpr struct in_place_t {} in_place{}` to `c10/util/in_place.h` 24 : // so that it can also be used in `c10/util/variant.h`. 25 : // - Remove special cases for pre-c++14 compilers to make code simpler. 26 : 27 : #ifndef C10_UTIL_OPTIONAL_H_ 28 : #define C10_UTIL_OPTIONAL_H_ 29 : 30 : #include <c10/macros/Macros.h> 31 : #include <c10/util/ArrayRef.h> 32 : #include <c10/util/in_place.h> 33 : 34 : #include <cassert> 35 : #include <functional> 36 : #include <initializer_list> 37 : #include <stdexcept> 38 : #include <string> 39 : #include <type_traits> 40 : #include <utility> 41 : 42 : #include <c10/util/C++17.h> 43 : #include <c10/util/Metaprogramming.h> 44 : 45 : C10_CLANG_DIAGNOSTIC_PUSH() 46 : #if C10_CLANG_HAS_WARNING("-Wstring-conversion") 47 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wstring-conversion") 48 : #endif 49 : #if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32") 50 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32") 51 : #endif 52 : #if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion") 53 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion") 54 : #endif 55 : #if C10_CLANG_HAS_WARNING("-Wimplicit-int-conversion") 56 : C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-conversion") 57 : #endif 58 : 59 : #if defined(_MSC_VER) && !defined(__clang__) 60 : #pragma warning(push) 61 : #pragma warning(disable : 4624) // destructor was implicitly defined as deleted 62 : #endif 63 : 64 : #define TR2_OPTIONAL_REQUIRES(...) \ 65 : typename std::enable_if<__VA_ARGS__::value, bool>::type = false 66 : 67 : namespace c10 { 68 : 69 : // 20.5.4, optional for object types 70 : template <class T> 71 : class optional; 72 : 73 : // 20.5.5, optional for lvalue reference types 74 : template <class T> 75 : class optional<T&>; 76 : 77 : // workaround: std utility functions aren't constexpr yet 78 : template <class T> 79 199233304 : inline constexpr T&& constexpr_forward( 80 : typename std::remove_reference<T>::type& t) noexcept { 81 199233304 : return static_cast<T&&>(t); 82 : } 83 : 84 : template <class T> 85 : inline constexpr T&& constexpr_forward( 86 : typename std::remove_reference<T>::type&& t) noexcept { 87 : static_assert(!std::is_lvalue_reference<T>::value, "!!"); 88 : return static_cast<T&&>(t); 89 : } 90 : 91 : template <class T> 92 196750336 : inline constexpr typename std::remove_reference<T>::type&& constexpr_move( 93 : T&& t) noexcept { 94 196750336 : return static_cast<typename std::remove_reference<T>::type&&>(t); 95 : } 96 : 97 : #if defined NDEBUG 98 : #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) 99 : #else 100 : #define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) \ 101 : ((CHECK) ? (EXPR) : ([] { assert(!#CHECK); }(), (EXPR))) 102 : #endif 103 : 104 : #if defined(__CUDA_ARCH__) 105 : #define TR2_OPTIONAL_HOST_CONSTEXPR 106 : #else 107 : #define TR2_OPTIONAL_HOST_CONSTEXPR constexpr 108 : #endif 109 : 110 : // Sphinx chokes on static_addressof, so exclude it from Doxygen 111 : // generation. See https://github.com/sphinx-doc/sphinx/issues/7944 112 : // \cond 113 : 114 : namespace detail_ { 115 : 116 : // VS doesn't handle constexpr well, so we need to skip these stuff. 117 : #if (defined _MSC_VER) 118 : template <typename T> 119 : T* static_addressof(T& ref) { 120 : return std::addressof(ref); 121 : } 122 : #else 123 : // static_addressof: a constexpr version of addressof 124 : template <typename T> 125 : struct has_overloaded_addressof { 126 : template <class X> 127 : constexpr static bool has_overload(...) { 128 : return false; 129 : } 130 : 131 : template <class X, size_t S = sizeof(std::declval<X&>().operator&())> 132 : constexpr static bool has_overload(bool) { 133 : return true; 134 : } 135 : 136 : constexpr static bool value = has_overload<T>(true); 137 : }; 138 : 139 : template <typename T, TR2_OPTIONAL_REQUIRES(!has_overloaded_addressof<T>)> 140 : constexpr T* static_addressof(T& ref) { 141 : return &ref; 142 : } 143 : 144 : template <typename T, TR2_OPTIONAL_REQUIRES(has_overloaded_addressof<T>)> 145 : T* static_addressof(T& ref) { 146 : return std::addressof(ref); 147 : } 148 : #endif 149 : 150 : // the call to convert<A>(b) has return type A and converts b to type A iff b 151 : // decltype(b) is implicitly convertible to A 152 : template <class U> 153 0 : constexpr U convert(U v) { 154 0 : return v; 155 : } 156 : 157 : } // namespace detail_ 158 : 159 : // \endcond 160 : 161 : constexpr struct trivial_init_t { 162 : } trivial_init{}; 163 : 164 : // 20.5.7, Disengaged state indicator 165 : struct nullopt_t { 166 : constexpr explicit nullopt_t(int) {} 167 : }; 168 : constexpr nullopt_t nullopt{0}; 169 : 170 : // 20.5.8, class bad_optional_access 171 : class bad_optional_access : public std::logic_error { 172 : public: 173 : explicit bad_optional_access(const std::string& what_arg) 174 : : logic_error{what_arg} {} 175 0 : explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} 176 : }; 177 : 178 : template <class T> 179 : union storage_t { 180 : unsigned char dummy_{}; 181 : T value_; 182 : 183 : #if __cplusplus >= 202002L 184 : constexpr 185 : #endif 186 216200968 : storage_t(trivial_init_t) noexcept { 187 216200968 : new (&dummy_) unsigned char; 188 216200968 : } 189 : 190 : template <class... Args> 191 105308712 : constexpr storage_t(Args&&... args) 192 105308712 : : value_(constexpr_forward<Args>(args)...) {} 193 : 194 321509680 : ~storage_t() {} 195 : }; 196 : 197 : template <class T> 198 : union constexpr_storage_t { 199 : unsigned char dummy_; 200 : T value_; 201 : 202 : #if __cplusplus >= 202002L 203 : // C++20 lifted the requirement to initialize a union member in order to be 204 : // constexpr. 205 : constexpr constexpr_storage_t(trivial_init_t) noexcept { 206 : new (&dummy_) unsigned char; 207 : } 208 : #else 209 2945770 : constexpr constexpr_storage_t(trivial_init_t) noexcept : dummy_() {} 210 : #endif 211 : 212 : template <class... Args> 213 92688986 : constexpr constexpr_storage_t(Args&&... args) 214 92688986 : : value_(constexpr_forward<Args>(args)...) {} 215 : 216 : ~constexpr_storage_t() = default; 217 : }; 218 : 219 : template <class T> 220 : struct optional_base { 221 : bool init_; 222 : storage_t<T> storage_; 223 : 224 110924592 : constexpr optional_base() noexcept : init_(false), storage_(trivial_init){}; 225 : 226 : explicit constexpr optional_base(const optional_base<T>& v) 227 : : init_(v.init_), storage_(trivial_init) { 228 : if (init_) { 229 : ::new (dataptr()) T(v.storage_.value_); 230 : } 231 : } 232 : 233 31316 : explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} 234 : 235 105276376 : explicit constexpr optional_base(optional_base<T>&& v) noexcept( 236 : std::is_nothrow_move_constructible<T>::value) 237 105276376 : : init_(v.init_), storage_(trivial_init) { 238 105276376 : if (init_) { 239 105276376 : ::new (dataptr()) T(std::move(v.storage_.value_)); 240 : } 241 105276376 : } 242 : 243 105277396 : explicit constexpr optional_base(T&& v) 244 105277396 : : init_(true), storage_(constexpr_move(v)) {} 245 : 246 : template <class... Args> 247 : explicit optional_base(in_place_t, Args&&... args) 248 : : init_(true), storage_(constexpr_forward<Args>(args)...) {} 249 : 250 : template < 251 : class U, 252 : class... Args, 253 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)> 254 : explicit optional_base( 255 : in_place_t, 256 : std::initializer_list<U> il, 257 : Args&&... args) 258 : : init_(true), storage_(il, std::forward<Args>(args)...) {} 259 : 260 : optional_base& operator=(const optional_base& rhs) { 261 : if (init_ && !rhs.init_) { 262 : clear(); 263 : } else if (!init_ && rhs.init_) { 264 : init_ = true; 265 : ::new (dataptr()) T(rhs.storage_.value_); 266 : } else if (init_ && rhs.init_) { 267 : storage_.value_ = rhs.storage_.value_; 268 : } 269 : return *this; 270 : } 271 : 272 : optional_base& operator=(optional_base&& rhs) noexcept( 273 : std::is_nothrow_move_assignable<T>::value&& 274 : std::is_nothrow_move_constructible<T>::value) { 275 : if (init_ && !rhs.init_) { 276 : clear(); 277 : } else if (!init_ && rhs.init_) { 278 : init_ = true; 279 : ::new (dataptr()) T(std::move(rhs.storage_.value_)); 280 : } else if (init_ && rhs.init_) { 281 : storage_.value_ = std::move(rhs.storage_.value_); 282 : } 283 : return *this; 284 : } 285 : 286 321509680 : ~optional_base() { 287 321509680 : if (init_) 288 210585088 : storage_.value_.T::~T(); 289 321509680 : } 290 : 291 321479384 : constexpr bool initialized() const noexcept { 292 321479384 : return init_; 293 : } 294 : 295 : void setInitialized(bool init) noexcept { 296 : init_ = init; 297 : } 298 : 299 : private: 300 105276376 : typename std::remove_const<T>::type* dataptr() { 301 105276376 : return std::addressof(storage_.value_); 302 : } 303 : 304 : constexpr const T* dataptr() const { 305 : return detail_::static_addressof(storage_.value_); 306 : } 307 : 308 : void clear() noexcept { 309 : if (init_) { 310 : dataptr()->~T(); 311 : } 312 : init_ = false; 313 : } 314 : }; 315 : 316 : template <class T> 317 : struct constexpr_optional_base { 318 : bool init_; 319 : constexpr_storage_t<T> storage_; 320 : 321 : constexpr constexpr_optional_base() noexcept 322 : : init_(false), storage_(trivial_init){}; 323 : 324 : explicit constexpr constexpr_optional_base( 325 : const constexpr_optional_base<T>& v) 326 : : init_(v.init_), storage_(trivial_init) { 327 : if (init_) { 328 : ::new (dataptr()) T(v.storage_.value_); 329 : } 330 : } 331 : 332 : explicit constexpr constexpr_optional_base( 333 : constexpr_optional_base<T>&& 334 : v) noexcept(std::is_nothrow_move_constructible<T>::value) 335 : : init_(v.init_), storage_(trivial_init) { 336 : if (init_) { 337 : ::new (dataptr()) T(std::move(v.storage_.value_)); 338 : } 339 : } 340 : 341 : explicit constexpr constexpr_optional_base(const T& v) 342 : : init_(true), storage_(v) {} 343 : 344 : explicit constexpr constexpr_optional_base(T&& v) 345 : : init_(true), storage_(constexpr_move(v)) {} 346 : 347 : template <class... Args> 348 : explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) 349 : : init_(true), storage_(constexpr_forward<Args>(args)...) {} 350 : 351 : template < 352 : class U, 353 : class... Args, 354 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)> 355 : constexpr explicit constexpr_optional_base( 356 : in_place_t, 357 : std::initializer_list<U> il, 358 : Args&&... args) 359 : : init_(true), storage_(il, std::forward<Args>(args)...) {} 360 : 361 : ~constexpr_optional_base() = default; 362 : 363 : constexpr_optional_base& operator=(const constexpr_optional_base& rhs) { 364 : if (init_ && !rhs.init_) { 365 : clear(); 366 : } else if (!init_ && rhs.init_) { 367 : init_ = true; 368 : ::new (dataptr()) T(rhs.storage_.value_); 369 : } else if (init_ && rhs.init_) { 370 : storage_.value_ = rhs.storage_.value_; 371 : } 372 : return *this; 373 : } 374 : 375 : constexpr_optional_base& operator=(constexpr_optional_base&& rhs) noexcept( 376 : std::is_nothrow_move_assignable<T>::value&& 377 : std::is_nothrow_move_constructible<T>::value) { 378 : if (init_ && !rhs.init_) { 379 : clear(); 380 : } else if (!init_ && rhs.init_) { 381 : init_ = true; 382 : ::new (dataptr()) T(std::move(rhs.storage_.value_)); 383 : } else if (init_ && rhs.init_) { 384 : storage_.value_ = std::move(rhs.storage_.value_); 385 : } 386 : return *this; 387 : } 388 : 389 : constexpr bool initialized() const noexcept { 390 : return init_; 391 : } 392 : void setInitialized(bool init) noexcept { 393 : init_ = init; 394 : } 395 : 396 : private: 397 : typename std::remove_const<T>::type* dataptr() { 398 : return std::addressof(storage_.value_); 399 : } 400 : 401 : constexpr const T* dataptr() const { 402 : return detail_::static_addressof(storage_.value_); 403 : } 404 : 405 : void clear() noexcept { 406 : init_ = false; 407 : } 408 : }; 409 : 410 : // HACK: Optimization for trivially copyable types. The mainline 411 : // implementation fails to have trivial copy/move operations in these 412 : // cases, and we care about them, so just implement that directly. 413 : template <class T> 414 : struct trivially_copyable_optimization_optional_base { 415 : bool init_; 416 : constexpr_storage_t<T> storage_; 417 : 418 2945770 : constexpr trivially_copyable_optimization_optional_base() noexcept 419 2945770 : : init_(false), storage_(trivial_init) {} 420 : 421 814728 : explicit constexpr trivially_copyable_optimization_optional_base(const T& v) 422 814728 : : init_(true), storage_(v) {} 423 : 424 91472940 : explicit constexpr trivially_copyable_optimization_optional_base(T&& v) 425 91472940 : : init_(true), storage_(constexpr_move(v)) {} 426 : 427 : template <class... Args> 428 401318 : explicit constexpr trivially_copyable_optimization_optional_base( 429 : in_place_t, 430 : Args&&... args) 431 401318 : : init_(true), storage_(constexpr_forward<Args>(args)...) {} 432 : 433 : template < 434 : class U, 435 : class... Args, 436 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)> 437 : constexpr explicit trivially_copyable_optimization_optional_base( 438 : in_place_t, 439 : std::initializer_list<U> il, 440 : Args&&... args) 441 : : init_(true), storage_(il, std::forward<Args>(args)...) {} 442 : 443 : ~trivially_copyable_optimization_optional_base() = default; 444 : 445 185760028 : constexpr bool initialized() const noexcept { 446 185760028 : return init_; 447 : } 448 : void setInitialized(bool init) noexcept { 449 : init_ = init; 450 : } 451 : }; 452 : 453 : // HACK: Optimization for ArrayRef<T>. We take advantage of an unused 454 : // bit pattern in ArrayRef (inspired by Arthur O'Dwyer's 455 : // tombstone_traits -- see https://youtu.be/MWBfmmg8-Yo?t=2466) to 456 : // keep the size of c10::optional::ArrayRef<T> down to 16 bytes, which 457 : // allows it to be passed to functions in registers instead of getting 458 : // passed in memory per item 5c of the classification algorithm in 459 : // section 3.2.3 of the System V ABI document 460 : // (https://www.uclibc.org/docs/psABI-x86_64.pdf). 461 : template <class ArrayRefT> 462 : class arrayref_optional_base { 463 : public: 464 : union storage { 465 : struct raw { 466 : // ArrayRef has the invariant that if Data is nullptr then 467 : // Length must be zero, so this is an unused bit pattern. 468 : const void* p = nullptr; 469 : size_t sz = 1; 470 : } uninitialized_{}; 471 : ArrayRefT value_; 472 : 473 16480 : constexpr storage() noexcept : uninitialized_() { 474 16480 : setUninitialized(); 475 16480 : } 476 : 477 16480 : constexpr void setUninitialized() noexcept { 478 16480 : uninitialized_.p = nullptr; 479 16480 : uninitialized_.sz = 1; 480 16480 : } 481 : 482 : explicit constexpr storage(ArrayRefT& v) : value_(v) {} 483 : 484 : template <typename T> 485 : explicit constexpr storage(const std::initializer_list<T>& v) : value_(v) {} 486 : 487 : template <class... Args> 488 14194 : explicit constexpr storage(Args&&... args) 489 14194 : : value_(constexpr_forward<Args>(args)...) {} 490 : }; 491 : 492 : storage storage_; 493 : 494 16480 : constexpr arrayref_optional_base() noexcept = default; 495 : 496 14194 : explicit constexpr arrayref_optional_base(const ArrayRefT& v) : storage_(v) {} 497 : 498 : template <class... Args> 499 : explicit constexpr arrayref_optional_base(in_place_t, Args&&... args) 500 : : storage_(constexpr_forward<Args>(args)...) {} 501 : 502 : template <typename T> 503 : explicit constexpr arrayref_optional_base( 504 : in_place_t, 505 : const std::initializer_list<T>& v) 506 : : storage_(v) {} 507 : 508 : constexpr bool initialized() const noexcept { 509 : return storage_.uninitialized_.p != nullptr || 510 : storage_.uninitialized_.sz == 0; 511 : } 512 : 513 : void setInitialized(bool init) noexcept { 514 : if (!init) { 515 : storage_.setUninitialized(); 516 : } else { 517 : assert(initialized()); 518 : } 519 : } 520 : }; 521 : 522 : namespace detail_ { 523 : template <typename T> 524 : struct is_arrayref : std::false_type {}; 525 : 526 : template <typename T> 527 : struct is_arrayref<c10::ArrayRef<T>> : std::true_type {}; 528 : } // namespace detail_ 529 : 530 : template <class T> 531 : using OptionalBase = std::conditional_t< 532 : detail_::is_arrayref<T>::value, 533 : arrayref_optional_base<T>, 534 : std::conditional_t< 535 : std::is_trivially_destructible<T>::value && 536 : C10_IS_TRIVIALLY_COPYABLE(T) && 537 : // Avoid using is_trivially_copy_{constructible,assignable} 538 : // because old GCC versions don't support them. Also, 539 : // is_trivially_copyable seems not to do what I expect, so check 540 : // trivially_copyable_optimization_optional_base directly. 541 : std::is_copy_constructible< 542 : trivially_copyable_optimization_optional_base<T>>::value && 543 : std::is_copy_assignable< 544 : trivially_copyable_optimization_optional_base<T>>::value, 545 : trivially_copyable_optimization_optional_base<T>, 546 : std::conditional_t< 547 : std::is_trivially_destructible<T>::value, // if possible 548 : constexpr_optional_base<std::remove_const_t<T>>, // use base with 549 : // trivial 550 : // destructor 551 : optional_base<std::remove_const_t<T>>>>>; 552 : 553 : template <class T> 554 : class optional : private OptionalBase<T> { 555 : template <class U> // re-declaration for nvcc on Windows. 556 : using OptionalBase = std::conditional_t< 557 : detail_::is_arrayref<U>::value, 558 : arrayref_optional_base<U>, 559 : std::conditional_t< 560 : std::is_trivially_destructible<U>::value && 561 : C10_IS_TRIVIALLY_COPYABLE(U) && 562 : // Avoid using is_trivially_copy_{constructible,assignable} 563 : // because old GCC versions don't support them. Also, 564 : // is_trivially_copyable seems not to do what I expect, so 565 : // check trivially_copyable_optimization_optional_base 566 : // directly. 567 : std::is_copy_constructible< 568 : trivially_copyable_optimization_optional_base<U>>::value && 569 : std::is_copy_assignable< 570 : trivially_copyable_optimization_optional_base<U>>::value, 571 : trivially_copyable_optimization_optional_base<U>, 572 : std::conditional_t< 573 : std::is_trivially_destructible<U>::value, // if possible 574 : constexpr_optional_base<std::remove_const_t<U>>, // use base 575 : // with 576 : // trivial 577 : // destructor 578 : optional_base<std::remove_const_t<U>>>>>; 579 : 580 : static_assert( 581 : !std::is_same<typename std::decay<T>::type, nullopt_t>::value, 582 : "bad T"); 583 : static_assert( 584 : !std::is_same<typename std::decay<T>::type, in_place_t>::value, 585 : "bad T"); 586 : 587 507239412 : constexpr bool initialized() const noexcept { 588 507239412 : return OptionalBase<T>::initialized(); 589 : } 590 418776 : typename std::remove_const<T>::type* dataptr() { 591 418776 : return std::addressof(OptionalBase<T>::storage_.value_); 592 : } 593 : constexpr const T* dataptr() const { 594 : return detail_::static_addressof(OptionalBase<T>::storage_.value_); 595 : } 596 : 597 0 : constexpr const T& contained_val() const& { 598 0 : return OptionalBase<T>::storage_.value_; 599 : } 600 : constexpr T&& contained_val() && { 601 : return std::move(OptionalBase<T>::storage_.value_); 602 : } 603 197127776 : constexpr T& contained_val() & { 604 197127776 : return OptionalBase<T>::storage_.value_; 605 : } 606 : 607 : void clear() noexcept { 608 : if (initialized()) 609 : dataptr()->~T(); 610 : OptionalBase<T>::setInitialized(false); 611 : } 612 : 613 : template <class... Args> 614 : void initialize(Args&&... args) noexcept( 615 : noexcept(T(std::forward<Args>(args)...))) { 616 : assert(!initialized()); 617 : ::new (static_cast<void*>(dataptr())) T(std::forward<Args>(args)...); 618 : OptionalBase<T>::setInitialized(true); 619 : } 620 : 621 : template <class U, class... Args> 622 : void initialize(std::initializer_list<U> il, Args&&... args) noexcept( 623 : noexcept(T(il, std::forward<Args>(args)...))) { 624 : assert(!initialized()); 625 : ::new (static_cast<void*>(dataptr())) T(il, std::forward<Args>(args)...); 626 : OptionalBase<T>::setInitialized(true); 627 : } 628 : 629 : public: 630 : typedef T value_type; 631 : 632 : // 20.5.5.1, constructors 633 16480 : constexpr optional() noexcept = default; 634 113870362 : constexpr optional(nullopt_t) noexcept : OptionalBase<T>(){}; 635 : 636 : optional(const optional& rhs) = default; 637 105276376 : optional(optional&& rhs) = default; 638 : 639 : // see https://github.com/akrzemi1/Optional/issues/16 640 : // and https://en.cppreference.com/w/cpp/utility/optional/optional, 641 : // in constructor 8, the std::optional spec can allow initialization 642 : // of optionals from convertible type U 643 : // 644 : // 8 - implicit move construct from value 645 : template < 646 : typename U = T, 647 : TR2_OPTIONAL_REQUIRES( 648 : std::is_constructible<T, U&&>::value && 649 : !std::is_same<typename std::decay<U>::type, in_place_t>::value && 650 : !std::is_same<typename std::decay<U>::type, optional<T>>::value && 651 : std::is_convertible<U&&, T>)> 652 197610574 : constexpr optional(U&& u) : OptionalBase<T>(std::forward<U>(u)) {} 653 : 654 : // 8 - explicit move construct from value 655 : template < 656 : typename U = T, 657 : TR2_OPTIONAL_REQUIRES( 658 : std::is_constructible<T, U&&>::value && 659 : !std::is_same<typename std::decay<U>::type, in_place_t>::value && 660 : !std::is_same<typename std::decay<U>::type, optional<T>>::value && 661 : !std::is_convertible<U&&, T>)> 662 : explicit constexpr optional(U&& u) : OptionalBase<T>(std::forward<U>(u)) {} 663 : 664 : template <class... Args> 665 401318 : explicit constexpr optional(in_place_t, Args&&... args) 666 401318 : : OptionalBase<T>(in_place_t{}, constexpr_forward<Args>(args)...) {} 667 : 668 : template < 669 : class U, 670 : class... Args, 671 : TR2_OPTIONAL_REQUIRES(std::is_constructible<T, std::initializer_list<U>>)> 672 : constexpr explicit optional( 673 : in_place_t, 674 : std::initializer_list<U> il, 675 : Args&&... args) 676 : : OptionalBase<T>(in_place_t{}, il, constexpr_forward<Args>(args)...) {} 677 : 678 : // 20.5.4.2, Destructor 679 321509680 : ~optional() = default; 680 : 681 : // 20.5.4.3, assignment 682 : optional& operator=(nullopt_t) noexcept { 683 : clear(); 684 : return *this; 685 : } 686 : 687 : optional& operator=(const optional& rhs) = default; 688 : 689 : optional& operator=(optional&& rhs) = default; 690 : 691 : template <class U = T> 692 : auto operator=(U&& v) -> typename std::enable_if< 693 : std::is_constructible<T, U>::value && 694 : !std::is_same<typename std::decay<U>::type, optional<T>>::value && 695 : (std::is_scalar<T>::value || 696 : std::is_same<typename std::decay<U>::type, T>::value) && 697 : std::is_assignable<T&, U>::value, 698 : optional&>::type { 699 : if (initialized()) { 700 : contained_val() = std::forward<U>(v); 701 : } else { 702 : initialize(std::forward<U>(v)); 703 : } 704 : return *this; 705 : } 706 : 707 : template <class... Args> 708 : void emplace(Args&&... args) { 709 : clear(); 710 : initialize(std::forward<Args>(args)...); 711 : } 712 : 713 : template <class U, class... Args> 714 : void emplace(std::initializer_list<U> il, Args&&... args) { 715 : clear(); 716 : initialize<U, Args...>(il, std::forward<Args>(args)...); 717 : } 718 : 719 : // 20.5.4.4, Swap 720 : void swap(optional<T>& rhs) noexcept( 721 : std::is_nothrow_move_constructible<T>::value&& noexcept( 722 : std::swap(std::declval<T&>(), std::declval<T&>()))) { 723 : if (initialized() == true && rhs.initialized() == false) { 724 : rhs.initialize(std::move(**this)); 725 : clear(); 726 : } else if (initialized() == false && rhs.initialized() == true) { 727 : initialize(std::move(*rhs)); 728 : rhs.clear(); 729 : } else if (initialized() == true && rhs.initialized() == true) { 730 : using std::swap; 731 : swap(**this, *rhs); 732 : } 733 : } 734 : 735 : // 20.5.4.5, Observers 736 : 737 92670626 : explicit constexpr operator bool() const noexcept { 738 92670626 : return initialized(); 739 : } 740 217022234 : constexpr bool has_value() const noexcept { 741 217022234 : return initialized(); 742 : } 743 : 744 : TR2_OPTIONAL_HOST_CONSTEXPR T const* operator->() const { 745 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); 746 : } 747 : 748 418776 : TR2_OPTIONAL_HOST_CONSTEXPR T* operator->() { 749 418776 : assert(initialized()); 750 418776 : return dataptr(); 751 : } 752 : 753 0 : TR2_OPTIONAL_HOST_CONSTEXPR T const& operator*() const& { 754 0 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); 755 : } 756 : 757 197126756 : TR2_OPTIONAL_HOST_CONSTEXPR T& operator*() & { 758 197126756 : assert(initialized()); 759 197126756 : return contained_val(); 760 : } 761 : 762 : TR2_OPTIONAL_HOST_CONSTEXPR T&& operator*() && { 763 : assert(initialized()); 764 : return constexpr_move(contained_val()); 765 : } 766 : 767 : TR2_OPTIONAL_HOST_CONSTEXPR T const& value() const& { 768 : return initialized() 769 : ? contained_val() 770 : : (throw bad_optional_access("bad optional access"), contained_val()); 771 : } 772 : 773 : TR2_OPTIONAL_HOST_CONSTEXPR T& value() & { 774 : return initialized() 775 : ? contained_val() 776 : : (throw bad_optional_access("bad optional access"), contained_val()); 777 : } 778 : 779 1020 : TR2_OPTIONAL_HOST_CONSTEXPR T&& value() && { 780 1020 : if (!initialized()) 781 0 : throw bad_optional_access("bad optional access"); 782 1020 : return std::move(contained_val()); 783 : } 784 : 785 : template <class V> 786 : constexpr T value_or(V&& v) const& { 787 : return *this ? **this : detail_::convert<T>(constexpr_forward<V>(v)); 788 : } 789 : 790 : template <class V> 791 : constexpr T value_or(V&& v) && { 792 : return *this 793 : ? constexpr_move(const_cast<optional<T>&>(*this).contained_val()) 794 : : detail_::convert<T>(constexpr_forward<V>(v)); 795 : } 796 : 797 : // 20.6.3.6, modifiers 798 : void reset() noexcept { 799 : clear(); 800 : } 801 : }; 802 : 803 : template <class T, class F> 804 0 : constexpr T value_or_else(const optional<T>& v, F&& func) { 805 : static_assert( 806 : std::is_convertible< 807 : typename guts::infer_function_traits_t<F>::return_type, 808 : T>::value, 809 : "func parameters must be a callable that returns a type convertible to the value stored in the optional"); 810 0 : return v.has_value() ? *v : detail_::convert<T>(std::forward<F>(func)()); 811 : } 812 : 813 : template <class T, class F> 814 : constexpr T value_or_else(optional<T>&& v, F&& func) { 815 : static_assert( 816 : std::is_convertible< 817 : typename guts::infer_function_traits_t<F>::return_type, 818 : T>::value, 819 : "func parameters must be a callable that returns a type convertible to the value stored in the optional"); 820 : return v.has_value() ? constexpr_move(std::move(v).contained_val()) 821 : : detail_::convert<T>(std::forward<F>(func)()); 822 : } 823 : 824 : // XXX: please refrain from using optional<T&>, since it is being against with 825 : // the optional standard in c++ 17, see the debate and the details here: 826 : // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3406#rationale.refs 827 : // if you need it, consider using optional<std::reference_wrapper<T>> or * 828 : // pointer 829 : // 830 : // we leave the implementation here in case we want to reconsider using it in 831 : // the future if it becomes a definitely necessary case. 832 : template <class T> 833 : class optional<T&> { 834 : // add this assert to prevent user from using optional reference as indicated 835 : // above 836 : static_assert( 837 : sizeof(T) == 0, 838 : "optional references is ill-formed, \ 839 : consider use optional of a std::reference_wrapper of type T to \ 840 : hold a reference if you really need to"); 841 : 842 : static_assert(!std::is_same<T, nullopt_t>::value, "bad T"); 843 : static_assert(!std::is_same<T, in_place_t>::value, "bad T"); 844 : T* ref; 845 : 846 : public: 847 : // 20.5.5.1, construction/destruction 848 : constexpr optional() noexcept : ref(nullptr) {} 849 : 850 : constexpr optional(nullopt_t) noexcept : ref(nullptr) {} 851 : 852 : template <typename U = T> 853 : constexpr optional(U& u) noexcept : ref(detail_::static_addressof(u)) {} 854 : 855 : template <typename U = T> 856 : optional(U&&) = delete; 857 : 858 : constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} 859 : 860 : explicit constexpr optional(in_place_t, T& v) noexcept 861 : : ref(detail_::static_addressof(v)) {} 862 : 863 : explicit optional(in_place_t, T&&) = delete; 864 : 865 : ~optional() = default; 866 : 867 : // 20.5.5.2, mutation 868 : optional& operator=(nullopt_t) noexcept { 869 : ref = nullptr; 870 : return *this; 871 : } 872 : 873 : // optional& operator=(const optional& rhs) noexcept { 874 : // ref = rhs.ref; 875 : // return *this; 876 : // } 877 : 878 : // optional& operator=(optional&& rhs) noexcept { 879 : // ref = rhs.ref; 880 : // return *this; 881 : // } 882 : 883 : template <typename U> 884 : auto operator=(U&& rhs) noexcept -> typename std::enable_if< 885 : std::is_same<typename std::decay<U>::type, optional<T&>>::value, 886 : optional&>::type { 887 : ref = rhs.ref; 888 : return *this; 889 : } 890 : 891 : template <typename U> 892 : auto operator=(U&& rhs) noexcept -> typename std::enable_if< 893 : !std::is_same<typename std::decay<U>::type, optional<T&>>::value, 894 : optional&>::type = delete; 895 : 896 : void emplace(T& v) noexcept { 897 : ref = detail_::static_addressof(v); 898 : } 899 : 900 : void emplace(T&&) = delete; 901 : 902 : void swap(optional<T&>& rhs) noexcept { 903 : std::swap(ref, rhs.ref); 904 : } 905 : 906 : // 20.5.5.3, observers 907 : TR2_OPTIONAL_HOST_CONSTEXPR T* operator->() const { 908 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); 909 : } 910 : 911 : TR2_OPTIONAL_HOST_CONSTEXPR T& operator*() const { 912 : return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); 913 : } 914 : 915 : constexpr T& value() const { 916 : return ref ? *ref 917 : : (throw bad_optional_access("bad optional access"), *ref); 918 : } 919 : 920 : explicit constexpr operator bool() const noexcept { 921 : return ref != nullptr; 922 : } 923 : 924 : constexpr bool has_value() const noexcept { 925 : return ref != nullptr; 926 : } 927 : 928 : template <class V> 929 : constexpr typename std::decay<T>::type value_or(V&& v) const { 930 : return *this ? **this 931 : : detail_::convert<typename std::decay<T>::type>( 932 : constexpr_forward<V>(v)); 933 : } 934 : 935 : // x.x.x.x, modifiers 936 : void reset() noexcept { 937 : ref = nullptr; 938 : } 939 : }; 940 : 941 : template <class T> 942 : class optional<T&&> { 943 : static_assert(sizeof(T) == 0, "optional rvalue references disallowed"); 944 : }; 945 : 946 : // 20.5.8, Relational operators 947 : template <class T> 948 : constexpr bool operator==(const optional<T>& x, const optional<T>& y) { 949 : return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; 950 : } 951 : 952 : template <class T> 953 : constexpr bool operator!=(const optional<T>& x, const optional<T>& y) { 954 : return !(x == y); 955 : } 956 : 957 : template <class T> 958 : constexpr bool operator<(const optional<T>& x, const optional<T>& y) { 959 : return (!y) ? false : (!x) ? true : *x < *y; 960 : } 961 : 962 : template <class T> 963 : constexpr bool operator>(const optional<T>& x, const optional<T>& y) { 964 : return (y < x); 965 : } 966 : 967 : template <class T> 968 : constexpr bool operator<=(const optional<T>& x, const optional<T>& y) { 969 : return !(y < x); 970 : } 971 : 972 : template <class T> 973 : constexpr bool operator>=(const optional<T>& x, const optional<T>& y) { 974 : return !(x < y); 975 : } 976 : 977 : // 20.5.9, Comparison with nullopt 978 : template <class T> 979 401402 : constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept { 980 401402 : return (!x); 981 : } 982 : 983 : template <class T> 984 : constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept { 985 : return (!x); 986 : } 987 : 988 : template <class T> 989 : constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept { 990 : return bool(x); 991 : } 992 : 993 : template <class T> 994 : constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept { 995 : return bool(x); 996 : } 997 : 998 : template <class T> 999 : constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { 1000 : return false; 1001 : } 1002 : 1003 : template <class T> 1004 : constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept { 1005 : return bool(x); 1006 : } 1007 : 1008 : template <class T> 1009 : constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept { 1010 : return (!x); 1011 : } 1012 : 1013 : template <class T> 1014 : constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { 1015 : return true; 1016 : } 1017 : 1018 : template <class T> 1019 : constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept { 1020 : return bool(x); 1021 : } 1022 : 1023 : template <class T> 1024 : constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { 1025 : return false; 1026 : } 1027 : 1028 : template <class T> 1029 : constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { 1030 : return true; 1031 : } 1032 : 1033 : template <class T> 1034 : constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept { 1035 : return (!x); 1036 : } 1037 : 1038 : // 20.5.10, Comparison with T 1039 : template <class T, class U> 1040 : constexpr bool operator==(const optional<T>& x, const U& v) { 1041 : return bool(x) ? *x == v : false; 1042 : } 1043 : 1044 : template <class T, class U> 1045 : constexpr bool operator==(const U& v, const optional<T>& x) { 1046 : return bool(x) ? v == *x : false; 1047 : } 1048 : 1049 : template <class T, class U> 1050 : constexpr bool operator!=(const optional<T>& x, const U& v) { 1051 : return bool(x) ? *x != v : true; 1052 : } 1053 : 1054 : template <class T, class U> 1055 : constexpr bool operator!=(const U& v, const optional<T>& x) { 1056 : return bool(x) ? v != *x : true; 1057 : } 1058 : 1059 : template <class T, class U> 1060 : constexpr bool operator<(const optional<T>& x, const U& v) { 1061 : return bool(x) ? *x < v : true; 1062 : } 1063 : 1064 : template <class T, class U> 1065 : constexpr bool operator>(const U& v, const optional<T>& x) { 1066 : return bool(x) ? v > *x : true; 1067 : } 1068 : 1069 : template <class T, class U> 1070 : constexpr bool operator>(const optional<T>& x, const U& v) { 1071 : return bool(x) ? *x > v : false; 1072 : } 1073 : 1074 : template <class T, class U> 1075 : constexpr bool operator<(const U& v, const optional<T>& x) { 1076 : return bool(x) ? v < *x : false; 1077 : } 1078 : 1079 : template <class T, class U> 1080 : constexpr bool operator>=(const optional<T>& x, const U& v) { 1081 : return bool(x) ? *x >= v : false; 1082 : } 1083 : 1084 : template <class T, class U> 1085 : constexpr bool operator<=(const U& v, const optional<T>& x) { 1086 : return bool(x) ? v <= *x : false; 1087 : } 1088 : 1089 : template <class T, class U> 1090 : constexpr bool operator<=(const optional<T>& x, const U& v) { 1091 : return bool(x) ? *x <= v : true; 1092 : } 1093 : 1094 : template <class T, class U> 1095 : constexpr bool operator>=(const U& v, const optional<T>& x) { 1096 : return bool(x) ? v >= *x : true; 1097 : } 1098 : 1099 : // Comparison of optional<T&> with T 1100 : template <class T> 1101 : constexpr bool operator==(const optional<T&>& x, const T& v) { 1102 : return bool(x) ? *x == v : false; 1103 : } 1104 : 1105 : template <class T> 1106 : constexpr bool operator==(const T& v, const optional<T&>& x) { 1107 : return bool(x) ? v == *x : false; 1108 : } 1109 : 1110 : template <class T> 1111 : constexpr bool operator!=(const optional<T&>& x, const T& v) { 1112 : return bool(x) ? *x != v : true; 1113 : } 1114 : 1115 : template <class T> 1116 : constexpr bool operator!=(const T& v, const optional<T&>& x) { 1117 : return bool(x) ? v != *x : true; 1118 : } 1119 : 1120 : template <class T> 1121 : constexpr bool operator<(const optional<T&>& x, const T& v) { 1122 : return bool(x) ? *x < v : true; 1123 : } 1124 : 1125 : template <class T> 1126 : constexpr bool operator>(const T& v, const optional<T&>& x) { 1127 : return bool(x) ? v > *x : true; 1128 : } 1129 : 1130 : template <class T> 1131 : constexpr bool operator>(const optional<T&>& x, const T& v) { 1132 : return bool(x) ? *x > v : false; 1133 : } 1134 : 1135 : template <class T> 1136 : constexpr bool operator<(const T& v, const optional<T&>& x) { 1137 : return bool(x) ? v < *x : false; 1138 : } 1139 : 1140 : template <class T> 1141 : constexpr bool operator>=(const optional<T&>& x, const T& v) { 1142 : return bool(x) ? *x >= v : false; 1143 : } 1144 : 1145 : template <class T> 1146 : constexpr bool operator<=(const T& v, const optional<T&>& x) { 1147 : return bool(x) ? v <= *x : false; 1148 : } 1149 : 1150 : template <class T> 1151 : constexpr bool operator<=(const optional<T&>& x, const T& v) { 1152 : return bool(x) ? *x <= v : true; 1153 : } 1154 : 1155 : template <class T> 1156 : constexpr bool operator>=(const T& v, const optional<T&>& x) { 1157 : return bool(x) ? v >= *x : true; 1158 : } 1159 : 1160 : // Comparison of optional<T const&> with T 1161 : template <class T> 1162 : constexpr bool operator==(const optional<const T&>& x, const T& v) { 1163 : return bool(x) ? *x == v : false; 1164 : } 1165 : 1166 : template <class T> 1167 : constexpr bool operator==(const T& v, const optional<const T&>& x) { 1168 : return bool(x) ? v == *x : false; 1169 : } 1170 : 1171 : template <class T> 1172 : constexpr bool operator!=(const optional<const T&>& x, const T& v) { 1173 : return bool(x) ? *x != v : true; 1174 : } 1175 : 1176 : template <class T> 1177 : constexpr bool operator!=(const T& v, const optional<const T&>& x) { 1178 : return bool(x) ? v != *x : true; 1179 : } 1180 : 1181 : template <class T> 1182 : constexpr bool operator<(const optional<const T&>& x, const T& v) { 1183 : return bool(x) ? *x < v : true; 1184 : } 1185 : 1186 : template <class T> 1187 : constexpr bool operator>(const T& v, const optional<const T&>& x) { 1188 : return bool(x) ? v > *x : true; 1189 : } 1190 : 1191 : template <class T> 1192 : constexpr bool operator>(const optional<const T&>& x, const T& v) { 1193 : return bool(x) ? *x > v : false; 1194 : } 1195 : 1196 : template <class T> 1197 : constexpr bool operator<(const T& v, const optional<const T&>& x) { 1198 : return bool(x) ? v < *x : false; 1199 : } 1200 : 1201 : template <class T> 1202 : constexpr bool operator>=(const optional<const T&>& x, const T& v) { 1203 : return bool(x) ? *x >= v : false; 1204 : } 1205 : 1206 : template <class T> 1207 : constexpr bool operator<=(const T& v, const optional<const T&>& x) { 1208 : return bool(x) ? v <= *x : false; 1209 : } 1210 : 1211 : template <class T> 1212 : constexpr bool operator<=(const optional<const T&>& x, const T& v) { 1213 : return bool(x) ? *x <= v : true; 1214 : } 1215 : 1216 : template <class T> 1217 : constexpr bool operator>=(const T& v, const optional<const T&>& x) { 1218 : return bool(x) ? v >= *x : true; 1219 : } 1220 : 1221 : // 20.5.12, Specialized algorithms 1222 : template <class T> 1223 : void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y))) { 1224 : x.swap(y); 1225 : } 1226 : 1227 : template <class T> 1228 418776 : constexpr optional<typename std::decay<T>::type> make_optional(T&& v) { 1229 418776 : return optional<typename std::decay<T>::type>(constexpr_forward<T>(v)); 1230 : } 1231 : 1232 : template <class X> 1233 : constexpr optional<X&> make_optional(std::reference_wrapper<X> v) { 1234 : return optional<X&>(v.get()); 1235 : } 1236 : 1237 : } // namespace c10 1238 : 1239 : namespace std { 1240 : template <typename T> 1241 : struct hash<c10::optional<T>> { 1242 : typedef c10::invoke_result_t<std::hash<T>, T> result_type; 1243 : typedef c10::optional<T> argument_type; 1244 : 1245 : constexpr result_type operator()(argument_type const& arg) const { 1246 : return arg ? std::hash<T>{}(*arg) : result_type{}; 1247 : } 1248 : }; 1249 : 1250 : template <typename T> 1251 : struct hash<c10::optional<T&>> { 1252 : typedef typename hash<T>::result_type result_type; 1253 : typedef c10::optional<T&> argument_type; 1254 : 1255 : constexpr result_type operator()(argument_type const& arg) const { 1256 : return arg ? std::hash<T>{}(*arg) : result_type{}; 1257 : } 1258 : }; 1259 : } // namespace std 1260 : 1261 : #undef TR2_OPTIONAL_REQUIRES 1262 : #undef TR2_OPTIONAL_ASSERTED_EXPRESSION 1263 : #undef TR2_OPTIONAL_HOST_CONSTEXPR 1264 : 1265 : C10_CLANG_DIAGNOSTIC_POP() 1266 : 1267 : #if defined(_MSC_VER) && !defined(__clang__) 1268 : #pragma warning(pop) 1269 : #endif 1270 : 1271 : #endif // C10_UTIL_OPTIONAL_H_ |
![]() |
Generated by: LCOV version 2.0-1 |
</html>