Thread safety for dynamic conversions / registration of new inheritance relationship

This commit is contained in:
Jason Turner 2010-08-02 17:01:38 +00:00
parent 8be4aa08db
commit cd015a8437

View File

@ -7,6 +7,7 @@
#include "bad_boxed_cast.hpp" #include "bad_boxed_cast.hpp"
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
#include <boost/type_traits/is_polymorphic.hpp> #include <boost/type_traits/is_polymorphic.hpp>
#include <boost/thread/shared_mutex.hpp>
namespace chaiscript namespace chaiscript
{ {
@ -118,21 +119,32 @@ namespace chaiscript
class Dynamic_Conversions class Dynamic_Conversions
{ {
public: public:
static Dynamic_Conversions &get()
{
static Dynamic_Conversions obj;
return obj;
}
template<typename Base, typename Derived> template<typename Base, typename Derived>
static void add_conversion() void add_conversion()
{ {
get_conversions().push_back( #ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
m_conversions.push_back(
boost::shared_ptr<Dynamic_Conversion>(new Dynamic_Conversion_Impl<Base, Derived>()) boost::shared_ptr<Dynamic_Conversion>(new Dynamic_Conversion_Impl<Base, Derived>())
); );
} }
static bool has_conversion(const Type_Info &base, const Type_Info &derived) bool has_conversion(const Type_Info &base, const Type_Info &derived)
{ {
const std::vector<boost::shared_ptr<Dynamic_Conversion> > &convs #ifndef CHAISCRIPT_NO_THREADS
= get_conversions(); boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
for (std::vector<boost::shared_ptr<Dynamic_Conversion> >::const_iterator itr = convs.begin(); for (std::vector<boost::shared_ptr<Dynamic_Conversion> >::const_iterator itr = m_conversions.begin();
itr != convs.end(); itr != m_conversions.end();
++itr) ++itr)
{ {
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived)) if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
@ -144,13 +156,14 @@ namespace chaiscript
return false; return false;
} }
static boost::shared_ptr<Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived) boost::shared_ptr<Dynamic_Conversion> get_conversion(const Type_Info &base, const Type_Info &derived)
{ {
const std::vector<boost::shared_ptr<Dynamic_Conversion> > &convs #ifndef CHAISCRIPT_NO_THREADS
= get_conversions(); boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
for (std::vector<boost::shared_ptr<Dynamic_Conversion> >::const_iterator itr = convs.begin(); for (std::vector<boost::shared_ptr<Dynamic_Conversion> >::const_iterator itr = m_conversions.begin();
itr != convs.end(); itr != m_conversions.end();
++itr) ++itr)
{ {
if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived)) if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived))
@ -162,12 +175,12 @@ namespace chaiscript
throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name()); throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name());
} }
private: private:
static std::vector<boost::shared_ptr<Dynamic_Conversion> > &get_conversions() Dynamic_Conversions() {}
{ #ifndef CHAISCRIPT_NO_THREADS
static std::vector<boost::shared_ptr<Dynamic_Conversion> > convs; boost::shared_mutex m_mutex;
return convs; #endif
} std::vector<boost::shared_ptr<Dynamic_Conversion> > m_conversions;
}; };
} }
@ -180,7 +193,7 @@ namespace chaiscript
BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value); BOOST_STATIC_ASSERT(boost::is_polymorphic<Base>::value);
BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value); BOOST_STATIC_ASSERT(boost::is_polymorphic<Derived>::value);
detail::Dynamic_Conversions::add_conversion<Base, Derived>(); detail::Dynamic_Conversions::get().add_conversion<Base, Derived>();
} }
template<typename Base, typename Derived> template<typename Base, typename Derived>
@ -191,14 +204,14 @@ namespace chaiscript
bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived)
{ {
return detail::Dynamic_Conversions::has_conversion(base, derived); return detail::Dynamic_Conversions::get().has_conversion(base, derived);
} }
template<typename Base> template<typename Base>
Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived)
{ {
try { try {
return detail::Dynamic_Conversions::get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived); return detail::Dynamic_Conversions::get().get_conversion(user_type<Base>(), derived.get_type_info())->convert(derived);
} catch (const std::out_of_range &) { } catch (const std::out_of_range &) {
throw bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); throw bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion");
} catch (const std::bad_cast &) { } catch (const std::bad_cast &) {