inheritance.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. #define LUABIND_BUILDING
  5. #include <limits>
  6. #include <map>
  7. #include <vector>
  8. #include <queue>
  9. #include <boost/dynamic_bitset.hpp>
  10. #include <boost/foreach.hpp>
  11. #include <boost/tuple/tuple.hpp>
  12. #include <boost/tuple/tuple_comparison.hpp>
  13. #include <luabind/typeid.hpp>
  14. #include <luabind/detail/inheritance.hpp>
  15. namespace luabind { namespace detail {
  16. class_id const class_id_map::local_id_base =
  17. std::numeric_limits<class_id>::max() / 2;
  18. namespace
  19. {
  20. struct edge
  21. {
  22. edge(class_id target, cast_function cast)
  23. : target(target)
  24. , cast(cast)
  25. {}
  26. class_id target;
  27. cast_function cast;
  28. };
  29. bool operator<(edge const& x, edge const& y)
  30. {
  31. return x.target < y.target;
  32. }
  33. struct vertex
  34. {
  35. vertex(class_id id)
  36. : id(id)
  37. {}
  38. class_id id;
  39. std::vector<edge> edges;
  40. };
  41. typedef std::pair<std::ptrdiff_t, int> cache_entry;
  42. class cache
  43. {
  44. public:
  45. static std::ptrdiff_t const unknown;
  46. static std::ptrdiff_t const invalid;
  47. cache_entry get(
  48. class_id src, class_id target, class_id dynamic_id
  49. , std::ptrdiff_t object_offset) const;
  50. void put(
  51. class_id src, class_id target, class_id dynamic_id
  52. , std::ptrdiff_t object_offset
  53. , std::size_t distance, std::ptrdiff_t offset);
  54. void invalidate();
  55. private:
  56. typedef boost::tuple<
  57. class_id, class_id, class_id, std::ptrdiff_t> key_type;
  58. typedef std::map<key_type, cache_entry> map_type;
  59. map_type m_cache;
  60. };
  61. std::ptrdiff_t const cache::unknown =
  62. std::numeric_limits<std::ptrdiff_t>::max();
  63. std::ptrdiff_t const cache::invalid = cache::unknown - 1;
  64. cache_entry cache::get(
  65. class_id src, class_id target, class_id dynamic_id
  66. , std::ptrdiff_t object_offset) const
  67. {
  68. map_type::const_iterator i = m_cache.find(
  69. key_type(src, target, dynamic_id, object_offset));
  70. return i != m_cache.end() ? i->second : cache_entry(unknown, -1);
  71. }
  72. void cache::put(
  73. class_id src, class_id target, class_id dynamic_id
  74. , std::ptrdiff_t object_offset, std::size_t distance, std::ptrdiff_t offset)
  75. {
  76. m_cache.insert(std::make_pair(
  77. key_type(src, target, dynamic_id, object_offset)
  78. , cache_entry(offset, distance)
  79. ));
  80. }
  81. void cache::invalidate()
  82. {
  83. m_cache.clear();
  84. }
  85. } // namespace unnamed
  86. class cast_graph::impl
  87. {
  88. public:
  89. std::pair<void*, int> cast(
  90. void* p, class_id src, class_id target
  91. , class_id dynamic_id, void const* dynamic_ptr) const;
  92. void insert(class_id src, class_id target, cast_function cast);
  93. private:
  94. std::vector<vertex> m_vertices;
  95. mutable cache m_cache;
  96. };
  97. namespace
  98. {
  99. struct queue_entry
  100. {
  101. queue_entry(void* p, class_id vertex_id, int distance)
  102. : p(p)
  103. , vertex_id(vertex_id)
  104. , distance(distance)
  105. {}
  106. void* p;
  107. class_id vertex_id;
  108. int distance;
  109. };
  110. } // namespace unnamed
  111. std::pair<void*, int> cast_graph::impl::cast(
  112. void* const p, class_id src, class_id target
  113. , class_id dynamic_id, void const* dynamic_ptr) const
  114. {
  115. if (src == target)
  116. return std::make_pair(p, 0);
  117. if (src >= m_vertices.size() || target >= m_vertices.size())
  118. return std::pair<void*, int>((void*)0, -1);
  119. std::ptrdiff_t const object_offset =
  120. (char const*)dynamic_ptr - (char const*)p;
  121. cache_entry cached = m_cache.get(src, target, dynamic_id, object_offset);
  122. if (cached.first != cache::unknown)
  123. {
  124. if (cached.first == cache::invalid)
  125. return std::pair<void*, int>((void*)0, -1);
  126. return std::make_pair((char*)p + cached.first, cached.second);
  127. }
  128. std::queue<queue_entry> q;
  129. q.push(queue_entry(p, src, 0));
  130. boost::dynamic_bitset<> visited(m_vertices.size());
  131. while (!q.empty())
  132. {
  133. queue_entry const qe = q.front();
  134. q.pop();
  135. visited[qe.vertex_id] = true;
  136. vertex const& v = m_vertices[qe.vertex_id];
  137. if (v.id == target)
  138. {
  139. m_cache.put(
  140. src, target, dynamic_id, object_offset
  141. , qe.distance, (char*)qe.p - (char*)p
  142. );
  143. return std::make_pair(qe.p, qe.distance);
  144. }
  145. BOOST_FOREACH(edge const& e, v.edges)
  146. {
  147. if (visited[e.target])
  148. continue;
  149. if (void* casted = e.cast(qe.p))
  150. q.push(queue_entry(casted, e.target, qe.distance + 1));
  151. }
  152. }
  153. m_cache.put(src, target, dynamic_id, object_offset, cache::invalid, -1);
  154. return std::pair<void*, int>((void*)0, -1);
  155. }
  156. void cast_graph::impl::insert(
  157. class_id src, class_id target, cast_function cast)
  158. {
  159. class_id const max_id = std::max(src, target);
  160. if (max_id >= m_vertices.size())
  161. {
  162. m_vertices.reserve(max_id + 1);
  163. for (class_id i = m_vertices.size(); i < max_id + 1; ++i)
  164. m_vertices.push_back(vertex(i));
  165. }
  166. std::vector<edge>& edges = m_vertices[src].edges;
  167. std::vector<edge>::iterator i = std::lower_bound(
  168. edges.begin(), edges.end(), edge(target, 0)
  169. );
  170. if (i == edges.end() || i->target != target)
  171. {
  172. edges.insert(i, edge(target, cast));
  173. m_cache.invalidate();
  174. }
  175. }
  176. std::pair<void*, int> cast_graph::cast(
  177. void* p, class_id src, class_id target
  178. , class_id dynamic_id, void const* dynamic_ptr) const
  179. {
  180. return m_impl->cast(p, src, target, dynamic_id, dynamic_ptr);
  181. }
  182. void cast_graph::insert(class_id src, class_id target, cast_function cast)
  183. {
  184. m_impl->insert(src, target, cast);
  185. }
  186. cast_graph::cast_graph()
  187. : m_impl(new impl)
  188. {}
  189. cast_graph::~cast_graph()
  190. {}
  191. LUABIND_API class_id allocate_class_id(type_id const& cls)
  192. {
  193. typedef std::map<type_id, class_id> map_type;
  194. static map_type registered;
  195. static class_id id = 0;
  196. std::pair<map_type::iterator, bool> inserted = registered.insert(
  197. std::make_pair(cls, id));
  198. if (inserted.second)
  199. ++id;
  200. return inserted.first->second;
  201. }
  202. }} // namespace luabind::detail