More thorough support for unique_ptr

* has a few issues, the main problem is that the base_class conversion
   is found before the unique_ptr conversion, so converting fails
This commit is contained in:
Jason Turner 2017-02-22 12:26:50 -08:00
parent f431dbffb4
commit fc0264272f
5 changed files with 98 additions and 4 deletions

View File

@ -86,6 +86,12 @@ namespace chaiscript
// 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_type_conversion<Type>(t_conversions->saves(), bv), t_conversions)); return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_conversion<Type>(t_conversions->saves(), bv), t_conversions));
} catch (...) { } catch (...) {
try {
throw;
} catch (const std::exception &e) {
std::cout << "EXCEPTION: " << e.what() << std::endl;
}
try { try {
// try going the other way // try going the other way
return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions)); return(detail::Cast_Helper<Type>::cast((*t_conversions)->boxed_type_down_conversion<Type>(t_conversions->saves(), bv), t_conversions));

View File

@ -238,6 +238,11 @@ namespace chaiscript
return m_data->m_type_info.bare_equal(ti); return m_data->m_type_info.bare_equal(ti);
} }
void reset_pointers() const
{
m_data->m_data_ptr = nullptr;
m_data->m_const_data_ptr = nullptr;
}
template<typename T> template<typename T>
auto pointer_sentinel(std::shared_ptr<T> &ptr) const auto pointer_sentinel(std::shared_ptr<T> &ptr) const

View File

