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

This commit is contained in:
Jason Turner
2010-08-02 01:38:25 +00:00
parent b971ee44ad
commit edee892cad
12 changed files with 873 additions and 526 deletions

View File

@@ -8,6 +8,7 @@
#define __boxed_value_hpp__
#include "type_info.hpp"
#include "../chaiscript_threading.hpp"
#include <map>
#include <boost/shared_ptr.hpp>
@@ -18,6 +19,8 @@
#include <boost/cstdint.hpp>
#include <boost/type_traits/add_const.hpp>
#include <boost/integer_traits.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
namespace chaiscript
{
@@ -117,6 +120,7 @@ namespace chaiscript
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{
bool b_const = boost::is_const<T>::value;
const std::type_info *ti = &typeid(typename Bare_Type<T>::type);
boost::shared_ptr<Data> data(new Data(
detail::Get_Type_Info<T>::get(),
@@ -126,14 +130,14 @@ namespace chaiscript
&Data::is_null<T>)
);
std::map<std::pair<const void *, bool>, Data>::iterator itr
= m_ptrs.find(std::make_pair(obj.get(), b_const));
std::map<boost::tuple<const void *, bool, const std::type_info *>, 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<Data> get(boost::reference_wrapper<T> obj)
{
bool b_const = boost::is_const<T>::value;
const std::type_info *ti = &typeid(typename Bare_Type<T>::type);
boost::shared_ptr<Data> data(new Data(
detail::Get_Type_Info<T>::get(),
@@ -156,8 +161,8 @@ namespace chaiscript
true)
);
std::map<std::pair<const void *, bool>, Data >::iterator itr
= m_ptrs.find(std::make_pair(obj.get_pointer(), b_const) );
std::map<boost::tuple<const void *, bool, const std::type_info *>, 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<typename T>
boost::shared_ptr<Data> get(const T& t)
{
const std::type_info *ti = &typeid(typename Bare_Type<T>::type);
boost::shared_ptr<Data> data(new Data(
detail::Get_Type_Info<T>::get(),
boost::any(boost::shared_ptr<T>(new T(t))),
@@ -188,7 +195,9 @@ namespace chaiscript
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj);
m_ptrs.insert(std::make_pair(std::make_pair(ptr->get(), false), *data));
boost::tuple<const void *, bool, const std::type_info *> key(ptr->get(), false, ti);
m_ptrs.insert(std::make_pair(key, *data));
return data;
}
@@ -215,13 +224,13 @@ namespace chaiscript
}
std::map<std::pair<const void *, bool>, Data>::iterator itr = m_ptrs.begin();
std::map<boost::tuple<const void *, bool, const std::type_info *>, Data>::iterator itr = m_ptrs.begin();
while (itr != m_ptrs.end())
{
if (itr->second.m_unique(&itr->second.m_obj))
{
std::map<std::pair<const void *, bool>, Data >::iterator todel = itr;
std::map<boost::tuple<const void *, bool, const std::type_info *>, Data >::iterator todel = itr;
++itr;
m_ptrs.erase(todel);
} else {
@@ -230,7 +239,7 @@ namespace chaiscript
}
}
std::map<std::pair<const void *, bool>, Data> m_ptrs;
std::map<boost::tuple<const void *, bool, const std::type_info *>, Data> m_ptrs;
int m_cullcount;
};
@@ -357,515 +366,6 @@ namespace chaiscript
boost::shared_ptr<Data> m_data;
};
namespace detail
{
// Cast_Helper helper classes
/**
* Generic Cast_Helper, for casting to any type
*/
template<typename Result>
struct Cast_Helper
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::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<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
if (!ob.get_type_info().is_const())
{
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
}
}
};
/**
* Cast_Helper for casting to a const & type
*/
template<typename Result>
struct Cast_Helper<const Result &>
{
typedef typename boost::reference_wrapper<typename boost::add_const<Result>::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<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
if (!ob.get_type_info().is_const())
{
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
}
}
};
/**
* Cast_Helper for casting to a const * type
*/
template<typename Result>
struct Cast_Helper<const Result *>
{
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<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
}
} else {
if (!ob.get_type_info().is_const())
{
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} else {
return (boost::any_cast<boost::shared_ptr<const Result> >(ob.get())).get();
}
}
}
};
/**
* Cast_Helper for casting to a * type
*/
template<typename Result>
struct Cast_Helper<Result *>
{
typedef Result * Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
}
}
};
/**
* Cast_Helper for casting to a & type
*/
template<typename Result>
struct Cast_Helper<Result &>
{
typedef typename boost::reference_wrapper<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (ob.is_ref())
{
return boost::any_cast<boost::reference_wrapper<Result> >(ob.get());
} else {
return boost::ref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
}
}
};
/**
* Cast_Helper for casting to a boost::shared_ptr<> type
*/
template<typename Result>
struct Cast_Helper<typename boost::shared_ptr<Result> >
{
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/**
* Cast_Helper for casting to a boost::shared_ptr<const> type
*/
template<typename Result>
struct Cast_Helper<typename boost::shared_ptr<const Result> >
{
typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().is_const())
{
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
} else {
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
/**
* Cast_Helper for casting to a const boost::shared_ptr<> & type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<Result> &>
{
typedef typename boost::shared_ptr<Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return boost::any_cast<boost::shared_ptr<Result> >(ob.get());
}
};
/**
* Cast_Helper for casting to a const boost::shared_ptr<const> & type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<const Result> &>
{
typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().is_const())
{
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
} else {
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
/**
* Cast_Helper for casting to a Boxed_Value type
*/
template<>
struct Cast_Helper<Boxed_Value>
{
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<const Boxed_Value &>
{
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<int &>(boxedvalue);
*/
template<typename Type>
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv)
{
try {
return detail::Cast_Helper<Type>::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<double>(v);
m_isfloat = true;
} else if (inp_ == typeid(float)) {
d = boxed_cast<float>(v);
m_isfloat = true;
} else if (inp_ == typeid(bool)) {
i = boxed_cast<bool>(v);
} else if (inp_ == typeid(char)) {
i = boxed_cast<char>(v);
} else if (inp_ == typeid(int)) {
i = boxed_cast<int>(v);
} else if (inp_ == typeid(unsigned int)) {
i = boxed_cast<unsigned int>(v);
} else if (inp_ == typeid(long)) {
i = boxed_cast<long>(v);
} else if (inp_ == typeid(unsigned long)) {
i = boxed_cast<unsigned long>(v);
} else if (inp_ == typeid(boost::int8_t)) {
i = boxed_cast<boost::int8_t>(v);
} else if (inp_ == typeid(boost::int16_t)) {
i = boxed_cast<boost::int16_t>(v);
} else if (inp_ == typeid(boost::int32_t)) {
i = boxed_cast<boost::int32_t>(v);
} else if (inp_ == typeid(boost::int64_t)) {
i = boxed_cast<boost::int64_t>(v);
} else if (inp_ == typeid(boost::uint8_t)) {
i = boxed_cast<boost::uint8_t>(v);
} else if (inp_ == typeid(boost::uint16_t)) {
i = boxed_cast<boost::uint16_t>(v);
} else if (inp_ == typeid(boost::uint32_t)) {
i = boxed_cast<boost::uint32_t>(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<int>::const_min
|| i > boost::integer_traits<int>::const_max)
{
return Boxed_Value(i);
} else {
return Boxed_Value(static_cast<int>(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<Boxed_POD_Value>
{
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<const Boxed_POD_Value &>
{
typedef Boxed_POD_Value Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
return Boxed_POD_Value(ob);
}
};
}
template<typename T>
Boxed_Value var(T t)
{
@@ -896,6 +396,7 @@ namespace chaiscript
return Boxed_Value(boost::shared_ptr<typename boost::add_const<T>::type >(new T(t)));
}
/**
* Return true if the two Boxed_Values share the same internal type
*/
@@ -905,7 +406,5 @@ namespace chaiscript
}
}
#endif