1 // Boost.TypeErasure library
2 //
3 // Copyright 2011 Steven Watanabe
4 //
5 // Distributed under the Boost Software License Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // $Id$
10 
11 #ifndef BOOST_TYPE_ERASURE_ANY_CAST_HPP_INCLUDED
12 #define BOOST_TYPE_ERASURE_ANY_CAST_HPP_INCLUDED
13 
14 #include <stdexcept>
15 #include <boost/throw_exception.hpp>
16 #include <boost/type_traits/add_const.hpp>
17 #include <boost/type_traits/is_pointer.hpp>
18 #include <boost/type_traits/remove_cv.hpp>
19 #include <boost/type_traits/remove_reference.hpp>
20 #include <boost/type_traits/remove_pointer.hpp>
21 #include <boost/type_traits/is_void.hpp>
22 #include <boost/mpl/assert.hpp>
23 #include <boost/mpl/bool.hpp>
24 #include <boost/type_erasure/any.hpp>
25 #include <boost/type_erasure/builtin.hpp>
26 #include <boost/type_erasure/exception.hpp>
27 #include <boost/type_erasure/detail/access.hpp>
28 
29 namespace boost {
30 namespace type_erasure {
31 
32 namespace detail {
33 
34 template<class Concept, class T>
get_pointer(::boost::type_erasure::any<Concept,T> & arg)35 void* get_pointer(::boost::type_erasure::any<Concept, T>& arg)
36 {
37     return ::boost::type_erasure::detail::access::data(arg).data;
38 }
39 
40 template<class Concept, class T>
get_pointer(const::boost::type_erasure::any<Concept,T> & arg)41 const void* get_pointer(const ::boost::type_erasure::any<Concept, T>& arg)
42 {
43     return ::boost::type_erasure::detail::access::data(arg).data;
44 }
45 
46 template<class Concept, class T>
get_pointer(::boost::type_erasure::any<Concept,T &> & arg)47 void* get_pointer(::boost::type_erasure::any<Concept, T&>& arg)
48 {
49     return ::boost::type_erasure::detail::access::data(arg).data;
50 }
51 
52 template<class Concept, class T>
get_pointer(const::boost::type_erasure::any<Concept,T &> & arg)53 void* get_pointer(const ::boost::type_erasure::any<Concept, T&>& arg)
54 {
55     return ::boost::type_erasure::detail::access::data(arg).data;
56 }
57 
58 template<class Concept, class T>
get_pointer(::boost::type_erasure::any<Concept,const T &> & arg)59 const void* get_pointer(::boost::type_erasure::any<Concept, const T&>& arg)
60 {
61     return ::boost::type_erasure::detail::access::data(arg).data;
62 }
63 
64 template<class Concept, class T>
get_pointer(const::boost::type_erasure::any<Concept,const T &> & arg)65 const void* get_pointer(const ::boost::type_erasure::any<Concept, const T&>& arg)
66 {
67     return ::boost::type_erasure::detail::access::data(arg).data;
68 }
69 
70 template<class T, class Concept, class Tag>
check_any_cast(const any<Concept,Tag> &,::boost::mpl::true_)71 bool check_any_cast(const any<Concept, Tag>&, ::boost::mpl::true_)
72 {
73     return true;
74 }
75 
76 template<class T, class Concept, class Tag>
check_any_cast(const any<Concept,Tag> & arg,::boost::mpl::false_)77 bool check_any_cast(const any<Concept, Tag>& arg, ::boost::mpl::false_)
78 {
79     typedef typename ::boost::remove_cv<
80         typename ::boost::remove_reference<Tag>::type
81     >::type tag_type;
82     return ::boost::type_erasure::detail::access::table(arg)
83         .template find<typeid_<tag_type> >()() == typeid(T);
84 }
85 
86 template<class T, class Concept, class Tag>
check_any_cast(const any<Concept,Tag> & arg)87 bool check_any_cast(const any<Concept, Tag>& arg)
88 {
89     return ::boost::type_erasure::detail::check_any_cast<T>(
90         arg, ::boost::is_void<typename ::boost::remove_reference<T>::type>());
91 }
92 
93 }
94 
95 /**
96  * Attempts to extract the object that @c arg holds.
97  * If casting to a pointer fails, \any_cast returns
98  * a null pointer.  Casting to @c void* always succeeds
99  * and returns the address of stored object.
100  *
101  * \code
102  * any<mpl::vector<typeid_<>, copy_constructible<> > > x(1);
103  * any_cast<int>(x);      // returns 1
104  * any_cast<int&>(x);     // returns a reference to the contents of x
105  * any_cast<double>(x);   // throws bad_any_cast
106  * any_cast<int*>(&x);    // returns a pointer to the contents of x
107  * any_cast<void*>(&x);   // returns a pointer to the contents of x
108  * any_cast<double*>(&x); // returns NULL
109  * \endcode
110  *
111  * \pre if @c arg is a pointer, @c T must be a pointer type.
112  * \pre @c Concept must contain @ref typeid_ "typeid_<Tag>".
113  *
114  * \throws bad_any_cast if @c arg doesn't contain
115  *         an object of type @c T and we're casting
116  *         to a value or reference.
117  */
118 template<class T, class Concept, class Tag>
119 T any_cast(any<Concept, Tag>& arg)
120 {
121     if(::boost::type_erasure::detail::check_any_cast<T>(arg)) {
122         return *static_cast<
123             typename ::boost::remove_reference<
124                 typename ::boost::add_const<T>::type
125             >::type*
126         >(::boost::type_erasure::detail::get_pointer(arg));
127     } else {
128         BOOST_THROW_EXCEPTION(::boost::type_erasure::bad_any_cast());
129     }
130 }
131 
132 /** \overload */
133 template<class T, class Concept, class Tag>
134 T any_cast(const any<Concept, Tag>& arg)
135 {
136     if(::boost::type_erasure::detail::check_any_cast<T>(arg)) {
137         return *static_cast<
138             typename ::boost::remove_reference<
139                 typename ::boost::add_const<T>::type
140             >::type*
141         >(::boost::type_erasure::detail::get_pointer(arg));
142     } else {
143         BOOST_THROW_EXCEPTION(::boost::type_erasure::bad_any_cast());
144     }
145 }
146 
147 /** \overload */
148 template<class T, class Concept, class Tag>
149 T any_cast(any<Concept, Tag>* arg)
150 {
151     BOOST_MPL_ASSERT((::boost::is_pointer<T>));
152     if(::boost::type_erasure::detail::check_any_cast<
153         typename ::boost::remove_pointer<T>::type>(*arg)) {
154         return static_cast<
155             typename ::boost::remove_pointer<T>::type*>(
156                 ::boost::type_erasure::detail::get_pointer(*arg));
157     } else {
158         return 0;
159     }
160 }
161 
162 /** \overload */
163 template<class T, class Concept, class Tag>
164 T any_cast(const any<Concept, Tag>* arg)
165 {
166     BOOST_MPL_ASSERT((::boost::is_pointer<T>));
167     if(::boost::type_erasure::detail::check_any_cast<
168         typename ::boost::remove_pointer<T>::type>(*arg)) {
169         return static_cast<
170             typename ::boost::remove_pointer<T>::type*>(
171                 ::boost::type_erasure::detail::get_pointer(*arg));
172     } else {
173         return 0;
174     }
175 }
176 
177 }
178 }
179 
180 #endif
181