First cast up chain, if that fails, cast down
This commit is contained in:
@@ -84,11 +84,18 @@ namespace chaiscript
|
|||||||
if (boost::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions)
|
if (boost::is_polymorphic<typename detail::Stripped_Type<Type>::type>::value && t_conversions)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
std::cout << "trying an up conversion " << typeid(Type).name() << std::endl;
|
||||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||||
// either way, we are not responsible if it doesn't work
|
// either way, we are not responsible if it doesn't work
|
||||||
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
|
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_cast<Type>(bv), t_conversions);
|
||||||
} catch (const boost::bad_any_cast &) {
|
} catch (...) {
|
||||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
try {
|
||||||
|
std::cout << "trying a down conversion " << typeid(Type).name() << std::endl;
|
||||||
|
// try going the other way - down the inheritance graph
|
||||||
|
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_dynamic_down_cast<Type>(bv), t_conversions);
|
||||||
|
} catch (const boost::bad_any_cast &) {
|
||||||
|
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If it's not polymorphic, just throw the error, don't waste the time on the
|
// If it's not polymorphic, just throw the error, don't waste the time on the
|
||||||
|
@@ -48,6 +48,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
|
virtual Boxed_Value convert(const Boxed_Value &derived) const = 0;
|
||||||
|
virtual Boxed_Value convert_down(const Boxed_Value &base) const = 0;
|
||||||
|
|
||||||
const Type_Info &base()
|
const Type_Info &base()
|
||||||
{
|
{
|
||||||
@@ -72,6 +73,57 @@ namespace chaiscript
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename From, typename To>
|
||||||
|
class Dynamic_Caster
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Boxed_Value cast(const Boxed_Value &t_from)
|
||||||
|
{
|
||||||
|
if (t_from.get_type_info().bare_equal(user_type<From>()))
|
||||||
|
{
|
||||||
|
if (t_from.is_pointer())
|
||||||
|
{
|
||||||
|
// Dynamic cast out the contained boxed value, which we know is the type we want
|
||||||
|
if (t_from.is_const())
|
||||||
|
{
|
||||||
|
boost::shared_ptr<const To> data
|
||||||
|
= boost::dynamic_pointer_cast<const To>(detail::Cast_Helper<boost::shared_ptr<const From> >::cast(t_from, 0));
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
throw std::bad_cast();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boxed_Value(data);
|
||||||
|
} else {
|
||||||
|
boost::shared_ptr<To> data
|
||||||
|
= boost::dynamic_pointer_cast<To>(detail::Cast_Helper<boost::shared_ptr<From> >::cast(t_from, 0));
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
{
|
||||||
|
throw std::bad_cast();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boxed_Value(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pull the reference out of the contained boxed value, which we know is the type we want
|
||||||
|
if (t_from.is_const())
|
||||||
|
{
|
||||||
|
const From &d = detail::Cast_Helper<const From &>::cast(t_from, 0);
|
||||||
|
const To &data = dynamic_cast<const To &>(d);
|
||||||
|
return Boxed_Value(boost::cref(data));
|
||||||
|
} else {
|
||||||
|
From &d = detail::Cast_Helper<From &>::cast(t_from, 0);
|
||||||
|
To &data = dynamic_cast<To &>(d);
|
||||||
|
return Boxed_Value(boost::ref(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Base, typename Derived>
|
template<typename Base, typename Derived>
|
||||||
class Dynamic_Conversion_Impl : public Dynamic_Conversion
|
class Dynamic_Conversion_Impl : public Dynamic_Conversion
|
||||||
{
|
{
|
||||||
@@ -81,50 +133,14 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Boxed_Value convert_down(const Boxed_Value &t_base) const
|
||||||
|
{
|
||||||
|
return Dynamic_Caster<Base, Derived>::cast(t_base);
|
||||||
|
}
|
||||||
|
|
||||||
virtual Boxed_Value convert(const Boxed_Value &t_derived) const
|
virtual Boxed_Value convert(const Boxed_Value &t_derived) const
|
||||||
{
|
{
|
||||||
if (t_derived.get_type_info().bare_equal(user_type<Derived>()))
|
return Dynamic_Caster<Derived, Base>::cast(t_derived);
|
||||||
{
|
|
||||||
if (t_derived.is_pointer())
|
|
||||||
{
|
|
||||||
// Dynamic cast out the contained boxed value, which we know is the type we want
|
|
||||||
if (t_derived.is_const())
|
|
||||||
{
|
|
||||||
boost::shared_ptr<const Base> data
|
|
||||||
= boost::dynamic_pointer_cast<const Base>(detail::Cast_Helper<boost::shared_ptr<const Derived> >::cast(t_derived, 0));
|
|
||||||
if (!data)
|
|
||||||
{
|
|
||||||
throw std::bad_cast();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Boxed_Value(data);
|
|
||||||
} else {
|
|
||||||
boost::shared_ptr<Base> data
|
|
||||||
= boost::dynamic_pointer_cast<Base>(detail::Cast_Helper<boost::shared_ptr<Derived> >::cast(t_derived, 0));
|
|
||||||
|
|
||||||
if (!data)
|
|
||||||
{
|
|
||||||
throw std::bad_cast();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Boxed_Value(data);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Pull the reference out of the contained boxed value, which we know is the type we want
|
|
||||||
if (t_derived.is_const())
|
|
||||||
{
|
|
||||||
const Derived &d = detail::Cast_Helper<const Derived &>::cast(t_derived, 0);
|
|
||||||
const Base &data = dynamic_cast<const Base &>(d);
|
|
||||||
return Boxed_Value(boost::cref(data));
|
|
||||||
} else {
|
|
||||||
Derived &d = detail::Cast_Helper<Derived &>::cast(t_derived, 0);
|
|
||||||
Base &data = dynamic_cast<Base &>(d);
|
|
||||||
return Boxed_Value(boost::ref(data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw exception::bad_boxed_dynamic_cast(t_derived.get_type_info(), typeid(Base), "Unknown dynamic_cast_conversion");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -155,7 +171,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
|
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) const
|
||||||
{
|
{
|
||||||
return has_conversion(base, derived);
|
return has_conversion(base, derived) || has_conversion(derived, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Base>
|
template<typename Base>
|
||||||
@@ -170,6 +186,19 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
Boxed_Value boxed_dynamic_down_cast(const Boxed_Value &base) const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return get_conversion(base.get_type_info(), user_type<Derived>())->convert_down(base);
|
||||||
|
} catch (const std::out_of_range &) {
|
||||||
|
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "No known conversion");
|
||||||
|
} catch (const std::bad_cast &) {
|
||||||
|
throw exception::bad_boxed_dynamic_cast(base.get_type_info(), typeid(Derived), "Unable to perform dynamic_cast operation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
|
bool has_conversion(const Type_Info &base, const Type_Info &derived) const
|
||||||
{
|
{
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
@@ -19,8 +19,9 @@ assert_equal(23, t.val)
|
|||||||
// in a shared_ptr<TestBaseType>. This is testing our ability
|
// in a shared_ptr<TestBaseType>. This is testing our ability
|
||||||
// to detect that and do the down casting for the user automatically
|
// to detect that and do the down casting for the user automatically
|
||||||
// at runtime
|
// at runtime
|
||||||
var d := derived_type_factory();
|
|
||||||
|
|
||||||
assert_equal(t.derived_only_func(), 19);
|
assert_equal(t.derived_only_func(), 19);
|
||||||
|
|
||||||
|
var d := derived_type_factory();
|
||||||
assert_equal(d.derived_only_func(), 19);
|
assert_equal(d.derived_only_func(), 19);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user