// This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2010, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef __boxed_value_hpp__ #define __boxed_value_hpp__ #include "type_info.hpp" #include "../chaiscript_threading.hpp" #include #include #include #include #include #include #include #include #include namespace chaiscript { /** * Boxed_Value is the main tool of the dispatchkit. It allows * for boxed / untyped containment of any C++ object. It uses * boost::any internally but also provides user access the underlying * stored type information */ class Boxed_Value { public: /** * used for explicitly creating a "void" object */ struct Void_Type { }; private: /** * structure which holds the internal state of a Boxed_Value */ struct Data { template static bool is_null(boost::any *a) { boost::shared_ptr *ptr = boost::any_cast >(a); return ptr->get() == 0; } Data(const Type_Info &ti, const boost::any &to, bool tr, const boost::function &t_is_null = boost::function()) : m_type_info(ti), m_obj(to), m_is_ref(tr), m_is_null(t_is_null) { } 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_is_null = rhs.m_is_null; return *this; } ~Data() { } Type_Info m_type_info; boost::any m_obj; bool m_is_ref; boost::function m_is_null; std::vector > m_dependencies; }; struct Object_Data { static boost::shared_ptr get(Boxed_Value::Void_Type) { return boost::shared_ptr (new Data( detail::Get_Type_Info::get(), boost::any(), false) ); } template static boost::shared_ptr get(const boost::shared_ptr *obj) { return get(*obj); } template static boost::shared_ptr get(const boost::shared_ptr &obj) { return boost::shared_ptr(new Data( detail::Get_Type_Info::get(), boost::any(obj), false, boost::function(&Data::is_null)) ); } template static boost::shared_ptr get(T *t) { return get(boost::ref(*t)); } template static boost::shared_ptr get(boost::reference_wrapper obj) { return boost::shared_ptr(new Data( detail::Get_Type_Info::get(), boost::any(obj), true) ); } template static boost::shared_ptr get(const T& t) { return boost::shared_ptr(new Data( detail::Get_Type_Info::get(), boost::any(boost::shared_ptr(new T(t))), false, boost::function(&Data::is_null)) ); } static boost::shared_ptr get() { return boost::shared_ptr (new Data( Type_Info(), boost::any(), false) ); } }; public: /** * Basic Boxed_Value constructor */ template explicit Boxed_Value(T t) : m_data(Object_Data::get(t)) { } /** * Copy constructor - each copy shares the same data pointer */ Boxed_Value(const Boxed_Value &t_so) : m_data(t_so.m_data) { } /** * Unknown-type constructor */ Boxed_Value() : m_data(Object_Data::get()) { } ~Boxed_Value() { } void swap(Boxed_Value &rhs) { std::swap(m_data, rhs.m_data); } /** * copy the values stored in rhs.m_data to m_data * m_data pointers are not shared in this case */ Boxed_Value assign(const Boxed_Value &rhs) { (*m_data) = (*rhs.m_data); return *this; } /** * shared data assignment, same as copy construction */ Boxed_Value &operator=(const Boxed_Value &rhs) { Boxed_Value temp(rhs); swap(temp); return *this; } const Type_Info &get_type_info() const { return m_data->m_type_info; } /** * return true if the object is uninitialized */ bool is_undef() const { return m_data->m_type_info.is_undef(); } bool is_const() const { return m_data->m_type_info.is_const(); } bool is_type(const Type_Info &ti) const { return m_data->m_type_info.bare_equal(ti); } bool is_null() const { if (m_data->m_is_null) { return m_data->m_is_null(&m_data->m_obj); } else { return false; } } const boost::any & get() const { return m_data->m_obj; } bool is_ref() const { return m_data->m_is_ref; } bool is_pointer() const { return !is_ref(); } void clear_dependencies() { m_data->m_dependencies.clear(); } template void add_dependencies(InItr begin, const InItr &end) { while (begin != end) { if (begin->m_data != m_data) { m_data->m_dependencies.push_back(begin->m_data); } ++begin; } } private: boost::shared_ptr m_data; }; /// Clean wrapper for providing the user with a Boxed_Value /// Suggested use: chai.add(var(myvariable), "myvariable"); /// \param t The value to box template Boxed_Value var(T t) { return Boxed_Value(t); } /// Wrapper for providing the user with a Boxed_Value that is const inside /// of the ChaiScript engine. /// Suggested use: chai.add(const_var(myvariable), "myvariable"); /// \param t The value to box template Boxed_Value const_var(T *t) { return Boxed_Value( const_cast::type *>(t) ); } /// boost::shared_ptr overload for const_var template Boxed_Value const_var(const boost::shared_ptr &t) { return Boxed_Value( boost::const_pointer_cast::type>(t) ); } /// boost::reference_wrapper overload for const_var template Boxed_Value const_var(const boost::reference_wrapper &t) { return Boxed_Value( boost::cref(t.get()) ); } /// Generic overload for const_var template Boxed_Value const_var(const T &t) { return Boxed_Value(boost::shared_ptr::type >(new T(t))); } /** * Return true if the two Boxed_Values share the same internal type */ static bool type_match(Boxed_Value l, Boxed_Value r) { return l.get_type_info() == r.get_type_info(); } } #endif