10 #ifndef CHAISCRIPT_BOXED_NUMERIC_HPP_ 11 #define CHAISCRIPT_BOXED_NUMERIC_HPP_ 17 #include "../language/chaiscript_algebraic.hpp" 19 #include "boxed_cast.hpp" 20 #include "boxed_cast_helper.hpp" 21 #include "boxed_value.hpp" 22 #include "type_info.hpp" 25 class Type_Conversions;
31 : std::runtime_error(
"Arithmetic error: " + reason) {
42 #ifdef CHAISCRIPT_MSVC 44 #pragma warning(disable : 4244 4018 4389 4146 4365 4267 4242) 48 #pragma GCC diagnostic push 49 #pragma GCC diagnostic ignored "-Wunknown-pragmas" 50 #pragma GCC diagnostic ignored "-Wpragmas" 51 #pragma GCC diagnostic ignored "-Wsign-compare" 52 #pragma GCC diagnostic ignored "-Wfloat-equal" 53 #pragma GCC diagnostic ignored "-Wconversion" 54 #pragma GCC diagnostic ignored "-Wsign-conversion" 55 #pragma GCC diagnostic ignored "-Wfloat-conversion" 56 #pragma GCC diagnostic ignored "-Wswitch" 62 enum class Common_Types {
77 constexpr
static inline void check_divide_by_zero([[maybe_unused]] T t) {
78 #ifndef CHAISCRIPT_NO_PROTECT_DIVIDEBYZERO 79 if constexpr (!std::is_floating_point<T>::value) {
87 constexpr
static Common_Types get_common_type(
size_t t_size,
bool t_signed) noexcept {
88 return (t_size == 1 && t_signed) ? (Common_Types::t_int8)
89 : (t_size == 1) ? (Common_Types::t_uint8)
90 : (t_size == 2 && t_signed) ? (Common_Types::t_int16)
91 : (t_size == 2) ? (Common_Types::t_uint16)
92 : (t_size == 4 && t_signed) ? (Common_Types::t_int32)
93 : (t_size == 4) ? (Common_Types::t_uint32)
94 : (t_size == 8 && t_signed) ? (Common_Types::t_int64)
95 : (Common_Types::t_uint64);
98 static Common_Types get_common_type(
const Boxed_Value &t_bv) {
99 const Type_Info &inp_ = t_bv.get_type_info();
101 if (inp_ == user_type<int>()) {
102 return get_common_type(
sizeof(
int),
true);
103 }
else if (inp_ == user_type<double>()) {
104 return Common_Types::t_double;
105 }
else if (inp_ == user_type<long double>()) {
106 return Common_Types::t_long_double;
107 }
else if (inp_ == user_type<float>()) {
108 return Common_Types::t_float;
109 }
else if (inp_ == user_type<char>()) {
110 return get_common_type(
sizeof(
char), std::is_signed<char>::value);
111 }
else if (inp_ == user_type<unsigned char>()) {
112 return get_common_type(
sizeof(
unsigned char),
false);
113 }
else if (inp_ == user_type<unsigned int>()) {
114 return get_common_type(
sizeof(
unsigned int),
false);
115 }
else if (inp_ == user_type<long>()) {
116 return get_common_type(
sizeof(
long),
true);
117 }
else if (inp_ == user_type<long long>()) {
118 return get_common_type(
sizeof(
long long),
true);
119 }
else if (inp_ == user_type<unsigned long>()) {
120 return get_common_type(
sizeof(
unsigned long),
false);
121 }
else if (inp_ == user_type<unsigned long long>()) {
122 return get_common_type(
sizeof(
unsigned long long),
false);
123 }
else if (inp_ == user_type<std::int8_t>()) {
124 return Common_Types::t_int8;
125 }
else if (inp_ == user_type<std::int16_t>()) {
126 return Common_Types::t_int16;
127 }
else if (inp_ == user_type<std::int32_t>()) {
128 return Common_Types::t_int32;
129 }
else if (inp_ == user_type<std::int64_t>()) {
130 return Common_Types::t_int64;
131 }
else if (inp_ == user_type<std::uint8_t>()) {
132 return Common_Types::t_uint8;
133 }
else if (inp_ == user_type<std::uint16_t>()) {
134 return Common_Types::t_uint16;
135 }
else if (inp_ == user_type<std::uint32_t>()) {
136 return Common_Types::t_uint32;
137 }
else if (inp_ == user_type<std::uint64_t>()) {
138 return Common_Types::t_uint64;
139 }
else if (inp_ == user_type<wchar_t>()) {
140 return get_common_type(
sizeof(
wchar_t), std::is_signed<wchar_t>::value);
141 }
else if (inp_ == user_type<char16_t>()) {
142 return get_common_type(
sizeof(char16_t), std::is_signed<char16_t>::value);
143 }
else if (inp_ == user_type<char32_t>()) {
144 return get_common_type(
sizeof(char32_t), std::is_signed<char32_t>::value);
150 template<
typename LHS,
typename RHS>
151 static auto go(Operators::Opers t_oper,
const Boxed_Value &t_bv, LHS *t_lhs,
const LHS &c_lhs,
const RHS &c_rhs) {
153 case Operators::Opers::equals:
155 case Operators::Opers::less_than:
157 case Operators::Opers::greater_than:
159 case Operators::Opers::less_than_equal:
161 case Operators::Opers::greater_than_equal:
163 case Operators::Opers::not_equal:
165 case Operators::Opers::sum:
167 case Operators::Opers::quotient:
168 check_divide_by_zero(c_rhs);
170 case Operators::Opers::product:
172 case Operators::Opers::difference:
178 if constexpr (!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value) {
180 case Operators::Opers::shift_left:
182 case Operators::Opers::shift_right:
184 case Operators::Opers::remainder:
185 check_divide_by_zero(c_rhs);
187 case Operators::Opers::bitwise_and:
189 case Operators::Opers::bitwise_or:
191 case Operators::Opers::bitwise_xor:
200 case Operators::Opers::assign:
203 case Operators::Opers::assign_product:
206 case Operators::Opers::assign_sum:
209 case Operators::Opers::assign_quotient:
210 check_divide_by_zero(c_rhs);
213 case Operators::Opers::assign_difference:
220 if constexpr (!std::is_floating_point<LHS>::value && !std::is_floating_point<RHS>::value) {
222 case Operators::Opers::assign_bitwise_and:
223 check_divide_by_zero(c_rhs);
226 case Operators::Opers::assign_bitwise_or:
229 case Operators::Opers::assign_shift_left:
232 case Operators::Opers::assign_shift_right:
235 case Operators::Opers::assign_remainder:
238 case Operators::Opers::assign_bitwise_xor:
250 template<
typename Callable>
251 inline static auto visit(
const Boxed_Value &bv, Callable &&callable) {
252 switch (get_common_type(bv)) {
253 case Common_Types::t_int32:
254 return callable(*static_cast<const std::int32_t *>(bv.get_const_ptr()));
255 case Common_Types::t_uint8:
256 return callable(*static_cast<const std::uint8_t *>(bv.get_const_ptr()));
257 case Common_Types::t_int8:
258 return callable(*static_cast<const std::int8_t *>(bv.get_const_ptr()));
259 case Common_Types::t_uint16:
260 return callable(*static_cast<const std::uint16_t *>(bv.get_const_ptr()));
261 case Common_Types::t_int16:
262 return callable(*static_cast<const std::int16_t *>(bv.get_const_ptr()));
263 case Common_Types::t_uint32:
264 return callable(*static_cast<const std::uint32_t *>(bv.get_const_ptr()));
265 case Common_Types::t_uint64:
266 return callable(*static_cast<const std::uint64_t *>(bv.get_const_ptr()));
267 case Common_Types::t_int64:
268 return callable(*static_cast<const std::int64_t *>(bv.get_const_ptr()));
269 case Common_Types::t_double:
270 return callable(*static_cast<const double *>(bv.get_const_ptr()));
271 case Common_Types::t_float:
272 return callable(*static_cast<const float *>(bv.get_const_ptr()));
273 case Common_Types::t_long_double:
274 return callable(*static_cast<const long double *>(bv.get_const_ptr()));
280 auto unary_operator = [t_oper, &t_lhs](
const auto &c_lhs) {
281 auto *lhs =
static_cast<std::decay_t<decltype(c_lhs)> *
>(t_lhs.get_ptr());
285 case Operators::Opers::pre_increment:
288 case Operators::Opers::pre_decrement:
297 case Operators::Opers::unary_minus:
299 case Operators::Opers::unary_plus:
305 if constexpr (!std::is_floating_point_v<std::decay_t<decltype(c_lhs)>>) {
307 case Operators::Opers::bitwise_complement:
317 return visit(t_lhs, unary_operator);
321 auto lhs_visit = [t_oper, &t_lhs, &t_rhs](
const auto &c_lhs) {
322 auto *lhs = t_lhs.is_return_value() ? nullptr :
static_cast<std::decay_t<decltype(c_lhs)> *
>(t_lhs.get_ptr());
324 auto rhs_visit = [t_oper, &t_lhs, lhs, &c_lhs](
const auto &c_rhs) {
return go(t_oper, t_lhs, lhs, c_lhs, c_rhs); };
326 return visit(t_rhs, rhs_visit);
329 return visit(t_lhs, lhs_visit);
332 template<
typename Target,
typename Source>
333 static inline Target get_as_aux(
const Boxed_Value &t_bv) {
334 return static_cast<Target
>(*
static_cast<const Source *
>(t_bv.get_const_ptr()));
337 template<
typename Source>
338 static std::string to_string_aux(
const Boxed_Value &v) {
339 std::ostringstream oss;
340 oss << *static_cast<const Source *>(v.get_const_ptr());
351 validate_boxed_number(bv);
361 validate_boxed_number(bv);
366 static bool is_floating_point(
const Boxed_Value &t_bv) {
367 const Type_Info &inp_ = t_bv.get_type_info();
369 if (inp_ == user_type<double>()) {
371 }
else if (inp_ == user_type<long double>()) {
373 }
else if (inp_ == user_type<float>()) {
381 if (inp_.bare_equal(user_type<int>())) {
383 }
else if (inp_.bare_equal(user_type<double>())) {
385 }
else if (inp_.bare_equal(user_type<float>())) {
387 }
else if (inp_.bare_equal(user_type<long double>())) {
389 }
else if (inp_.bare_equal(user_type<char>())) {
391 }
else if (inp_.bare_equal(user_type<unsigned char>())) {
393 }
else if (inp_.bare_equal(user_type<wchar_t>())) {
395 }
else if (inp_.bare_equal(user_type<char16_t>())) {
397 }
else if (inp_.bare_equal(user_type<char32_t>())) {
399 }
else if (inp_.bare_equal(user_type<unsigned int>())) {
401 }
else if (inp_.bare_equal(user_type<long>())) {
403 }
else if (inp_.bare_equal(user_type<long long>())) {
405 }
else if (inp_.bare_equal(user_type<unsigned long>())) {
407 }
else if (inp_.bare_equal(user_type<unsigned long long>())) {
409 }
else if (inp_.bare_equal(user_type<int8_t>())) {
411 }
else if (inp_.bare_equal(user_type<int16_t>())) {
413 }
else if (inp_.bare_equal(user_type<int32_t>())) {
415 }
else if (inp_.bare_equal(user_type<int64_t>())) {
417 }
else if (inp_.bare_equal(user_type<uint8_t>())) {
419 }
else if (inp_.bare_equal(user_type<uint16_t>())) {
421 }
else if (inp_.bare_equal(user_type<uint32_t>())) {
423 }
else if (inp_.bare_equal(user_type<uint64_t>())) {
430 template<
typename Source,
typename Target>
431 static void check_type() {
432 #ifdef CHAISCRIPT_MSVC 434 #pragma warning(push) 435 #pragma warning(disable : 4127 6287) 437 if (
sizeof(Source) !=
sizeof(Target) || std::is_signed<Source>() != std::is_signed<Target>()
438 || std::is_floating_point<Source>() != std::is_floating_point<Target>()) {
441 #ifdef CHAISCRIPT_MSVC 446 template<
typename Target>
447 Target get_as_checked()
const {
448 switch (get_common_type(bv)) {
449 case Common_Types::t_int32:
450 check_type<int32_t, Target>();
451 return get_as_aux<Target, int32_t>(bv);
452 case Common_Types::t_uint8:
453 check_type<uint8_t, Target>();
454 return get_as_aux<Target, uint8_t>(bv);
455 case Common_Types::t_int8:
456 check_type<int8_t, Target>();
457 return get_as_aux<Target, int8_t>(bv);
458 case Common_Types::t_uint16:
459 check_type<uint16_t, Target>();
460 return get_as_aux<Target, uint16_t>(bv);
461 case Common_Types::t_int16:
462 check_type<int16_t, Target>();
463 return get_as_aux<Target, int16_t>(bv);
464 case Common_Types::t_uint32:
465 check_type<uint32_t, Target>();
466 return get_as_aux<Target, uint32_t>(bv);
467 case Common_Types::t_uint64:
468 check_type<uint64_t, Target>();
469 return get_as_aux<Target, uint64_t>(bv);
470 case Common_Types::t_int64:
471 check_type<int64_t, Target>();
472 return get_as_aux<Target, int64_t>(bv);
473 case Common_Types::t_double:
474 check_type<double, Target>();
475 return get_as_aux<Target, double>(bv);
476 case Common_Types::t_float:
477 check_type<float, Target>();
478 return get_as_aux<Target, float>(bv);
479 case Common_Types::t_long_double:
480 check_type<long double, Target>();
481 return get_as_aux<Target, long double>(bv);
487 template<
typename Target>
488 Target get_as()
const {
489 switch (get_common_type(bv)) {
490 case Common_Types::t_int32:
491 return get_as_aux<Target, int32_t>(bv);
492 case Common_Types::t_uint8:
493 return get_as_aux<Target, uint8_t>(bv);
494 case Common_Types::t_int8:
495 return get_as_aux<Target, int8_t>(bv);
496 case Common_Types::t_uint16:
497 return get_as_aux<Target, uint16_t>(bv);
498 case Common_Types::t_int16:
499 return get_as_aux<Target, int16_t>(bv);
500 case Common_Types::t_uint32:
501 return get_as_aux<Target, uint32_t>(bv);
502 case Common_Types::t_uint64:
503 return get_as_aux<Target, uint64_t>(bv);
504 case Common_Types::t_int64:
505 return get_as_aux<Target, int64_t>(bv);
506 case Common_Types::t_double:
507 return get_as_aux<Target, double>(bv);
508 case Common_Types::t_float:
509 return get_as_aux<Target, float>(bv);
510 case Common_Types::t_long_double:
511 return get_as_aux<Target, long double>(bv);
517 std::string to_string()
const {
518 switch (get_common_type(bv)) {
519 case Common_Types::t_int32:
520 return std::to_string(get_as<int32_t>());
521 case Common_Types::t_uint8:
522 return std::to_string(get_as<uint32_t>());
523 case Common_Types::t_int8:
524 return std::to_string(get_as<int32_t>());
525 case Common_Types::t_uint16:
526 return std::to_string(get_as<uint16_t>());
527 case Common_Types::t_int16:
528 return std::to_string(get_as<int16_t>());
529 case Common_Types::t_uint32:
530 return std::to_string(get_as<uint32_t>());
531 case Common_Types::t_uint64:
532 return std::to_string(get_as<uint64_t>());
533 case Common_Types::t_int64:
534 return std::to_string(get_as<int64_t>());
535 case Common_Types::t_double:
536 return to_string_aux<double>(bv);
537 case Common_Types::t_float:
538 return to_string_aux<float>(bv);
539 case Common_Types::t_long_double:
540 return to_string_aux<long double>(bv);
546 static void validate_boxed_number(
const Boxed_Value &v) {
547 const Type_Info &inp_ = v.get_type_info();
548 if (inp_ == user_type<bool>()) {
552 if (!inp_.is_arithmetic()) {
558 return boxed_cast<
bool>(oper(Operators::Opers::equals, t_lhs.bv, t_rhs.bv));
562 return boxed_cast<
bool>(oper(Operators::Opers::less_than, t_lhs.bv, t_rhs.bv));
566 return boxed_cast<
bool>(oper(Operators::Opers::greater_than, t_lhs.bv, t_rhs.bv));
570 return boxed_cast<
bool>(oper(Operators::Opers::greater_than_equal, t_lhs.bv, t_rhs.bv));
574 return boxed_cast<
bool>(oper(Operators::Opers::less_than_equal, t_lhs.bv, t_rhs.bv));
578 return boxed_cast<
bool>(oper(Operators::Opers::not_equal, t_lhs.bv, t_rhs.bv));
586 return Boxed_Number(oper(Operators::Opers::sum, t_lhs.bv, t_rhs.bv));
594 return Boxed_Number(oper(Operators::Opers::difference, t_lhs.bv, t_rhs.bv));
598 return Boxed_Number(oper(Operators::Opers::assign_bitwise_and, t_lhs.bv, t_rhs.bv));
602 return Boxed_Number(oper(Operators::Opers::assign, t_lhs.bv, t_rhs.bv));
606 return Boxed_Number(oper(Operators::Opers::assign_bitwise_or, t_lhs.bv, t_rhs.bv));
610 return Boxed_Number(oper(Operators::Opers::assign_bitwise_xor, t_lhs.bv, t_rhs.bv));
614 return Boxed_Number(oper(Operators::Opers::assign_remainder, t_lhs.bv, t_rhs.bv));
618 return Boxed_Number(oper(Operators::Opers::assign_shift_left, t_lhs.bv, t_rhs.bv));
622 return Boxed_Number(oper(Operators::Opers::assign_shift_right, t_lhs.bv, t_rhs.bv));
626 return Boxed_Number(oper(Operators::Opers::bitwise_and, t_lhs.bv, t_rhs.bv));
634 return Boxed_Number(oper(Operators::Opers::bitwise_xor, t_lhs.bv, t_rhs.bv));
638 return Boxed_Number(oper(Operators::Opers::bitwise_or, t_lhs.bv, t_rhs.bv));
642 return Boxed_Number(oper(Operators::Opers::assign_product, t_lhs.bv, t_rhs.bv));
646 return Boxed_Number(oper(Operators::Opers::assign_quotient, t_lhs.bv, t_rhs.bv));
650 return Boxed_Number(oper(Operators::Opers::assign_sum, t_lhs.bv, t_rhs.bv));
653 return Boxed_Number(oper(Operators::Opers::assign_difference, t_lhs.bv, t_rhs.bv));
657 return Boxed_Number(oper(Operators::Opers::quotient, t_lhs.bv, t_rhs.bv));
661 return Boxed_Number(oper(Operators::Opers::shift_left, t_lhs.bv, t_rhs.bv));
665 return Boxed_Number(oper(Operators::Opers::product, t_lhs.bv, t_rhs.bv));
669 return Boxed_Number(oper(Operators::Opers::remainder, t_lhs.bv, t_rhs.bv));
673 return Boxed_Number(oper(Operators::Opers::shift_right, t_lhs.bv, t_rhs.bv));
677 return oper(t_oper, t_lhs, t_rhs);
680 static Boxed_Value do_oper(Operators::Opers t_oper,
const Boxed_Value &t_lhs) {
return oper(t_oper, t_lhs); }
704 #pragma GCC diagnostic pop 707 #ifdef CHAISCRIPT_MSVC Compile time deduced information about a type.
Definition: type_info.hpp:27
Boxed_Value const_var(const T &t)
Takes an object and returns an immutable Boxed_Value.
Definition: boxed_value.hpp:336
decltype(auto) boxed_cast(const Boxed_Value &bv, const Type_Conversions_State *t_conversions=nullptr)
Function for extracting a value stored in a Boxed_Value object.
Definition: boxed_cast.hpp:71
Definition: type_conversions.hpp:417
Namespace chaiscript contains every API call that the average user will be concerned with...
A wrapper for holding any valid C++ type.
Definition: boxed_value.hpp:24
Cast_Helper for converting from Boxed_Value to Boxed_Number.
Definition: boxed_number.hpp:688
Classes which may be thrown during error cases when ChaiScript is executing.
Definition: bad_boxed_cast.hpp:25
Thrown in the event that an Any cannot be cast to the desired type.
Definition: any.hpp:20
Represents any numeric type, generically. Used internally for generic operations between POD values...
Definition: boxed_number.hpp:60
Definition: boxed_number.hpp:29
The exposed Cast_Helper object that by default just calls the Cast_Helper_Inner.
Definition: boxed_cast_helper.hpp:251