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