#ifndef __boxed_value_hpp__ #define __boxed_value_hpp__ #include "type_info.hpp" #include #include #include #include #include #include #include namespace dispatchkit { class Boxed_Value { public: struct Void_Type { }; private: struct Data { struct Shared_Ptr_Proxy { virtual ~Shared_Ptr_Proxy() { } virtual bool unique(boost::any *) = 0; virtual long use_count(boost::any *) = 0; }; template struct Shared_Ptr_Proxy_Impl : Shared_Ptr_Proxy { virtual ~Shared_Ptr_Proxy_Impl() { } virtual bool unique(boost::any *a) { boost::shared_ptr *ptr = boost::any_cast >(a); return ptr->unique(); } virtual long use_count(boost::any *a) { boost::shared_ptr *ptr = boost::any_cast >(a); return ptr->use_count(); } }; Data(const Type_Info &ti, const boost::any &to, bool tr, const boost::shared_ptr &t_proxy = boost::shared_ptr()) : m_type_info(ti), m_obj(to), m_is_ref(tr), m_ptr_proxy(t_proxy) { } Data &operator=(const Data &rhs) { m_type_info = rhs.m_type_info; m_obj = rhs.m_obj; m_is_ref = rhs.m_is_ref; m_ptr_proxy = rhs.m_ptr_proxy; return *this; } static bool get_false() { return false; } Type_Info m_type_info; boost::any m_obj; bool m_is_ref; boost::shared_ptr m_ptr_proxy; }; struct Object_Cache { boost::shared_ptr get(Boxed_Value::Void_Type) { return boost::shared_ptr (new Data( Get_Type_Info::get(), boost::any(), false) ); } template boost::shared_ptr get(boost::shared_ptr obj) { boost::shared_ptr data(new Data( Get_Type_Info::get(), boost::any(obj), false, boost::shared_ptr(new Data::Shared_Ptr_Proxy_Impl())) ); std::map::iterator itr = m_ptrs.find(obj.get()); if (itr != m_ptrs.end()) { (*data) = (itr->second); } else { m_ptrs.insert(std::make_pair(obj.get(), *data)); } return data; } template boost::shared_ptr get(boost::reference_wrapper obj) { boost::shared_ptr data(new Data( Get_Type_Info::get(), boost::any(obj), true) ); std::map::iterator itr = m_ptrs.find(obj.get_pointer()); if (itr != m_ptrs.end()) { // std::cout << "Reference wrapper ptr found, using it" << std::endl; (*data) = (itr->second); } return data; } template boost::shared_ptr get(const T& t) { boost::shared_ptr data(new Data( Get_Type_Info::get(), boost::any(boost::shared_ptr(new T(t))), false, boost::shared_ptr(new Data::Shared_Ptr_Proxy_Impl())) ); boost::shared_ptr *ptr = boost::any_cast >(&data->m_obj); m_ptrs.insert(std::make_pair(ptr->get(), *data)); return data; } boost::shared_ptr get() { return boost::shared_ptr (new Data( Type_Info(), boost::any(), false) ); } void cull() { std::map::iterator itr = m_ptrs.begin(); while (itr != m_ptrs.end()) { if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1) { std::map::iterator todel = itr; // std::cout << "Releasing unique ptr " << std::endl; ++itr; m_ptrs.erase(todel); } else { ++itr; } } // std::cout << "References held: " << m_ptrs.size() << std::endl; } std::map m_ptrs; }; public: template explicit Boxed_Value(T t) : m_data(get_object_cache().get(t)) { get_object_cache().cull(); } Boxed_Value(const Boxed_Value &t_so) : m_data(t_so.m_data) { } Boxed_Value() : m_data(get_object_cache().get()) { } ~Boxed_Value() { } Object_Cache &get_object_cache() { static Object_Cache oc; return oc; } Boxed_Value assign(const Boxed_Value &rhs) { (*m_data) = (*rhs.m_data); return *this; } Boxed_Value &operator=(const Boxed_Value &rhs) { m_data = rhs.m_data; return *this; } const Type_Info &get_type_info() const { return m_data->m_type_info; } bool is_unknown() const { return m_data->m_type_info.m_is_unknown; } boost::any get() const { return m_data->m_obj; } bool is_ref() const { return m_data->m_is_ref; } private: boost::shared_ptr m_data; }; //cast_help specializations template struct Cast_Helper { typedef typename boost::reference_wrapper::type > Result_Type; static Result_Type cast(const Boxed_Value &ob) { if (ob.is_ref()) { return boost::cref((boost::any_cast >(ob.get())).get()); } else { return boost::cref(*(boost::any_cast >(ob.get()))); } } }; template struct Cast_Helper { typedef typename boost::reference_wrapper::type > Result_Type; static Result_Type cast(const Boxed_Value &ob) { if (ob.is_ref()) { return boost::cref((boost::any_cast >(ob.get())).get()); } else { return boost::cref(*(boost::any_cast >(ob.get()))); } } }; template struct Cast_Helper { typedef const 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(); } } }; 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(); } } }; 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()))); } } }; 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()); } }; template<> struct Cast_Helper { typedef Boxed_Value Result_Type; static Result_Type cast(const Boxed_Value &ob) { return ob; } }; 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.m_type_info), 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(); } const std::type_info *from; const std::type_info *to; private: std::string m_what; }; template typename Cast_Helper::Result_Type boxed_cast(const Boxed_Value &bv) { try { return Cast_Helper::cast(bv); } catch (const boost::bad_any_cast &) { throw bad_boxed_cast(bv.get_type_info(), typeid(Type)); } } struct Boxed_POD_Value { Boxed_POD_Value(const Boxed_Value &v) : d(0), i(0), m_isfloat(false) { if (!v.get_type_info().m_type_info) { throw boost::bad_any_cast(); } const std::type_info &inp_ = *v.get_type_info().m_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(int8_t)) { i = boxed_cast(v); } else if (inp_ == typeid(int16_t)) { i = boxed_cast(v); } else if (inp_ == typeid(int32_t)) { i = boxed_cast(v); } else if (inp_ == typeid(int64_t)) { i = boxed_cast(v); } else if (inp_ == typeid(uint8_t)) { i = boxed_cast(v); } else if (inp_ == typeid(uint16_t)) { i = boxed_cast(v); } else if (inp_ == typeid(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 Boxed_Value(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); } 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); } 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); } return Boxed_Value(((m_isfloat)?d:i) - ((r.m_isfloat)?r.d:r.i)); } double d; int64_t i; bool m_isfloat; }; template<> struct Cast_Helper { typedef Boxed_POD_Value Result_Type; static Result_Type cast(const Boxed_Value &ob) { return Boxed_POD_Value(ob); } }; } #endif