summaryrefslogtreecommitdiff
path: root/boost/type_erasure/register_binding.hpp
blob: 46364c977511d205803cdf2af2002bdd157e49b9 (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
// 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_REGISTER_BINDING_HPP_INCLUDED
#define BOOST_TYPE_ERASURE_REGISTER_BINDING_HPP_INCLUDED

#include <boost/type_erasure/detail/check_map.hpp>
#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/auto_link.hpp>
#include <boost/type_erasure/static_binding.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/remove_if.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/has_key.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/mpl/for_each.hpp>
#include <vector>
#include <typeinfo>

namespace boost {
namespace type_erasure {
namespace detail {

typedef std::vector<const std::type_info*> key_type;
typedef void (*value_type)();
BOOST_TYPE_ERASURE_DECL void register_function_impl(const key_type& key, value_type fn);
BOOST_TYPE_ERASURE_DECL value_type lookup_function_impl(const key_type& key);

template<class Map>
struct append_to_key_static {
    append_to_key_static(key_type* k) : key(k) {} 
    template<class P>
    void operator()(P) {
        key->push_back(&typeid(typename ::boost::mpl::at<Map, P>::type));
    }
    key_type* key;
};

// This placeholder exists solely to create a normalized
// representation of a primitive concept.  For the moment
// I'm going to be conservative and require a bijection
// between the original placeholders and the normalized
// placeholders.  It should be safe to map everything
// to a single placeholder, though, as long as the
// key includes every instance of each placeholder
// as a separate element.  i.e. we should be able to
// turn addable<_a, _b> into addable<_, _> and
// addable<_a, _a> into addable<_, _> as well if we always
// add typeids for both arguments to the search key.
template<int N>
struct _ : ::boost::type_erasure::placeholder {};

struct counting_map_appender
{
    template<class State, class Key>
    struct apply
    {
        typedef typename ::boost::mpl::insert<
            State,
            ::boost::mpl::pair<
                Key,
                ::boost::type_erasure::detail::_<
                    ::boost::mpl::size<State>::value
                >
            >
        >::type type;
    };
};

template<class Map>
struct register_function {
    template<class F>
    void operator()(F) {
        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_static<Map>(&key));
        value_type fn = reinterpret_cast<value_type>(&::boost::type_erasure::detail::rebind_placeholders<F, Map>::type::value);
        ::boost::type_erasure::detail::register_function_impl(key, fn);
    }
};

}

/**
 * Registers a model of a concept to allow downcasting @ref any
 * via @ref dynamic_any_cast.
 */
template<class Concept, class Map>
void register_binding(const static_binding<Map>&)
{
    typedef typename ::boost::type_erasure::detail::normalize_concept<
        Concept
    >::type normalized;
    typedef typename ::boost::mpl::transform<normalized,
        ::boost::type_erasure::detail::maybe_adapt_to_vtable< ::boost::mpl::_1>
    >::type actual_concept;
    typedef typename ::boost::type_erasure::detail::get_placeholder_normalization_map<
        Concept
    >::type placeholder_subs;
    typedef typename ::boost::type_erasure::detail::add_deductions<Map, placeholder_subs>::type actual_map;
    ::boost::mpl::for_each<actual_concept>(::boost::type_erasure::detail::register_function<actual_map>());
}

/**
 * \overload
 */
template<class Concept, class T>
void register_binding()
{
    // Find all placeholders
    typedef typename ::boost::type_erasure::detail::normalize_concept_impl<Concept>::type normalized;
    typedef typename normalized::first basic;
    typedef typename ::boost::mpl::fold<
        basic,
        ::boost::mpl::set0<>,
        ::boost::type_erasure::detail::get_placeholders< ::boost::mpl::_2, ::boost::mpl::_1>
    >::type all_placeholders;
    // remove deduced placeholders
    typedef typename ::boost::mpl::fold<
        typename normalized::second,
        ::boost::mpl::set0<>,
        ::boost::mpl::insert< ::boost::mpl::_1, ::boost::mpl::second< ::boost::mpl::_2> >
    >::type xtra_deduced;
    typedef typename ::boost::mpl::remove_if<
        all_placeholders,
        ::boost::mpl::or_<
            ::boost::type_erasure::detail::is_deduced< ::boost::mpl::_1>,
            ::boost::mpl::has_key<xtra_deduced, ::boost::mpl::_1>
        >,
        ::boost::mpl::back_inserter< ::boost::mpl::vector0<> >
    >::type unknown_placeholders;
    // Bind the single remaining placeholder to T
    BOOST_MPL_ASSERT((boost::mpl::equal_to<boost::mpl::size<unknown_placeholders>, boost::mpl::int_<1> >));
    register_binding<Concept>(::boost::type_erasure::make_binding<
        ::boost::mpl::map< ::boost::mpl::pair<typename ::boost::mpl::front<unknown_placeholders>::type, T> > >());
}

}
}

#endif