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)
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>
16 namespace luabind
{ namespace detail
{
18 class_id
const class_id_map::local_id_base
=
19 std::numeric_limits
<class_id
>::max() / 2;
26 edge(class_id target
, cast_function cast
)
35 bool operator<(edge
const& x
, edge
const& y
)
37 return x
.target
< y
.target
;
47 std::vector
<edge
> edges
;
50 typedef std::pair
<std::ptrdiff_t, std::size_t> cache_entry
;
55 static std::ptrdiff_t const unknown
;
56 static std::ptrdiff_t const invalid
;
59 class_id src
, class_id target
, class_id dynamic_id
60 , std::ptrdiff_t object_offset
) const;
63 class_id src
, class_id target
, class_id dynamic_id
64 , std::ptrdiff_t object_offset
65 , std::size_t distance
, std::ptrdiff_t offset
);
71 class_id
, class_id
, class_id
, std::ptrdiff_t> key_type
;
72 typedef std::map
<key_type
, cache_entry
> map_type
;
76 std::ptrdiff_t const cache::unknown
=
77 std::numeric_limits
<std::ptrdiff_t>::max();
78 std::ptrdiff_t const cache::invalid
= cache::unknown
- 1;
80 cache_entry
cache::get(
81 class_id src
, class_id target
, class_id dynamic_id
82 , std::ptrdiff_t object_offset
) const
84 map_type::const_iterator i
= m_cache
.find(
85 key_type(src
, target
, dynamic_id
, object_offset
));
86 return i
!= m_cache
.end() ? i
->second
: cache_entry(unknown
, -1);
90 class_id src
, class_id target
, class_id dynamic_id
91 , std::ptrdiff_t object_offset
, std::size_t distance
, std::ptrdiff_t offset
)
93 m_cache
.insert(std::make_pair(
94 key_type(src
, target
, dynamic_id
, offset
)
95 , cache_entry(offset
, distance
)
99 void cache::invalidate()
104 } // namespace unnamed
106 class cast_graph::impl
109 std::pair
<void*, std::size_t> cast(
110 void* p
, class_id src
, class_id target
111 , class_id dynamic_id
, void const* dynamic_ptr
) const;
112 void insert(class_id src
, class_id target
, cast_function cast
);
115 std::vector
<vertex
> m_vertices
;
116 mutable cache m_cache
;
124 queue_entry(void* p
, class_id vertex_id
, std::size_t distance
)
126 , vertex_id(vertex_id
)
132 std::size_t distance
;
135 } // namespace unnamed
137 std::pair
<void*, std::size_t> cast_graph::impl::cast(
138 void* const p
, class_id src
, class_id target
139 , class_id dynamic_id
, void const* dynamic_ptr
) const
142 return std::make_pair(p
, 0);
144 if (src
>= m_vertices
.size() || target
>= m_vertices
.size())
145 return std::pair
<void*, std::size_t>(0, -1);
147 std::ptrdiff_t const object_offset
=
148 (char const*)dynamic_ptr
- (char const*)p
;
150 cache_entry cached
= m_cache
.get(src
, target
, dynamic_id
, object_offset
);
152 if (cached
.first
!= cache::unknown
)
154 if (cached
.first
== cache::invalid
)
155 return std::pair
<void*, std::size_t>(0, -1);
156 return std::make_pair((char*)p
+ cached
.first
, cached
.second
);
159 std::queue
<queue_entry
> q
;
160 q
.push(queue_entry(p
, src
, 0));
162 boost::dynamic_bitset
<> visited(m_vertices
.size());
166 queue_entry
const qe
= q
.front();
169 visited
[qe
.vertex_id
] = true;
170 vertex
const& v
= m_vertices
[qe
.vertex_id
];
175 src
, target
, dynamic_id
, object_offset
176 , qe
.distance
, (char*)qe
.p
- (char*)p
179 return std::make_pair(qe
.p
, qe
.distance
);
182 BOOST_FOREACH(edge
const& e
, v
.edges
)
184 if (visited
[e
.target
])
186 if (void* casted
= e
.cast(qe
.p
))
187 q
.push(queue_entry(casted
, e
.target
, qe
.distance
+ 1));
191 m_cache
.put(src
, target
, dynamic_id
, object_offset
, cache::invalid
, -1);
193 return std::pair
<void*, std::size_t>(0, -1);
196 void cast_graph::impl::insert(
197 class_id src
, class_id target
, cast_function cast
)
199 class_id
const max_id
= std::max(src
, target
);
201 if (max_id
>= m_vertices
.size())
203 m_vertices
.reserve(max_id
+ 1);
204 for (class_id i
= m_vertices
.size(); i
< max_id
+ 1; ++i
)
205 m_vertices
.push_back(vertex(i
));
208 std::vector
<edge
>& edges
= m_vertices
[src
].edges
;
210 std::vector
<edge
>::iterator i
= std::lower_bound(
211 edges
.begin(), edges
.end(), edge(target
, 0)
214 if (i
== edges
.end() || i
->target
!= target
)
216 edges
.insert(i
, edge(target
, cast
));
217 m_cache
.invalidate();
221 std::pair
<void*, std::size_t> cast_graph::cast(
222 void* p
, class_id src
, class_id target
223 , class_id dynamic_id
, void const* dynamic_ptr
) const
225 return m_impl
->cast(p
, src
, target
, dynamic_id
, dynamic_ptr
);
228 void cast_graph::insert(class_id src
, class_id target
, cast_function cast
)
230 m_impl
->insert(src
, target
, cast
);
233 cast_graph::cast_graph()
237 cast_graph::~cast_graph()
240 LUABIND_API class_id
allocate_class_id()
242 static class_id id
= 0;
246 }} // namespace luabind::detail