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)
5 #define LUABIND_BUILDING
11 #include <boost/dynamic_bitset.hpp>
12 #include <boost/foreach.hpp>
13 #include <boost/tuple/tuple.hpp>
14 #include <boost/tuple/tuple_comparison.hpp>
15 #include <luabind/typeid.hpp>
16 #include <luabind/detail/inheritance.hpp>
18 namespace luabind
{ namespace detail
{
20 class_id
const class_id_map::local_id_base
=
21 std::numeric_limits
<class_id
>::max() / 2;
28 edge(class_id target
, cast_function cast
)
37 bool operator<(edge
const& x
, edge
const& y
)
39 return x
.target
< y
.target
;
49 std::vector
<edge
> edges
;
52 typedef std::pair
<std::ptrdiff_t, std::size_t> cache_entry
;
57 static std::ptrdiff_t const unknown
;
58 static std::ptrdiff_t const invalid
;
61 class_id src
, class_id target
, class_id dynamic_id
62 , std::ptrdiff_t object_offset
) const;
65 class_id src
, class_id target
, class_id dynamic_id
66 , std::ptrdiff_t object_offset
67 , std::size_t distance
, std::ptrdiff_t offset
);
73 class_id
, class_id
, class_id
, std::ptrdiff_t> key_type
;
74 typedef std::map
<key_type
, cache_entry
> map_type
;
78 std::ptrdiff_t const cache::unknown
=
79 std::numeric_limits
<std::ptrdiff_t>::max();
80 std::ptrdiff_t const cache::invalid
= cache::unknown
- 1;
82 cache_entry
cache::get(
83 class_id src
, class_id target
, class_id dynamic_id
84 , std::ptrdiff_t object_offset
) const
86 map_type::const_iterator i
= m_cache
.find(
87 key_type(src
, target
, dynamic_id
, object_offset
));
88 return i
!= m_cache
.end() ? i
->second
: cache_entry(unknown
, -1);
92 class_id src
, class_id target
, class_id dynamic_id
93 , std::ptrdiff_t object_offset
, std::size_t distance
, std::ptrdiff_t offset
)
95 m_cache
.insert(std::make_pair(
96 key_type(src
, target
, dynamic_id
, offset
)
97 , cache_entry(offset
, distance
)
101 void cache::invalidate()
106 } // namespace unnamed
108 class cast_graph::impl
111 std::pair
<void*, std::size_t> cast(
112 void* p
, class_id src
, class_id target
113 , class_id dynamic_id
, void const* dynamic_ptr
) const;
114 void insert(class_id src
, class_id target
, cast_function cast
);
117 std::vector
<vertex
> m_vertices
;
118 mutable cache m_cache
;
126 queue_entry(void* p
, class_id vertex_id
, std::size_t distance
)
128 , vertex_id(vertex_id
)
134 std::size_t distance
;
137 } // namespace unnamed
139 std::pair
<void*, std::size_t> cast_graph::impl::cast(
140 void* const p
, class_id src
, class_id target
141 , class_id dynamic_id
, void const* dynamic_ptr
) const
144 return std::make_pair(p
, 0);
146 if (src
>= m_vertices
.size() || target
>= m_vertices
.size())
147 return std::pair
<void*, std::size_t>(0, -1);
149 std::ptrdiff_t const object_offset
=
150 (char const*)dynamic_ptr
- (char const*)p
;
152 cache_entry cached
= m_cache
.get(src
, target
, dynamic_id
, object_offset
);
154 if (cached
.first
!= cache::unknown
)
156 if (cached
.first
== cache::invalid
)
157 return std::pair
<void*, std::size_t>(0, -1);
158 return std::make_pair((char*)p
+ cached
.first
, cached
.second
);
161 std::queue
<queue_entry
> q
;
162 q
.push(queue_entry(p
, src
, 0));
164 boost::dynamic_bitset
<> visited(m_vertices
.size());
168 queue_entry
const qe
= q
.front();
171 visited
[qe
.vertex_id
] = true;
172 vertex
const& v
= m_vertices
[qe
.vertex_id
];
177 src
, target
, dynamic_id
, object_offset
178 , qe
.distance
, (char*)qe
.p
- (char*)p
181 return std::make_pair(qe
.p
, qe
.distance
);
184 BOOST_FOREACH(edge
const& e
, v
.edges
)
186 if (visited
[e
.target
])
188 if (void* casted
= e
.cast(qe
.p
))
189 q
.push(queue_entry(casted
, e
.target
, qe
.distance
+ 1));
193 m_cache
.put(src
, target
, dynamic_id
, object_offset
, cache::invalid
, -1);
195 return std::pair
<void*, std::size_t>(0, -1);
198 void cast_graph::impl::insert(
199 class_id src
, class_id target
, cast_function cast
)
201 class_id
const max_id
= std::max(src
, target
);
203 if (max_id
>= m_vertices
.size())
205 m_vertices
.reserve(max_id
+ 1);
206 for (class_id i
= m_vertices
.size(); i
< max_id
+ 1; ++i
)
207 m_vertices
.push_back(vertex(i
));
210 std::vector
<edge
>& edges
= m_vertices
[src
].edges
;
212 std::vector
<edge
>::iterator i
= std::lower_bound(
213 edges
.begin(), edges
.end(), edge(target
, 0)
216 if (i
== edges
.end() || i
->target
!= target
)
218 edges
.insert(i
, edge(target
, cast
));
219 m_cache
.invalidate();
223 std::pair
<void*, std::size_t> cast_graph::cast(
224 void* p
, class_id src
, class_id target
225 , class_id dynamic_id
, void const* dynamic_ptr
) const
227 return m_impl
->cast(p
, src
, target
, dynamic_id
, dynamic_ptr
);
230 void cast_graph::insert(class_id src
, class_id target
, cast_function cast
)
232 m_impl
->insert(src
, target
, cast
);
235 cast_graph::cast_graph()
239 cast_graph::~cast_graph()
242 LUABIND_API class_id
allocate_class_id()
244 static class_id id
= 0;
248 }} // namespace luabind::detail