diff --git a/include/chaiscript/chaiscript.hpp b/include/chaiscript/chaiscript.hpp index e22895c..346c0a9 100644 --- a/include/chaiscript/chaiscript.hpp +++ b/include/chaiscript/chaiscript.hpp @@ -22,6 +22,7 @@ #include "dispatchkit/bootstrap_stl.hpp" #include "dispatchkit/function_call.hpp" #include "dispatchkit/dynamic_object.hpp" +#include "dispatchkit/boxed_pod_value.hpp" #ifdef BOOST_HAS_DECLSPEC #define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport) diff --git a/include/chaiscript/dispatchkit/bad_boxed_cast.hpp b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp new file mode 100644 index 0000000..9b3e734 --- /dev/null +++ b/include/chaiscript/dispatchkit/bad_boxed_cast.hpp @@ -0,0 +1,56 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org) +// and Jason Turner (lefticus@gmail.com) +// http://www.chaiscript.com + +#ifndef __bad_boxed_cast_hpp__ +#define __bad_boxed_cast_hpp__ + +#include "type_info.hpp" + +namespace chaiscript +{ + + /** + * class that is thrown in the event of a bad_boxed_cast. That is, + * in the case that a Boxed_Value cannot be cast to the desired type + */ + class bad_boxed_cast : public std::bad_cast + { + public: + bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to, + const std::string &what) + : from(t_from), to(&t_to), m_what(what) + { + } + + bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw() + : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") + { + } + + bad_boxed_cast(const std::string &w) throw() + : m_what(w) + { + } + + virtual ~bad_boxed_cast() throw() {} + + virtual const char * what () throw() + { + return m_what.c_str(); + } + + Type_Info from; + const std::type_info *to; + + private: + std::string m_what; + }; +} + + + +#endif + diff --git a/include/chaiscript/dispatchkit/bootstrap.hpp b/include/chaiscript/dispatchkit/bootstrap.hpp index 706fb95..3e04156 100644 --- a/include/chaiscript/dispatchkit/bootstrap.hpp +++ b/include/chaiscript/dispatchkit/bootstrap.hpp @@ -11,6 +11,7 @@ #include "dynamic_object.hpp" #include "register_function.hpp" #include "operators.hpp" +#include "boxed_pod_value.hpp" namespace chaiscript { diff --git a/include/chaiscript/dispatchkit/boxed_cast.hpp b/include/chaiscript/dispatchkit/boxed_cast.hpp new file mode 100644 index 0000000..878b6fb --- /dev/null +++ b/include/chaiscript/dispatchkit/boxed_cast.hpp @@ -0,0 +1,53 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org) +// and Jason Turner (lefticus@gmail.com) +// http://www.chaiscript.com + +#ifndef __boxed_cast_hpp__ +#define __boxed_cast_hpp__ + +#include "type_info.hpp" +#include "boxed_value.hpp" +#include "boxed_cast_helper.hpp" +#include "dynamic_cast_conversion.hpp" + +#include "../chaiscript_threading.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace chaiscript +{ + + /** + * boxed_cast function for casting a Boxed_Value into a given type + * example: + * int &i = boxed_cast(boxedvalue); + */ + template + typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv) + { + try { + return detail::Cast_Helper::cast(bv); + } catch (const boost::bad_any_cast &) { + try { + // 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 + return detail::Cast_Helper::cast(boxed_dynamic_cast(bv)); + } catch (const boost::bad_any_cast &) { + throw bad_boxed_cast(bv.get_type_info(), typeid(Type)); + } + } + } + +} + + + +#endif + diff --git a/include/chaiscript/dispatchkit/boxed_cast_helper.hpp b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp new file mode 100644 index 0000000..1fd6ef2 --- /dev/null +++ b/include/chaiscript/dispatchkit/boxed_cast_helper.hpp @@ -0,0 +1,252 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org) +// and Jason Turner (lefticus@gmail.com) +// http://www.chaiscript.com + +#ifndef __boxed_cast_helper_hpp__ +#define __boxed_cast_helper_hpp__ + +#include "type_info.hpp" +#include "boxed_value.hpp" + +#include +#include +#include +#include + +namespace chaiscript +{ + namespace detail + { + // Cast_Helper helper classes + + /** + * Generic Cast_Helper, for casting to any type + */ + template + struct Cast_Helper + { + typedef typename boost::reference_wrapper::type > Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + if (ob.is_ref()) + { + if (!ob.get_type_info().is_const()) + { + return boost::cref((boost::any_cast >(ob.get())).get()); + } else { + return boost::any_cast >(ob.get()); + } + } else { + if (!ob.get_type_info().is_const()) + { + return boost::cref(*(boost::any_cast >(ob.get()))); + } else { + return boost::cref(*(boost::any_cast >(ob.get()))); + } + } + } + }; + + /** + * Cast_Helper for casting to a const & type + */ + template + struct Cast_Helper + { + typedef typename boost::reference_wrapper::type > Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + if (ob.is_ref()) + { + if (!ob.get_type_info().is_const()) + { + return boost::cref((boost::any_cast >(ob.get())).get()); + } else { + return boost::any_cast >(ob.get()); + } + } else { + if (!ob.get_type_info().is_const()) + { + return boost::cref(*(boost::any_cast >(ob.get()))); + } else { + return boost::cref(*(boost::any_cast >(ob.get()))); + } + } + } + }; + + /** + * Cast_Helper for casting to a const * type + */ + template + struct Cast_Helper + { + typedef const Result * Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + if (ob.is_ref()) + { + if (!ob.get_type_info().is_const()) + { + return (boost::any_cast >(ob.get())).get_pointer(); + } else { + return (boost::any_cast >(ob.get())).get_pointer(); + } + } else { + if (!ob.get_type_info().is_const()) + { + return (boost::any_cast >(ob.get())).get(); + } else { + return (boost::any_cast >(ob.get())).get(); + } + } + } + }; + + /** + * Cast_Helper for casting to a * type + */ + template + struct Cast_Helper + { + typedef Result * Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + if (ob.is_ref()) + { + return (boost::any_cast >(ob.get())).get_pointer(); + } else { + return (boost::any_cast >(ob.get())).get(); + } + } + }; + + /** + * Cast_Helper for casting to a & type + */ + template + struct Cast_Helper + { + typedef typename boost::reference_wrapper Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + if (ob.is_ref()) + { + return boost::any_cast >(ob.get()); + } else { + return boost::ref(*(boost::any_cast >(ob.get()))); + } + } + }; + + /** + * Cast_Helper for casting to a boost::shared_ptr<> type + */ + template + struct Cast_Helper > + { + typedef typename boost::shared_ptr Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + return boost::any_cast >(ob.get()); + } + }; + + /** + * Cast_Helper for casting to a boost::shared_ptr type + */ + template + struct Cast_Helper > + { + typedef typename boost::shared_ptr Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + if (!ob.get_type_info().is_const()) + { + return boost::const_pointer_cast(boost::any_cast >(ob.get())); + } else { + return boost::any_cast >(ob.get()); + } + } + }; + + /** + * Cast_Helper for casting to a const boost::shared_ptr<> & type + */ + template + struct Cast_Helper &> + { + typedef typename boost::shared_ptr Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + return boost::any_cast >(ob.get()); + } + }; + + /** + * Cast_Helper for casting to a const boost::shared_ptr & type + */ + template + struct Cast_Helper &> + { + typedef typename boost::shared_ptr Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + if (!ob.get_type_info().is_const()) + { + return boost::const_pointer_cast(boost::any_cast >(ob.get())); + } else { + return boost::any_cast >(ob.get()); + } + } + }; + + + + /** + * Cast_Helper for casting to a Boxed_Value type + */ + template<> + struct Cast_Helper + { + typedef const Boxed_Value & Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + return ob; + } + }; + + /** + * Cast_Helper for casting to a const Boxed_Value & type + */ + template<> + struct Cast_Helper + { + typedef const Boxed_Value & Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + return ob; + } + }; + } + + +} + + + +#endif + diff --git a/include/chaiscript/dispatchkit/boxed_pod_value.hpp b/include/chaiscript/dispatchkit/boxed_pod_value.hpp new file mode 100644 index 0000000..0fb3cbd --- /dev/null +++ b/include/chaiscript/dispatchkit/boxed_pod_value.hpp @@ -0,0 +1,262 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2010, Jonathan Turner (jturner@minnow-lang.org) +// and Jason Turner (lefticus@gmail.com) +// http://www.chaiscript.com + +#ifndef __boxed_pod_value_hpp__ +#define __boxed_pod_value_hpp__ + +#include "type_info.hpp" +#include "boxed_value.hpp" +#include "boxed_cast_helper.hpp" +#include +#include +#include + +namespace chaiscript +{ + + /** + * Object which attempts to convert a Boxed_Value into a generic + * POD type and provide generic POD type operations + */ + struct Boxed_POD_Value + { + Boxed_POD_Value(const Boxed_Value &v) + : d(0), i(0), m_isfloat(false) + { + if (v.get_type_info().is_undef()) + { + throw boost::bad_any_cast(); + } + + const Type_Info &inp_ = v.get_type_info(); + + if (inp_ == typeid(double)) + { + d = boxed_cast(v); + m_isfloat = true; + } else if (inp_ == typeid(float)) { + d = boxed_cast(v); + m_isfloat = true; + } else if (inp_ == typeid(bool)) { + i = boxed_cast(v); + } else if (inp_ == typeid(char)) { + i = boxed_cast(v); + } else if (inp_ == typeid(int)) { + i = boxed_cast(v); + } else if (inp_ == typeid(unsigned int)) { + i = boxed_cast(v); + } else if (inp_ == typeid(long)) { + i = boxed_cast(v); + } else if (inp_ == typeid(unsigned long)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int8_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int16_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int32_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::int64_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::uint8_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::uint16_t)) { + i = boxed_cast(v); + } else if (inp_ == typeid(boost::uint32_t)) { + i = boxed_cast(v); + } else { + throw boost::bad_any_cast(); + } + } + + bool operator==(const Boxed_POD_Value &r) const + { + return ((m_isfloat)?d:i) == ((r.m_isfloat)?r.d:r.i); + } + + bool operator<(const Boxed_POD_Value &r) const + { + return ((m_isfloat)?d:i) < ((r.m_isfloat)?r.d:r.i); + } + + bool operator>(const Boxed_POD_Value &r) const + { + return ((m_isfloat)?d:i) > ((r.m_isfloat)?r.d:r.i); + } + + bool operator>=(const Boxed_POD_Value &r) const + { + return ((m_isfloat)?d:i) >= ((r.m_isfloat)?r.d:r.i); + } + + bool operator<=(const Boxed_POD_Value &r) const + { + return ((m_isfloat)?d:i) <= ((r.m_isfloat)?r.d:r.i); + } + + bool operator!=(const Boxed_POD_Value &r) const + { + return ((m_isfloat)?d:i) != ((r.m_isfloat)?r.d:r.i); + } + + Boxed_Value operator+(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return smart_size(i + r.i); + } + + return Boxed_Value(((m_isfloat)?d:i) + ((r.m_isfloat)?r.d:r.i)); + } + + Boxed_Value operator-(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return smart_size(i - r.i); + } + + return Boxed_Value(((m_isfloat)?d:i) - ((r.m_isfloat)?r.d:r.i)); + } + + Boxed_Value operator&(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return Boxed_Value(i & r.i); + } + + throw bad_boxed_cast("& only valid for integer types"); + } + + Boxed_Value operator^(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return Boxed_Value(i ^ r.i); + } + + throw bad_boxed_cast("^ only valid for integer types"); + } + + Boxed_Value operator|(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return Boxed_Value(i | r.i); + } + + throw bad_boxed_cast("| only valid for integer types"); + } + + Boxed_Value operator/(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return smart_size(i / r.i); + } + + return Boxed_Value(((m_isfloat)?d:i) / ((r.m_isfloat)?r.d:r.i)); + } + + Boxed_Value operator<<(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return smart_size(i << r.i); + } + + throw bad_boxed_cast("<< only valid for integer types"); + } + + + Boxed_Value operator*(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return smart_size(i * r.i); + } + + return Boxed_Value(((m_isfloat)?d:i) * ((r.m_isfloat)?r.d:r.i)); + } + + + Boxed_Value operator%(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return smart_size(i % r.i); + } + + throw bad_boxed_cast("% only valid for integer types"); + } + + Boxed_Value operator>>(const Boxed_POD_Value &r) const + { + if (!m_isfloat && !r.m_isfloat) + { + return smart_size(i >> r.i); + } + + throw bad_boxed_cast(">> only valid for integer types"); + } + + Boxed_Value smart_size(boost::int64_t i) const + { + if (i < boost::integer_traits::const_min + || i > boost::integer_traits::const_max) + { + return Boxed_Value(i); + } else { + return Boxed_Value(static_cast(i)); + } + } + + + + double d; + boost::int64_t i; + + bool m_isfloat; + }; + + namespace detail + { + /** + * Cast_Helper for converting from Boxed_Value to Boxed_POD_Value + */ + template<> + struct Cast_Helper + { + typedef Boxed_POD_Value Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + return Boxed_POD_Value(ob); + } + }; + + /** + * Cast_Helper for converting from Boxed_Value to Boxed_POD_Value + */ + template<> + struct Cast_Helper + { + typedef Boxed_POD_Value Result_Type; + + static Result_Type cast(const Boxed_Value &ob) + { + return Boxed_POD_Value(ob); + } + }; + } + + +} + + + +#endif + diff --git a/include/chaiscript/dispatchkit/boxed_value.hpp b/include/chaiscript/dispatchkit/boxed_value.hpp index 7555d54..e9ae280 100644 --- a/include/chaiscript/dispatchkit/boxed_value.hpp +++ b/include/chaiscript/dispatchkit/boxed_value.hpp @@ -8,6 +8,7 @@ #define __boxed_value_hpp__ #include "type_info.hpp" + #include "../chaiscript_threading.hpp" #include #include @@ -18,6 +19,8 @@ #include #include #include +#include +#include namespace chaiscript { @@ -117,6 +120,7 @@ namespace chaiscript boost::shared_ptr get(const boost::shared_ptr &obj) { bool b_const = boost::is_const::value; + const std::type_info *ti = &typeid(typename Bare_Type::type); boost::shared_ptr data(new Data( detail::Get_Type_Info::get(), @@ -126,14 +130,14 @@ namespace chaiscript &Data::is_null) ); - std::map, Data>::iterator itr - = m_ptrs.find(std::make_pair(obj.get(), b_const)); + std::map, Data>::iterator itr + = m_ptrs.find(boost::make_tuple(obj.get(), b_const, ti)); if (itr != m_ptrs.end()) { (*data) = (itr->second); } else { - m_ptrs.insert(std::make_pair(std::make_pair(obj.get(), b_const), *data)); + m_ptrs.insert(std::make_pair(boost::make_tuple(obj.get(), b_const, ti), *data)); } return data; @@ -149,6 +153,7 @@ namespace chaiscript boost::shared_ptr get(boost::reference_wrapper obj) { bool b_const = boost::is_const::value; + const std::type_info *ti = &typeid(typename Bare_Type::type); boost::shared_ptr data(new Data( detail::Get_Type_Info::get(), @@ -156,8 +161,8 @@ namespace chaiscript true) ); - std::map, Data >::iterator itr - = m_ptrs.find(std::make_pair(obj.get_pointer(), b_const) ); + std::map, Data >::iterator itr + = m_ptrs.find(boost::make_tuple(obj.get_pointer(), b_const, ti) ); // If the ptr is found in the cache and it is the correct type, // return it. It may be the incorrect type when two variables share the @@ -178,6 +183,8 @@ namespace chaiscript template boost::shared_ptr get(const T& t) { + const std::type_info *ti = &typeid(typename Bare_Type::type); + boost::shared_ptr data(new Data( detail::Get_Type_Info::get(), boost::any(boost::shared_ptr(new T(t))), @@ -188,7 +195,9 @@ namespace chaiscript boost::shared_ptr *ptr = boost::any_cast >(&data->m_obj); - m_ptrs.insert(std::make_pair(std::make_pair(ptr->get(), false), *data)); + boost::tuple key(ptr->get(), false, ti); + + m_ptrs.insert(std::make_pair(key, *data)); return data; } @@ -215,13 +224,13 @@ namespace chaiscript } - std::map, Data>::iterator itr = m_ptrs.begin(); + std::map, Data>::iterator itr = m_ptrs.begin(); while (itr != m_ptrs.end()) { if (itr->second.m_unique(&itr->second.m_obj)) { - std::map, Data >::iterator todel = itr; + std::map, Data >::iterator todel = itr; ++itr; m_ptrs.erase(todel); } else { @@ -230,7 +239,7 @@ namespace chaiscript } } - std::map, Data> m_ptrs; + std::map, Data> m_ptrs; int m_cullcount; }; @@ -357,515 +366,6 @@ namespace chaiscript boost::shared_ptr m_data; }; - - namespace detail - { - // Cast_Helper helper classes - - /** - * Generic Cast_Helper, for casting to any type - */ - template - struct Cast_Helper - { - typedef typename boost::reference_wrapper::type > Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - if (ob.is_ref()) - { - if (!ob.get_type_info().is_const()) - { - return boost::cref((boost::any_cast >(ob.get())).get()); - } else { - return boost::any_cast >(ob.get()); - } - } else { - if (!ob.get_type_info().is_const()) - { - return boost::cref(*(boost::any_cast >(ob.get()))); - } else { - return boost::cref(*(boost::any_cast >(ob.get()))); - } - } - } - }; - - /** - * Cast_Helper for casting to a const & type - */ - template - struct Cast_Helper - { - typedef typename boost::reference_wrapper::type > Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - if (ob.is_ref()) - { - if (!ob.get_type_info().is_const()) - { - return boost::cref((boost::any_cast >(ob.get())).get()); - } else { - return boost::any_cast >(ob.get()); - } - } else { - if (!ob.get_type_info().is_const()) - { - return boost::cref(*(boost::any_cast >(ob.get()))); - } else { - return boost::cref(*(boost::any_cast >(ob.get()))); - } - } - } - }; - - /** - * Cast_Helper for casting to a const * type - */ - template - struct Cast_Helper - { - typedef const Result * Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - if (ob.is_ref()) - { - if (!ob.get_type_info().is_const()) - { - return (boost::any_cast >(ob.get())).get_pointer(); - } else { - return (boost::any_cast >(ob.get())).get_pointer(); - } - } else { - if (!ob.get_type_info().is_const()) - { - return (boost::any_cast >(ob.get())).get(); - } else { - return (boost::any_cast >(ob.get())).get(); - } - } - } - }; - - /** - * Cast_Helper for casting to a * type - */ - template - struct Cast_Helper - { - typedef Result * Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - if (ob.is_ref()) - { - return (boost::any_cast >(ob.get())).get_pointer(); - } else { - return (boost::any_cast >(ob.get())).get(); - } - } - }; - - /** - * Cast_Helper for casting to a & type - */ - template - struct Cast_Helper - { - typedef typename boost::reference_wrapper Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - if (ob.is_ref()) - { - return boost::any_cast >(ob.get()); - } else { - return boost::ref(*(boost::any_cast >(ob.get()))); - } - } - }; - - /** - * Cast_Helper for casting to a boost::shared_ptr<> type - */ - template - struct Cast_Helper > - { - typedef typename boost::shared_ptr Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - return boost::any_cast >(ob.get()); - } - }; - - /** - * Cast_Helper for casting to a boost::shared_ptr type - */ - template - struct Cast_Helper > - { - typedef typename boost::shared_ptr Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - if (!ob.get_type_info().is_const()) - { - return boost::const_pointer_cast(boost::any_cast >(ob.get())); - } else { - return boost::any_cast >(ob.get()); - } - } - }; - - /** - * Cast_Helper for casting to a const boost::shared_ptr<> & type - */ - template - struct Cast_Helper &> - { - typedef typename boost::shared_ptr Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - return boost::any_cast >(ob.get()); - } - }; - - /** - * Cast_Helper for casting to a const boost::shared_ptr & type - */ - template - struct Cast_Helper &> - { - typedef typename boost::shared_ptr Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - if (!ob.get_type_info().is_const()) - { - return boost::const_pointer_cast(boost::any_cast >(ob.get())); - } else { - return boost::any_cast >(ob.get()); - } - } - }; - - - - /** - * Cast_Helper for casting to a Boxed_Value type - */ - template<> - struct Cast_Helper - { - typedef const Boxed_Value & Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - return ob; - } - }; - - /** - * Cast_Helper for casting to a const Boxed_Value & type - */ - template<> - struct Cast_Helper - { - typedef const Boxed_Value & Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - return ob; - } - }; - } - - /** - * class that is thrown in the event of a bad_boxed_cast. That is, - * in the case that a Boxed_Value cannot be cast to the desired type - */ - class bad_boxed_cast : public std::bad_cast - { - public: - bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw() - : from(t_from), to(&t_to), m_what("Cannot perform boxed_cast") - { - } - - bad_boxed_cast(const std::string &w) throw() - : m_what(w) - { - } - - virtual ~bad_boxed_cast() throw() {} - - virtual const char * what () throw() - { - return m_what.c_str(); - } - - Type_Info from; - const std::type_info *to; - - private: - std::string m_what; - }; - - /** - * boxed_cast function for casting a Boxed_Value into a given type - * example: - * int &i = boxed_cast(boxedvalue); - */ - template - typename detail::Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv) - { - try { - return detail::Cast_Helper::cast(bv); - } catch (const boost::bad_any_cast &) { - throw bad_boxed_cast(bv.get_type_info(), typeid(Type)); - } - } - - /** - * Object which attempts to convert a Boxed_Value into a generic - * POD type and provide generic POD type operations - */ - struct Boxed_POD_Value - { - Boxed_POD_Value(const Boxed_Value &v) - : d(0), i(0), m_isfloat(false) - { - if (v.get_type_info().is_undef()) - { - throw boost::bad_any_cast(); - } - - const Type_Info &inp_ = v.get_type_info(); - - if (inp_ == typeid(double)) - { - d = boxed_cast(v); - m_isfloat = true; - } else if (inp_ == typeid(float)) { - d = boxed_cast(v); - m_isfloat = true; - } else if (inp_ == typeid(bool)) { - i = boxed_cast(v); - } else if (inp_ == typeid(char)) { - i = boxed_cast(v); - } else if (inp_ == typeid(int)) { - i = boxed_cast(v); - } else if (inp_ == typeid(unsigned int)) { - i = boxed_cast(v); - } else if (inp_ == typeid(long)) { - i = boxed_cast(v); - } else if (inp_ == typeid(unsigned long)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int8_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int16_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int32_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::int64_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::uint8_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::uint16_t)) { - i = boxed_cast(v); - } else if (inp_ == typeid(boost::uint32_t)) { - i = boxed_cast(v); - } else { - throw boost::bad_any_cast(); - } - } - - bool operator==(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) == ((r.m_isfloat)?r.d:r.i); - } - - bool operator<(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) < ((r.m_isfloat)?r.d:r.i); - } - - bool operator>(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) > ((r.m_isfloat)?r.d:r.i); - } - - bool operator>=(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) >= ((r.m_isfloat)?r.d:r.i); - } - - bool operator<=(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) <= ((r.m_isfloat)?r.d:r.i); - } - - bool operator!=(const Boxed_POD_Value &r) const - { - return ((m_isfloat)?d:i) != ((r.m_isfloat)?r.d:r.i); - } - - Boxed_Value operator+(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i + r.i); - } - - return Boxed_Value(((m_isfloat)?d:i) + ((r.m_isfloat)?r.d:r.i)); - } - - Boxed_Value operator-(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i - r.i); - } - - return Boxed_Value(((m_isfloat)?d:i) - ((r.m_isfloat)?r.d:r.i)); - } - - Boxed_Value operator&(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return Boxed_Value(i & r.i); - } - - throw bad_boxed_cast("& only valid for integer types"); - } - - Boxed_Value operator^(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return Boxed_Value(i ^ r.i); - } - - throw bad_boxed_cast("^ only valid for integer types"); - } - - Boxed_Value operator|(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return Boxed_Value(i | r.i); - } - - throw bad_boxed_cast("| only valid for integer types"); - } - - Boxed_Value operator/(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i / r.i); - } - - return Boxed_Value(((m_isfloat)?d:i) / ((r.m_isfloat)?r.d:r.i)); - } - - Boxed_Value operator<<(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i << r.i); - } - - throw bad_boxed_cast("<< only valid for integer types"); - } - - - Boxed_Value operator*(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i * r.i); - } - - return Boxed_Value(((m_isfloat)?d:i) * ((r.m_isfloat)?r.d:r.i)); - } - - - Boxed_Value operator%(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i % r.i); - } - - throw bad_boxed_cast("% only valid for integer types"); - } - - Boxed_Value operator>>(const Boxed_POD_Value &r) const - { - if (!m_isfloat && !r.m_isfloat) - { - return smart_size(i >> r.i); - } - - throw bad_boxed_cast(">> only valid for integer types"); - } - - Boxed_Value smart_size(boost::int64_t i) const - { - if (i < boost::integer_traits::const_min - || i > boost::integer_traits::const_max) - { - return Boxed_Value(i); - } else { - return Boxed_Value(static_cast(i)); - } - } - - - - double d; - boost::int64_t i; - - bool m_isfloat; - }; - - namespace detail - { - /** - * Cast_Helper for converting from Boxed_Value to Boxed_POD_Value - */ - template<> - struct Cast_Helper - { - typedef Boxed_POD_Value Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - return Boxed_POD_Value(ob); - } - }; - - /** - * Cast_Helper for converting from Boxed_Value to Boxed_POD_Value - */ - template<> - struct Cast_Helper - { - typedef Boxed_POD_Value Result_Type; - - static Result_Type cast(const Boxed_Value &ob) - { - return Boxed_POD_Value(ob); - } - }; - } - template Boxed_Value var(T t) { @@ -896,6 +396,7 @@ namespace chaiscript return Boxed_Value(boost::shared_ptr::type >(new T(t))); } + /** * Return true if the two Boxed_Values share the same internal type */ @@ -905,7 +406,5 @@ namespace chaiscript } } - - #endif diff --git a/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp new file mode 100644 index 0000000..daa507b --- /dev/null +++ b/include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp @@ -0,0 +1,211 @@ +#ifndef __chaiscriptdispatchkit_dynamic_cast_conversion_hpp__ +#define __chaiscriptdispatchkit_dynamic_cast_conversion_hpp__ + +#include "type_info.hpp" +#include "boxed_value.hpp" +#include "boxed_cast_helper.hpp" +#include "bad_boxed_cast.hpp" + +namespace chaiscript +{ + class bad_boxed_dynamic_cast : public bad_boxed_cast + { + public: + bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to, + const std::string &t_what) + : bad_boxed_cast(t_from, t_to, t_what) + { + } + + bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) throw() + : bad_boxed_cast(t_from, t_to) + { + } + + bad_boxed_dynamic_cast(const std::string &w) throw() + : bad_boxed_cast(w) + { + } + }; + + + namespace detail + { + class Dynamic_Conversion + { + public: + virtual Boxed_Value convert(const Boxed_Value &derived) = 0; + const Type_Info &base() + { + return m_base; + } + const Type_Info &derived() + { + return m_derived; + } + + protected: + Dynamic_Conversion(const Type_Info &t_base, const Type_Info &t_derived) + : m_base(t_base), m_derived(t_derived) + { + } + + private: + Type_Info m_base; + Type_Info m_derived; + + }; + + template + class Dynamic_Conversion_Impl : public Dynamic_Conversion + { + public: + Dynamic_Conversion_Impl() + : Dynamic_Conversion(user_type(), user_type()) + { + } + + virtual Boxed_Value convert(const Boxed_Value &derived) + { + if (derived.get_type_info().bare_equal(user_type())) + { + if (derived.is_pointer()) + { + // Dynamic cast out the contained boxed value, which we know is the type we want + if (derived.is_const()) + { + boost::shared_ptr data + = boost::dynamic_pointer_cast(detail::Cast_Helper >::cast(derived)); + if (!data) + { + throw std::bad_cast(); + } + + return Boxed_Value(data); + } else { + std::cout << "performing boxed_dynamic_cast" << std::endl; + boost::shared_ptr data + = boost::dynamic_pointer_cast(detail::Cast_Helper >::cast(derived)); + + if (!data) + { + throw std::bad_cast(); + } + + std::cout << "typeinfo " << typeid(data).name() << std::endl; + Boxed_Value ret(data); + std::cout << " It worked " << ret.get_type_info().name() << std::endl; + + return ret; + } + } else { + // Pull the reference out of the contained boxed value, which we know is the type we want + if (derived.is_const()) + { + const Derived &d = detail::Cast_Helper::cast(derived); + const Base &data = dynamic_cast(d); + return Boxed_Value(boost::cref(data)); + } else { + Derived &d = detail::Cast_Helper::cast(derived); + Base &data = dynamic_cast(d); + return Boxed_Value(boost::ref(data)); + } + } + } else { + throw bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unknown dynamic_cast_conversion"); + } + + } + }; + + class Dynamic_Conversions + { + public: + template + static void add_conversion() + { + get_conversions().push_back( + boost::shared_ptr(new Dynamic_Conversion_Impl()) + ); + } + + static bool has_conversion(const Type_Info &base, const Type_Info &derived) + { + const std::vector > &convs + = get_conversions(); + + for (std::vector >::const_iterator itr = convs.begin(); + itr != convs.end(); + ++itr) + { + if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived)) + { + return true; + } + } + + return false; + } + + static boost::shared_ptr get_conversion(const Type_Info &base, const Type_Info &derived) + { + const std::vector > &convs + = get_conversions(); + + for (std::vector >::const_iterator itr = convs.begin(); + itr != convs.end(); + ++itr) + { + if ((*itr)->base().bare_equal(base) && (*itr)->derived().bare_equal(derived)) + { + return *itr; + } + } + + throw std::out_of_range("No such conversion exists from " + derived.bare_name() + " to " + base.bare_name()); + } + + private: + static std::vector > &get_conversions() + { + static std::vector > convs; + return convs; + } + }; + } + + template + void register_base_class() + { + detail::Dynamic_Conversions::add_conversion(); + } + + template + bool dynamic_cast_converts() + { + return dynamic_cast_converts(user_type(), user_type()); + } + + bool dynamic_cast_converts(const Type_Info &base, const Type_Info &derived) + { + return detail::Dynamic_Conversions::has_conversion(base, derived); + } + + template + Boxed_Value boxed_dynamic_cast(const Boxed_Value &derived) + { + std::cout << " Attempting conversion from " << derived.get_type_info().bare_name() << " to "<< typeid(Base).name() + << std::endl; + try { + return detail::Dynamic_Conversions::get_conversion(user_type(), derived.get_type_info())->convert(derived); + } catch (const std::out_of_range &) { + throw bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "No known conversion"); + } catch (const std::bad_cast &) { + throw bad_boxed_dynamic_cast(derived.get_type_info(), typeid(Base), "Unable to perform dynamic_cast operation"); + } + } + +} + + +#endif diff --git a/include/chaiscript/dispatchkit/operators.hpp b/include/chaiscript/dispatchkit/operators.hpp index 7825c1d..af18c59 100644 --- a/include/chaiscript/dispatchkit/operators.hpp +++ b/include/chaiscript/dispatchkit/operators.hpp @@ -152,7 +152,7 @@ namespace chaiscript return (-l); #pragma warning(pop) #else - return (-1); + return (-l); #endif } diff --git a/include/chaiscript/dispatchkit/proxy_functions.hpp b/include/chaiscript/dispatchkit/proxy_functions.hpp index 2a82253..a60ab89 100644 --- a/include/chaiscript/dispatchkit/proxy_functions.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions.hpp @@ -20,6 +20,8 @@ namespace chaiscript { + class Boxed_POD_Value; + /** * Helper for building a list of parameters for calling a Proxy_Function * it does automatic conversion to Boxed_Value types via operator<< @@ -97,7 +99,8 @@ namespace chaiscript if (ti.is_undef() || vals[0].get_type_info().is_undef() || ti.bare_equal(user_type()) || ti.bare_equal(user_type()) - || ti.bare_equal(vals[0].get_type_info())) + || ti.bare_equal(vals[0].get_type_info()) + || dynamic_cast_converts(ti, vals[0].get_type_info()) ) { return true; } else { diff --git a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp index 649d49b..1c67f3c 100644 --- a/include/chaiscript/dispatchkit/proxy_functions_detail.hpp +++ b/include/chaiscript/dispatchkit/proxy_functions_detail.hpp @@ -15,6 +15,7 @@ #define __proxy_functions_detail_hpp__ #include "boxed_value.hpp" +#include "boxed_cast.hpp" #include "type_info.hpp" #include "handle_return.hpp" #include diff --git a/include/chaiscript/dispatchkit/type_info.hpp b/include/chaiscript/dispatchkit/type_info.hpp index 8f2a141..26aaf8d 100644 --- a/include/chaiscript/dispatchkit/type_info.hpp +++ b/include/chaiscript/dispatchkit/type_info.hpp @@ -18,6 +18,14 @@ namespace chaiscript { + + template + struct Bare_Type + { + typedef typename boost::remove_const::type>::type>::type type; + }; + + /** * compile time deduced information about a type */ @@ -132,7 +140,7 @@ namespace chaiscript return Type_Info(boost::is_const::value, boost::is_reference::value, boost::is_pointer::value, boost::is_void::value, &typeid(T), - &typeid(typename boost::remove_const::type>::type>::type)); + &typeid(typename Bare_Type::type)); } }; @@ -144,7 +152,7 @@ namespace chaiscript return Type_Info(boost::is_const::value, boost::is_reference::value, boost::is_pointer::value, boost::is_void::value, &typeid(boost::shared_ptr ), - &typeid(typename boost::remove_const::type>::type>::type)); + &typeid(typename Bare_Type::type)); } }; @@ -156,7 +164,7 @@ namespace chaiscript return Type_Info(boost::is_const::value, boost::is_reference::value, boost::is_pointer::value, boost::is_void::value, &typeid(const boost::shared_ptr &), - &typeid(typename boost::remove_const::type>::type>::type)); + &typeid(typename Bare_Type::type)); } }; @@ -168,7 +176,7 @@ namespace chaiscript return Type_Info(boost::is_const::value, boost::is_reference::value, boost::is_pointer::value, boost::is_void::value, &typeid(boost::reference_wrapper ), - &typeid(typename boost::remove_const::type>::type>::type)); + &typeid(Bare_Type::type)); } }; }