1 /*============================================================================= 2 Copyright (c) 2013 Shuangyang Yang 3 Copyright (c) 2007-2013 Hartmut Kaiser 4 Copyright (c) Christopher Diggins 2005 5 Copyright (c) Pablo Aguilar 2005 6 Copyright (c) Kevlin Henney 2001 7 8 Distributed under the Boost Software License, Version 1.0. (See accompanying 9 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 10 11 The class hpx::util::any is built based on boost::spirit::hold_any class. 12 It adds support for HPX serialization, move assignment, == operator. 13 ==============================================================================*/ 14 #ifndef HPX_UTIL_ANY_HPP 15 #define HPX_UTIL_ANY_HPP 16 17 #include <hpx/config.hpp> 18 #include <hpx/runtime/serialization/base_object.hpp> 19 #include <hpx/runtime/serialization/detail/raw_ptr.hpp> 20 #include <hpx/runtime/serialization/serialize.hpp> 21 #include <hpx/traits/supports_streaming_with_any.hpp> 22 #include <hpx/util/assert.hpp> 23 #include <hpx/util/decay.hpp> 24 25 #include <boost/detail/sp_typeinfo.hpp> 26 #include <boost/functional/hash.hpp> 27 28 #include <algorithm> 29 #include <cstddef> 30 #include <iosfwd> 31 #include <stdexcept> 32 #include <type_traits> 33 #include <typeinfo> 34 #include <utility> 35 #include <vector> 36 37 /////////////////////////////////////////////////////////////////////////////// 38 #if BOOST_WORKAROUND(HPX_MSVC, >= 1400) 39 # pragma warning(push) 40 # pragma warning(disable: 4100) // 'x': unreferenced formal parameter 41 # pragma warning(disable: 4127) // conditional expression is constant 42 #endif 43 44 /////////////////////////////////////////////////////////////////////////////// 45 namespace hpx { namespace util 46 { 47 struct bad_any_cast 48 : std::bad_cast 49 { bad_any_casthpx::util::bad_any_cast50 bad_any_cast(boost::detail::sp_typeinfo const& src, 51 boost::detail::sp_typeinfo const& dest) 52 : from(src.name()), to(dest.name()) 53 {} 54 whathpx::util::bad_any_cast55 virtual const char* what() const throw() { return "bad any cast"; } 56 57 const char* from; 58 const char* to; 59 }; 60 61 namespace detail { namespace any 62 { 63 template <typename T> 64 struct get_table; 65 66 // serializable function pointer table 67 template <typename IArchive, typename OArchive, typename Char> 68 struct fxn_ptr_table 69 { ~fxn_ptr_tablehpx::util::detail::any::fxn_ptr_table70 virtual ~fxn_ptr_table() {} 71 virtual fxn_ptr_table * get_ptr() = 0; 72 73 boost::detail::sp_typeinfo const& (*get_type)(); 74 void (*static_delete)(void**); 75 void (*destruct)(void**); 76 void (*clone)(void* const*, void**); 77 void (*copy)(void* const*, void**); 78 bool (*equal_to)(void* const*, void* const*); 79 std::basic_istream<Char>& (*stream_in)(std::basic_istream<Char>&, void**); 80 std::basic_ostream<Char>& (*stream_out)(std::basic_ostream<Char>&, 81 void* const*); 82 83 virtual void save_object(void *const*, OArchive & ar, unsigned) = 0; 84 virtual void load_object(void **, IArchive & ar, unsigned) = 0; 85 86 template <typename Archive> serializehpx::util::detail::any::fxn_ptr_table87 void serialize(Archive & ar, unsigned) {} 88 89 HPX_SERIALIZATION_POLYMORPHIC_ABSTRACT(fxn_ptr_table); 90 }; 91 92 // function pointer table 93 template <typename Char> 94 struct fxn_ptr_table<void, void, Char> 95 { ~fxn_ptr_tablehpx::util::detail::any::fxn_ptr_table96 virtual ~fxn_ptr_table() {} 97 virtual fxn_ptr_table * get_ptr() = 0; 98 99 boost::detail::sp_typeinfo const& (*get_type)(); 100 void (*static_delete)(void**); 101 void (*destruct)(void**); 102 void (*clone)(void* const*, void**); 103 void (*copy)(void* const*, void**); 104 bool (*equal_to)(void* const*, void* const*); 105 std::basic_istream<Char>& (*stream_in)(std::basic_istream<Char>&, void**); 106 std::basic_ostream<Char>& (*stream_out)(std::basic_ostream<Char>&, 107 void* const*); 108 }; 109 110 template <typename T 111 , typename Small 112 , typename Enable = typename traits::supports_streaming_with_any<T>::type> 113 struct streaming_base; 114 115 template <typename T> 116 struct streaming_base<T, std::true_type, std::true_type> 117 { 118 template <typename Char> 119 static std::basic_istream<Char>& stream_inhpx::util::detail::any::streaming_base120 stream_in (std::basic_istream<Char>& i, void** obj) 121 { 122 i >> *reinterpret_cast<T*>(obj); 123 return i; 124 } 125 126 template <typename Char> 127 static std::basic_ostream<Char>& stream_outhpx::util::detail::any::streaming_base128 stream_out(std::basic_ostream<Char>& o, void* const* obj) 129 { 130 o << *reinterpret_cast<T const*>(obj); 131 return o; 132 } 133 }; 134 135 template <typename T> 136 struct streaming_base<T, std::false_type, std::true_type> 137 { 138 template <typename Char> 139 static std::basic_istream<Char>& stream_inhpx::util::detail::any::streaming_base140 stream_in (std::basic_istream<Char>& i, void** obj) 141 { 142 i >> **reinterpret_cast<T**>(obj); 143 return i; 144 } 145 146 template <typename Char> 147 static std::basic_ostream<Char>& stream_outhpx::util::detail::any::streaming_base148 stream_out(std::basic_ostream<Char>& o, void* const* obj) 149 { 150 o << **reinterpret_cast<T* const*>(obj); 151 return o; 152 } 153 }; 154 155 template <typename T, typename Small> 156 struct streaming_base<T, Small, std::false_type> 157 { 158 template <typename Char> 159 static std::basic_istream<Char>& stream_inhpx::util::detail::any::streaming_base160 stream_in (std::basic_istream<Char>& i, void** obj) 161 { 162 return i; 163 } 164 165 template <typename Char> 166 static std::basic_ostream<Char>& stream_outhpx::util::detail::any::streaming_base167 stream_out(std::basic_ostream<Char>& o, void* const* obj) 168 { 169 return o; 170 } 171 }; 172 173 // static functions for small value-types 174 template <typename Small> 175 struct fxns; 176 177 template <> 178 struct fxns<std::true_type> 179 { 180 template<typename T, typename IArchive, typename OArchive, typename Char> 181 struct type : public streaming_base<T, std::true_type> 182 { get_ptrhpx::util::detail::any::fxns::type183 static fxn_ptr_table<IArchive, OArchive, Char> *get_ptr() 184 { 185 return detail::any::get_table<T>:: 186 template get<IArchive, OArchive, Char>(); 187 } 188 get_typehpx::util::detail::any::fxns::type189 static boost::detail::sp_typeinfo const& get_type() 190 { 191 return BOOST_SP_TYPEID(T); 192 } constructhpx::util::detail::any::fxns::type193 static T & construct(void ** f) 194 { 195 new (f) T; 196 return *reinterpret_cast<T *>(f); 197 } 198 gethpx::util::detail::any::fxns::type199 static T & get(void **f) 200 { 201 return *reinterpret_cast<T *>(f); 202 } 203 gethpx::util::detail::any::fxns::type204 static T const & get(void *const*f) 205 { 206 return *reinterpret_cast<T const *>(f); 207 } static_deletehpx::util::detail::any::fxns::type208 static void static_delete(void** x) 209 { 210 reinterpret_cast<T*>(x)->~T(); 211 } destructhpx::util::detail::any::fxns::type212 static void destruct(void** x) 213 { 214 reinterpret_cast<T*>(x)->~T(); 215 } clonehpx::util::detail::any::fxns::type216 static void clone(void* const* src, void** dest) 217 { 218 new (dest) T(*reinterpret_cast<T const*>(src)); 219 } copyhpx::util::detail::any::fxns::type220 static void copy(void* const* src, void** dest) 221 { 222 *reinterpret_cast<T*>(dest) = 223 *reinterpret_cast<T const*>(src); 224 } equal_tohpx::util::detail::any::fxns::type225 static bool equal_to(void* const* x, void* const* y) 226 { 227 return (get(x) == get(y)); 228 } 229 }; 230 }; 231 232 // static functions for big value-types (bigger than a void*) 233 template <> 234 struct fxns<std::false_type> 235 { 236 template<typename T, typename IArchive, typename OArchive, typename Char> 237 struct type : public streaming_base<T, std::false_type> 238 { get_ptrhpx::util::detail::any::fxns::type239 static fxn_ptr_table<IArchive, OArchive, Char> *get_ptr() 240 { 241 return detail::any::get_table<T>:: 242 template get<IArchive, OArchive, Char>(); 243 } get_typehpx::util::detail::any::fxns::type244 static boost::detail::sp_typeinfo const& get_type() 245 { 246 return BOOST_SP_TYPEID(T); 247 } constructhpx::util::detail::any::fxns::type248 static T & construct(void ** f) 249 { 250 *f = new T; 251 return **reinterpret_cast<T **>(f); 252 } gethpx::util::detail::any::fxns::type253 static T & get(void **f) 254 { 255 return **reinterpret_cast<T **>(f); 256 } gethpx::util::detail::any::fxns::type257 static T const & get(void *const*f) 258 { 259 return **reinterpret_cast<T *const *>(f); 260 } static_deletehpx::util::detail::any::fxns::type261 static void static_delete(void** x) 262 { 263 // destruct and free memory 264 delete (*reinterpret_cast<T**>(x)); 265 } destructhpx::util::detail::any::fxns::type266 static void destruct(void** x) 267 { 268 // destruct only, we'll reuse memory 269 (*reinterpret_cast<T**>(x))->~T(); 270 } clonehpx::util::detail::any::fxns::type271 static void clone(void* const* src, void** dest) 272 { 273 *dest = new T(**reinterpret_cast<T* const*>(src)); 274 } copyhpx::util::detail::any::fxns::type275 static void copy(void* const* src, void** dest) 276 { 277 **reinterpret_cast<T**>(dest) = 278 **reinterpret_cast<T* const*>(src); 279 } equal_tohpx::util::detail::any::fxns::type280 static bool equal_to(void* const* x, void* const* y) 281 { 282 return (get(x) == get(y)); 283 } 284 }; 285 }; 286 287 /////////////////////////////////////////////////////////////////////// 288 template <typename IArchive, typename OArchive, typename Vtable, typename Char> 289 struct fxn_ptr 290 : fxn_ptr_table<IArchive, OArchive, Char> 291 { 292 typedef fxn_ptr_table<IArchive, OArchive, Char> base_type; 293 fxn_ptrhpx::util::detail::any::fxn_ptr294 fxn_ptr() 295 { 296 base_type::get_type = Vtable::get_type; 297 base_type::static_delete = Vtable::static_delete; 298 base_type::destruct = Vtable::destruct; 299 base_type::clone = Vtable::clone; 300 base_type::copy = Vtable::copy; 301 base_type::equal_to = Vtable::equal_to; 302 base_type::stream_in = Vtable::stream_in; 303 base_type::stream_out = Vtable::stream_out; 304 } 305 get_ptrhpx::util::detail::any::fxn_ptr306 virtual base_type * get_ptr() 307 { 308 return Vtable::get_ptr(); 309 } 310 save_objecthpx::util::detail::any::fxn_ptr311 void save_object(void *const* object, OArchive & ar, unsigned) 312 { 313 ar & Vtable::get(object); 314 } load_objecthpx::util::detail::any::fxn_ptr315 void load_object(void ** object, IArchive & ar, unsigned) 316 { 317 ar & Vtable::construct(object); 318 } 319 320 template <typename Archive> serializehpx::util::detail::any::fxn_ptr321 void serialize(Archive & ar, unsigned) 322 { 323 ar & hpx::serialization::base_object<base_type>(*this); 324 } 325 HPX_SERIALIZATION_POLYMORPHIC_TEMPLATE(fxn_ptr); 326 }; 327 328 template <typename Vtable, typename Char> 329 struct fxn_ptr<void, void, Vtable, Char> 330 : fxn_ptr_table<void, void, Char> 331 { 332 typedef fxn_ptr_table<void, void, Char> base_type; 333 fxn_ptrhpx::util::detail::any::fxn_ptr334 fxn_ptr() 335 { 336 base_type::get_type = Vtable::get_type; 337 base_type::static_delete = Vtable::static_delete; 338 base_type::destruct = Vtable::destruct; 339 base_type::clone = Vtable::clone; 340 base_type::copy = Vtable::copy; 341 base_type::equal_to = Vtable::equal_to; 342 base_type::stream_in = Vtable::stream_in; 343 base_type::stream_out = Vtable::stream_out; 344 } 345 get_ptrhpx::util::detail::any::fxn_ptr346 virtual base_type * get_ptr() 347 { 348 return Vtable::get_ptr(); 349 } 350 }; 351 352 /////////////////////////////////////////////////////////////////////// 353 template <typename T> 354 struct get_table 355 { 356 typedef std::integral_constant<bool, (sizeof(T) <= sizeof(void*))> is_small; 357 358 template <typename IArchive, typename OArchive, typename Char> gethpx::util::detail::any::get_table359 static fxn_ptr_table<IArchive, OArchive, Char>* get() 360 { 361 362 typedef 363 typename fxns<is_small>:: 364 template type<T, IArchive, OArchive, Char> 365 fxn_type; 366 367 typedef 368 fxn_ptr<IArchive, OArchive, fxn_type, Char> 369 fxn_ptr_type; 370 371 static fxn_ptr_type static_table; 372 373 return &static_table; 374 } 375 }; 376 377 /////////////////////////////////////////////////////////////////////// 378 struct empty 379 { 380 template <typename Archive> serializehpx::util::detail::any::empty381 void serialize(Archive & ar, unsigned) {} operator ==hpx::util::detail::any::empty382 bool operator==(empty const&) const 383 { 384 return false; // undefined 385 } operator !=hpx::util::detail::any::empty386 bool operator!=(empty const&) const 387 { 388 return false; // undefined 389 } 390 }; 391 392 template <typename Char> 393 inline std::basic_istream<Char>& operator >>(std::basic_istream<Char> & i,empty &)394 operator>> (std::basic_istream<Char>& i, empty&) 395 { 396 // If this assertion fires you tried to insert from a std istream 397 // into an empty any instance. This simply can't work, because 398 // there is no way to figure out what type to extract from the 399 // stream. 400 // The only way to make this work is to assign an arbitrary 401 // value of the required type to the any instance you want to 402 // stream to. This assignment has to be executed before the actual 403 // call to the operator>>(). 404 HPX_ASSERT(false && 405 "Tried to insert from a std istream into an empty " 406 "any instance"); 407 return i; 408 } 409 410 template <typename Char> 411 inline std::basic_ostream<Char>& operator <<(std::basic_ostream<Char> & o,empty const &)412 operator<< (std::basic_ostream<Char>& o, empty const&) 413 { 414 return o; 415 } 416 }} // namespace hpx::util::detail::any 417 }} // namespace hpx::util 418 419 namespace hpx { namespace util 420 { 421 /////////////////////////////////////////////////////////////////////////// 422 template < 423 typename IArchive = serialization::input_archive, 424 typename OArchive = serialization::output_archive, 425 typename Char = char> 426 class basic_any 427 { 428 public: 429 // constructors basic_any()430 basic_any() noexcept 431 : table(detail::any::get_table<detail::any::empty>:: 432 template get<IArchive, OArchive, Char>()), 433 object(nullptr) 434 { 435 } 436 basic_any(basic_any const & x)437 basic_any(basic_any const& x) 438 : table(detail::any::get_table<detail::any::empty>:: 439 template get<IArchive, OArchive, Char>()), 440 object(nullptr) 441 { 442 assign(x); 443 } 444 445 template <typename T> basic_any(T const & x)446 explicit basic_any(T const& x) 447 : table(detail::any::get_table< 448 typename util::decay<T>::type 449 >::template get<IArchive, OArchive, Char>()), 450 object(nullptr) 451 { 452 typedef typename util::decay<T>::type value_type; 453 new_object(object, x, 454 typename detail::any::get_table<value_type>::is_small()); 455 } 456 457 // Move constructor basic_any(basic_any && x)458 basic_any(basic_any&& x) noexcept 459 : table(x.table), 460 object(x.object) 461 { 462 x.table = detail::any::get_table<detail::any::empty>:: 463 template get<IArchive, OArchive, Char>(); 464 x.object = nullptr; 465 } 466 467 // Perfect forwarding of T 468 template <typename T> basic_any(T && x,typename std::enable_if<!std::is_same<basic_any,typename util::decay<T>::type>::value>::type * =nullptr)469 explicit basic_any(T&& x, 470 typename std::enable_if< 471 !std::is_same< 472 basic_any, 473 typename util::decay<T>::type 474 >::value>::type* = nullptr) 475 : table(detail::any::get_table< 476 typename util::decay<T>::type 477 >::template get<IArchive, OArchive, Char>()), 478 object(nullptr) 479 { 480 typedef typename util::decay<T>::type value_type; 481 new_object(object, std::forward<T>(x), 482 typename detail::any::get_table<value_type>::is_small()); 483 } 484 ~basic_any()485 ~basic_any() 486 { 487 table->static_delete(&object); 488 } 489 490 private: 491 // assignment assign(basic_any const & x)492 basic_any& assign(basic_any const& x) 493 { 494 if (&x != this) { 495 // are we copying between the same type? 496 if (table == x.table) { 497 // if so, we can avoid reallocation 498 table->copy(&x.object, &object); 499 } 500 else { 501 reset(); 502 x.table->clone(&x.object, &object); 503 table = x.table; 504 } 505 } 506 return *this; 507 } 508 509 template <typename T> new_object(void * & object,T && x,std::true_type)510 static void new_object(void*& object, T && x, std::true_type) 511 { 512 typedef typename util::decay<T>::type value_type; 513 new (&object) value_type(std::forward<T>(x)); 514 } 515 516 template <typename T> new_object(void * & object,T && x,std::false_type)517 static void new_object(void*& object, T && x, std::false_type) 518 { 519 typedef typename util::decay<T>::type value_type; 520 object = new value_type(std::forward<T>(x)); 521 } 522 523 public: 524 // copy assignment operator operator =(basic_any const & x)525 basic_any& operator=(basic_any const& x) 526 { 527 basic_any(x).swap(*this); 528 return *this; 529 } 530 531 // move assignement operator =(basic_any && rhs)532 basic_any& operator=(basic_any&& rhs) noexcept 533 { 534 rhs.swap(*this); 535 basic_any().swap(rhs); 536 return *this; 537 } 538 539 // Perfect forwarding of T 540 template <typename T> operator =(T && rhs)541 basic_any& operator=(T&& rhs) 542 { 543 basic_any(std::forward<T>(rhs)).swap(*this); 544 return *this; 545 } 546 547 // equality operator operator ==(basic_any const & x,basic_any const & y)548 friend bool operator==(basic_any const& x, basic_any const& y) 549 { 550 if (&x == &y) // same object 551 { 552 return true; 553 } 554 555 if (x.table == y.table) // same type 556 { 557 return x.table->equal_to(&x.object, &y.object); // equal value? 558 } 559 560 return false; 561 562 } 563 564 template <typename T> operator ==(basic_any const & b,T const & x)565 friend bool operator==(basic_any const& b, T const& x) 566 { 567 typedef typename util::decay<T>::type value_type; 568 569 if (b.type() == BOOST_SP_TYPEID(value_type)) // same type 570 { 571 return b.cast<value_type>() == x; 572 } 573 574 return false; 575 } 576 577 // inequality operator operator !=(basic_any const & x,basic_any const & y)578 friend bool operator!=(basic_any const& x, basic_any const& y) 579 { 580 return !(x==y); 581 } 582 583 template <typename T> operator !=(basic_any const & b,T const & x)584 friend bool operator!=(basic_any const& b, T const& x) 585 { 586 return !(b==x); 587 } 588 589 // utility functions swap(basic_any & x)590 basic_any& swap(basic_any& x) noexcept 591 { 592 std::swap(table, x.table); 593 std::swap(object, x.object); 594 return *this; 595 } 596 type() const597 boost::detail::sp_typeinfo const& type() const 598 { 599 return table->get_type(); 600 } 601 602 template <typename T> cast() const603 T const& cast() const 604 { 605 if (type() != BOOST_SP_TYPEID(T)) 606 throw bad_any_cast(type(), BOOST_SP_TYPEID(T)); 607 608 return detail::any::get_table<T>::is_small::value ? 609 *reinterpret_cast<T const*>(&object) : 610 *reinterpret_cast<T const*>(object); 611 } 612 613 // implicit casting is disabled by default for compatibility with boost::any 614 #ifdef HPX_ANY_IMPLICIT_CASTING 615 // automatic casting operator 616 template <typename T> operator T const&() const617 operator T const& () const { return cast<T>(); } 618 #endif // implicit casting 619 empty() const620 bool empty() const noexcept 621 { 622 return table == detail::any::get_table<detail::any::empty>:: 623 template get<IArchive, OArchive, Char>(); 624 } 625 reset()626 void reset() 627 { 628 if (!empty()) 629 { 630 table->static_delete(&object); 631 table = detail::any::get_table<detail::any::empty>:: 632 template get<IArchive, OArchive, Char>(); 633 object = nullptr; 634 } 635 } 636 637 // these functions have been added in the assumption that the embedded 638 // type has a corresponding operator defined, which is completely safe 639 // because hpx::util::any is used only in contexts where these operators 640 // exist 641 template <typename IArchive_, typename OArchive_, typename Char_> 642 friend std::basic_istream<Char_>& 643 operator>> (std::basic_istream<Char_>& i, 644 basic_any<IArchive_, OArchive_, Char_>& obj); 645 646 template <typename IArchive_, typename OArchive_, typename Char_> 647 friend std::basic_ostream<Char_>& 648 operator<< (std::basic_ostream<Char_>& o, 649 basic_any<IArchive_, OArchive_, Char_> const& obj); 650 651 private: 652 653 friend class hpx::serialization::access; 654 load(IArchive & ar,const unsigned version)655 void load(IArchive &ar, const unsigned version) 656 { 657 bool is_empty; 658 ar & is_empty; 659 660 if (is_empty) 661 { 662 reset(); 663 } 664 else 665 { 666 typename detail::any::fxn_ptr_table< 667 IArchive, OArchive, Char 668 > *p = nullptr; 669 ar >> hpx::serialization::detail::raw_ptr(p); 670 table = p->get_ptr(); 671 delete p; 672 table->load_object(&object, ar, version); 673 } 674 } 675 save(OArchive & ar,const unsigned version) const676 void save(OArchive &ar, const unsigned version) const 677 { 678 bool is_empty = empty(); 679 ar & is_empty; 680 if (!is_empty) 681 { 682 ar << hpx::serialization::detail::raw_ptr(table); 683 table->save_object(&object, ar, version); 684 } 685 } 686 687 HPX_SERIALIZATION_SPLIT_MEMBER(); 688 689 private: // types 690 template <typename T, typename IArchive_, typename OArchive_, typename Char_> 691 friend T* any_cast(basic_any<IArchive_, OArchive_, Char_> *) noexcept; 692 693 // fields 694 detail::any::fxn_ptr_table<IArchive, OArchive, Char>* table; 695 void* object; 696 }; 697 698 /////////////////////////////////////////////////////////////////////////// 699 template <typename IArchive_, typename OArchive_, typename Char_> 700 std::basic_istream<Char_>& operator >>(std::basic_istream<Char_> & i,basic_any<IArchive_,OArchive_,Char_> & obj)701 operator>> (std::basic_istream<Char_>& i, 702 basic_any<IArchive_, OArchive_, Char_>& obj) 703 { 704 return obj.table->stream_in(i, &obj.object); 705 } 706 707 template <typename IArchive_, typename OArchive_, typename Char_> 708 std::basic_ostream<Char_>& operator <<(std::basic_ostream<Char_> & o,basic_any<IArchive_,OArchive_,Char_> const & obj)709 operator<< (std::basic_ostream<Char_>& o, 710 basic_any<IArchive_, OArchive_, Char_> const& obj) 711 { 712 return obj.table->stream_out(o, &obj.object); 713 } 714 715 /////////////////////////////////////////////////////////////////////////// 716 template <typename Char> // default is char 717 class basic_any<void, void, Char> 718 { 719 public: 720 // constructors basic_any()721 basic_any() noexcept 722 : table(detail::any::get_table< 723 detail::any::empty>::template get<void, void, Char>()), 724 object(nullptr) 725 { 726 } 727 basic_any(basic_any const & x)728 basic_any(basic_any const& x) 729 : table(detail::any::get_table< 730 detail::any::empty>::template get<void, void, Char>()), 731 object(nullptr) 732 { 733 assign(x); 734 } 735 736 template <typename T> basic_any(T const & x)737 explicit basic_any(T const& x) 738 : table(detail::any::get_table< 739 typename util::decay<T>::type 740 >::template get<void, void, Char>()), 741 object(nullptr) 742 { 743 typedef typename util::decay<T>::type value_type; 744 new_object(object, x, 745 typename detail::any::get_table<value_type>::is_small()); 746 } 747 748 // Move constructor basic_any(basic_any && x)749 basic_any(basic_any&& x) noexcept 750 : table(x.table), 751 object(x.object) 752 { 753 x.object = nullptr; 754 x.table = detail::any::get_table<detail::any::empty>:: 755 template get<void, void, Char>(); 756 } 757 758 // Perfect forwarding of T 759 template <typename T> basic_any(T && x,typename std::enable_if<!std::is_same<basic_any,typename util::decay<T>::type>::value>::type * =nullptr)760 explicit basic_any(T&& x, 761 typename std::enable_if< 762 !std::is_same< 763 basic_any, 764 typename util::decay<T>::type 765 >::value>::type* = nullptr) 766 : table(detail::any::get_table< 767 typename util::decay<T>::type 768 >::template get<void, void, Char>()), 769 object(nullptr) 770 { 771 typedef typename util::decay<T>::type value_type; 772 new_object(object, std::forward<T>(x), 773 typename detail::any::get_table<value_type>::is_small()); 774 } 775 ~basic_any()776 ~basic_any() 777 { 778 table->static_delete(&object); 779 } 780 781 private: assign(basic_any const & x)782 basic_any& assign(basic_any const& x) 783 { 784 if (&x != this) { 785 // are we copying between the same type? 786 if (table == x.table) { 787 // if so, we can avoid reallocation 788 table->copy(&x.object, &object); 789 } 790 else { 791 reset(); 792 x.table->clone(&x.object, &object); 793 table = x.table; 794 } 795 } 796 return *this; 797 } 798 799 template <typename T> new_object(void * & object,T && x,std::true_type)800 static void new_object(void*& object, T && x, std::true_type) 801 { 802 typedef typename util::decay<T>::type value_type; 803 new (&object) value_type(std::forward<T>(x)); 804 } 805 806 template <typename T> new_object(void * & object,T && x,std::false_type)807 static void new_object(void*& object, T && x, std::false_type) 808 { 809 typedef typename util::decay<T>::type value_type; 810 object = new value_type(std::forward<T>(x)); 811 } 812 813 public: 814 // copy assignment operator operator =(basic_any const & x)815 basic_any& operator=(basic_any const& x) 816 { 817 basic_any(x).swap(*this); 818 return *this; 819 } 820 821 // move assignment operator =(basic_any && rhs)822 basic_any& operator=(basic_any&& rhs) 823 { 824 rhs.swap(*this); 825 basic_any().swap(rhs); 826 return *this; 827 } 828 829 // Perfect forwarding of T 830 template <typename T> operator =(T && rhs)831 basic_any& operator=(T&& rhs) 832 { 833 basic_any(std::forward<T>(rhs)).swap(*this); 834 return *this; 835 } 836 837 // equality operator operator ==(basic_any const & x,basic_any const & y)838 friend bool operator==(basic_any const& x, basic_any const& y) 839 { 840 if (&x == &y) // same object 841 { 842 return true; 843 } 844 845 if (x.table == y.table) // same type 846 { 847 return x.table->equal_to(&x.object, &y.object); // equal value? 848 } 849 850 return false; 851 } 852 853 template <typename T> operator ==(basic_any const & b,T const & x)854 friend bool operator==(basic_any const& b, T const& x) 855 { 856 typedef typename util::decay<T>::type value_type; 857 858 if (b.type() == BOOST_SP_TYPEID(value_type)) // same type 859 { 860 return b.cast<value_type>() == x; 861 } 862 863 return false; 864 } 865 866 // inequality operator operator !=(basic_any const & x,basic_any const & y)867 friend bool operator!=(basic_any const& x, basic_any const& y) 868 { 869 return !(x == y); 870 } 871 872 template <typename T> operator !=(basic_any const & b,T const & x)873 friend bool operator!=(basic_any const& b, T const& x) 874 { 875 return !(b == x); 876 } 877 878 // utility functions swap(basic_any & x)879 basic_any& swap(basic_any& x) noexcept 880 { 881 std::swap(table, x.table); 882 std::swap(object, x.object); 883 return *this; 884 } 885 type() const886 boost::detail::sp_typeinfo const& type() const 887 { 888 return table->get_type(); 889 } 890 891 template <typename T> cast() const892 T const& cast() const 893 { 894 if (type() != BOOST_SP_TYPEID(T)) 895 throw bad_any_cast(type(), BOOST_SP_TYPEID(T)); 896 897 return hpx::util::detail::any::get_table<T>::is_small::value ? 898 *reinterpret_cast<T const*>(&object) : 899 *reinterpret_cast<T const*>(object); 900 } 901 902 // implicit casting is disabled by default for compatibility with boost::any 903 #ifdef HPX_ANY_IMPLICIT_CASTING 904 // automatic casting operator 905 template <typename T> operator T const&() const906 operator T const& () const { return cast<T>(); } 907 #endif // implicit casting 908 empty() const909 bool empty() const noexcept 910 { 911 return table == 912 detail::any::get_table<detail::any::empty>:: 913 template get<void, void, Char>(); 914 } 915 reset()916 void reset() 917 { 918 if (!empty()) 919 { 920 table->static_delete(&object); 921 table = detail::any::get_table<detail::any::empty>:: 922 template get<void, void, Char>(); 923 object = nullptr; 924 } 925 } 926 927 // these functions have been added in the assumption that the embedded 928 // type has a corresponding operator defined, which is completely safe 929 // because hpx::util::any is used only in contexts where these operators 930 // exist 931 template <typename IArchive_, typename OArchive_, typename Char_> 932 friend std::basic_istream<Char_>& 933 operator>> (std::basic_istream<Char_>& i, 934 basic_any<IArchive_, OArchive_, Char_>& obj); 935 936 template <typename IArchive_, typename OArchive_, typename Char_> 937 friend std::basic_ostream<Char_>& 938 operator<< (std::basic_ostream<Char_>& o, 939 basic_any<IArchive_, OArchive_, Char_> const& obj); 940 941 private: // types 942 template <typename T, typename IArchive_, typename OArchive_, typename Char_> 943 friend T* any_cast(basic_any<IArchive_, OArchive_, Char_> *) noexcept; 944 945 // fields 946 detail::any::fxn_ptr_table<void, void, Char>* table; 947 void* object; 948 }; 949 /////////////////////////////////////////////////////////////////////////// 950 951 template <typename IArchive, typename OArchive, typename Char> swap(basic_any<IArchive,OArchive,Char> & lhs,basic_any<IArchive,OArchive,Char> & rhs)952 void swap(basic_any<IArchive, OArchive, Char>& lhs, 953 basic_any<IArchive, OArchive, Char>& rhs) noexcept 954 { 955 lhs.swap(rhs); 956 } 957 958 // boost::any-like casting 959 template <typename T, typename IArchive, typename OArchive, typename Char> any_cast(basic_any<IArchive,OArchive,Char> * operand)960 inline T* any_cast (basic_any<IArchive, OArchive, Char>* operand) noexcept 961 { 962 if (operand && operand->type() == BOOST_SP_TYPEID(T)) { 963 return hpx::util::detail::any::get_table<T>::is_small::value ? 964 reinterpret_cast<T*>(reinterpret_cast<void*>(&operand->object)) : 965 reinterpret_cast<T*>(reinterpret_cast<void*>(operand->object)); 966 } 967 return nullptr; 968 } 969 970 template <typename T, typename IArchive, typename OArchive, typename Char> any_cast(basic_any<IArchive,OArchive,Char> const * operand)971 inline T const* any_cast(basic_any<IArchive, OArchive, 972 Char> const* operand) noexcept 973 { 974 return any_cast<T>(const_cast<basic_any<IArchive, OArchive, Char>*>(operand)); 975 } 976 977 template <typename T, typename IArchive, typename OArchive, typename Char> 978 T any_cast(basic_any<IArchive, OArchive, Char>& operand) 979 { 980 typedef typename std::remove_reference<T>::type nonref; 981 982 nonref* result = any_cast<nonref>(&operand); 983 if(!result) 984 throw bad_any_cast(operand.type(), BOOST_SP_TYPEID(T)); 985 return static_cast<T>(*result); 986 } 987 988 template <typename T, typename IArchive, typename OArchive, typename Char> 989 T const& any_cast(basic_any<IArchive, OArchive, Char> const& operand) 990 { 991 typedef typename std::remove_reference<T>::type nonref; 992 993 return any_cast<nonref const&>(const_cast<basic_any<IArchive, OArchive, 994 Char> &>(operand)); 995 } 996 997 /////////////////////////////////////////////////////////////////////////////// 998 // backwards compatibility 999 typedef basic_any<serialization::input_archive, serialization::output_archive, 1000 char> any; 1001 typedef basic_any<serialization::input_archive, serialization::output_archive, 1002 wchar_t> wany; 1003 1004 typedef basic_any<void, void, char> any_nonser; 1005 typedef basic_any<void, void, wchar_t> wany_nonser; 1006 1007 /////////////////////////////////////////////////////////////////////////// 1008 namespace detail 1009 { 1010 struct hash_binary_filter : serialization::binary_filter 1011 { hash_binary_filterhpx::util::detail::hash_binary_filter1012 explicit hash_binary_filter(std::size_t seed = 0) 1013 : hash(seed) 1014 {} 1015 1016 // compression API set_max_lengthhpx::util::detail::hash_binary_filter1017 void set_max_length(std::size_t size) 1018 {} savehpx::util::detail::hash_binary_filter1019 void save(void const* src, std::size_t src_count) 1020 { 1021 char const* data = static_cast<char const*>(src); 1022 boost::hash_range(hash, data, data + src_count); 1023 } flushhpx::util::detail::hash_binary_filter1024 bool flush(void* dst, std::size_t dst_count, 1025 std::size_t& written) 1026 { 1027 written = dst_count; 1028 return true; 1029 } 1030 1031 // decompression API init_datahpx::util::detail::hash_binary_filter1032 std::size_t init_data(char const* buffer, 1033 std::size_t size, std::size_t buffer_size) 1034 { 1035 return 0; 1036 } loadhpx::util::detail::hash_binary_filter1037 void load(void* dst, std::size_t dst_count) 1038 {} 1039 serializehpx::util::detail::hash_binary_filter1040 template <class T> void serialize(T&, unsigned){} 1041 HPX_SERIALIZATION_POLYMORPHIC(hash_binary_filter); 1042 1043 std::size_t hash; 1044 }; 1045 } 1046 1047 struct hash_any 1048 { 1049 template <typename Char> operator ()hpx::util::hash_any1050 size_t operator()(const basic_any< 1051 serialization::input_archive, 1052 serialization::output_archive, 1053 Char 1054 > &elem) const 1055 { 1056 detail::hash_binary_filter hasher; 1057 1058 { 1059 std::vector<char> data; 1060 serialization::output_archive ar ( 1061 data, 0U, nullptr, &hasher); 1062 ar << elem; 1063 } // let archive go out of scope 1064 1065 return hasher.hash; 1066 } 1067 }; 1068 }} // namespace hpx::util 1069 1070 /////////////////////////////////////////////////////////////////////////////// 1071 #if BOOST_WORKAROUND(HPX_MSVC, >= 1400) 1072 # pragma warning(pop) 1073 #endif 1074 1075 #endif 1076