summaryrefslogtreecommitdiff
path: root/boost/type_erasure/dynamic_any_cast.hpp
blob: 01aa2b6ef982fe778f66aa81a970c0267d44b367 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
// Boost.TypeErasure library
//
// Copyright 2015 Steven Watanabe
//
// Distributed under the Boost Software License Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// $Id$

#ifndef BOOST_TYPE_ERASURE_DYNAMIC_ANY_CAST_HPP_INCLUDED
#define BOOST_TYPE_ERASURE_DYNAMIC_ANY_CAST_HPP_INCLUDED

#include <boost/type_erasure/detail/normalize.hpp>
#include <boost/type_erasure/binding_of.hpp>
#include <boost/type_erasure/static_binding.hpp>
#include <boost/type_erasure/dynamic_binding.hpp>
#include <boost/type_erasure/concept_of.hpp>
#include <boost/type_erasure/placeholder_of.hpp>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/binding.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/type_traits/add_const.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/remove_reference.hpp>

namespace boost {
namespace type_erasure {

namespace detail {

template<class P, class P2, class Any>
struct make_ref_placeholder;

template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2, const Any&> { typedef const P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2, Any&> { typedef P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2&, const Any&> { typedef P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2&, Any&> { typedef P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, const P2&, const Any&> { typedef const P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, const P2&, Any&> { typedef const P& type; };

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template<class P, class P2, class Any>
struct make_ref_placeholder { typedef P&& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2&, Any> { typedef P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, const P2&, Any> { typedef const P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2&&, Any> { typedef P&& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2&&, const Any&> { typedef const P& type; };
template<class P, class P2, class Any>
struct make_ref_placeholder<P, P2&&, Any&> { typedef P& type; };
#endif

template<class R, class Tag>
struct make_result_placeholder_map
{
    typedef ::boost::mpl::map<
        ::boost::mpl::pair<
            typename ::boost::remove_const<
                typename ::boost::remove_reference<
                    typename ::boost::type_erasure::placeholder_of<R>::type
                >::type
            >::type,
            typename ::boost::remove_const<
                typename ::boost::remove_reference<
                    Tag
                >::type
            >::type
        >
    > type;
};

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template<class R, class Any, class Map>
R dynamic_any_cast_impl(Any&& arg, const static_binding<Map>& map)
#else
template<class R, class Any, class Map>
R dynamic_any_cast_impl(Any& arg, const static_binding<Map>& map)
#endif
{
    typedef typename ::boost::remove_const<typename ::boost::remove_reference<Any>::type>::type src_type;
    typedef typename ::boost::type_erasure::detail::normalize_concept<
        typename ::boost::type_erasure::concept_of<src_type>::type
    >::type normalized;
    typedef typename ::boost::mpl::fold<
        normalized,
        ::boost::mpl::set0<>,
        ::boost::type_erasure::detail::get_placeholders<
            ::boost::mpl::_2,
            ::boost::mpl::_1
        >
    >::type placeholders;
    typedef ::boost::type_erasure::detail::substitution_map< ::boost::mpl::map0<> > identity_map;
    ::boost::type_erasure::dynamic_binding<placeholders> my_binding(
        ::boost::type_erasure::binding_of(arg),
        ::boost::type_erasure::make_binding<identity_map>());
    typedef typename ::boost::remove_const<
        typename ::boost::remove_reference<
            typename ::boost::type_erasure::placeholder_of<R>::type
        >::type
    >::type result_placeholder;
    ::boost::type_erasure::binding< typename ::boost::type_erasure::concept_of<R>::type> new_binding(
        my_binding,
        map);
    typedef ::boost::type_erasure::any<
        typename ::boost::type_erasure::concept_of<R>::type,
        typename ::boost::type_erasure::detail::make_ref_placeholder<
            result_placeholder,
            typename ::boost::type_erasure::placeholder_of<src_type>::type,
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
            Any
#else
            Any&
#endif
        >::type
    > result_ref_type;
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
    return result_ref_type(std::forward<Any>(arg), new_binding);
#else
    return result_ref_type(arg, new_binding);
#endif
}

}

#ifdef BOOST_TYPE_ERASURE_DOXYGEN

/**
 * Downcasts or crosscasts an @ref any.
 *
 * \pre @c R and @c Any must both be specializations of @ref any.
 * \pre PlaceholderMap must be an MPL map with a key
 *      for every non-deduced placeholder used by R.
 *      The value associated with each key should
 *      be the corresponding placeholder in Any.
 * \pre The concept of Any must include @ref typeid_, for every
 *      @ref placeholder which is used by R.
 * 
 * The single argument form can only be used when @c R uses
 * a single non-deduced placeholder.
 *
 * \throws bad_any_cast if the concepts used by R were
 *         not previously registered via a call to
 *         @ref register_binding.
 *
 * Example:
 * \code
 * // Assume that typeid_<>, copy_constructible<>, and incrementable<>
 * // have all been registered for int.
 * any<mpl::vector<typeid_<>, copy_constructible<> > > x(1);
 * typedef any<
 *     mpl::vector<
 *         typeid_<>,
 *         copy_constructible<>,
 *         incrementable<>
 *     >
 * > incrementable_any;
 * auto y = dynamic_any_cast<incrementable_any>(x);
 * ++y;
 * assert(any_cast<int>(y) == 2);
 * \endcode
 */
template<class R, class Any>
R dynamic_any_cast(Any&& arg);

/**
 * \overload
 */
template<class R, class Any, class Map>
R dynamic_any_cast(Any&& arg, const static_binding<Map>&);

#else

template<class R, class Concept, class Tag>
R dynamic_any_cast(const any<Concept, Tag>& arg)
{
    return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg,
        ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>());
}

template<class R, class Concept, class Tag>
R dynamic_any_cast(any<Concept, Tag>& arg)
{
    return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg,
        ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>());
}

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template<class R, class Concept, class Tag>
R dynamic_any_cast(any<Concept, Tag>&& arg)
{
    return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(::std::move(arg),
        ::boost::type_erasure::make_binding<typename ::boost::type_erasure::detail::make_result_placeholder_map<R, Tag>::type>());
}
#endif

template<class R, class Concept, class Tag, class Map>
R dynamic_any_cast(const any<Concept, Tag>& arg, const static_binding<Map>& map)
{
    return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, map);
}

template<class R, class Concept, class Tag, class Map>
R dynamic_any_cast(any<Concept, Tag>& arg, const static_binding<Map>& map)
{
    return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(arg, map);
}

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template<class R, class Concept, class Tag, class Map>
R dynamic_any_cast(any<Concept, Tag>&& arg, const static_binding<Map>& map)
{
    return ::boost::type_erasure::detail::dynamic_any_cast_impl<R>(::std::move(arg), map);
}
#endif

#endif

}
}

#endif