├── README.md ├── test.cu ├── demo.cpp └── variant.hpp /README.md: -------------------------------------------------------------------------------- 1 | variant 2 | ======= 3 | 4 | Standalone C++11 implementation of std::variant 5 | -------------------------------------------------------------------------------- /test.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include "variant.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | __host__ __device__ 8 | void test() 9 | { 10 | using namespace std; 11 | 12 | variant v1; 13 | assert(v1.index() == 0); 14 | 15 | variant v2 = 13; 16 | assert(v2.index() == 1); 17 | 18 | variant v3 = 13; 19 | assert(v3.index() == 1); 20 | 21 | assert(v2 == v3); 22 | assert(!(v2 != v3)); 23 | 24 | assert(v1 != v3); 25 | assert(!(v1 == v3)); 26 | } 27 | 28 | __global__ void kernel() 29 | { 30 | test(); 31 | } 32 | 33 | int main() 34 | { 35 | test(); 36 | 37 | kernel<<<1,1>>>(); 38 | 39 | assert(cudaDeviceSynchronize() == cudaSuccess); 40 | 41 | std::cout << "OK" << std::endl; 42 | 43 | return 0; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /demo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "variant.hpp" 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | using namespace std; 9 | 10 | variant v1; 11 | assert(v1.index() == 0); 12 | assert(get<0>(v1) == 0); 13 | assert(get(v1) == 0); 14 | assert(holds_alternative(v1)); 15 | assert(variant_size::value == 4); 16 | 17 | variant v2 = 13; 18 | assert(v2.index() == 1); 19 | assert(get<1>(v2) == 13); 20 | assert(get(v2) == 13); 21 | assert(holds_alternative(v2)); 22 | assert(variant_size::value == 4); 23 | 24 | variant v3 = 13; 25 | assert(v3.index() == 1); 26 | assert(get<1>(v3) == 13); 27 | assert(get(v3) == 13); 28 | assert(holds_alternative(v3)); 29 | assert(variant_size::value == 4); 30 | 31 | assert(v2 == v3); 32 | assert(v1 != v3); 33 | 34 | std::cout << "v1: " << v1 << std::endl; 35 | std::cout << "v2: " << v2 << std::endl; 36 | std::cout << "v3: " << v3 << std::endl; 37 | 38 | variant v4 = std::string("hello, world!"); 39 | assert(v4.index() == 4); 40 | assert(get<4>(v4) == "hello, world!"); 41 | assert(get(v4) == "hello, world!"); 42 | assert(holds_alternative(v4)); 43 | assert(variant_size::value == 5); 44 | 45 | std::cout << "v4: " << v4 << std::endl; 46 | 47 | auto s = get<4>(std::move(v4)); 48 | assert(s == "hello, world!"); 49 | assert(get<4>(v4) == ""); 50 | assert(get(v4) == ""); 51 | assert(holds_alternative(v4)); 52 | 53 | variant v5 = 7.f; 54 | variant v6 = 13.; 55 | assert(v5.index() == 0); 56 | assert(get<0>(v5) == 7.f); 57 | assert(get(v5) == 7.f); 58 | assert(holds_alternative(v5)); 59 | assert(v6.index() == 1); 60 | assert(get<1>(v6) == 13.); 61 | assert(get(v6) == 13.); 62 | assert(holds_alternative(v6)); 63 | 64 | v5.swap(v6); 65 | 66 | assert(v5.index() == 1); 67 | assert(get<1>(v5) == 13.); 68 | assert(get(v5) == 13.); 69 | assert(holds_alternative(v5)); 70 | 71 | assert(v6.index() == 0); 72 | assert(get<0>(v6) == 7.f); 73 | assert(get(v6) == 7.f); 74 | assert(holds_alternative(v6)); 75 | 76 | variant v7 = 13.; 77 | try 78 | { 79 | auto got = get<0>(v7); 80 | assert(0); 81 | } 82 | catch(bad_variant_access&) 83 | { 84 | } 85 | 86 | std::cout << "OK" << std::endl; 87 | 88 | return 0; 89 | } 90 | 91 | -------------------------------------------------------------------------------- /variant.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions 5 | // are met: 6 | // * Redistributions of source code must retain the above copyright 7 | // notice, this list of conditions and the following disclaimer. 8 | // * Redistributions in binary form must reproduce the above copyright 9 | // notice, this list of conditions and the following disclaimer in the 10 | // documentation and/or other materials provided with the distribution. 11 | // * Neither the name of NVIDIA CORPORATION nor the names of its 12 | // contributors may be used to endorse or promote products derived 13 | // from this software without specific prior written permission. 14 | // 15 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 16 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 19 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | #pragma once 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | // allow the user to define an annotation to apply to these functions 38 | #ifndef VARIANT_ANNOTATION 39 | # if defined(__CUDACC__) && !(defined(__CUDA__) && defined(__clang__)) 40 | # define VARIANT_ANNOTATION __host__ __device__ 41 | # else 42 | # define VARIANT_ANNOTATION 43 | # define VARIANT_ANNOTATION_NEEDS_UNDEF 44 | # endif 45 | #endif 46 | 47 | 48 | // define the incantation to silence nvcc errors concerning __host__ __device__ functions 49 | #if defined(__CUDACC__) && !(defined(__CUDA__) && defined(__clang__)) 50 | # define VARIANT_EXEC_CHECK_DISABLE \ 51 | # pragma nv_exec_check_disable 52 | #else 53 | # define VARIANT_EXEC_CHECK_DISABLE 54 | #endif 55 | 56 | // allow the user to define a namespace for these functions 57 | #if !defined(VARIANT_NAMESPACE) 58 | 59 | # if defined(VARIANT_NAMESPACE_OPEN_BRACE) or defined(VARIANT_NAMESPACE_CLOSE_BRACE) 60 | # error "All or none of VARIANT_NAMESPACE, VARIANT_NAMESPACE_OPEN_BRACE, and VARIANT_NAMESPACE_CLOSE_BRACE must be defined." 61 | # endif 62 | 63 | # define VARIANT_NAMESPACE std 64 | # define VARIANT_NAMESPACE_OPEN_BRACE namespace std { 65 | # define VARIANT_NAMESPACE_CLOSE_BRACE } 66 | # define VARIANT_NAMESPACE_NEEDS_UNDEF 67 | 68 | #else 69 | 70 | # if !defined(VARIANT_NAMESPACE_OPEN_BRACE) or !defined(VARIANT_NAMESPACE_CLOSE_BRACE) 71 | # error "All or none of VARIANT_NAMESPACE, VARIANT_NAMESPACE_OPEN_BRACE, and VARIANT_NAMESPACE_CLOSE_BRACE must be defined." 72 | # endif 73 | 74 | #endif 75 | 76 | 77 | // allow the user to define a singly-nested namespace for private implementation details 78 | #if !defined(VARIANT_DETAIL_NAMESPACE) 79 | # define VARIANT_DETAIL_NAMESPACE detail 80 | # define VARIANT_DETAIL_NAMESPACE_NEEDS_UNDEF 81 | #endif 82 | 83 | 84 | VARIANT_NAMESPACE_OPEN_BRACE 85 | 86 | 87 | namespace VARIANT_DETAIL_NAMESPACE 88 | { 89 | 90 | 91 | template 92 | struct constexpr_max 93 | { 94 | static const size_t value = i < constexpr_max::value ? constexpr_max::value : i; 95 | }; 96 | 97 | 98 | template 99 | struct constexpr_max 100 | { 101 | static const size_t value = i; 102 | }; 103 | 104 | 105 | } // end VARIANT_DETAIL_NAMESPACE 106 | 107 | 108 | template 109 | class variant; 110 | 111 | 112 | template 113 | struct variant_size; 114 | 115 | template 116 | struct variant_size> : std::integral_constant {}; 117 | 118 | template 119 | struct variant_size : variant_size {}; 120 | 121 | template 122 | struct variant_size : variant_size {}; 123 | 124 | template 125 | struct variant_size : variant_size {}; 126 | 127 | 128 | template struct variant_alternative; 129 | 130 | 131 | template 132 | struct variant_alternative> 133 | : variant_alternative> 134 | {}; 135 | 136 | 137 | template 138 | struct variant_alternative<0, variant> 139 | { 140 | typedef T0 type; 141 | }; 142 | 143 | 144 | template 145 | using variant_alternative_t = typename variant_alternative::type; 146 | 147 | 148 | static constexpr const size_t variant_npos = static_cast(-1); 149 | 150 | 151 | namespace VARIANT_DETAIL_NAMESPACE 152 | { 153 | 154 | 155 | template 156 | struct propagate_reference; 157 | 158 | 159 | template 160 | struct propagate_reference 161 | { 162 | typedef U& type; 163 | }; 164 | 165 | 166 | template 167 | struct propagate_reference 168 | { 169 | typedef const U& type; 170 | }; 171 | 172 | 173 | template 174 | struct propagate_reference 175 | { 176 | typedef U&& type; 177 | }; 178 | 179 | 180 | template 181 | struct variant_alternative_reference 182 | : propagate_reference< 183 | VariantReference, 184 | variant_alternative_t< 185 | i, 186 | typename std::decay::type 187 | > 188 | > 189 | {}; 190 | 191 | 192 | template 193 | using variant_alternative_reference_t = typename variant_alternative_reference::type; 194 | 195 | 196 | } // end VARIANT_DETAIL_NAMESPACE 197 | 198 | 199 | template 200 | VARIANT_ANNOTATION 201 | typename std::result_of< 202 | Visitor&&(VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant&&>) 203 | >::type 204 | visit(Visitor&& visitor, Variant&& var); 205 | 206 | 207 | template 208 | VARIANT_ANNOTATION 209 | typename std::result_of< 210 | Visitor&&(VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant1&&>, 211 | VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant2&&>) 212 | >::type 213 | visit(Visitor&& visitor, Variant1&& var1, Variant2&& var2); 214 | 215 | 216 | namespace VARIANT_DETAIL_NAMESPACE 217 | { 218 | 219 | 220 | template 221 | struct find_type_impl; 222 | 223 | 224 | // no match, keep going 225 | template 226 | struct find_type_impl 227 | : find_type_impl 228 | {}; 229 | 230 | 231 | // found a match 232 | template 233 | struct find_type_impl 234 | { 235 | static constexpr const size_t value = i; 236 | }; 237 | 238 | 239 | // no match 240 | template 241 | struct find_type_impl 242 | { 243 | static constexpr const size_t value = variant_npos; 244 | }; 245 | 246 | 247 | template 248 | using find_type = find_type_impl<0,T,Types...>; 249 | 250 | 251 | template 252 | struct is_variant_alternative; 253 | 254 | template 255 | struct is_variant_alternative> 256 | : std::integral_constant< 257 | bool, 258 | (find_type::value != variant_npos) 259 | > 260 | {}; 261 | 262 | 263 | } // end VARIANT_DETAIL_NAMESPACE 264 | 265 | 266 | class bad_variant_access : public std::logic_error 267 | { 268 | public: 269 | explicit bad_variant_access(const std::string& what_arg) : logic_error(what_arg) {} 270 | explicit bad_variant_access(const char* what_arg) : logic_error(what_arg) {} 271 | }; 272 | 273 | 274 | namespace VARIANT_DETAIL_NAMESPACE 275 | { 276 | 277 | 278 | VARIANT_ANNOTATION 279 | inline void throw_bad_variant_access(const char* what_arg) 280 | { 281 | #ifdef __CUDA_ARCH__ 282 | printf("bad_variant_access: %s\n", what_arg); 283 | assert(0); 284 | #else 285 | throw bad_variant_access(what_arg); 286 | #endif 287 | } 288 | 289 | 290 | template 291 | struct first_type 292 | { 293 | using type = T; 294 | }; 295 | 296 | template 297 | using first_type_t = typename first_type::type; 298 | 299 | 300 | template 301 | class variant_storage 302 | { 303 | typedef typename std::aligned_storage< 304 | constexpr_max::value 305 | >::type storage_type; 306 | 307 | storage_type storage_; 308 | }; 309 | 310 | template<> 311 | class variant_storage<> {}; 312 | 313 | } // end VARIANT_DETAIL_NAMESPACE 314 | 315 | 316 | template 317 | class variant : private VARIANT_DETAIL_NAMESPACE::variant_storage 318 | { 319 | public: 320 | VARIANT_ANNOTATION 321 | variant() 322 | : variant(VARIANT_DETAIL_NAMESPACE::first_type_t{}) 323 | {} 324 | 325 | private: 326 | struct binary_move_construct_visitor 327 | { 328 | template 329 | VARIANT_ANNOTATION 330 | void operator()(T& self, T& other) 331 | { 332 | new (&self) T(std::move(other)); 333 | } 334 | 335 | template 336 | VARIANT_ANNOTATION 337 | void operator()(Args&&...){} 338 | }; 339 | 340 | public: 341 | VARIANT_ANNOTATION 342 | variant(variant&& other) 343 | : index_(other.index()) 344 | { 345 | auto visitor = binary_move_construct_visitor(); 346 | VARIANT_NAMESPACE::visit(visitor, *this, other); 347 | } 348 | 349 | private: 350 | struct binary_copy_construct_visitor 351 | { 352 | template 353 | VARIANT_ANNOTATION 354 | void operator()(T& self, const T& other) 355 | { 356 | new (&self) T(other); 357 | } 358 | 359 | template 360 | VARIANT_ANNOTATION 361 | void operator()(Args&&...){} 362 | }; 363 | 364 | public: 365 | VARIANT_ANNOTATION 366 | variant(const variant& other) 367 | : index_(other.index()) 368 | { 369 | auto visitor = binary_copy_construct_visitor(); 370 | VARIANT_NAMESPACE::visit(visitor, *this, other); 371 | } 372 | 373 | private: 374 | template 375 | struct unary_copy_construct_visitor 376 | { 377 | const T& other; 378 | 379 | VARIANT_ANNOTATION 380 | void operator()(T& self) 381 | { 382 | new (&self) T(other); 383 | } 384 | 385 | template 386 | VARIANT_ANNOTATION 387 | void operator()(U&&) {} 388 | }; 389 | 390 | public: 391 | template::value 394 | >::type> 395 | VARIANT_ANNOTATION 396 | variant(const T& other) 397 | : index_(VARIANT_DETAIL_NAMESPACE::find_type::value) 398 | { 399 | VARIANT_NAMESPACE::visit(unary_copy_construct_visitor{other}, *this); 400 | } 401 | 402 | private: 403 | template 404 | struct unary_move_construct_visitor 405 | { 406 | T& other; 407 | 408 | VARIANT_ANNOTATION 409 | void operator()(T& self) 410 | { 411 | new (&self) T(std::move(other)); 412 | } 413 | 414 | template 415 | VARIANT_ANNOTATION 416 | void operator()(U&&){} 417 | }; 418 | 419 | public: 420 | template::value 423 | >::type> 424 | VARIANT_ANNOTATION 425 | variant(T&& other) 426 | : index_(VARIANT_DETAIL_NAMESPACE::find_type::value) 427 | { 428 | auto visitor = unary_move_construct_visitor{other}; 429 | VARIANT_NAMESPACE::visit(visitor, *this); 430 | } 431 | 432 | private: 433 | struct destruct_visitor 434 | { 435 | template 436 | VARIANT_ANNOTATION 437 | typename std::enable_if< 438 | !std::is_trivially_destructible::value 439 | >::type 440 | operator()(T& x) 441 | { 442 | x.~T(); 443 | } 444 | 445 | template 446 | VARIANT_ANNOTATION 447 | typename std::enable_if< 448 | std::is_trivially_destructible::value 449 | >::type 450 | operator()(T&) 451 | { 452 | // omit invocations of destructors for trivially destructible types 453 | } 454 | }; 455 | 456 | public: 457 | VARIANT_ANNOTATION 458 | ~variant() 459 | { 460 | auto visitor = destruct_visitor(); 461 | VARIANT_NAMESPACE::visit(visitor, *this); 462 | } 463 | 464 | private: 465 | struct copy_assign_visitor 466 | { 467 | VARIANT_EXEC_CHECK_DISABLE 468 | template 469 | VARIANT_ANNOTATION 470 | void operator()(T& self, const T& other) const 471 | { 472 | self = other; 473 | } 474 | 475 | template 476 | VARIANT_ANNOTATION 477 | void operator()(Args&&...) const {} 478 | }; 479 | 480 | struct destroy_and_copy_construct_visitor 481 | { 482 | VARIANT_EXEC_CHECK_DISABLE 483 | template 484 | VARIANT_ANNOTATION 485 | void operator()(A& a, const B& b) const 486 | { 487 | // copy b to a temporary 488 | B tmp = b; 489 | 490 | // destroy a 491 | a.~A(); 492 | 493 | // placement move from tmp to a 494 | new (&a) B(std::move(tmp)); 495 | } 496 | }; 497 | 498 | struct destroy_and_move_construct_visitor 499 | { 500 | VARIANT_EXEC_CHECK_DISABLE 501 | template 502 | VARIANT_ANNOTATION 503 | void operator()(A& a, B&& b) const 504 | { 505 | // destroy a 506 | a.~A(); 507 | 508 | using type = typename std::decay::type; 509 | 510 | // placement move from b 511 | new (&a) type(std::move(b)); 512 | } 513 | }; 514 | 515 | public: 516 | VARIANT_ANNOTATION 517 | variant& operator=(const variant& other) 518 | { 519 | if(index() == other.index()) 520 | { 521 | VARIANT_NAMESPACE::visit(copy_assign_visitor(), *this, other); 522 | } 523 | else 524 | { 525 | VARIANT_NAMESPACE::visit(destroy_and_copy_construct_visitor(), *this, other); 526 | index_ = other.index(); 527 | } 528 | 529 | return *this; 530 | } 531 | 532 | private: 533 | struct move_assign_visitor 534 | { 535 | template 536 | VARIANT_ANNOTATION 537 | void operator()(T& self, T& other) 538 | { 539 | self = std::move(other); 540 | } 541 | 542 | template 543 | VARIANT_ANNOTATION 544 | void operator()(Args&&...){} 545 | }; 546 | 547 | 548 | public: 549 | VARIANT_ANNOTATION 550 | variant& operator=(variant&& other) 551 | { 552 | if(index() == other.index()) 553 | { 554 | auto visitor = move_assign_visitor(); 555 | VARIANT_NAMESPACE::visit(visitor, *this, other); 556 | } 557 | else 558 | { 559 | auto visitor = destroy_and_move_construct_visitor(); 560 | VARIANT_NAMESPACE::visit(visitor, *this, std::move(other)); 561 | index_ = other.index(); 562 | } 563 | 564 | return *this; 565 | } 566 | 567 | VARIANT_ANNOTATION 568 | size_t index() const 569 | { 570 | return index_; 571 | } 572 | 573 | private: 574 | struct swap_visitor 575 | { 576 | template 577 | VARIANT_ANNOTATION 578 | void operator()(A& a, B& b) 579 | { 580 | // XXX can't call std::swap because __host__ __device__ 581 | // should call swap CPO instead 582 | A tmp = std::move(a); 583 | a = std::move(b); 584 | b = std::move(tmp); 585 | } 586 | }; 587 | 588 | public: 589 | VARIANT_ANNOTATION 590 | void swap(variant& other) 591 | { 592 | if(index() == other.index()) 593 | { 594 | auto visitor = swap_visitor(); 595 | VARIANT_NAMESPACE::visit(visitor, *this, other); 596 | } 597 | else 598 | { 599 | variant tmp = *this; 600 | *this = other; 601 | other = std::move(tmp); 602 | } 603 | } 604 | 605 | private: 606 | struct equals 607 | { 608 | template 609 | VARIANT_ANNOTATION 610 | bool operator()(const U1&, const U2&) 611 | { 612 | return false; 613 | } 614 | 615 | template 616 | VARIANT_ANNOTATION 617 | bool operator()(const T& lhs, const T& rhs) 618 | { 619 | return lhs == rhs; 620 | } 621 | }; 622 | 623 | 624 | public: 625 | VARIANT_ANNOTATION 626 | bool operator==(const variant& rhs) const 627 | { 628 | auto visitor = equals(); 629 | return index() == rhs.index() && VARIANT_NAMESPACE::visit(visitor, *this, rhs); 630 | } 631 | 632 | VARIANT_ANNOTATION 633 | bool operator!=(const variant& rhs) const 634 | { 635 | return !operator==(rhs); 636 | } 637 | 638 | private: 639 | struct less 640 | { 641 | template 642 | VARIANT_ANNOTATION 643 | bool operator()(const U1&, const U2&) 644 | { 645 | return false; 646 | } 647 | 648 | template 649 | VARIANT_ANNOTATION 650 | bool operator()(const T& lhs, const T& rhs) 651 | { 652 | return lhs < rhs; 653 | } 654 | }; 655 | 656 | public: 657 | VARIANT_ANNOTATION 658 | bool operator<(const variant& rhs) const 659 | { 660 | if(index() != rhs.index()) return index() < rhs.index(); 661 | 662 | return VARIANT_NAMESPACE::visit(less(), *this, rhs); 663 | } 664 | 665 | VARIANT_ANNOTATION 666 | bool operator<=(const variant& rhs) const 667 | { 668 | return !(rhs < *this); 669 | } 670 | 671 | VARIANT_ANNOTATION 672 | bool operator>(const variant& rhs) const 673 | { 674 | return rhs < *this; 675 | } 676 | 677 | VARIANT_ANNOTATION 678 | bool operator>=(const variant& rhs) const 679 | { 680 | return !(*this < rhs); 681 | } 682 | 683 | private: 684 | size_t index_; 685 | }; 686 | 687 | 688 | namespace VARIANT_DETAIL_NAMESPACE 689 | { 690 | 691 | 692 | struct ostream_output_visitor 693 | { 694 | std::ostream &os; 695 | 696 | ostream_output_visitor(std::ostream& os) : os(os) {} 697 | 698 | template 699 | std::ostream& operator()(const T& x) 700 | { 701 | return os << x; 702 | } 703 | }; 704 | 705 | 706 | } // VARIANT_DETAIL_NAMESPACE 707 | 708 | 709 | template 710 | std::ostream &operator<<(std::ostream& os, const variant& v) 711 | { 712 | auto visitor = VARIANT_DETAIL_NAMESPACE::ostream_output_visitor(os); 713 | return VARIANT_NAMESPACE::visit(visitor, v); 714 | } 715 | 716 | 717 | namespace VARIANT_DETAIL_NAMESPACE 718 | { 719 | 720 | 721 | template 722 | struct apply_visitor_impl : apply_visitor_impl 723 | { 724 | typedef apply_visitor_impl super_t; 725 | 726 | VARIANT_ANNOTATION 727 | static Result do_it(VisitorReference visitor, void* ptr, size_t index) 728 | { 729 | if(index == 0) 730 | { 731 | return visitor(*reinterpret_cast(ptr)); 732 | } 733 | 734 | return super_t::do_it(visitor, ptr, --index); 735 | } 736 | 737 | 738 | VARIANT_ANNOTATION 739 | static Result do_it(VisitorReference visitor, const void* ptr, size_t index) 740 | { 741 | if(index == 0) 742 | { 743 | return visitor(*reinterpret_cast(ptr)); 744 | } 745 | 746 | return super_t::do_it(visitor, ptr, --index); 747 | } 748 | }; 749 | 750 | 751 | template 752 | struct apply_visitor_impl 753 | { 754 | VARIANT_ANNOTATION 755 | static Result do_it(VisitorReference visitor, void* ptr, size_t) 756 | { 757 | return visitor(*reinterpret_cast(ptr)); 758 | } 759 | 760 | VARIANT_ANNOTATION 761 | static Result do_it(VisitorReference visitor, const void* ptr, size_t) 762 | { 763 | return visitor(*reinterpret_cast(ptr)); 764 | } 765 | }; 766 | 767 | 768 | template 769 | struct apply_visitor; 770 | 771 | 772 | template 773 | struct apply_visitor> 774 | : apply_visitor_impl 775 | {}; 776 | 777 | 778 | } // end VARIANT_DETAIL_ANNOTATION 779 | 780 | 781 | template 782 | VARIANT_ANNOTATION 783 | typename std::result_of< 784 | Visitor&&(VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant&&>) 785 | >::type 786 | visit(Visitor&& visitor, Variant&& var) 787 | { 788 | using result_type = typename std::result_of< 789 | Visitor&&(VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant&&>) 790 | >::type; 791 | 792 | using impl = VARIANT_DETAIL_NAMESPACE::apply_visitor::type>; 793 | 794 | return impl::do_it(std::forward(visitor), &var, var.index()); 795 | } 796 | 797 | 798 | namespace VARIANT_DETAIL_NAMESPACE 799 | { 800 | 801 | 802 | template 803 | struct unary_visitor_binder 804 | { 805 | VisitorReference visitor; 806 | ElementReference x; 807 | 808 | VARIANT_ANNOTATION 809 | unary_visitor_binder(VisitorReference visitor, ElementReference ref) : visitor(std::forward(visitor)), x(ref) {} 810 | 811 | template 812 | VARIANT_ANNOTATION 813 | Result operator()(T&& y) 814 | { 815 | return visitor(std::forward(x), std::forward(y)); 816 | } 817 | }; 818 | 819 | 820 | template 821 | struct rvalue_reference_to_lvalue_reference 822 | { 823 | using type = Reference; 824 | }; 825 | 826 | template 827 | struct rvalue_reference_to_lvalue_reference 828 | { 829 | using type = T&; 830 | }; 831 | 832 | 833 | template 834 | struct binary_visitor_binder 835 | { 836 | VisitorReference visitor; 837 | // since rvalue references can't be members of classes, we transform any 838 | // VariantReference which is an rvalue reference to an lvalue reference 839 | // when we use y in operator(), we cast it back to the original reference type 840 | typename rvalue_reference_to_lvalue_reference::type y; 841 | 842 | VARIANT_ANNOTATION 843 | binary_visitor_binder(VisitorReference visitor, VariantReference ref) : visitor(std::forward(visitor)), y(ref) {} 844 | 845 | template 846 | VARIANT_ANNOTATION 847 | Result operator()(T&& x) 848 | { 849 | auto unary_visitor = unary_visitor_binder(std::forward(visitor), std::forward(x)); 850 | return VARIANT_NAMESPACE::visit(unary_visitor, std::forward(y)); 851 | } 852 | }; 853 | 854 | 855 | } // end VARIANT_DETAIL_NAMESPACE 856 | 857 | 858 | template 859 | VARIANT_ANNOTATION 860 | typename std::result_of< 861 | Visitor&&(VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant1&&>, 862 | VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant2&&>) 863 | >::type 864 | visit(Visitor&& visitor, Variant1&& var1, Variant2&& var2) 865 | { 866 | using result_type = typename std::result_of< 867 | Visitor&&(VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant1&&>, 868 | VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t<0,Variant2&&>) 869 | >::type; 870 | 871 | auto visitor_wrapper = VARIANT_DETAIL_NAMESPACE::binary_visitor_binder(std::forward(visitor), std::forward(var2)); 872 | 873 | return VARIANT_NAMESPACE::visit(visitor_wrapper, std::forward(var1)); 874 | } 875 | 876 | 877 | namespace VARIANT_DETAIL_NAMESPACE 878 | { 879 | 880 | 881 | template 882 | struct get_visitor 883 | { 884 | VARIANT_ANNOTATION 885 | T* operator()(T& x) const 886 | { 887 | return &x; 888 | } 889 | 890 | VARIANT_ANNOTATION 891 | const T* operator()(const T& x) const 892 | { 893 | return &x; 894 | } 895 | 896 | template 897 | VARIANT_ANNOTATION 898 | T* operator()(U&&) const 899 | { 900 | return nullptr; 901 | } 902 | }; 903 | 904 | } // end VARIANT_DETAIL_NAMESPACE 905 | 906 | 907 | template 908 | VARIANT_ANNOTATION 909 | VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t&> 910 | get(variant& v) 911 | { 912 | if(i != v.index()) 913 | { 914 | VARIANT_DETAIL_NAMESPACE::throw_bad_variant_access("i does not equal index()"); 915 | } 916 | 917 | using type = typename std::decay< 918 | variant_alternative_t> 919 | >::type; 920 | 921 | auto visitor = VARIANT_DETAIL_NAMESPACE::get_visitor(); 922 | return *VARIANT_NAMESPACE::visit(visitor, v); 923 | } 924 | 925 | 926 | template 927 | VARIANT_ANNOTATION 928 | VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t&&> 929 | get(variant&& v) 930 | { 931 | if(i != v.index()) 932 | { 933 | VARIANT_DETAIL_NAMESPACE::throw_bad_variant_access("i does not equal index()"); 934 | } 935 | 936 | using type = typename std::decay< 937 | variant_alternative_t> 938 | >::type; 939 | 940 | auto visitor = VARIANT_DETAIL_NAMESPACE::get_visitor(); 941 | return std::move(*VARIANT_NAMESPACE::visit(visitor, v)); 942 | } 943 | 944 | 945 | template 946 | VARIANT_ANNOTATION 947 | VARIANT_DETAIL_NAMESPACE::variant_alternative_reference_t&> 948 | get(const variant& v) 949 | { 950 | if(i != v.index()) 951 | { 952 | VARIANT_DETAIL_NAMESPACE::throw_bad_variant_access("i does not equal index()"); 953 | } 954 | 955 | using type = typename std::decay< 956 | variant_alternative_t> 957 | >::type; 958 | 959 | auto visitor = VARIANT_DETAIL_NAMESPACE::get_visitor(); 960 | return *VARIANT_NAMESPACE::visit(visitor, v); 961 | } 962 | 963 | 964 | namespace VARIANT_DETAIL_NAMESPACE 965 | { 966 | 967 | 968 | template 969 | struct find_exactly_one_impl; 970 | 971 | template 972 | struct find_exactly_one_impl : find_exactly_one_impl {}; 973 | 974 | template 975 | struct find_exactly_one_impl : std::integral_constant 976 | { 977 | static_assert(find_exactly_one_impl::value == variant_npos, "type can only occur once in type list"); 978 | }; 979 | 980 | 981 | template 982 | struct find_exactly_one_impl : std::integral_constant {}; 983 | 984 | template 985 | struct find_exactly_one : find_exactly_one_impl<0,T,Types...> 986 | { 987 | static_assert(find_exactly_one::value != variant_npos, "type not found in type list"); 988 | }; 989 | 990 | 991 | } // end VARIANT_DETAIL_NAMESPACE 992 | 993 | 994 | template 995 | VARIANT_ANNOTATION 996 | bool holds_alternative(const variant& v) 997 | { 998 | constexpr size_t i = VARIANT_DETAIL_NAMESPACE::find_exactly_one::value; 999 | return i == v.index(); 1000 | } 1001 | 1002 | 1003 | template 1004 | VARIANT_ANNOTATION 1005 | typename std::remove_reference::type& 1006 | get(variant& v) 1007 | { 1008 | return get::value>(v); 1009 | } 1010 | 1011 | 1012 | template 1013 | VARIANT_ANNOTATION 1014 | const typename std::remove_reference::type& 1015 | get(const variant& v) 1016 | { 1017 | return get::value>(v); 1018 | } 1019 | 1020 | 1021 | template 1022 | VARIANT_ANNOTATION 1023 | typename std::remove_reference::type&& 1024 | get(variant&& v) 1025 | { 1026 | return std::move(get::value>(v)); 1027 | } 1028 | 1029 | 1030 | VARIANT_NAMESPACE_CLOSE_BRACE 1031 | 1032 | 1033 | #ifdef VARIANT_ANNOTATION_NEEDS_UNDEF 1034 | # undef VARIANT_ANNOTATION 1035 | # undef VARIANT_ANNOTATION_NEEDS_UNDEF 1036 | #endif 1037 | 1038 | #ifdef VARIANT_NAMESPACE_NEEDS_UNDEF 1039 | # undef VARIANT_NAMESPACE 1040 | # undef VARIANT_NAMESPACE_OPEN_BRACE 1041 | # undef VARIANT_NAMESPACE_CLOSE_BRACE 1042 | # undef VARIANT_NAMESPACE_NEEDS_UNDEF 1043 | #endif 1044 | 1045 | #ifdef VARIANT_DETAIL_NAMESPACE_NEEDS_UNDEF 1046 | # undef VARIANT_DETAIL_NAMESPACE 1047 | # undef VARIANT_DETAIL_NAMESPACE_NEEDS_UNDEF 1048 | #endif 1049 | 1050 | #undef VARIANT_EXEC_CHECK_DISABLE 1051 | 1052 | --------------------------------------------------------------------------------