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