// This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2011, Jonathan Turner (jonathan@emptycrate.com) // and Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ #define CHAISCRIPT_BOXED_NUMERIC_HPP_ #include "type_info.hpp" #include "boxed_value.hpp" #include "boxed_cast_helper.hpp" #include #include #include namespace chaiscript { /// \brief Represents any numeric type, generically. Used internally for generic operations between POD values class Boxed_Numeric { private: template struct choose_const { typedef T& type; }; template struct choose_const { typedef const T& type; }; template struct lhs_type { typedef typename choose_const::type type; }; struct equals { static const bool lhs_const = true; template static bool go(const T &t, const U &u) { return t == u; } }; struct add { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t + u); } }; struct subtract { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t - u); } }; struct multiply { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t * u); } }; struct divide { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t / u); } }; struct assign_product { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t *= u)); } }; struct assign_quotient { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t /= u)); } }; struct assign_sum { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t += u)); } }; struct assign_difference { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t -= u)); } }; struct pre_increment { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U) { return var(&++t); } }; struct pre_decrement { static const bool lhs_const = false; template static Boxed_Value go(boost::reference_wrapper, const U) { std::cout<< "why where?"<< std::endl; throw boost::bad_any_cast(); } template static Boxed_Value go(T &t, const U) { return var(&--t); } }; template static Ret oper_lhs(L l, const Boxed_Numeric &r) { const Type_Info &inp_ = r.bv.get_type_info(); if (inp_ == typeid(double)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(float)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(bool)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(char)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(int)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(unsigned int)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(long)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(unsigned long)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(boost::int8_t)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(boost::int16_t)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(boost::int32_t)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(boost::int64_t)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(boost::uint8_t)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(boost::uint16_t)) { return O::go(l, boxed_cast(r.bv)); } else if (inp_ == typeid(boost::uint32_t)) { return O::go(l, boxed_cast(r.bv)); } else { throw boost::bad_any_cast(); } } template static Ret oper(const Boxed_Numeric &l, const Boxed_Numeric &r) { const Type_Info &inp_ = l.bv.get_type_info(); if (inp_ == typeid(double)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(float)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(bool)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(char)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(int)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(unsigned int)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(long)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(unsigned long)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int8_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int16_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int32_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int64_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::uint8_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::uint16_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::uint32_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else { throw boost::bad_any_cast(); } }; public: Boxed_Numeric(const Boxed_Value &v) : bv(v), d(0), i(0), isfloat(false) { const Type_Info &inp_ = v.get_type_info(); if (!inp_.is_arithmetic()) { throw boost::bad_any_cast(); } if (inp_ == typeid(double)) { d = boxed_cast(v); isfloat = true; } else if (inp_ == typeid(float)) { d = boxed_cast(v); 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_Numeric &r) const { return oper(*this, r); } bool operator<(const Boxed_Numeric &r) const { return ((isfloat)?d:i) < ((r.isfloat)?r.d:r.i); } bool operator>(const Boxed_Numeric &r) const { return ((isfloat)?d:i) > ((r.isfloat)?r.d:r.i); } bool operator>=(const Boxed_Numeric &r) const { return ((isfloat)?d:i) >= ((r.isfloat)?r.d:r.i); } bool operator<=(const Boxed_Numeric &r) const { return ((isfloat)?d:i) <= ((r.isfloat)?r.d:r.i); } bool operator!=(const Boxed_Numeric &r) const { return ((isfloat)?d:i) != ((r.isfloat)?r.d:r.i); } Boxed_Value operator--() const { return oper(*this, var(0)); } Boxed_Value operator++() const { return oper(*this, var(0)); } Boxed_Value operator+(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator-(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator&(const Boxed_Numeric &r) const { if (!isfloat && !r.isfloat) { return Boxed_Value(i & r.i); } throw exception::bad_boxed_cast("& only valid for integer types"); } Boxed_Value operator^(const Boxed_Numeric &r) const { if (!isfloat && !r.isfloat) { return Boxed_Value(i ^ r.i); } throw exception::bad_boxed_cast("^ only valid for integer types"); } Boxed_Value operator|(const Boxed_Numeric &r) const { if (!isfloat && !r.isfloat) { return Boxed_Value(i | r.i); } throw exception::bad_boxed_cast("| only valid for integer types"); } Boxed_Value operator*=(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator/=(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator+=(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator-=(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator/(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator<<(const Boxed_Numeric &r) const { if (!isfloat && !r.isfloat) { return smart_size(i << r.i); } throw exception::bad_boxed_cast("<< only valid for integer types"); } Boxed_Value operator*(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator%(const Boxed_Numeric &r) const { if (!isfloat && !r.isfloat) { return smart_size(i % r.i); } throw exception::bad_boxed_cast("% only valid for integer types"); } Boxed_Value operator>>(const Boxed_Numeric &r) const { if (!isfloat && !r.isfloat) { return smart_size(i >> r.i); } throw exception::bad_boxed_cast(">> only valid for integer types"); } Boxed_Value smart_size(boost::int64_t t_i) const { if (t_i < boost::integer_traits::const_min || t_i > boost::integer_traits::const_max) { return Boxed_Value(t_i); } else { return Boxed_Value(static_cast(t_i)); } } Boxed_Value bv; double d; boost::int64_t i; bool isfloat; }; namespace detail { /** * Cast_Helper for converting from Boxed_Value to Boxed_Numeric */ template<> struct Cast_Helper { typedef Boxed_Numeric Result_Type; static Result_Type cast(const Boxed_Value &ob) { return Boxed_Numeric(ob); } }; /** * Cast_Helper for converting from Boxed_Value to Boxed_Numeric */ template<> struct Cast_Helper : Cast_Helper { }; /** * Cast_Helper for converting from Boxed_Value to Boxed_Numeric */ template<> struct Cast_Helper : Cast_Helper { }; } } #endif