From edee892cad57a058ab8bb287b6bd44fdf1d0b251 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Mon, 2 Aug 2010 01:38:25 +0000 Subject: [PATCH] Initial check in of support for upcasting during function invocation. No examples or tests are checked in yet. Some reorg was necessary to get things compiling in the right order. Is not currently thread safe and probably does not work properly across module boundaries --- include/chaiscript/chaiscript.hpp | 1 + .../chaiscript/dispatchkit/bad_boxed_cast.hpp | 56 ++ include/chaiscript/dispatchkit/bootstrap.hpp | 1 + include/chaiscript/dispatchkit/boxed_cast.hpp | 53 ++ .../dispatchkit/boxed_cast_helper.hpp | 252 ++++++++ .../dispatchkit/boxed_pod_value.hpp | 262 +++++++++ .../chaiscript/dispatchkit/boxed_value.hpp | 539 +----------------- .../dispatchkit/dynamic_cast_conversion.hpp | 211 +++++++ include/chaiscript/dispatchkit/operators.hpp | 2 +- .../dispatchkit/proxy_functions.hpp | 5 +- .../dispatchkit/proxy_functions_detail.hpp | 1 + include/chaiscript/dispatchkit/type_info.hpp | 16 +- 12 files changed, 873 insertions(+), 526 deletions(-) create mode 100644 include/chaiscript/dispatchkit/bad_boxed_cast.hpp create mode 100644 include/chaiscript/dispatchkit/boxed_cast.hpp create mode 100644 include/chaiscript/dispatchkit/boxed_cast_helper.hpp create mode 100644 include/chaiscript/dispatchkit/boxed_pod_value.hpp create mode 100644 include/chaiscript/dispatchkit/dynamic_cast_conversion.hpp 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)); } }; }