summaryrefslogtreecommitdiff
path: root/boost/type_erasure/detail/dynamic_vtable.hpp
blob: 9e014ed61b18cf8608587c0cf2d9a4f195fe543e (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
// 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_DETAIL_DYNAMIC_VTABLE_HPP_INCLUDED
#define BOOST_TYPE_ERASURE_DETAIL_DYNAMIC_VTABLE_HPP_INCLUDED

#include <boost/type_erasure/detail/get_placeholders.hpp>
#include <boost/type_erasure/detail/rebind_placeholders.hpp>
#include <boost/type_erasure/detail/normalize.hpp>
#include <boost/type_erasure/detail/adapt_to_vtable.hpp>
#include <boost/type_erasure/detail/vtable.hpp>
#include <boost/type_erasure/static_binding.hpp>
#include <boost/type_erasure/register_binding.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/index_of.hpp>
#include <typeinfo>

namespace boost {
namespace type_erasure {
namespace detail {

#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS)

template<class P>
struct dynamic_binding_impl
{
    const std::type_info * type;
};

template<class Table>
struct append_to_key {
    template<class P>
    void operator()(P) {
        key->push_back(static_cast<const dynamic_binding_impl<P>*>(table)->type);
    }
    const Table * table;
    key_type * key;
};

template<class... P>
struct dynamic_vtable : dynamic_binding_impl<P>... {
    dynamic_vtable() = default;
    template<class... T>
    constexpr dynamic_vtable(T* ...t) : dynamic_binding_impl<P>{t}... {}
    template<class F>
    typename F::type lookup(F*) const {
        key_type key;
        typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mpl::set0<> >::type placeholders;
        typedef typename ::boost::mpl::fold<
            placeholders,
            ::boost::mpl::map0<>,
            ::boost::type_erasure::detail::counting_map_appender
        >::type placeholder_map;
        key.push_back(&typeid(typename ::boost::type_erasure::detail::rebind_placeholders<F, placeholder_map>::type));
        ::boost::mpl::for_each<placeholders>(append_to_key<dynamic_vtable>{this, &key});
        return reinterpret_cast<typename F::type>(lookup_function_impl(key));
    }
    template<class Bindings>
    void init() {
        *this = dynamic_vtable(&typeid(typename boost::mpl::at<Bindings, P>::type)...);
    }
    template<class Bindings, class Src>
    void convert_from(const Src& src) {
        *this = dynamic_vtable(
            (&src.lookup((::boost::type_erasure::typeid_<typename ::boost::mpl::at<Bindings, P>::type>*)0)())...);
    }
};

template<class L>
struct make_dynamic_vtable_impl;

template<class... P>
struct make_dynamic_vtable_impl<stored_arg_pack<P...> >
{
    typedef dynamic_vtable<P...> type;
};

template<class PlaceholderList>
struct make_dynamic_vtable
    : make_dynamic_vtable_impl<typename make_arg_pack<PlaceholderList>::type>
{};

#else

template<class Bindings>
struct dynamic_vtable_initializer
{
    dynamic_vtable_initializer(const std::type_info**& ptr) : types(&ptr) {}
    template<class P>
    void operator()(P)
    {
        *(*types)++ = &typeid(typename ::boost::mpl::at<Bindings, P>::type);
    }
    const ::std::type_info*** types;
};

template<class Placeholders>
struct dynamic_vtable
{
    const ::std::type_info * types[(::boost::mpl::size<Placeholders>::value)];
    struct append_to_key
    {
        append_to_key(const std::type_info * const * t, key_type* k) : types(t), key(k) {}
        template<class P>
        void operator()(P)
        {
            key->push_back(types[(::boost::mpl::index_of<Placeholders, P>::type::value)]);
        }
        const std::type_info * const * types;
        key_type * key;
    };
    template<class F>
    typename F::type lookup(F*) const {
        key_type key;
        typedef typename ::boost::type_erasure::detail::get_placeholders<F, ::boost::mpl::set0<> >::type placeholders;
        typedef typename ::boost::mpl::fold<
            placeholders,
            ::boost::mpl::map0<>,
            ::boost::type_erasure::detail::counting_map_appender
        >::type placeholder_map;
        key.push_back(&typeid(typename ::boost::type_erasure::detail::rebind_placeholders<F, placeholder_map>::type));
        ::boost::mpl::for_each<placeholders>(append_to_key(types, &key));
        return reinterpret_cast<typename F::type>(lookup_function_impl(key));
    }
    template<class Bindings>
    void init()
    {
        const std::type_info* ptr = types;
        ::boost::mpl::for_each<Placeholders>(dynamic_vtable_initializer<Bindings>(ptr));
    }
    template<class Bindings, class Src>
    struct converter
    {
        converter(const std::type_info**& t, const Src& s) : types(&t), src(&s) {}
        template<class P>
        void operator()(P)
        {
            *(*types)++ = &src->lookup((::boost::type_erasure::typeid_<typename ::boost::mpl::at<Bindings, P>::type>*)0)();
        }
        const std::type_info*** types;
        const Src * src;
    };
    template<class Bindings, class Src>
    void convert_from(const Src& src) {
        const ::std::type_info** ptr = types;
        ::boost::mpl::for_each<Placeholders>(converter<Bindings, Src>(ptr, src));
    }
};

template<class Placeholders>
struct make_dynamic_vtable
{
    typedef dynamic_vtable<Placeholders> type;
};

#endif

}
}
}

#endif