1 // Copyright Daniel Wallin 2009. Use, modification and distribution is
2 // subject to the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4 
5 #ifndef LUABIND_INHERITANCE_090217_HPP
6 # define LUABIND_INHERITANCE_090217_HPP
7 
8 # include <luabind/typeid.hpp>
9 
10 # include <boost/scoped_ptr.hpp>
11 
12 # include <cassert>
13 # include <limits>
14 # include <map>
15 # include <memory>
16 # include <vector>
17 
18 
19 namespace luabind { namespace detail {
20 
21 LUABIND_API extern char classid_map_tag;
22 LUABIND_API extern char class_map_tag;
23 extern char cast_graph_tag; // Not used in headers, thus no LUABIND_API.
24 
25 typedef void*(*cast_function)(void*);
26 typedef std::size_t class_id;
27 
28 class_id const unknown_class = (std::numeric_limits<class_id>::max)();
29 
30 class class_rep;
31 
32 class LUABIND_API cast_graph
33 {
34 public:
35     cast_graph();
36     ~cast_graph();
37 
38     // `src` and `p` here describe the *most derived* object. This means that
39     // for a polymorphic type, the pointer must be cast with
40     // dynamic_cast<void*> before being passed in here, and `src` has to
41     // match typeid(*p).
42     std::pair<void*, int> cast(
43         void* p, class_id src, class_id target
44       , class_id dynamic_id, void const* dynamic_ptr) const;
45     void insert(class_id src, class_id target, cast_function cast);
46 
47 private:
48     class impl;
49     boost::scoped_ptr<impl> m_impl;
50 };
51 
52 // Maps a type_id to a class_id. Note that this actually partitions the
53 // id-space into two, using one half for "local" ids; ids that are used only as
54 // keys into the conversion cache. This is needed because we need a unique key
55 // even for types that hasn't been registered explicitly.
56 class LUABIND_API class_id_map
57 {
58 public:
59     class_id_map();
60 
61     class_id get(type_id const& type) const;
62     class_id get_local(type_id const& type);
63     void put(class_id id, type_id const& type);
64 
65 private:
66     typedef std::map<type_id, class_id> map_type;
67     map_type m_classes;
68     class_id m_local_id;
69 
70     static class_id const local_id_base;
71 };
72 
class_id_map()73 inline class_id_map::class_id_map()
74   : m_local_id(local_id_base)
75 {}
76 
get(type_id const & type) const77 inline class_id class_id_map::get(type_id const& type) const
78 {
79     map_type::const_iterator i = m_classes.find(type);
80     if (i == m_classes.end() || i->second >= local_id_base)
81         return unknown_class;
82     return i->second;
83 }
84 
get_local(type_id const & type)85 inline class_id class_id_map::get_local(type_id const& type)
86 {
87     std::pair<map_type::iterator, bool> result = m_classes.insert(
88         std::make_pair(type, 0));
89 
90     if (result.second)
91         result.first->second = m_local_id++;
92 
93     assert(m_local_id >= local_id_base);
94 
95     return result.first->second;
96 }
97 
put(class_id id,type_id const & type)98 inline void class_id_map::put(class_id id, type_id const& type)
99 {
100     assert(id < local_id_base);
101 
102     std::pair<map_type::iterator, bool> result = m_classes.insert(
103         std::make_pair(type, 0));
104 
105     assert(
106         result.second
107         || result.first->second == id
108         || result.first->second >= local_id_base
109     );
110 
111     result.first->second = id;
112 }
113 
114 class class_map
115 {
116 public:
117     class_rep* get(class_id id) const;
118     void put(class_id id, class_rep* cls);
119 
120 private:
121     std::vector<class_rep*> m_classes;
122 };
123 
get(class_id id) const124 inline class_rep* class_map::get(class_id id) const
125 {
126     if (id >= m_classes.size())
127         return 0;
128     return m_classes[id];
129 }
130 
put(class_id id,class_rep * cls)131 inline void class_map::put(class_id id, class_rep* cls)
132 {
133     if (id >= m_classes.size())
134         m_classes.resize(id + 1);
135     m_classes[id] = cls;
136 }
137 
138 template <class S, class T>
139 struct static_cast_
140 {
executeluabind::detail::static_cast_141     static void* execute(void* p)
142     {
143         return static_cast<T*>(static_cast<S*>(p));
144     }
145 };
146 
147 template <class S, class T>
148 struct dynamic_cast_
149 {
executeluabind::detail::dynamic_cast_150     static void* execute(void* p)
151     {
152         return dynamic_cast<T*>(static_cast<S*>(p));
153     }
154 };
155 
156 // Thread safe class_id allocation.
157 LUABIND_API class_id allocate_class_id(type_id const& cls);
158 
159 template <class T>
160 struct registered_class
161 {
162     static class_id const id;
163 };
164 
165 template <class T>
166 class_id const registered_class<T>::id = allocate_class_id(typeid(T));
167 
168 template <class T>
169 struct registered_class<T const>
170   : registered_class<T>
171 {};
172 
173 }} // namespace luabind::detail
174 
175 #endif // LUABIND_INHERITANCE_090217_HPP
176