#ifndef __boxed_value_hpp__ #define __boxed_value_hpp__ #include "type_info.hpp" #include #include #include #include #include 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)) { } Boxed_Value(const Boxed_Value &t_so) : m_data(t_so.m_data) { } Boxed_Value() : m_data(get_object_cache().get()) { } ~Boxed_Value() { get_object_cache().cull(); } 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 { typename boost::reference_wrapper::type > operator()(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 { typename boost::reference_wrapper::type > operator()(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 { const Result *operator()(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 { Result *operator()(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 { typename boost::reference_wrapper operator()(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 > { typename boost::shared_ptr operator()(Boxed_Value ob) { return boost::any_cast >(ob.get()); } }; template<> struct Cast_Helper { Boxed_Value operator()(Boxed_Value ob) { return ob; } }; struct Boxed_POD_Value { Boxed_POD_Value(const Boxed_Value &v) : d(0), i(0), m_isfloat(false) { const int inp_ = int(v.get_type_info().m_type_info); const int char_ = int(&typeid(char)); const int bool_ = int(&typeid(bool)); const int double_ = int(&typeid(double)); const int float_ = int(&typeid(float)); const int long_ = int(&typeid(long)); const int unsigned_long_ = int(&typeid(unsigned long)); const int int_ = int(&typeid(int)); const int unsigned_int_ = int(&typeid(unsigned int)); const int uint8_t_ = int(&typeid(uint8_t)); const int uint16_t_ = int(&typeid(uint16_t)); const int uint32_t_ = int(&typeid(uint32_t)); // const int uint64_t_ = int(&typeid(uint64_t)); const int int8_t_ = int(&typeid(int8_t)); const int int16_t_ = int(&typeid(int16_t)); const int int32_t_ = int(&typeid(int32_t)); const int int64_t_ = int(&typeid(int64_t)); if (inp_ == double_) { d = Cast_Helper()(v); m_isfloat = true; } else if (inp_ == float_) { d = Cast_Helper()(v); m_isfloat = true; } else if (inp_ == bool_ ) { i = Cast_Helper()(v); } else if (inp_ == char_) { i = Cast_Helper()(v); } else if (inp_ == int_) { i = Cast_Helper()(v); } else if (inp_ == unsigned_int_) { i = Cast_Helper()(v); } else if (inp_ == long_) { i = Cast_Helper()(v); } else if (inp_ == unsigned_long_) { i = Cast_Helper()(v); } else if (inp_ == int8_t_) { i = Cast_Helper()(v); } else if (inp_ == int16_t_) { i = Cast_Helper()(v); } else if (inp_ == int32_t_) { i = Cast_Helper()(v); } else if (inp_ == int64_t_) { i = Cast_Helper()(v); } else if (inp_ == uint8_t_) { i = Cast_Helper()(v); } else if (inp_ == uint16_t_) { i = Cast_Helper()(v); } else if (inp_ == uint32_t_) { i = Cast_Helper()(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 { Boxed_POD_Value operator()(Boxed_Value ob) { return Boxed_POD_Value(ob); } }; #endif