1 // This file is distributed under the BSD License. 2 // See "license.txt" for details. 3 // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) 4 // Copyright 2009-2017, Jason Turner (jason@emptycrate.com) 5 // http://www.chaiscript.com 6 7 // This is an open source non-commercial project. Dear PVS-Studio, please check it. 8 // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com 9 10 #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ 11 #define CHAISCRIPT_BOXED_NUMERIC_HPP_ 12 13 #include <cstdint> 14 #include <sstream> 15 #include <string> 16 17 #include "../language/chaiscript_algebraic.hpp" 18 #include "any.hpp" 19 #include "boxed_cast.hpp" 20 #include "boxed_cast_helper.hpp" 21 #include "boxed_value.hpp" 22 #include "type_info.hpp" 23 24 namespace chaiscript { 25 class Type_Conversions; 26 } // namespace chaiscript 27 28 namespace chaiscript 29 { 30 namespace exception 31 { 32 struct arithmetic_error : std::runtime_error 33 { arithmetic_errorchaiscript::exception::arithmetic_error34 explicit arithmetic_error(const std::string& reason) : std::runtime_error("Arithmetic error: " + reason) {} 35 arithmetic_error(const arithmetic_error &) = default; 36 ~arithmetic_error() noexcept override = default; 37 }; 38 } 39 } 40 41 namespace chaiscript 42 { 43 44 // Due to the nature of generating every possible arithmetic operation, there 45 // are going to be warnings generated on every platform regarding size and sign, 46 // this is OK, so we're disabling size/and sign type warnings 47 #ifdef CHAISCRIPT_MSVC 48 #pragma warning(push) 49 #pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242) 50 #endif 51 52 53 #ifdef __GNUC__ 54 #pragma GCC diagnostic push 55 #pragma GCC diagnostic ignored "-Wunknown-pragmas" 56 #pragma GCC diagnostic ignored "-Wpragmas" 57 #pragma GCC diagnostic ignored "-Wsign-compare" 58 #pragma GCC diagnostic ignored "-Wfloat-equal" 59 #pragma GCC diagnostic ignored "-Wconversion" 60 #pragma GCC diagnostic ignored "-Wsign-conversion" 61 #pragma GCC diagnostic ignored "-Wfloat-conversion" 62 #endif 63 64 /// \brief Represents any numeric type, generically. Used internally for generic operations between POD values 65 class Boxed_Number 66 { 67 private: 68 enum class Common_Types { 69 t_int32, 70 t_double, 71 t_uint8, 72 t_int8, 73 t_uint16, 74 t_int16, 75 t_uint32, 76 t_uint64, 77 t_int64, 78 t_float, 79 t_long_double 80 }; 81 82 template<typename T> check_divide_by_zero(T t,typename std::enable_if<std::is_integral<T>::value>::type * =nullptr)83 static inline void check_divide_by_zero(T t, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr) 84 { 85 #ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO 86 if (t == 0) { 87 throw chaiscript::exception::arithmetic_error("divide by zero"); 88 } 89 #endif 90 } 91 92 template<typename T> check_divide_by_zero(T,typename std::enable_if<std::is_floating_point<T>::value>::type * =nullptr)93 static inline void check_divide_by_zero(T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr) 94 { 95 } 96 get_common_type(size_t t_size,bool t_signed)97 static constexpr Common_Types get_common_type(size_t t_size, bool t_signed) 98 { 99 return (t_size == 1 && t_signed)?(Common_Types::t_int8) 100 :(t_size == 1)?(Common_Types::t_uint8) 101 :(t_size == 2 && t_signed)?(Common_Types::t_int16) 102 :(t_size == 2)?(Common_Types::t_uint16) 103 :(t_size == 4 && t_signed)?(Common_Types::t_int32) 104 :(t_size == 4)?(Common_Types::t_uint32) 105 :(t_size == 8 && t_signed)?(Common_Types::t_int64) 106 :(Common_Types::t_uint64); 107 } 108 109 get_common_type(const Boxed_Value & t_bv)110 static Common_Types get_common_type(const Boxed_Value &t_bv) 111 { 112 const Type_Info &inp_ = t_bv.get_type_info(); 113 114 if (inp_ == typeid(int)) { 115 return get_common_type(sizeof(int), true); 116 } else if (inp_ == typeid(double)) { 117 return Common_Types::t_double; 118 } else if (inp_ == typeid(long double)) { 119 return Common_Types::t_long_double; 120 } else if (inp_ == typeid(float)) { 121 return Common_Types::t_float; 122 } else if (inp_ == typeid(char)) { 123 return get_common_type(sizeof(char), std::is_signed<char>::value); 124 } else if (inp_ == typeid(unsigned char)) { 125 return get_common_type(sizeof(unsigned char), false); 126 } else if (inp_ == typeid(unsigned int)) { 127 return get_common_type(sizeof(unsigned int), false); 128 } else if (inp_ == typeid(long)) { 129 return get_common_type(sizeof(long), true); 130 } else if (inp_ == typeid(long long)) { 131 return get_common_type(sizeof(long long), true); 132 } else if (inp_ == typeid(unsigned long)) { 133 return get_common_type(sizeof(unsigned long), false); 134 } else if (inp_ == typeid(unsigned long long)) { 135 return get_common_type(sizeof(unsigned long long), false); 136 } else if (inp_ == typeid(std::int8_t)) { 137 return Common_Types::t_int8; 138 } else if (inp_ == typeid(std::int16_t)) { 139 return Common_Types::t_int16; 140 } else if (inp_ == typeid(std::int32_t)) { 141 return Common_Types::t_int32; 142 } else if (inp_ == typeid(std::int64_t)) { 143 return Common_Types::t_int64; 144 } else if (inp_ == typeid(std::uint8_t)) { 145 return Common_Types::t_uint8; 146 } else if (inp_ == typeid(std::uint16_t)) { 147 return Common_Types::t_uint16; 148 } else if (inp_ == typeid(std::uint32_t)) { 149 return Common_Types::t_uint32; 150 } else if (inp_ == typeid(std::uint64_t)) { 151 return Common_Types::t_uint64; 152 } else if (inp_ == typeid(wchar_t)) { 153 return get_common_type(sizeof(wchar_t), std::is_signed<wchar_t>::value); 154 } else if (inp_ == typeid(char16_t)) { 155 return get_common_type(sizeof(char16_t), std::is_signed<char16_t>::value); 156 } else if (inp_ == typeid(char32_t)) { 157 return get_common_type(sizeof(char32_t), std::is_signed<char32_t>::value); 158 } else { 159 throw chaiscript::detail::exception::bad_any_cast(); 160 } 161 } 162 163 template<typename T> boolean_go(Operators::Opers t_oper,const T & t,const T & u)164 static Boxed_Value boolean_go(Operators::Opers t_oper, const T &t, const T &u) 165 { 166 switch (t_oper) 167 { 168 case Operators::Opers::equals: 169 return const_var(t == u); 170 case Operators::Opers::less_than: 171 return const_var(t < u); 172 case Operators::Opers::greater_than: 173 return const_var(t > u); 174 case Operators::Opers::less_than_equal: 175 return const_var(t <= u); 176 case Operators::Opers::greater_than_equal: 177 return const_var(t >= u); 178 case Operators::Opers::not_equal: 179 return const_var(t != u); 180 default: 181 throw chaiscript::detail::exception::bad_any_cast(); 182 } 183 } 184 185 template<typename T> unary_go(Operators::Opers t_oper,T & t,const Boxed_Value & t_lhs)186 static Boxed_Value unary_go(Operators::Opers t_oper, T &t, const Boxed_Value &t_lhs) 187 { 188 switch (t_oper) 189 { 190 case Operators::Opers::pre_increment: 191 ++t; 192 break; 193 case Operators::Opers::pre_decrement: 194 --t; 195 break; 196 default: 197 throw chaiscript::detail::exception::bad_any_cast(); 198 } 199 200 return t_lhs; 201 } 202 203 template<typename T, typename U> binary_go(Operators::Opers t_oper,T & t,const U & u,const Boxed_Value & t_lhs)204 static Boxed_Value binary_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) 205 { 206 switch (t_oper) 207 { 208 case Operators::Opers::assign: 209 t = u; 210 break; 211 case Operators::Opers::assign_product: 212 t *= u; 213 break; 214 case Operators::Opers::assign_sum: 215 t += u; 216 break; 217 case Operators::Opers::assign_quotient: 218 check_divide_by_zero(u); 219 t /= u; 220 break; 221 case Operators::Opers::assign_difference: 222 t -= u; 223 break; 224 default: 225 throw chaiscript::detail::exception::bad_any_cast(); 226 } 227 228 return t_lhs; 229 } 230 231 template<typename T, typename U> binary_int_go(Operators::Opers t_oper,T & t,const U & u,const Boxed_Value & t_lhs)232 static Boxed_Value binary_int_go(Operators::Opers t_oper, T &t, const U &u, const Boxed_Value &t_lhs) 233 { 234 switch (t_oper) 235 { 236 case Operators::Opers::assign_bitwise_and: 237 t &= u; 238 break; 239 case Operators::Opers::assign_bitwise_or: 240 t |= u; 241 break; 242 case Operators::Opers::assign_shift_left: 243 t <<= u; 244 break; 245 case Operators::Opers::assign_shift_right: 246 t >>= u; 247 break; 248 case Operators::Opers::assign_remainder: 249 check_divide_by_zero(u); 250 t %= u; 251 break; 252 case Operators::Opers::assign_bitwise_xor: 253 t ^= u; 254 break; 255 default: 256 throw chaiscript::detail::exception::bad_any_cast(); 257 } 258 return t_lhs; 259 } 260 261 template<typename T> const_unary_int_go(Operators::Opers t_oper,const T & t)262 static Boxed_Value const_unary_int_go(Operators::Opers t_oper, const T &t) 263 { 264 switch (t_oper) 265 { 266 case Operators::Opers::bitwise_complement: 267 return const_var(~t); 268 default: 269 throw chaiscript::detail::exception::bad_any_cast(); 270 } 271 } 272 273 template<typename T> const_binary_int_go(Operators::Opers t_oper,const T & t,const T & u)274 static Boxed_Value const_binary_int_go(Operators::Opers t_oper, const T &t, const T &u) 275 { 276 switch (t_oper) 277 { 278 case Operators::Opers::shift_left: 279 return const_var(t << u); 280 case Operators::Opers::shift_right: 281 return const_var(t >> u); 282 case Operators::Opers::remainder: 283 check_divide_by_zero(u); 284 return const_var(t % u); 285 case Operators::Opers::bitwise_and: 286 return const_var(t & u); 287 case Operators::Opers::bitwise_or: 288 return const_var(t | u); 289 case Operators::Opers::bitwise_xor: 290 return const_var(t ^ u); 291 default: 292 throw chaiscript::detail::exception::bad_any_cast(); 293 } 294 } 295 296 template<typename T> const_unary_go(Operators::Opers t_oper,const T & t)297 static Boxed_Value const_unary_go(Operators::Opers t_oper, const T &t) 298 { 299 switch (t_oper) 300 { 301 case Operators::Opers::unary_minus: 302 return const_var(-t); 303 case Operators::Opers::unary_plus: 304 return const_var(+t); 305 default: 306 throw chaiscript::detail::exception::bad_any_cast(); 307 } 308 } 309 310 template<typename T> const_binary_go(Operators::Opers t_oper,const T & t,const T & u)311 static Boxed_Value const_binary_go(Operators::Opers t_oper, const T &t, const T &u) 312 { 313 switch (t_oper) 314 { 315 case Operators::Opers::sum: 316 return const_var(t + u); 317 case Operators::Opers::quotient: 318 check_divide_by_zero(u); 319 return const_var(t / u); 320 case Operators::Opers::product: 321 return const_var(t * u); 322 case Operators::Opers::difference: 323 return const_var(t - u); 324 default: 325 throw chaiscript::detail::exception::bad_any_cast(); 326 } 327 } 328 329 template<typename LHS, typename RHS> go(Operators::Opers t_oper,const Boxed_Value & t_lhs,const Boxed_Value & t_rhs)330 static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) 331 -> typename std::enable_if<!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value, Boxed_Value>::type 332 { 333 typedef typename std::common_type<LHS, RHS>::type common_type; 334 if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag) 335 { 336 return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); 337 } else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { 338 return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs); 339 } else if (t_oper > Operators::Opers::non_const_int_flag && t_oper < Operators::Opers::const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { 340 return binary_int_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs); 341 } else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) { 342 return const_binary_int_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); 343 } else if (t_oper > Operators::Opers::const_flag) { 344 return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); 345 } else { 346 throw chaiscript::detail::exception::bad_any_cast(); 347 } 348 } 349 350 template<typename LHS, typename RHS> go(Operators::Opers t_oper,const Boxed_Value & t_lhs,const Boxed_Value & t_rhs)351 static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) 352 -> typename std::enable_if<std::is_floating_point<LHS>::value || std::is_floating_point<RHS>::value, Boxed_Value>::type 353 { 354 typedef typename std::common_type<LHS, RHS>::type common_type; 355 if (t_oper > Operators::Opers::boolean_flag && t_oper < Operators::Opers::non_const_flag) 356 { 357 return boolean_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); 358 } else if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { 359 return binary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), get_as_aux<common_type, RHS>(t_rhs), t_lhs); 360 } else if (t_oper > Operators::Opers::const_flag) { 361 return const_binary_go(t_oper, get_as_aux<common_type, LHS>(t_lhs), get_as_aux<common_type, RHS>(t_rhs)); 362 } else { 363 throw chaiscript::detail::exception::bad_any_cast(); 364 } 365 } 366 367 // Unary 368 template<typename LHS> go(Operators::Opers t_oper,const Boxed_Value & t_lhs)369 static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) 370 -> typename std::enable_if<!std::is_floating_point<LHS>::value, Boxed_Value>::type 371 { 372 if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { 373 return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs); 374 } else if (t_oper > Operators::Opers::const_int_flag && t_oper < Operators::Opers::const_flag) { 375 return const_unary_int_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr())); 376 } else if (t_oper > Operators::Opers::const_flag) { 377 return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr())); 378 } else { 379 throw chaiscript::detail::exception::bad_any_cast(); 380 } 381 } 382 383 template<typename LHS> go(Operators::Opers t_oper,const Boxed_Value & t_lhs)384 static auto go(Operators::Opers t_oper, const Boxed_Value &t_lhs) 385 -> typename std::enable_if<std::is_floating_point<LHS>::value, Boxed_Value>::type 386 { 387 if (t_oper > Operators::Opers::non_const_flag && t_oper < Operators::Opers::non_const_int_flag && !t_lhs.is_const() && !t_lhs.is_return_value()) { 388 return unary_go(t_oper, *static_cast<LHS *>(t_lhs.get_ptr()), t_lhs); 389 } else if (t_oper > Operators::Opers::const_flag) { 390 return const_unary_go(t_oper, *static_cast<const LHS *>(t_lhs.get_const_ptr())); 391 } else { 392 throw chaiscript::detail::exception::bad_any_cast(); 393 } 394 } 395 396 template<typename LHS> oper_rhs(Operators::Opers t_oper,const Boxed_Value & t_lhs,const Boxed_Value & t_rhs)397 inline static Boxed_Value oper_rhs(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) 398 { 399 switch (get_common_type(t_rhs)) { 400 case Common_Types::t_int32: 401 return go<LHS, int32_t>(t_oper, t_lhs, t_rhs); 402 case Common_Types::t_uint8: 403 return go<LHS, uint8_t>(t_oper, t_lhs, t_rhs); 404 case Common_Types::t_int8: 405 return go<LHS, int8_t>(t_oper, t_lhs, t_rhs); 406 case Common_Types::t_uint16: 407 return go<LHS, uint16_t>(t_oper, t_lhs, t_rhs); 408 case Common_Types::t_int16: 409 return go<LHS, int16_t>(t_oper, t_lhs, t_rhs); 410 case Common_Types::t_uint32: 411 return go<LHS, uint32_t>(t_oper, t_lhs, t_rhs); 412 case Common_Types::t_uint64: 413 return go<LHS, uint64_t>(t_oper, t_lhs, t_rhs); 414 case Common_Types::t_int64: 415 return go<LHS, int64_t>(t_oper, t_lhs, t_rhs); 416 case Common_Types::t_double: 417 return go<LHS, double>(t_oper, t_lhs, t_rhs); 418 case Common_Types::t_float: 419 return go<LHS, float>(t_oper, t_lhs, t_rhs); 420 case Common_Types::t_long_double: 421 return go<LHS, long double>(t_oper, t_lhs, t_rhs); 422 } 423 424 throw chaiscript::detail::exception::bad_any_cast(); 425 } 426 oper(Operators::Opers t_oper,const Boxed_Value & t_lhs)427 inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) 428 { 429 switch (get_common_type(t_lhs)) { 430 case Common_Types::t_int32: 431 return go<int32_t>(t_oper, t_lhs); 432 case Common_Types::t_uint8: 433 return go<uint8_t>(t_oper, t_lhs); 434 case Common_Types::t_int8: 435 return go<int8_t>(t_oper, t_lhs); 436 case Common_Types::t_uint16: 437 return go<uint16_t>(t_oper, t_lhs); 438 case Common_Types::t_int16: 439 return go<int16_t>(t_oper, t_lhs); 440 case Common_Types::t_uint32: 441 return go<uint32_t>(t_oper, t_lhs); 442 case Common_Types::t_uint64: 443 return go<uint64_t>(t_oper, t_lhs); 444 case Common_Types::t_int64: 445 return go<int64_t>(t_oper, t_lhs); 446 case Common_Types::t_double: 447 return go<double>(t_oper, t_lhs); 448 case Common_Types::t_float: 449 return go<float>(t_oper, t_lhs); 450 case Common_Types::t_long_double: 451 return go<long double>(t_oper, t_lhs); 452 } 453 454 throw chaiscript::detail::exception::bad_any_cast(); 455 } 456 457 oper(Operators::Opers t_oper,const Boxed_Value & t_lhs,const Boxed_Value & t_rhs)458 inline static Boxed_Value oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) 459 { 460 switch (get_common_type(t_lhs)) { 461 case Common_Types::t_int32: 462 return oper_rhs<int32_t>(t_oper, t_lhs, t_rhs); 463 case Common_Types::t_uint8: 464 return oper_rhs<uint8_t>(t_oper, t_lhs, t_rhs); 465 case Common_Types::t_int8: 466 return oper_rhs<int8_t>(t_oper, t_lhs, t_rhs); 467 case Common_Types::t_uint16: 468 return oper_rhs<uint16_t>(t_oper, t_lhs, t_rhs); 469 case Common_Types::t_int16: 470 return oper_rhs<int16_t>(t_oper, t_lhs, t_rhs); 471 case Common_Types::t_uint32: 472 return oper_rhs<uint32_t>(t_oper, t_lhs, t_rhs); 473 case Common_Types::t_uint64: 474 return oper_rhs<uint64_t>(t_oper, t_lhs, t_rhs); 475 case Common_Types::t_int64: 476 return oper_rhs<int64_t>(t_oper, t_lhs, t_rhs); 477 case Common_Types::t_double: 478 return oper_rhs<double>(t_oper, t_lhs, t_rhs); 479 case Common_Types::t_float: 480 return oper_rhs<float>(t_oper, t_lhs, t_rhs); 481 case Common_Types::t_long_double: 482 return oper_rhs<long double>(t_oper, t_lhs, t_rhs); 483 } 484 485 throw chaiscript::detail::exception::bad_any_cast(); 486 } 487 488 template<typename Target, typename Source> get_as_aux(const Boxed_Value & t_bv)489 static inline Target get_as_aux(const Boxed_Value &t_bv) 490 { 491 return static_cast<Target>(*static_cast<const Source *>(t_bv.get_const_ptr())); 492 } 493 494 template<typename Source> to_string_aux(const Boxed_Value & v)495 static std::string to_string_aux(const Boxed_Value &v) 496 { 497 std::ostringstream oss; 498 oss << *static_cast<const Source *>(v.get_const_ptr()); 499 return oss.str(); 500 } 501 502 public: Boxed_Number()503 Boxed_Number() 504 : bv(Boxed_Value(0)) 505 { 506 } 507 Boxed_Number(Boxed_Value v)508 explicit Boxed_Number(Boxed_Value v) 509 : bv(std::move(v)) 510 { 511 validate_boxed_number(bv); 512 } 513 514 Boxed_Number(const Boxed_Number &) = default; 515 Boxed_Number(Boxed_Number &&) = default; 516 Boxed_Number& operator=(Boxed_Number &&) = default; 517 Boxed_Number(T t)518 template<typename T> explicit Boxed_Number(T t) 519 : bv(Boxed_Value(t)) 520 { 521 validate_boxed_number(bv); 522 } 523 clone(const Boxed_Value & t_bv)524 static Boxed_Value clone(const Boxed_Value &t_bv) { 525 return Boxed_Number(t_bv).get_as(t_bv.get_type_info()).bv; 526 } 527 is_floating_point(const Boxed_Value & t_bv)528 static bool is_floating_point(const Boxed_Value &t_bv) 529 { 530 const Type_Info &inp_ = t_bv.get_type_info(); 531 532 if (inp_ == typeid(double)) { 533 return true; 534 } else if (inp_ == typeid(long double)) { 535 return true; 536 } else if (inp_ == typeid(float)) { 537 return true; 538 } else { 539 return false; 540 } 541 } 542 get_as(const Type_Info & inp_) const543 Boxed_Number get_as(const Type_Info &inp_) const 544 { 545 if (inp_.bare_equal_type_info(typeid(int))) { 546 return Boxed_Number(get_as<int>()); 547 } else if (inp_.bare_equal_type_info(typeid(double))) { 548 return Boxed_Number(get_as<double>()); 549 } else if (inp_.bare_equal_type_info(typeid(float))) { 550 return Boxed_Number(get_as<float>()); 551 } else if (inp_.bare_equal_type_info(typeid(long double))) { 552 return Boxed_Number(get_as<long double>()); 553 } else if (inp_.bare_equal_type_info(typeid(char))) { 554 return Boxed_Number(get_as<char>()); 555 } else if (inp_.bare_equal_type_info(typeid(unsigned char))) { 556 return Boxed_Number(get_as<unsigned char>()); 557 } else if (inp_.bare_equal_type_info(typeid(wchar_t))) { 558 return Boxed_Number(get_as<wchar_t>()); 559 } else if (inp_.bare_equal_type_info(typeid(char16_t))) { 560 return Boxed_Number(get_as<char16_t>()); 561 } else if (inp_.bare_equal_type_info(typeid(char32_t))) { 562 return Boxed_Number(get_as<char32_t>()); 563 } else if (inp_.bare_equal_type_info(typeid(unsigned int))) { 564 return Boxed_Number(get_as<unsigned int>()); 565 } else if (inp_.bare_equal_type_info(typeid(long))) { 566 return Boxed_Number(get_as<long>()); 567 } else if (inp_.bare_equal_type_info(typeid(long long))) { 568 return Boxed_Number(get_as<long long>()); 569 } else if (inp_.bare_equal_type_info(typeid(unsigned long))) { 570 return Boxed_Number(get_as<unsigned long>()); 571 } else if (inp_.bare_equal_type_info(typeid(unsigned long long))) { 572 return Boxed_Number(get_as<unsigned long long>()); 573 } else if (inp_.bare_equal_type_info(typeid(int8_t))) { 574 return Boxed_Number(get_as<int8_t>()); 575 } else if (inp_.bare_equal_type_info(typeid(int16_t))) { 576 return Boxed_Number(get_as<int16_t>()); 577 } else if (inp_.bare_equal_type_info(typeid(int32_t))) { 578 return Boxed_Number(get_as<int32_t>()); 579 } else if (inp_.bare_equal_type_info(typeid(int64_t))) { 580 return Boxed_Number(get_as<int64_t>()); 581 } else if (inp_.bare_equal_type_info(typeid(uint8_t))) { 582 return Boxed_Number(get_as<uint8_t>()); 583 } else if (inp_.bare_equal_type_info(typeid(uint16_t))) { 584 return Boxed_Number(get_as<uint16_t>()); 585 } else if (inp_.bare_equal_type_info(typeid(uint32_t))) { 586 return Boxed_Number(get_as<uint32_t>()); 587 } else if (inp_.bare_equal_type_info(typeid(uint64_t))) { 588 return Boxed_Number(get_as<uint64_t>()); 589 } else { 590 throw chaiscript::detail::exception::bad_any_cast(); 591 } 592 593 } 594 595 template<typename Source, typename Target> check_type()596 static void check_type() 597 { 598 #ifdef CHAISCRIPT_MSVC 599 // MSVC complains about this being redundant / tautologica l 600 #pragma warning(push) 601 #pragma warning(disable : 4127 6287) 602 #endif 603 if (sizeof(Source) != sizeof(Target) 604 || std::is_signed<Source>() != std::is_signed<Target>() 605 || std::is_floating_point<Source>() != std::is_floating_point<Target>()) 606 { 607 throw chaiscript::detail::exception::bad_any_cast(); 608 } 609 #ifdef CHAISCRIPT_MSVC 610 #pragma warning(pop) 611 #endif 612 } 613 get_as_checked() const614 template<typename Target> Target get_as_checked() const 615 { 616 switch (get_common_type(bv)) { 617 case Common_Types::t_int32: 618 check_type<int32_t, Target>(); 619 return get_as_aux<Target, int32_t>(bv); 620 case Common_Types::t_uint8: 621 check_type<uint8_t, Target>(); 622 return get_as_aux<Target, uint8_t>(bv); 623 case Common_Types::t_int8: 624 check_type<int8_t, Target>(); 625 return get_as_aux<Target, int8_t>(bv); 626 case Common_Types::t_uint16: 627 check_type<uint16_t, Target>(); 628 return get_as_aux<Target, uint16_t>(bv); 629 case Common_Types::t_int16: 630 check_type<int16_t, Target>(); 631 return get_as_aux<Target, int16_t>(bv); 632 case Common_Types::t_uint32: 633 check_type<uint32_t, Target>(); 634 return get_as_aux<Target, uint32_t>(bv); 635 case Common_Types::t_uint64: 636 check_type<uint64_t, Target>(); 637 return get_as_aux<Target, uint64_t>(bv); 638 case Common_Types::t_int64: 639 check_type<int64_t, Target>(); 640 return get_as_aux<Target, int64_t>(bv); 641 case Common_Types::t_double: 642 check_type<double, Target>(); 643 return get_as_aux<Target, double>(bv); 644 case Common_Types::t_float: 645 check_type<float, Target>(); 646 return get_as_aux<Target, float>(bv); 647 case Common_Types::t_long_double: 648 check_type<long double, Target>(); 649 return get_as_aux<Target, long double>(bv); 650 } 651 652 throw chaiscript::detail::exception::bad_any_cast(); 653 } 654 655 get_as() const656 template<typename Target> Target get_as() const 657 { 658 switch (get_common_type(bv)) { 659 case Common_Types::t_int32: 660 return get_as_aux<Target, int32_t>(bv); 661 case Common_Types::t_uint8: 662 return get_as_aux<Target, uint8_t>(bv); 663 case Common_Types::t_int8: 664 return get_as_aux<Target, int8_t>(bv); 665 case Common_Types::t_uint16: 666 return get_as_aux<Target, uint16_t>(bv); 667 case Common_Types::t_int16: 668 return get_as_aux<Target, int16_t>(bv); 669 case Common_Types::t_uint32: 670 return get_as_aux<Target, uint32_t>(bv); 671 case Common_Types::t_uint64: 672 return get_as_aux<Target, uint64_t>(bv); 673 case Common_Types::t_int64: 674 return get_as_aux<Target, int64_t>(bv); 675 case Common_Types::t_double: 676 return get_as_aux<Target, double>(bv); 677 case Common_Types::t_float: 678 return get_as_aux<Target, float>(bv); 679 case Common_Types::t_long_double: 680 return get_as_aux<Target, long double>(bv); 681 } 682 683 throw chaiscript::detail::exception::bad_any_cast(); 684 } 685 to_string() const686 std::string to_string() const 687 { 688 switch (get_common_type(bv)) { 689 case Common_Types::t_int32: 690 return std::to_string(get_as<int32_t>()); 691 case Common_Types::t_uint8: 692 return std::to_string(get_as<uint32_t>()); 693 case Common_Types::t_int8: 694 return std::to_string(get_as<int32_t>()); 695 case Common_Types::t_uint16: 696 return std::to_string(get_as<uint16_t>()); 697 case Common_Types::t_int16: 698 return std::to_string(get_as<int16_t>()); 699 case Common_Types::t_uint32: 700 return std::to_string(get_as<uint32_t>()); 701 case Common_Types::t_uint64: 702 return std::to_string(get_as<uint64_t>()); 703 case Common_Types::t_int64: 704 return std::to_string(get_as<int64_t>()); 705 case Common_Types::t_double: 706 return to_string_aux<double>(bv); 707 case Common_Types::t_float: 708 return to_string_aux<float>(bv); 709 case Common_Types::t_long_double: 710 return to_string_aux<long double>(bv); 711 } 712 713 throw chaiscript::detail::exception::bad_any_cast(); 714 } 715 validate_boxed_number(const Boxed_Value & v)716 static void validate_boxed_number(const Boxed_Value &v) 717 { 718 const Type_Info &inp_ = v.get_type_info(); 719 if (inp_ == typeid(bool)) 720 { 721 throw chaiscript::detail::exception::bad_any_cast(); 722 } 723 724 if (!inp_.is_arithmetic()) 725 { 726 throw chaiscript::detail::exception::bad_any_cast(); 727 } 728 } 729 730 731 equals(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)732 static bool equals(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 733 { 734 return boxed_cast<bool>(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv)); 735 } 736 less_than(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)737 static bool less_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 738 { 739 return boxed_cast<bool>(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv)); 740 } 741 greater_than(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)742 static bool greater_than(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 743 { 744 return boxed_cast<bool>(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv)); 745 } 746 greater_than_equal(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)747 static bool greater_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 748 { 749 return boxed_cast<bool>(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv)); 750 } 751 less_than_equal(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)752 static bool less_than_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 753 { 754 return boxed_cast<bool>(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv)); 755 } 756 not_equal(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)757 static bool not_equal(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 758 { 759 return boxed_cast<bool>(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv)); 760 } 761 pre_decrement(Boxed_Number t_lhs)762 static Boxed_Number pre_decrement(Boxed_Number t_lhs) 763 { 764 return Boxed_Number(oper(Operators::Opers::pre_decrement, t_lhs.bv)); 765 } 766 pre_increment(Boxed_Number t_lhs)767 static Boxed_Number pre_increment(Boxed_Number t_lhs) 768 { 769 return Boxed_Number(oper(Operators::Opers::pre_increment, t_lhs.bv)); 770 } 771 sum(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)772 static const Boxed_Number sum(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 773 { 774 return Boxed_Number(oper(Operators::Opers::sum, t_lhs.bv, t_rhs.bv)); 775 } 776 unary_plus(const Boxed_Number & t_lhs)777 static const Boxed_Number unary_plus(const Boxed_Number &t_lhs) 778 { 779 return Boxed_Number(oper(Operators::Opers::unary_plus, t_lhs.bv)); 780 } 781 unary_minus(const Boxed_Number & t_lhs)782 static const Boxed_Number unary_minus(const Boxed_Number &t_lhs) 783 { 784 return Boxed_Number(oper(Operators::Opers::unary_minus, t_lhs.bv)); 785 } 786 difference(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)787 static const Boxed_Number difference(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 788 { 789 return Boxed_Number(oper(Operators::Opers::difference, t_lhs.bv, t_rhs.bv)); 790 } 791 assign_bitwise_and(Boxed_Number t_lhs,const Boxed_Number & t_rhs)792 static Boxed_Number assign_bitwise_and(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 793 { 794 return Boxed_Number(oper(Operators::Opers::assign_bitwise_and, t_lhs.bv, t_rhs.bv)); 795 } 796 assign(Boxed_Number t_lhs,const Boxed_Number & t_rhs)797 static Boxed_Number assign(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 798 { 799 return Boxed_Number(oper(Operators::Opers::assign, t_lhs.bv, t_rhs.bv)); 800 } 801 assign_bitwise_or(Boxed_Number t_lhs,const Boxed_Number & t_rhs)802 static Boxed_Number assign_bitwise_or(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 803 { 804 return Boxed_Number(oper(Operators::Opers::assign_bitwise_or, t_lhs.bv, t_rhs.bv)); 805 } 806 assign_bitwise_xor(Boxed_Number t_lhs,const Boxed_Number & t_rhs)807 static Boxed_Number assign_bitwise_xor(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 808 { 809 return Boxed_Number(oper(Operators::Opers::assign_bitwise_xor, t_lhs.bv, t_rhs.bv)); 810 } 811 assign_remainder(Boxed_Number t_lhs,const Boxed_Number & t_rhs)812 static Boxed_Number assign_remainder(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 813 { 814 return Boxed_Number(oper(Operators::Opers::assign_remainder, t_lhs.bv, t_rhs.bv)); 815 } 816 assign_shift_left(Boxed_Number t_lhs,const Boxed_Number & t_rhs)817 static Boxed_Number assign_shift_left(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 818 { 819 return Boxed_Number(oper(Operators::Opers::assign_shift_left, t_lhs.bv, t_rhs.bv)); 820 } 821 assign_shift_right(Boxed_Number t_lhs,const Boxed_Number & t_rhs)822 static Boxed_Number assign_shift_right(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 823 { 824 return Boxed_Number(oper(Operators::Opers::assign_shift_right, t_lhs.bv, t_rhs.bv)); 825 } 826 bitwise_and(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)827 static const Boxed_Number bitwise_and(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 828 { 829 return Boxed_Number(oper(Operators::Opers::bitwise_and, t_lhs.bv, t_rhs.bv)); 830 } 831 bitwise_complement(const Boxed_Number & t_lhs)832 static const Boxed_Number bitwise_complement(const Boxed_Number &t_lhs) 833 { 834 return Boxed_Number(oper(Operators::Opers::bitwise_complement, t_lhs.bv, Boxed_Value(0))); 835 } 836 bitwise_xor(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)837 static const Boxed_Number bitwise_xor(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 838 { 839 return Boxed_Number(oper(Operators::Opers::bitwise_xor, t_lhs.bv, t_rhs.bv)); 840 } 841 bitwise_or(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)842 static const Boxed_Number bitwise_or(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 843 { 844 return Boxed_Number(oper(Operators::Opers::bitwise_or, t_lhs.bv, t_rhs.bv)); 845 } 846 assign_product(Boxed_Number t_lhs,const Boxed_Number & t_rhs)847 static Boxed_Number assign_product(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 848 { 849 return Boxed_Number(oper(Operators::Opers::assign_product, t_lhs.bv, t_rhs.bv)); 850 } 851 assign_quotient(Boxed_Number t_lhs,const Boxed_Number & t_rhs)852 static Boxed_Number assign_quotient(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 853 { 854 return Boxed_Number(oper(Operators::Opers::assign_quotient, t_lhs.bv, t_rhs.bv)); 855 } 856 assign_sum(Boxed_Number t_lhs,const Boxed_Number & t_rhs)857 static Boxed_Number assign_sum(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 858 { 859 return Boxed_Number(oper(Operators::Opers::assign_sum, t_lhs.bv, t_rhs.bv)); 860 } assign_difference(Boxed_Number t_lhs,const Boxed_Number & t_rhs)861 static Boxed_Number assign_difference(Boxed_Number t_lhs, const Boxed_Number &t_rhs) 862 { 863 return Boxed_Number(oper(Operators::Opers::assign_difference, t_lhs.bv, t_rhs.bv)); 864 } 865 quotient(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)866 static const Boxed_Number quotient(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 867 { 868 return Boxed_Number(oper(Operators::Opers::quotient, t_lhs.bv, t_rhs.bv)); 869 } 870 shift_left(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)871 static const Boxed_Number shift_left(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 872 { 873 return Boxed_Number(oper(Operators::Opers::shift_left, t_lhs.bv, t_rhs.bv)); 874 } 875 product(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)876 static const Boxed_Number product(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 877 { 878 return Boxed_Number(oper(Operators::Opers::product, t_lhs.bv, t_rhs.bv)); 879 } 880 remainder(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)881 static const Boxed_Number remainder(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 882 { 883 return Boxed_Number(oper(Operators::Opers::remainder, t_lhs.bv, t_rhs.bv)); 884 } 885 shift_right(const Boxed_Number & t_lhs,const Boxed_Number & t_rhs)886 static const Boxed_Number shift_right(const Boxed_Number &t_lhs, const Boxed_Number &t_rhs) 887 { 888 return Boxed_Number(oper(Operators::Opers::shift_right, t_lhs.bv, t_rhs.bv)); 889 } 890 891 892 do_oper(Operators::Opers t_oper,const Boxed_Value & t_lhs,const Boxed_Value & t_rhs)893 static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs, const Boxed_Value &t_rhs) 894 { 895 return oper(t_oper, t_lhs, t_rhs); 896 } 897 do_oper(Operators::Opers t_oper,const Boxed_Value & t_lhs)898 static Boxed_Value do_oper(Operators::Opers t_oper, const Boxed_Value &t_lhs) 899 { 900 return oper(t_oper, t_lhs); 901 } 902 903 904 905 Boxed_Value bv; 906 }; 907 908 namespace detail 909 { 910 /// Cast_Helper for converting from Boxed_Value to Boxed_Number 911 template<> 912 struct Cast_Helper<Boxed_Number> 913 { castchaiscript::detail::Cast_Helper914 static Boxed_Number cast(const Boxed_Value &ob, const Type_Conversions_State *) 915 { 916 return Boxed_Number(ob); 917 } 918 }; 919 920 /// Cast_Helper for converting from Boxed_Value to Boxed_Number 921 template<> 922 struct Cast_Helper<const Boxed_Number &> : Cast_Helper<Boxed_Number> 923 { 924 }; 925 926 /// Cast_Helper for converting from Boxed_Value to Boxed_Number 927 template<> 928 struct Cast_Helper<const Boxed_Number> : Cast_Helper<Boxed_Number> 929 { 930 }; 931 } 932 933 #ifdef __GNUC__ 934 #pragma GCC diagnostic pop 935 #endif 936 937 #ifdef CHAISCRIPT_MSVC 938 #pragma warning(pop) 939 #endif 940 941 } 942 943 944 945 #endif 946 947