1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 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 http://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 16 #include "tensorflow/core/lib/gtl/optional.h" 17 18 #include <string> 19 #include <utility> 20 21 #include "tensorflow/core/platform/test.h" 22 #include "tensorflow/core/platform/types.h" 23 24 namespace tensorflow { 25 namespace { 26 27 using tensorflow::gtl::in_place; 28 using tensorflow::gtl::in_place_t; 29 using tensorflow::gtl::make_optional; 30 using tensorflow::gtl::nullopt; 31 using tensorflow::gtl::nullopt_t; 32 using tensorflow::gtl::optional; 33 34 template <typename T> 35 string TypeQuals(T&) { 36 return "&"; 37 } 38 template <typename T> 39 string TypeQuals(T&&) { 40 return "&&"; 41 } 42 template <typename T> 43 string TypeQuals(const T&) { 44 return "c&"; 45 } 46 template <typename T> 47 string TypeQuals(const T&&) { 48 return "c&&"; 49 } 50 51 struct StructorListener { 52 int construct0 = 0; 53 int construct1 = 0; 54 int construct2 = 0; 55 int listinit = 0; 56 int copy = 0; 57 int move = 0; 58 int copy_assign = 0; 59 int move_assign = 0; 60 int destruct = 0; 61 }; 62 63 struct Listenable { 64 static StructorListener* listener; 65 66 Listenable() { ++listener->construct0; } 67 Listenable(int /*unused*/) { ++listener->construct1; } // NOLINT 68 Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; } 69 Listenable(std::initializer_list<int> /*unused*/) { ++listener->listinit; } 70 Listenable(const Listenable& /*unused*/) { ++listener->copy; } 71 Listenable(Listenable&& /*unused*/) { ++listener->move; } // NOLINT 72 Listenable& operator=(const Listenable& /*unused*/) { 73 ++listener->copy_assign; 74 return *this; 75 } 76 Listenable& operator=(Listenable&& /*unused*/) { // NOLINT 77 ++listener->move_assign; 78 return *this; 79 } 80 ~Listenable() { ++listener->destruct; } 81 }; 82 83 StructorListener* Listenable::listener = nullptr; 84 85 // clang on macos -- even the latest major version at time of writing (8.x) -- 86 // does not like much of our constexpr business. clang < 3.0 also has trouble. 87 #if defined(__clang__) && defined(__APPLE__) 88 #define SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG 89 #endif 90 91 struct ConstexprType { 92 constexpr ConstexprType() : x(0) {} 93 constexpr explicit ConstexprType(int i) : x(i) {} 94 #ifndef SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG 95 constexpr ConstexprType(std::initializer_list<int> il) : x(il.size()) {} 96 #endif 97 constexpr ConstexprType(const char* s) : x(-1) {} // NOLINT 98 int x; 99 }; 100 101 struct Copyable { 102 Copyable() {} 103 Copyable(const Copyable&) {} 104 Copyable& operator=(const Copyable&) { return *this; } 105 }; 106 107 struct MoveableThrow { 108 MoveableThrow() {} 109 MoveableThrow(MoveableThrow&&) {} 110 MoveableThrow& operator=(MoveableThrow&&) { return *this; } 111 }; 112 113 struct MoveableNoThrow { 114 MoveableNoThrow() {} 115 MoveableNoThrow(MoveableNoThrow&&) noexcept {} 116 MoveableNoThrow& operator=(MoveableNoThrow&&) noexcept { return *this; } 117 }; 118 119 struct NonMovable { 120 NonMovable() {} 121 NonMovable(const NonMovable&) = delete; 122 NonMovable& operator=(const NonMovable&) = delete; 123 NonMovable(NonMovable&&) = delete; 124 NonMovable& operator=(NonMovable&&) = delete; 125 }; 126 127 TEST(optionalTest, DefaultConstructor) { 128 optional<int> empty; 129 EXPECT_FALSE(!!empty); 130 constexpr optional<int> cempty; 131 static_assert(!cempty.has_value(), ""); 132 EXPECT_TRUE(std::is_nothrow_default_constructible<optional<int>>::value); 133 } 134 135 TEST(optionalTest, NullOptConstructor) { 136 optional<int> empty(nullopt); 137 EXPECT_FALSE(!!empty); 138 // Creating a temporary nullopt_t object instead of using nullopt because 139 // nullopt cannot be constexpr and have external linkage at the same time. 140 constexpr optional<int> cempty{nullopt_t(nullopt_t::init)}; 141 static_assert(!cempty.has_value(), ""); 142 EXPECT_TRUE((std::is_nothrow_constructible<optional<int>, nullopt_t>::value)); 143 } 144 145 TEST(optionalTest, CopyConstructor) { 146 optional<int> empty, opt42 = 42; 147 optional<int> empty_copy(empty); 148 EXPECT_FALSE(!!empty_copy); 149 optional<int> opt42_copy(opt42); 150 EXPECT_TRUE(!!opt42_copy); 151 EXPECT_EQ(42, opt42_copy); 152 // test copyablility 153 EXPECT_TRUE(std::is_copy_constructible<optional<int>>::value); 154 EXPECT_TRUE(std::is_copy_constructible<optional<Copyable>>::value); 155 EXPECT_FALSE(std::is_copy_constructible<optional<MoveableThrow>>::value); 156 EXPECT_FALSE(std::is_copy_constructible<optional<MoveableNoThrow>>::value); 157 EXPECT_FALSE(std::is_copy_constructible<optional<NonMovable>>::value); 158 } 159 160 TEST(optionalTest, MoveConstructor) { 161 optional<int> empty, opt42 = 42; 162 optional<int> empty_move(std::move(empty)); 163 EXPECT_FALSE(!!empty_move); 164 optional<int> opt42_move(std::move(opt42)); 165 EXPECT_TRUE(!!opt42_move); 166 EXPECT_EQ(42, opt42_move); 167 // test movability 168 EXPECT_TRUE(std::is_move_constructible<optional<int>>::value); 169 EXPECT_TRUE(std::is_move_constructible<optional<Copyable>>::value); 170 EXPECT_TRUE(std::is_move_constructible<optional<MoveableThrow>>::value); 171 EXPECT_TRUE(std::is_move_constructible<optional<MoveableNoThrow>>::value); 172 EXPECT_FALSE(std::is_move_constructible<optional<NonMovable>>::value); 173 // test noexcept 174 EXPECT_TRUE(std::is_nothrow_move_constructible<optional<int>>::value); 175 EXPECT_FALSE( 176 std::is_nothrow_move_constructible<optional<MoveableThrow>>::value); 177 EXPECT_TRUE( 178 std::is_nothrow_move_constructible<optional<MoveableNoThrow>>::value); 179 } 180 181 TEST(optionalTest, Destructor) { 182 struct Trivial {}; 183 184 struct NonTrivial { 185 ~NonTrivial() {} 186 }; 187 188 EXPECT_TRUE(std::is_trivially_destructible<optional<int>>::value); 189 EXPECT_TRUE(std::is_trivially_destructible<optional<Trivial>>::value); 190 EXPECT_FALSE(std::is_trivially_destructible<optional<NonTrivial>>::value); 191 } 192 193 TEST(optionalTest, InPlaceConstructor) { 194 constexpr optional<ConstexprType> opt0{in_place_t()}; 195 static_assert(opt0, ""); 196 static_assert(opt0->x == 0, ""); 197 constexpr optional<ConstexprType> opt1{in_place_t(), 1}; 198 static_assert(opt1, ""); 199 static_assert(opt1->x == 1, ""); 200 #ifndef SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG 201 constexpr optional<ConstexprType> opt2{in_place_t(), {1, 2}}; 202 static_assert(opt2, ""); 203 static_assert(opt2->x == 2, ""); 204 #endif 205 206 // TODO(b/34201852): uncomment these when std::is_constructible<T, Args&&...> 207 // SFINAE is added to optional::optional(in_place_t, Args&&...). 208 // struct I { 209 // I(in_place_t); 210 // }; 211 212 // EXPECT_FALSE((std::is_constructible<optional<I>, in_place_t>::value)); 213 // EXPECT_FALSE((std::is_constructible<optional<I>, const 214 // in_place_t&>::value)); 215 } 216 217 // template<U=T> optional(U&&); 218 TEST(optionalTest, ValueConstructor) { 219 constexpr optional<int> opt0(0); 220 static_assert(opt0, ""); 221 static_assert(*opt0 == 0, ""); 222 EXPECT_TRUE((std::is_convertible<int, optional<int>>::value)); 223 // Copy initialization ( = "abc") won't work due to optional(optional&&) 224 // is not constexpr. Use list initialization instead. This invokes 225 // optional<ConstexprType>::optional<U>(U&&), with U = const char (&) [4], 226 // which direct-initializes the ConstexprType value held by the optional 227 // via ConstexprType::ConstexprType(const char*). 228 constexpr optional<ConstexprType> opt1 = {"abc"}; 229 static_assert(opt1, ""); 230 static_assert(-1 == opt1->x, ""); 231 EXPECT_TRUE( 232 (std::is_convertible<const char*, optional<ConstexprType>>::value)); 233 // direct initialization 234 constexpr optional<ConstexprType> opt2{2}; 235 static_assert(opt2, ""); 236 static_assert(2 == opt2->x, ""); 237 EXPECT_FALSE((std::is_convertible<int, optional<ConstexprType>>::value)); 238 239 // this invokes optional<int>::optional(int&&) 240 // NOTE: this has different behavior than assignment, e.g. 241 // "opt3 = {};" clears the optional rather than setting the value to 0 242 constexpr optional<int> opt3({}); 243 static_assert(opt3, ""); 244 static_assert(*opt3 == 0, ""); 245 246 // this invokes the move constructor with a default constructed optional 247 // because non-template function is a better match than template function. 248 optional<ConstexprType> opt4({}); 249 EXPECT_FALSE(!!opt4); 250 } 251 252 struct Implicit {}; 253 254 struct Explicit {}; 255 256 struct Convert { 257 Convert(const Implicit&) // NOLINT(runtime/explicit) 258 : implicit(true), move(false) {} 259 Convert(Implicit&&) // NOLINT(runtime/explicit) 260 : implicit(true), move(true) {} 261 explicit Convert(const Explicit&) : implicit(false), move(false) {} 262 explicit Convert(Explicit&&) : implicit(false), move(true) {} 263 264 bool implicit; 265 bool move; 266 }; 267 268 struct ConvertFromOptional { 269 ConvertFromOptional(const Implicit&) // NOLINT(runtime/explicit) 270 : implicit(true), move(false), from_optional(false) {} 271 ConvertFromOptional(Implicit&&) // NOLINT(runtime/explicit) 272 : implicit(true), move(true), from_optional(false) {} 273 ConvertFromOptional(const optional<Implicit>&) // NOLINT(runtime/explicit) 274 : implicit(true), move(false), from_optional(true) {} 275 ConvertFromOptional(optional<Implicit>&&) // NOLINT(runtime/explicit) 276 : implicit(true), move(true), from_optional(true) {} 277 explicit ConvertFromOptional(const Explicit&) 278 : implicit(false), move(false), from_optional(false) {} 279 explicit ConvertFromOptional(Explicit&&) 280 : implicit(false), move(true), from_optional(false) {} 281 explicit ConvertFromOptional(const optional<Explicit>&) 282 : implicit(false), move(false), from_optional(true) {} 283 explicit ConvertFromOptional(optional<Explicit>&&) 284 : implicit(false), move(true), from_optional(true) {} 285 286 bool implicit; 287 bool move; 288 bool from_optional; 289 }; 290 291 TEST(optionalTest, ConvertingConstructor) { 292 optional<Implicit> i_empty; 293 optional<Implicit> i(in_place); 294 optional<Explicit> e_empty; 295 optional<Explicit> e(in_place); 296 { 297 // implicitly constructing optional<Convert> from optional<Implicit> 298 optional<Convert> empty = i_empty; 299 EXPECT_FALSE(!!empty); 300 optional<Convert> opt_copy = i; 301 EXPECT_TRUE(!!opt_copy); 302 EXPECT_TRUE(opt_copy->implicit); 303 EXPECT_FALSE(opt_copy->move); 304 optional<Convert> opt_move = optional<Implicit>(in_place); 305 EXPECT_TRUE(!!opt_move); 306 EXPECT_TRUE(opt_move->implicit); 307 EXPECT_TRUE(opt_move->move); 308 } 309 { 310 // explicitly constructing optional<Convert> from optional<Explicit> 311 optional<Convert> empty(e_empty); 312 EXPECT_FALSE(!!empty); 313 optional<Convert> opt_copy(e); 314 EXPECT_TRUE(!!opt_copy); 315 EXPECT_FALSE(opt_copy->implicit); 316 EXPECT_FALSE(opt_copy->move); 317 EXPECT_FALSE((std::is_convertible<const optional<Explicit>&, 318 optional<Convert>>::value)); 319 optional<Convert> opt_move{optional<Explicit>(in_place)}; 320 EXPECT_TRUE(!!opt_move); 321 EXPECT_FALSE(opt_move->implicit); 322 EXPECT_TRUE(opt_move->move); 323 EXPECT_FALSE( 324 (std::is_convertible<optional<Explicit>&&, optional<Convert>>::value)); 325 } 326 { 327 // implicitly constructing optional<ConvertFromOptional> from 328 // optional<Implicit> via ConvertFromOptional(optional<Implicit>&&) 329 // check that ConvertFromOptional(Implicit&&) is NOT called 330 static_assert( 331 gtl::internal_optional::is_constructible_convertible_from_optional< 332 ConvertFromOptional, Implicit>::value, 333 ""); 334 optional<ConvertFromOptional> opt0 = i_empty; 335 EXPECT_TRUE(!!opt0); 336 EXPECT_TRUE(opt0->implicit); 337 EXPECT_FALSE(opt0->move); 338 EXPECT_TRUE(opt0->from_optional); 339 optional<ConvertFromOptional> opt1 = optional<Implicit>(); 340 EXPECT_TRUE(!!opt1); 341 EXPECT_TRUE(opt1->implicit); 342 EXPECT_TRUE(opt1->move); 343 EXPECT_TRUE(opt1->from_optional); 344 } 345 { 346 // implicitly constructing optional<ConvertFromOptional> from 347 // optional<Explicit> via ConvertFromOptional(optional<Explicit>&&) 348 // check that ConvertFromOptional(Explicit&&) is NOT called 349 optional<ConvertFromOptional> opt0(e_empty); 350 EXPECT_TRUE(!!opt0); 351 EXPECT_FALSE(opt0->implicit); 352 EXPECT_FALSE(opt0->move); 353 EXPECT_TRUE(opt0->from_optional); 354 EXPECT_FALSE((std::is_convertible<const optional<Explicit>&, 355 optional<ConvertFromOptional>>::value)); 356 optional<ConvertFromOptional> opt1{optional<Explicit>()}; 357 EXPECT_TRUE(!!opt1); 358 EXPECT_FALSE(opt1->implicit); 359 EXPECT_TRUE(opt1->move); 360 EXPECT_TRUE(opt1->from_optional); 361 EXPECT_FALSE((std::is_convertible<optional<Explicit>&&, 362 optional<ConvertFromOptional>>::value)); 363 } 364 } 365 366 TEST(optionalTest, StructorBasic) { 367 StructorListener listener; 368 Listenable::listener = &listener; 369 { 370 optional<Listenable> empty; 371 EXPECT_FALSE(!!empty); 372 optional<Listenable> opt0(in_place); 373 EXPECT_TRUE(!!opt0); 374 optional<Listenable> opt1(in_place, 1); 375 EXPECT_TRUE(!!opt1); 376 optional<Listenable> opt2(in_place, 1, 2); 377 EXPECT_TRUE(!!opt2); 378 } 379 EXPECT_EQ(1, listener.construct0); 380 EXPECT_EQ(1, listener.construct1); 381 EXPECT_EQ(1, listener.construct2); 382 EXPECT_EQ(3, listener.destruct); 383 } 384 385 TEST(optionalTest, CopyMoveStructor) { 386 StructorListener listener; 387 Listenable::listener = &listener; 388 optional<Listenable> original(in_place); 389 EXPECT_EQ(1, listener.construct0); 390 EXPECT_EQ(0, listener.copy); 391 EXPECT_EQ(0, listener.move); 392 optional<Listenable> copy(original); 393 EXPECT_EQ(1, listener.construct0); 394 EXPECT_EQ(1, listener.copy); 395 EXPECT_EQ(0, listener.move); 396 optional<Listenable> move(std::move(original)); 397 EXPECT_EQ(1, listener.construct0); 398 EXPECT_EQ(1, listener.copy); 399 EXPECT_EQ(1, listener.move); 400 } 401 402 TEST(optionalTest, ListInit) { 403 StructorListener listener; 404 Listenable::listener = &listener; 405 optional<Listenable> listinit1(in_place, {1}); 406 optional<Listenable> listinit2(in_place, {1, 2}); 407 EXPECT_EQ(2, listener.listinit); 408 } 409 410 TEST(optionalTest, AssignFromNullopt) { 411 optional<int> opt(1); 412 opt = nullopt; 413 EXPECT_FALSE(!!opt); 414 415 StructorListener listener; 416 Listenable::listener = &listener; 417 optional<Listenable> opt1(in_place); 418 opt1 = nullopt; 419 EXPECT_FALSE(opt1); 420 EXPECT_EQ(1, listener.construct0); 421 EXPECT_EQ(1, listener.destruct); 422 423 EXPECT_TRUE((std::is_nothrow_assignable<optional<int>, nullopt_t>::value)); 424 EXPECT_TRUE( 425 (std::is_nothrow_assignable<optional<Listenable>, nullopt_t>::value)); 426 } 427 428 TEST(optionalTest, CopyAssignment) { 429 const optional<int> empty, opt1 = 1, opt2 = 2; 430 optional<int> empty_to_opt1, opt1_to_opt2, opt2_to_empty; 431 432 EXPECT_FALSE(!!empty_to_opt1); 433 empty_to_opt1 = empty; 434 EXPECT_FALSE(!!empty_to_opt1); 435 empty_to_opt1 = opt1; 436 EXPECT_TRUE(!!empty_to_opt1); 437 EXPECT_EQ(1, empty_to_opt1.value()); 438 439 EXPECT_FALSE(!!opt1_to_opt2); 440 opt1_to_opt2 = opt1; 441 EXPECT_TRUE(!!opt1_to_opt2); 442 EXPECT_EQ(1, opt1_to_opt2.value()); 443 opt1_to_opt2 = opt2; 444 EXPECT_TRUE(!!opt1_to_opt2); 445 EXPECT_EQ(2, opt1_to_opt2.value()); 446 447 EXPECT_FALSE(!!opt2_to_empty); 448 opt2_to_empty = opt2; 449 EXPECT_TRUE(!!opt2_to_empty); 450 EXPECT_EQ(2, opt2_to_empty.value()); 451 opt2_to_empty = empty; 452 EXPECT_FALSE(!!opt2_to_empty); 453 454 EXPECT_TRUE(std::is_copy_assignable<optional<Copyable>>::value); 455 EXPECT_FALSE(std::is_copy_assignable<optional<MoveableThrow>>::value); 456 EXPECT_FALSE(std::is_copy_assignable<optional<MoveableNoThrow>>::value); 457 EXPECT_FALSE(std::is_copy_assignable<optional<NonMovable>>::value); 458 } 459 460 TEST(optionalTest, MoveAssignment) { 461 StructorListener listener; 462 Listenable::listener = &listener; 463 464 optional<Listenable> empty1, empty2, set1(in_place), set2(in_place); 465 EXPECT_EQ(2, listener.construct0); 466 optional<Listenable> empty_to_empty, empty_to_set, set_to_empty(in_place), 467 set_to_set(in_place); 468 EXPECT_EQ(4, listener.construct0); 469 empty_to_empty = std::move(empty1); 470 empty_to_set = std::move(set1); 471 set_to_empty = std::move(empty2); 472 set_to_set = std::move(set2); 473 EXPECT_EQ(0, listener.copy); 474 EXPECT_EQ(1, listener.move); 475 EXPECT_EQ(1, listener.destruct); 476 EXPECT_EQ(1, listener.move_assign); 477 478 EXPECT_TRUE(std::is_move_assignable<optional<Copyable>>::value); 479 EXPECT_TRUE(std::is_move_assignable<optional<MoveableThrow>>::value); 480 EXPECT_TRUE(std::is_move_assignable<optional<MoveableNoThrow>>::value); 481 EXPECT_FALSE(std::is_move_assignable<optional<NonMovable>>::value); 482 483 EXPECT_FALSE(std::is_nothrow_move_assignable<optional<MoveableThrow>>::value); 484 EXPECT_TRUE( 485 std::is_nothrow_move_assignable<optional<MoveableNoThrow>>::value); 486 } 487 488 struct NoConvertToOptional { 489 // disable implicit conversion from const NoConvertToOptional& 490 // to optional<NoConvertToOptional>. 491 NoConvertToOptional(const NoConvertToOptional&) = delete; 492 }; 493 494 struct CopyConvert { 495 CopyConvert(const NoConvertToOptional&); 496 CopyConvert& operator=(const CopyConvert&) = delete; 497 CopyConvert& operator=(const NoConvertToOptional&); 498 }; 499 500 struct CopyConvertFromOptional { 501 CopyConvertFromOptional(const NoConvertToOptional&); 502 CopyConvertFromOptional(const optional<NoConvertToOptional>&); 503 CopyConvertFromOptional& operator=(const CopyConvertFromOptional&) = delete; 504 CopyConvertFromOptional& operator=(const NoConvertToOptional&); 505 CopyConvertFromOptional& operator=(const optional<NoConvertToOptional>&); 506 }; 507 508 struct MoveConvert { 509 MoveConvert(NoConvertToOptional&&); 510 MoveConvert& operator=(const MoveConvert&) = delete; 511 MoveConvert& operator=(NoConvertToOptional&&); 512 }; 513 514 struct MoveConvertFromOptional { 515 MoveConvertFromOptional(NoConvertToOptional&&); 516 MoveConvertFromOptional(optional<NoConvertToOptional>&&); 517 MoveConvertFromOptional& operator=(const MoveConvertFromOptional&) = delete; 518 MoveConvertFromOptional& operator=(NoConvertToOptional&&); 519 MoveConvertFromOptional& operator=(optional<NoConvertToOptional>&&); 520 }; 521 522 // template <class U = T> optional<T>& operator=(U&& v); 523 TEST(optionalTest, ValueAssignment) { 524 optional<int> opt; 525 EXPECT_FALSE(!!opt); 526 opt = 42; 527 EXPECT_TRUE(!!opt); 528 EXPECT_EQ(42, opt.value()); 529 opt = nullopt; 530 EXPECT_FALSE(!!opt); 531 opt = 42; 532 EXPECT_TRUE(!!opt); 533 EXPECT_EQ(42, opt.value()); 534 opt = 43; 535 EXPECT_TRUE(!!opt); 536 EXPECT_EQ(43, opt.value()); 537 opt = {}; // this should clear optional 538 EXPECT_FALSE(!!opt); 539 540 opt = {44}; 541 EXPECT_TRUE(!!opt); 542 EXPECT_EQ(44, opt.value()); 543 544 // U = const NoConvertToOptional& 545 EXPECT_TRUE((std::is_assignable<optional<CopyConvert>&, 546 const NoConvertToOptional&>::value)); 547 // U = const optional<NoConvertToOptional>& 548 EXPECT_TRUE((std::is_assignable<optional<CopyConvertFromOptional>&, 549 const NoConvertToOptional&>::value)); 550 // U = const NoConvertToOptional& triggers SFINAE because 551 // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false 552 EXPECT_FALSE((std::is_assignable<optional<MoveConvert>&, 553 const NoConvertToOptional&>::value)); 554 // U = NoConvertToOptional 555 EXPECT_TRUE((std::is_assignable<optional<MoveConvert>&, 556 NoConvertToOptional&&>::value)); 557 // U = const NoConvertToOptional& triggers SFINAE because 558 // std::is_constructible_v<MoveConvertFromOptional, const 559 // NoConvertToOptional&> is false 560 EXPECT_FALSE((std::is_assignable<optional<MoveConvertFromOptional>&, 561 const NoConvertToOptional&>::value)); 562 // U = NoConvertToOptional 563 EXPECT_TRUE((std::is_assignable<optional<MoveConvertFromOptional>&, 564 NoConvertToOptional&&>::value)); 565 // U = const optional<NoConvertToOptional>& 566 EXPECT_TRUE( 567 (std::is_assignable<optional<CopyConvertFromOptional>&, 568 const optional<NoConvertToOptional>&>::value)); 569 // U = optional<NoConvertToOptional> 570 EXPECT_TRUE((std::is_assignable<optional<MoveConvertFromOptional>&, 571 optional<NoConvertToOptional>&&>::value)); 572 } 573 574 // template <class U> optional<T>& operator=(const optional<U>& rhs); 575 // template <class U> optional<T>& operator=(optional<U>&& rhs); 576 TEST(optionalTest, ConvertingAssignment) { 577 optional<int> opt_i; 578 optional<char> opt_c('c'); 579 opt_i = opt_c; 580 EXPECT_TRUE(!!opt_i); 581 EXPECT_EQ(*opt_c, *opt_i); 582 opt_i = optional<char>(); 583 EXPECT_FALSE(!!opt_i); 584 opt_i = optional<char>('d'); 585 EXPECT_TRUE(!!opt_i); 586 EXPECT_EQ('d', *opt_i); 587 588 optional<string> opt_str; 589 optional<const char*> opt_cstr("abc"); 590 opt_str = opt_cstr; 591 EXPECT_TRUE(!!opt_str); 592 EXPECT_EQ(string("abc"), *opt_str); 593 opt_str = optional<const char*>(); 594 EXPECT_FALSE(!!opt_str); 595 opt_str = optional<const char*>("def"); 596 EXPECT_TRUE(!!opt_str); 597 EXPECT_EQ(string("def"), *opt_str); 598 599 // operator=(const optional<U>&) with U = NoConvertToOptional 600 EXPECT_TRUE( 601 (std::is_assignable<optional<CopyConvert>, 602 const optional<NoConvertToOptional>&>::value)); 603 // operator=(const optional<U>&) with U = NoConvertToOptional 604 // triggers SFINAE because 605 // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false 606 EXPECT_FALSE( 607 (std::is_assignable<optional<MoveConvert>&, 608 const optional<NoConvertToOptional>&>::value)); 609 // operator=(optional<U>&&) with U = NoConvertToOptional 610 EXPECT_TRUE((std::is_assignable<optional<MoveConvert>&, 611 optional<NoConvertToOptional>&&>::value)); 612 // operator=(const optional<U>&) with U = NoConvertToOptional triggers SFINAE 613 // because std::is_constructible_v<MoveConvertFromOptional, 614 // const NoConvertToOptional&> is false. 615 // operator=(U&&) with U = const optional<NoConverToOptional>& triggers SFINAE 616 // because std::is_constructible<MoveConvertFromOptional, 617 // optional<NoConvertToOptional>&&> is true. 618 EXPECT_FALSE( 619 (std::is_assignable<optional<MoveConvertFromOptional>&, 620 const optional<NoConvertToOptional>&>::value)); 621 } 622 623 TEST(optionalTest, ResetAndHasValue) { 624 StructorListener listener; 625 Listenable::listener = &listener; 626 optional<Listenable> opt; 627 EXPECT_FALSE(!!opt); 628 EXPECT_FALSE(opt.has_value()); 629 opt.emplace(); 630 EXPECT_TRUE(!!opt); 631 EXPECT_TRUE(opt.has_value()); 632 opt.reset(); 633 EXPECT_FALSE(!!opt); 634 EXPECT_FALSE(opt.has_value()); 635 EXPECT_EQ(1, listener.destruct); 636 opt.reset(); 637 EXPECT_FALSE(!!opt); 638 EXPECT_FALSE(opt.has_value()); 639 640 constexpr optional<int> empty; 641 static_assert(!empty.has_value(), ""); 642 constexpr optional<int> nonempty(1); 643 static_assert(nonempty.has_value(), ""); 644 } 645 646 TEST(optionalTest, Emplace) { 647 StructorListener listener; 648 Listenable::listener = &listener; 649 optional<Listenable> opt; 650 EXPECT_FALSE(!!opt); 651 opt.emplace(1); 652 EXPECT_TRUE(!!opt); 653 opt.emplace(1, 2); 654 EXPECT_EQ(1, listener.construct1); 655 EXPECT_EQ(1, listener.construct2); 656 EXPECT_EQ(1, listener.destruct); 657 } 658 659 TEST(optionalTest, ListEmplace) { 660 StructorListener listener; 661 Listenable::listener = &listener; 662 optional<Listenable> opt; 663 EXPECT_FALSE(!!opt); 664 opt.emplace({1}); 665 EXPECT_TRUE(!!opt); 666 opt.emplace({1, 2}); 667 EXPECT_EQ(2, listener.listinit); 668 EXPECT_EQ(1, listener.destruct); 669 } 670 671 TEST(optionalTest, Swap) { 672 optional<int> opt_empty, opt1 = 1, opt2 = 2; 673 EXPECT_FALSE(!!opt_empty); 674 EXPECT_TRUE(!!opt1); 675 EXPECT_EQ(1, opt1.value()); 676 EXPECT_TRUE(!!opt2); 677 EXPECT_EQ(2, opt2.value()); 678 swap(opt_empty, opt1); 679 EXPECT_FALSE(!!opt1); 680 EXPECT_TRUE(!!opt_empty); 681 EXPECT_EQ(1, opt_empty.value()); 682 EXPECT_TRUE(!!opt2); 683 EXPECT_EQ(2, opt2.value()); 684 swap(opt_empty, opt1); 685 EXPECT_FALSE(!!opt_empty); 686 EXPECT_TRUE(!!opt1); 687 EXPECT_EQ(1, opt1.value()); 688 EXPECT_TRUE(!!opt2); 689 EXPECT_EQ(2, opt2.value()); 690 swap(opt1, opt2); 691 EXPECT_FALSE(!!opt_empty); 692 EXPECT_TRUE(!!opt1); 693 EXPECT_EQ(2, opt1.value()); 694 EXPECT_TRUE(!!opt2); 695 EXPECT_EQ(1, opt2.value()); 696 697 EXPECT_TRUE(noexcept(opt1.swap(opt2))); 698 EXPECT_TRUE(noexcept(swap(opt1, opt2))); 699 } 700 701 TEST(optionalTest, PointerStuff) { 702 optional<string> opt(in_place, "foo"); 703 EXPECT_EQ("foo", *opt); 704 const auto& opt_const = opt; 705 EXPECT_EQ("foo", *opt_const); 706 EXPECT_EQ(opt->size(), 3); 707 EXPECT_EQ(opt_const->size(), 3); 708 709 constexpr optional<ConstexprType> opt1(1); 710 static_assert(opt1->x == 1, ""); 711 } 712 713 // gcc has a bug pre 4.9 where it doesn't do correct overload resolution 714 // between rvalue reference qualified member methods. Skip that test to make 715 // the build green again when using the old compiler. 716 #if defined(__GNUC__) && !defined(__clang__) 717 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9) 718 #define SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG 719 #endif 720 #endif 721 722 TEST(optionalTest, Value) { 723 using O = optional<string>; 724 using CO = const optional<string>; 725 O lvalue(in_place, "lvalue"); 726 CO clvalue(in_place, "clvalue"); 727 EXPECT_EQ("lvalue", lvalue.value()); 728 EXPECT_EQ("clvalue", clvalue.value()); 729 EXPECT_EQ("xvalue", O(in_place, "xvalue").value()); 730 #ifndef SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG 731 EXPECT_EQ("cxvalue", CO(in_place, "cxvalue").value()); 732 EXPECT_EQ("&", TypeQuals(lvalue.value())); 733 EXPECT_EQ("c&", TypeQuals(clvalue.value())); 734 EXPECT_EQ("&&", TypeQuals(O(in_place, "xvalue").value())); 735 EXPECT_EQ("c&&", TypeQuals(CO(in_place, "cxvalue").value())); 736 #endif 737 } 738 739 TEST(optionalTest, DerefOperator) { 740 using O = optional<string>; 741 using CO = const optional<string>; 742 O lvalue(in_place, "lvalue"); 743 CO clvalue(in_place, "clvalue"); 744 EXPECT_EQ("lvalue", *lvalue); 745 EXPECT_EQ("clvalue", *clvalue); 746 EXPECT_EQ("xvalue", *O(in_place, "xvalue")); 747 #ifndef SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG 748 EXPECT_EQ("cxvalue", *CO(in_place, "cxvalue")); 749 EXPECT_EQ("&", TypeQuals(*lvalue)); 750 EXPECT_EQ("c&", TypeQuals(*clvalue)); 751 EXPECT_EQ("&&", TypeQuals(*O(in_place, "xvalue"))); 752 EXPECT_EQ("c&&", TypeQuals(*CO(in_place, "cxvalue"))); 753 #endif 754 755 constexpr optional<int> opt1(1); 756 static_assert(*opt1 == 1, ""); 757 758 #if !defined(SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG) && \ 759 !defined(SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG) 760 using COI = const optional<int>; 761 static_assert(*COI(2) == 2, ""); 762 #endif 763 } 764 765 TEST(optionalTest, ValueOr) { 766 optional<double> opt_empty, opt_set = 1.2; 767 EXPECT_EQ(42.0, opt_empty.value_or(42)); 768 EXPECT_EQ(1.2, opt_set.value_or(42)); 769 EXPECT_EQ(42.0, optional<double>().value_or(42)); 770 EXPECT_EQ(1.2, optional<double>(1.2).value_or(42)); 771 772 #ifndef SKIP_CONSTEXPR_TEST_DUE_TO_CLANG_BUG 773 constexpr optional<double> copt_empty; 774 static_assert(42.0 == copt_empty.value_or(42), ""); 775 776 constexpr optional<double> copt_set = {1.2}; 777 static_assert(1.2 == copt_set.value_or(42), ""); 778 779 using COD = const optional<double>; 780 static_assert(42.0 == COD().value_or(42), ""); 781 static_assert(1.2 == COD(1.2).value_or(42), ""); 782 #endif 783 } 784 785 // make_optional cannot be constexpr until C++17 786 TEST(optionalTest, make_optional) { 787 auto opt_int = make_optional(42); 788 EXPECT_TRUE((std::is_same<decltype(opt_int), optional<int>>::value)); 789 EXPECT_EQ(42, opt_int); 790 791 StructorListener listener; 792 Listenable::listener = &listener; 793 794 optional<Listenable> opt0 = make_optional<Listenable>(); 795 EXPECT_EQ(1, listener.construct0); 796 optional<Listenable> opt1 = make_optional<Listenable>(1); 797 EXPECT_EQ(1, listener.construct1); 798 optional<Listenable> opt2 = make_optional<Listenable>(1, 2); 799 EXPECT_EQ(1, listener.construct2); 800 optional<Listenable> opt3 = make_optional<Listenable>({1}); 801 optional<Listenable> opt4 = make_optional<Listenable>({1, 2}); 802 EXPECT_EQ(2, listener.listinit); 803 } 804 805 TEST(optionalTest, Comparisons) { 806 optional<int> ae, be, a2 = 2, b2 = 2, a4 = 4, b4 = 4; 807 808 #define optionalTest_Comparisons_EXPECT_LESS(x, y) \ 809 EXPECT_FALSE((x) == (y)); \ 810 EXPECT_TRUE((x) != (y)); \ 811 EXPECT_TRUE((x) < (y)); \ 812 EXPECT_FALSE((x) > (y)); \ 813 EXPECT_TRUE((x) <= (y)); \ 814 EXPECT_FALSE((x) >= (y)); 815 816 #define optionalTest_Comparisons_EXPECT_SAME(x, y) \ 817 EXPECT_TRUE((x) == (y)); \ 818 EXPECT_FALSE((x) != (y)); \ 819 EXPECT_FALSE((x) < (y)); \ 820 EXPECT_FALSE((x) > (y)); \ 821 EXPECT_TRUE((x) <= (y)); \ 822 EXPECT_TRUE((x) >= (y)); 823 824 #define optionalTest_Comparisons_EXPECT_GREATER(x, y) \ 825 EXPECT_FALSE((x) == (y)); \ 826 EXPECT_TRUE((x) != (y)); \ 827 EXPECT_FALSE((x) < (y)); \ 828 EXPECT_TRUE((x) > (y)); \ 829 EXPECT_FALSE((x) <= (y)); \ 830 EXPECT_TRUE((x) >= (y)); 831 832 // LHS: nullopt, ae, a2, 3, a4 833 // RHS: nullopt, be, b2, 3, b4 834 835 // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(nullopt,nullopt); 836 optionalTest_Comparisons_EXPECT_SAME(nullopt, be); 837 optionalTest_Comparisons_EXPECT_LESS(nullopt, b2); 838 // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(nullopt,3); 839 optionalTest_Comparisons_EXPECT_LESS(nullopt, b4); 840 841 optionalTest_Comparisons_EXPECT_SAME(ae, nullopt); 842 optionalTest_Comparisons_EXPECT_SAME(ae, be); 843 optionalTest_Comparisons_EXPECT_LESS(ae, b2); 844 optionalTest_Comparisons_EXPECT_LESS(ae, 3); 845 optionalTest_Comparisons_EXPECT_LESS(ae, b4); 846 847 optionalTest_Comparisons_EXPECT_GREATER(a2, nullopt); 848 optionalTest_Comparisons_EXPECT_GREATER(a2, be); 849 optionalTest_Comparisons_EXPECT_SAME(a2, b2); 850 optionalTest_Comparisons_EXPECT_LESS(a2, 3); 851 optionalTest_Comparisons_EXPECT_LESS(a2, b4); 852 853 // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(3,nullopt); 854 optionalTest_Comparisons_EXPECT_GREATER(3, be); 855 optionalTest_Comparisons_EXPECT_GREATER(3, b2); 856 optionalTest_Comparisons_EXPECT_SAME(3, 3); 857 optionalTest_Comparisons_EXPECT_LESS(3, b4); 858 859 optionalTest_Comparisons_EXPECT_GREATER(a4, nullopt); 860 optionalTest_Comparisons_EXPECT_GREATER(a4, be); 861 optionalTest_Comparisons_EXPECT_GREATER(a4, b2); 862 optionalTest_Comparisons_EXPECT_GREATER(a4, 3); 863 optionalTest_Comparisons_EXPECT_SAME(a4, b4); 864 } 865 866 TEST(optionalTest, SwapRegression) { 867 StructorListener listener; 868 Listenable::listener = &listener; 869 870 { 871 optional<Listenable> a; 872 optional<Listenable> b(in_place); 873 a.swap(b); 874 } 875 876 EXPECT_EQ(1, listener.construct0); 877 EXPECT_EQ(1, listener.move); 878 EXPECT_EQ(2, listener.destruct); 879 880 { 881 optional<Listenable> a(in_place); 882 optional<Listenable> b; 883 a.swap(b); 884 } 885 886 EXPECT_EQ(2, listener.construct0); 887 EXPECT_EQ(2, listener.move); 888 EXPECT_EQ(4, listener.destruct); 889 } 890 891 TEST(optionalTest, BigStringLeakCheck) { 892 constexpr size_t n = 1 << 16; 893 894 using OS = optional<string>; 895 896 OS a; 897 OS b = nullopt; 898 OS c = string(n, 'c'); 899 string sd(n, 'd'); 900 OS d = sd; 901 OS e(in_place, n, 'e'); 902 OS f; 903 f.emplace(n, 'f'); 904 905 OS ca(a); 906 OS cb(b); 907 OS cc(c); 908 OS cd(d); 909 OS ce(e); 910 911 OS oa; 912 OS ob = nullopt; 913 OS oc = string(n, 'c'); 914 string sod(n, 'd'); 915 OS od = sod; 916 OS oe(in_place, n, 'e'); 917 OS of; 918 of.emplace(n, 'f'); 919 920 OS ma(std::move(oa)); 921 OS mb(std::move(ob)); 922 OS mc(std::move(oc)); 923 OS md(std::move(od)); 924 OS me(std::move(oe)); 925 OS mf(std::move(of)); 926 927 OS aa1; 928 OS ab1 = nullopt; 929 OS ac1 = string(n, 'c'); 930 string sad1(n, 'd'); 931 OS ad1 = sad1; 932 OS ae1(in_place, n, 'e'); 933 OS af1; 934 af1.emplace(n, 'f'); 935 936 OS aa2; 937 OS ab2 = nullopt; 938 OS ac2 = string(n, 'c'); 939 string sad2(n, 'd'); 940 OS ad2 = sad2; 941 OS ae2(in_place, n, 'e'); 942 OS af2; 943 af2.emplace(n, 'f'); 944 945 aa1 = af2; 946 ab1 = ae2; 947 ac1 = ad2; 948 ad1 = ac2; 949 ae1 = ab2; 950 af1 = aa2; 951 952 OS aa3; 953 OS ab3 = nullopt; 954 OS ac3 = string(n, 'c'); 955 string sad3(n, 'd'); 956 OS ad3 = sad3; 957 OS ae3(in_place, n, 'e'); 958 OS af3; 959 af3.emplace(n, 'f'); 960 961 aa3 = nullopt; 962 ab3 = nullopt; 963 ac3 = nullopt; 964 ad3 = nullopt; 965 ae3 = nullopt; 966 af3 = nullopt; 967 968 OS aa4; 969 OS ab4 = nullopt; 970 OS ac4 = string(n, 'c'); 971 string sad4(n, 'd'); 972 OS ad4 = sad4; 973 OS ae4(in_place, n, 'e'); 974 OS af4; 975 af4.emplace(n, 'f'); 976 977 aa4 = OS(in_place, n, 'a'); 978 ab4 = OS(in_place, n, 'b'); 979 ac4 = OS(in_place, n, 'c'); 980 ad4 = OS(in_place, n, 'd'); 981 ae4 = OS(in_place, n, 'e'); 982 af4 = OS(in_place, n, 'f'); 983 984 OS aa5; 985 OS ab5 = nullopt; 986 OS ac5 = string(n, 'c'); 987 string sad5(n, 'd'); 988 OS ad5 = sad5; 989 OS ae5(in_place, n, 'e'); 990 OS af5; 991 af5.emplace(n, 'f'); 992 993 string saa5(n, 'a'); 994 string sab5(n, 'a'); 995 string sac5(n, 'a'); 996 string sad52(n, 'a'); 997 string sae5(n, 'a'); 998 string saf5(n, 'a'); 999 1000 aa5 = saa5; 1001 ab5 = sab5; 1002 ac5 = sac5; 1003 ad5 = sad52; 1004 ae5 = sae5; 1005 af5 = saf5; 1006 1007 OS aa6; 1008 OS ab6 = nullopt; 1009 OS ac6 = string(n, 'c'); 1010 string sad6(n, 'd'); 1011 OS ad6 = sad6; 1012 OS ae6(in_place, n, 'e'); 1013 OS af6; 1014 af6.emplace(n, 'f'); 1015 1016 aa6 = string(n, 'a'); 1017 ab6 = string(n, 'b'); 1018 ac6 = string(n, 'c'); 1019 ad6 = string(n, 'd'); 1020 ae6 = string(n, 'e'); 1021 af6 = string(n, 'f'); 1022 1023 OS aa7; 1024 OS ab7 = nullopt; 1025 OS ac7 = string(n, 'c'); 1026 string sad7(n, 'd'); 1027 OS ad7 = sad7; 1028 OS ae7(in_place, n, 'e'); 1029 OS af7; 1030 af7.emplace(n, 'f'); 1031 1032 aa7.emplace(n, 'A'); 1033 ab7.emplace(n, 'B'); 1034 ac7.emplace(n, 'C'); 1035 ad7.emplace(n, 'D'); 1036 ae7.emplace(n, 'E'); 1037 af7.emplace(n, 'F'); 1038 } 1039 1040 TEST(optionalTest, MoveAssignRegression) { 1041 StructorListener listener; 1042 Listenable::listener = &listener; 1043 1044 { 1045 optional<Listenable> a; 1046 Listenable b; 1047 a = std::move(b); 1048 } 1049 1050 EXPECT_EQ(1, listener.construct0); 1051 EXPECT_EQ(1, listener.move); 1052 EXPECT_EQ(2, listener.destruct); 1053 } 1054 1055 TEST(optionalTest, ValueType) { 1056 EXPECT_TRUE((std::is_same<optional<int>::value_type, int>::value)); 1057 EXPECT_TRUE((std::is_same<optional<string>::value_type, string>::value)); 1058 EXPECT_FALSE((std::is_same<optional<int>::value_type, nullopt_t>::value)); 1059 } 1060 1061 TEST(optionalTest, Hash) { 1062 std::hash<optional<int>> hash; 1063 std::set<size_t> hashcodes; 1064 hashcodes.insert(hash(nullopt)); 1065 for (int i = 0; i < 100; ++i) { 1066 hashcodes.insert(hash(i)); 1067 } 1068 EXPECT_GT(hashcodes.size(), 90); 1069 } 1070 1071 struct MoveMeNoThrow { 1072 MoveMeNoThrow() : x(0) {} 1073 MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) { 1074 LOG(FATAL) << "Should not be called."; 1075 } 1076 MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {} 1077 int x; 1078 }; 1079 1080 struct MoveMeThrow { 1081 MoveMeThrow() : x(0) {} 1082 MoveMeThrow(const MoveMeThrow& other) : x(other.x) {} 1083 MoveMeThrow(MoveMeThrow&& other) : x(other.x) {} 1084 int x; 1085 }; 1086 1087 TEST(optionalTest, NoExcept) { 1088 static_assert( 1089 std::is_nothrow_move_constructible<optional<MoveMeNoThrow>>::value, ""); 1090 static_assert( 1091 !std::is_nothrow_move_constructible<optional<MoveMeThrow>>::value, ""); 1092 std::vector<optional<MoveMeNoThrow>> v; 1093 v.reserve(10); 1094 for (int i = 0; i < 10; ++i) v.emplace_back(); 1095 } 1096 1097 } // namespace 1098 } // namespace tensorflow 1099