// 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; #pragma GCC diagnostic ignored "-Wsign-compare" template static bool go(const T &t, const U &u) { return t == u; } }; struct less_than { static const bool lhs_const = true; #pragma GCC diagnostic ignored "-Wsign-compare" template static bool go(const T &t, const U &u) { return t < u; } }; struct greater_than { static const bool lhs_const = true; #pragma GCC diagnostic ignored "-Wsign-compare" template static bool go(const T &t, const U &u) { return t > u; } }; struct greater_than_equal { static const bool lhs_const = true; #pragma GCC diagnostic ignored "-Wsign-compare" template static bool go(const T &t, const U &u) { return t >= u; } }; struct less_than_equal { static const bool lhs_const = true; #pragma GCC diagnostic ignored "-Wsign-compare" template static bool go(const T &t, const U &u) { return t <= u; } }; struct not_equal { static const bool lhs_const = true; #pragma GCC diagnostic ignored "-Wsign-compare" 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 { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t.get() = u.get())); } }; struct assign_difference { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t -= u)); } }; struct assign_bitwise_and { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t &= u)); } }; struct assign_bitwise_or { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t |= u)); } }; struct assign_bitwise_xor { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t ^= u)); } }; struct assign_remainder { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t %= u)); } }; struct assign_bitshift_left { static const bool lhs_const = false; template static Boxed_Value go(T &t, const U &u) { return var(&(t <<= u)); } }; struct assign_bitshift_right { 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 unary_plus { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U) { return const_var(+t); } }; struct bitwise_complement { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U) { return const_var(~t); } }; struct unary_minus { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U) { return const_var(-t); } }; struct bitwise_and { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t & u); } }; struct bitwise_xor { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t ^ u); } }; struct bitwise_or { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t | u); } }; struct remainder { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t % u); } }; struct left_shift { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t << u); } }; struct right_shift { static const bool lhs_const = true; template static Boxed_Value go(const T &t, const U &u) { return const_var(t >> u); } }; 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(long double)) { 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(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 if (inp_ == typeid(boost::uint64_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(long 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 if (inp_ == typeid(boost::uint64_t)) { return oper_lhs(boxed_cast::type>(l.bv), r); } else { throw boost::bad_any_cast(); } } template static Ret oper_int_lhs(L l, const Boxed_Numeric &r) { const Type_Info &inp_ = r.bv.get_type_info(); 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(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 if (inp_ == typeid(boost::uint64_t)) { return O::go(l, boxed_cast(r.bv)); } else { throw boost::bad_any_cast(); } } template static Ret oper_int(const Boxed_Numeric &l, const Boxed_Numeric &r) { const Type_Info &inp_ = l.bv.get_type_info(); if (inp_ == typeid(bool)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(char)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(int)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(unsigned int)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(long)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(unsigned long)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int8_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int16_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int32_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::int64_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::uint8_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::uint16_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::uint32_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else if (inp_ == typeid(boost::uint64_t)) { return oper_int_lhs(boxed_cast::type>(l.bv), r); } else { throw boost::bad_any_cast(); } }; public: Boxed_Numeric(const Boxed_Value &v) : bv(v) { const Type_Info &inp_ = v.get_type_info(); if (!inp_.is_arithmetic()) { throw boost::bad_any_cast(); } } bool operator==(const Boxed_Numeric &r) const { return oper(*this, r); } bool operator<(const Boxed_Numeric &r) const { return oper(*this, r); } bool operator>(const Boxed_Numeric &r) const { return oper(*this, r); } bool operator>=(const Boxed_Numeric &r) const { return oper(*this, r); } bool operator<=(const Boxed_Numeric &r) const { return oper(*this, r); } bool operator!=(const Boxed_Numeric &r) const { return oper(*this, r); } 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 { return oper(*this, Boxed_Value(0)); } Boxed_Value operator-() const { return oper(*this, Boxed_Value(0)); } Boxed_Value operator-(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator&=(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator=(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator|=(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator^=(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator%=(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator<<=(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator>>=(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator&(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator~() const { return oper_int(*this, Boxed_Value(0)); } Boxed_Value operator^(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator|(const Boxed_Numeric &r) const { return oper_int(*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 { return oper(*this, r); } Boxed_Value operator<<(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator*(const Boxed_Numeric &r) const { return oper(*this, r); } Boxed_Value operator%(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value operator>>(const Boxed_Numeric &r) const { return oper_int(*this, r); } Boxed_Value bv; }; 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