@@ -48,12 +48,13 @@ namespace chaiscript
4848 {
4949 public:
5050 virtual Boxed_Value convert (const Boxed_Value &derived) const = 0;
51+ virtual Boxed_Value convert_down (const Boxed_Value &base) const = 0;
5152
52- const Type_Info &base ()
53+ const Type_Info &base () const
5354 {
5455 return m_base;
5556 }
56- const Type_Info &derived ()
57+ const Type_Info &derived () const
5758 {
5859 return m_derived;
5960 }
@@ -72,59 +73,74 @@ namespace chaiscript
7273
7374 };
7475
75- template <typename Base, typename Derived>
76- class Dynamic_Conversion_Impl : public Dynamic_Conversion
77- {
78- public:
79- Dynamic_Conversion_Impl ()
80- : Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
81- {
82- }
83-
84- virtual Boxed_Value convert (const Boxed_Value &t_derived) const
85- {
86- if (t_derived.get_type_info ().bare_equal (user_type<Derived>()))
76+ template <typename From, typename To>
77+ class Dynamic_Caster
78+ {
79+ public:
80+ static Boxed_Value cast (const Boxed_Value &t_from)
8781 {
88- if (t_derived. is_pointer ( ))
82+ if (t_from. get_type_info (). bare_equal (user_type<From>() ))
8983 {
90- // Dynamic cast out the contained boxed value, which we know is the type we want
91- if (t_derived.is_const ())
84+ if (t_from.is_pointer ())
9285 {
93- std::shared_ptr<const Base> data
94- = std::dynamic_pointer_cast<const Base>(detail::Cast_Helper<std::shared_ptr<const Derived> >::cast (t_derived, nullptr ));
95- if (!data)
86+ // Dynamic cast out the contained boxed value, which we know is the type we want
87+ if (t_from.is_const ())
9688 {
97- throw std::bad_cast ();
89+ std::shared_ptr<const To> data
90+ = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast (t_from, nullptr ));
91+ if (!data)
92+ {
93+ throw std::bad_cast ();
94+ }
95+
96+ return Boxed_Value (data);
97+ } else {
98+ std::shared_ptr<To> data
99+ = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast (t_from, nullptr ));
100+
101+ if (!data)
102+ {
103+ throw std::bad_cast ();
104+ }
105+
106+ return Boxed_Value (data);
98107 }
99-
100- return Boxed_Value (data);
101108 } else {
102- std::shared_ptr<Base> data
103- = std::dynamic_pointer_cast<Base>(detail::Cast_Helper<std::shared_ptr<Derived> >::cast (t_derived, nullptr ));
104-
105- if (!data)
109+ // Pull the reference out of the contained boxed value, which we know is the type we want
110+ if (t_from.is_const ())
106111 {
107- throw std::bad_cast ();
112+ const From &d = detail::Cast_Helper<const From &>::cast (t_from, 0 );
113+ const To &data = dynamic_cast <const To &>(d);
114+ return Boxed_Value (std::cref (data));
115+ } else {
116+ From &d = detail::Cast_Helper<From &>::cast (t_from, 0 );
117+ To &data = dynamic_cast <To &>(d);
118+ return Boxed_Value (std::ref (data));
108119 }
109-
110- return Boxed_Value (data);
111120 }
112121 } else {
113- // Pull the reference out of the contained boxed value, which we know is the type we want
114- if (t_derived.is_const ())
115- {
116- const Derived &d = detail::Cast_Helper<const Derived &>::cast (t_derived, 0 );
117- const Base &data = dynamic_cast <const Base &>(d);
118- return Boxed_Value (std::cref (data));
119- } else {
120- Derived &d = detail::Cast_Helper<Derived &>::cast (t_derived, 0 );
121- Base &data = dynamic_cast <Base &>(d);
122- return Boxed_Value (std::ref (data));
123- }
122+ throw chaiscript::exception::bad_boxed_dynamic_cast (t_from.get_type_info (), typeid (To), " Unknown dynamic_cast_conversion" );
124123 }
125- } else {
126- throw chaiscript::exception::bad_boxed_dynamic_cast (t_derived.get_type_info (), typeid (Base), " Unknown dynamic_cast_conversion" );
127124 }
125+ };
126+
127+ template <typename Base, typename Derived>
128+ class Dynamic_Conversion_Impl : public Dynamic_Conversion
129+ {
130+ public:
131+ Dynamic_Conversion_Impl ()
132+ : Dynamic_Conversion(user_type<Base>(), user_type<Derived>())
133+ {
134+ }
135+
136+ virtual Boxed_Value convert_down (const Boxed_Value &t_base) const
137+ {
138+ return Dynamic_Caster<Base, Derived>::cast (t_base);
139+ }
140+
141+ virtual Boxed_Value convert (const Boxed_Value &t_derived) const
142+ {
143+ return Dynamic_Caster<Derived, Base>::cast (t_derived);
128144 }
129145 };
130146 }
@@ -155,7 +171,7 @@ namespace chaiscript
155171
156172 bool dynamic_cast_converts (const Type_Info &base, const Type_Info &derived) const
157173 {
158- return has_conversion (base, derived);
174+ return has_conversion (base, derived) || has_conversion (derived, base) ;
159175 }
160176
161177 template <typename Base>
@@ -170,6 +186,19 @@ namespace chaiscript
170186 }
171187 }
172188
189+ template <typename Derived>
190+ Boxed_Value boxed_dynamic_down_cast (const Boxed_Value &base) const
191+ {
192+ try {
193+ return get_conversion (base.get_type_info (), user_type<Derived>())->convert_down (base);
194+ } catch (const std::out_of_range &) {
195+ throw exception::bad_boxed_dynamic_cast (base.get_type_info (), typeid (Derived), " No known conversion" );
196+ } catch (const std::bad_cast &) {
197+ throw exception::bad_boxed_dynamic_cast (base.get_type_info (), typeid (Derived), " Unable to perform dynamic_cast operation" );
198+ }
199+ }
200+
201+
173202 bool has_conversion (const Type_Info &base, const Type_Info &derived) const
174203 {
175204 chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l (m_mutex);
@@ -242,8 +271,6 @@ namespace chaiscript
242271 // / chai.add(chaiscript::base_class<Base, Derived>());
243272 // / \endcode
244273 // /
245- // / \todo Move share static type registration code into a mechanism that allows it to be properly
246- // / shared by all modules
247274 template <typename Base, typename Derived>
248275 Dynamic_Cast_Conversion base_class ()
249276 {
0 commit comments