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