@ -367,6 +367,7 @@ namespace chaiscript
chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex); chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
/// \todo error if a conversion already exists /// \todo error if a conversion already exists
m_conversions.insert(conversion); m_conversions.insert(conversion);
std::cout << "Adding Conversion: TO: " << conversion->to().bare_type_info()->name() << " FROM: " << conversion->from().bare_type_info()->name() << std::endl;
m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()}); m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
m_num_types = m_convertableTypes.size(); m_num_types = m_convertableTypes.size();
} }
@ -410,12 +411,17 @@ namespace chaiscript
Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
{ {
try { try {
Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from); std::cout << "boxed_type_conversion" << std::endl;
auto conversion = get_conversion(to, from.get_type_info());
std::cout << "Conversion found!" << std::endl;
Boxed_Value ret = conversion->convert(from);
std::cout << "Conversion succeeded!" << std::endl;
if (t_saves.enabled) { t_saves.saves.push_back(ret); } if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret; return ret;
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {
std::cout << "Bad Cast!?" << std::endl;
throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation"); throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
} }
} }
@ -423,6 +429,7 @@ namespace chaiscript
Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
{ {
try { try {
std::cout << "boxed_type_down_conversion" << std::endl;
Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to); Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
if (t_saves.enabled) { t_saves.saves.push_back(ret); } if (t_saves.enabled) { t_saves.saves.push_back(ret); }
return ret; return ret;
@ -455,10 +462,12 @@ namespace chaiscript
{ {
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);
std::cout << "Getting conversion TO: " << to.name() << " FROM: " << from.name() << std::endl;
const auto itr = find(to, from); const auto itr = find(to, from);
if (itr != m_conversions.end()) if (itr != m_conversions.end())
{ {
std::cout << "Found" << std::endl;
return *itr; return *itr;
} else { } else {
throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name()); throw std::out_of_range("No such conversion exists from " + from.bare_name() + " to " + to.bare_name());
@ -476,7 +485,7 @@ namespace chaiscript
return std::find_if(m_conversions.begin(), m_conversions.end(), return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
{ {
return (conversion->to().bare_equal(to) && conversion->from().bare_equal(from)) return (conversion->to().type_info == to.type_info conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
|| (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from)); || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
} }
); );
@ -485,6 +494,7 @@ namespace chaiscript
std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find( std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
const Type_Info &to, const Type_Info &from) const const Type_Info &to, const Type_Info &from) const
{ {
std::cout << "Finding: TO: " << to.bare_type_info()->name() << " FROM: " << from.bare_type_info()->name() << std::endl;
return std::find_if(m_conversions.begin(), m_conversions.end(), return std::find_if(m_conversions.begin(), m_conversions.end(),
[&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
{ {
@ -588,6 +598,24 @@ namespace chaiscript
return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func); return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
} }
template<typename From, typename To>
Type_Conversion unique_ptr_conversion()
{
static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
std::cout << " unique_ptr_conversion " << std::endl;
// not even attempting to call boxed_cast so that we don't get caught in some call recursion
auto bv = chaiscript::Boxed_Value(std::unique_ptr<To>(detail::Cast_Helper<std::unique_ptr<From> &&>::cast(t_bv, nullptr)));
t_bv.reset_pointers();
return bv;
};
return chaiscript::make_shared<detail::Type_Conversion_Base,
detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::unique_ptr<From>>(),
user_type<std::unique_ptr<To>>(), func);
}
template<typename From, typename To, typename Callable> template<typename From, typename To, typename Callable>
Type_Conversion type_conversion(const Callable &t_function) Type_Conversion type_conversion(const Callable &t_function)
{ {

View File

@ -143,11 +143,11 @@ namespace chaiscript
} }
}; };
// shared_ptr
template<typename T> template<typename T>
struct Get_Type_Info<std::shared_ptr<T> > struct Get_Type_Info<std::shared_ptr<T> >
{ {
// typedef T type;
static constexpr Type_Info get() static constexpr Type_Info get()
{ {
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value, return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
@ -176,6 +176,45 @@ namespace chaiscript
} }
}; };
// unique_ptr
template<typename T>
struct Get_Type_Info<std::unique_ptr<T> >
{
static constexpr Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(std::unique_ptr<T> ),
&typeid(typename Bare_Type<T>::type));
}
};
template<typename T>
struct Get_Type_Info<std::unique_ptr<T> &> : Get_Type_Info<std::unique_ptr<T>>
{
};
template<typename T>
struct Get_Type_Info<std::unique_ptr<T> &&> : Get_Type_Info<std::unique_ptr<T>>
{
};
template<typename T>
struct Get_Type_Info<const std::unique_ptr<T> &>
{
static constexpr Type_Info get()
{
return Type_Info(std::is_const<T>::value, std::is_reference<T>::value, std::is_pointer<T>::value,
std::is_void<T>::value,
std::is_arithmetic<T>::value && !std::is_same<typename std::remove_const<typename std::remove_reference<T>::type>::type, bool>::value,
&typeid(const std::unique_ptr<T> &),
&typeid(typename Bare_Type<T>::type));
}
};
// reference_wrapper
template<typename T> template<typename T>
struct Get_Type_Info<std::reference_wrapper<T> > struct Get_Type_Info<std::reference_wrapper<T> >
{ {

View File

@ -1154,6 +1154,8 @@ std::unique_ptr<Unique_Ptr_Test_Class> make_Unique_Ptr_Test_Class()
return std::make_unique<Unique_Ptr_Test_Class>(); return std::make_unique<Unique_Ptr_Test_Class>();
} }
TEST_CASE("Call methods through unique_ptr") TEST_CASE("Call methods through unique_ptr")
{ {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
@ -1180,6 +1182,10 @@ std::unique_ptr<Unique_Ptr_Test_Derived_Class> make_Unique_Ptr_Test_Derived_Clas
return std::make_unique<Unique_Ptr_Test_Derived_Class>(); return std::make_unique<Unique_Ptr_Test_Derived_Class>();
} }
void call_unique_ptr_with_conversion_to_base(std::unique_ptr<Unique_Ptr_Test_Base_Class> &&)
{
}
TEST_CASE("Call methods on base class through unique_ptr<derived>") TEST_CASE("Call methods on base class through unique_ptr<derived>")
{ {
chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser()); chaiscript::ChaiScript_Basic chai(create_chaiscript_stdlib(),create_chaiscript_parser());
@ -1190,6 +1196,16 @@ TEST_CASE("Call methods on base class through unique_ptr<derived>")
chai.add(chaiscript::base_class<Unique_Ptr_Test_Base_Class, Unique_Ptr_Test_Derived_Class>()); chai.add(chaiscript::base_class<Unique_Ptr_Test_Base_Class, Unique_Ptr_Test_Derived_Class>());
CHECK(chai.eval<int>("uptr.getI()") == 5); CHECK(chai.eval<int>("uptr.getI()") == 5);
CHECK(chai.eval<int>("var uptr2 = make_Unique_Ptr_Test_Derived_Class(); uptr2.getI()") == 5); CHECK(chai.eval<int>("var uptr2 = make_Unique_Ptr_Test_Derived_Class(); uptr2.getI()") == 5);
chai.add(chaiscript::unique_ptr_conversion<Unique_Ptr_Test_Derived_Class, Unique_Ptr_Test_Base_Class>());
chai.add(chaiscript::fun(call_unique_ptr_with_conversion_to_base), "call_unique_ptr_with_conversion_to_base");
CHECK(!chai.eval<bool>("uptr2.is_var_null"));
std::cout << "Attempting conversion" << std::endl;
CHECK_NOTHROW(chai.eval("call_unique_ptr_with_conversion_to_base(uptr2)"));
INFO("Conversion succeeded");
CHECK(chai.eval<bool>("uptr2.is_var_null"));
} }