1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2004-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_oct_inttypes_h)
27 #define octave_oct_inttypes_h 1
28 
29 #include "octave-config.h"
30 
31 #include <cmath>
32 #include <cstdlib>
33 
34 #include <iosfwd>
35 #include <limits>
36 
37 #include "lo-mappers.h"
38 #include "lo-traits.h"
39 
40 template <typename T> class octave_int;
41 
42 typedef octave_int<int8_t> octave_int8;
43 typedef octave_int<int16_t> octave_int16;
44 typedef octave_int<int32_t> octave_int32;
45 typedef octave_int<int64_t> octave_int64;
46 
47 typedef octave_int<uint8_t> octave_uint8;
48 typedef octave_int<uint16_t> octave_uint16;
49 typedef octave_int<uint32_t> octave_uint32;
50 typedef octave_int<uint64_t> octave_uint64;
51 
52 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
53 
54 namespace octave
55 {
56   namespace math
57   {
round(long double x)58     inline long double round (long double x)
59     {
60       return std::roundl (x);
61     }
62 
isnan(long double x)63     inline long double isnan (long double x)
64     {
65       return isnan (static_cast<double> (x));
66     }
67   }
68 }
69 
70 #endif
71 
72 // FIXME: we define this by our own because some compilers, such as
73 // MSVC, do not provide std::abs (int64_t) and std::abs (uint64_t).  In
74 // the future, it should go away in favor of std::abs.
75 
76 template <typename T>
77 inline T
octave_int_abs(T x)78 octave_int_abs (T x)
79 {
80   return (x >= 0 ? x : -x);
81 }
82 
83 // Query for an integer type of certain sizeof, and signedness.
84 
85 template <int qsize, bool qsigned>
86 struct query_integer_type
87 {
88 public:
89 
90   static const bool registered = false;
91 
92   // Void shall result in a compile-time error if we attempt to use it
93   // in computations.
94 
95   typedef void type;
96 };
97 
98 #define OCTAVE_REGISTER_INT_TYPE(TYPE)                                  \
99   template <>                                                           \
100   class query_integer_type<sizeof (TYPE),                               \
101                            std::numeric_limits<TYPE>::is_signed>        \
102   {                                                                     \
103   public:                                                               \
104                                                                         \
105     static const bool registered = true;                                \
106                                                                         \
107     typedef TYPE type;                                                  \
108   }
109 
110 // No two registered integers can share sizeof and signedness.
111 OCTAVE_REGISTER_INT_TYPE (int8_t);
112 OCTAVE_REGISTER_INT_TYPE (uint8_t);
113 OCTAVE_REGISTER_INT_TYPE (int16_t);
114 OCTAVE_REGISTER_INT_TYPE (uint16_t);
115 OCTAVE_REGISTER_INT_TYPE (int32_t);
116 OCTAVE_REGISTER_INT_TYPE (uint32_t);
117 OCTAVE_REGISTER_INT_TYPE (int64_t);
118 OCTAVE_REGISTER_INT_TYPE (uint64_t);
119 
120 #undef OCTAVE_REGISTER_INT_TYPE
121 
122 // Handles non-homogeneous integer comparisons.  Avoids doing useless
123 // tests.
124 
125 class octave_int_cmp_op
126 {
127   // This determines a suitable promotion type for T1 when meeting T2
128   // in a binary relation.  If promotion to int or T2 is safe, it is
129   // used.  Otherwise, the signedness of T1 is preserved and it is
130   // widened if T2 is wider.  Notice that if this is applied to both
131   // types, they must end up with equal size.
132 
133   template <typename T1, typename T2>
134   class prom
135   {
136     // Promote to int?
137     static const bool pint = (sizeof (T1) < sizeof (int)
138                               && sizeof (T2) < sizeof (int));
139 
140     static const bool t1sig = std::numeric_limits<T1>::is_signed;
141     static const bool t2sig = std::numeric_limits<T2>::is_signed;
142 
143     static const bool psig
144       = (pint || (sizeof (T2) > sizeof (T1) && t2sig) || t1sig);
145 
146     static const int psize
147       = (pint
148          ? sizeof (int)
149          : (sizeof (T2) > sizeof (T1) ? sizeof (T2) : sizeof (T1)));
150   public:
151 
152     typedef typename query_integer_type<psize, psig>::type type;
153   };
154 
155   // Implements comparisons between two types of equal size but
156   // possibly different signedness.
157 
158   template <typename xop, int size>
159   class uiop
160   {
161     typedef typename query_integer_type<size, false>::type utype;
162     typedef typename query_integer_type<size, true>::type stype;
163 
164   public:
165 
op(utype x,utype y)166     static bool op (utype x, utype y)
167     {
168       return xop::op (x, y);
169     }
170 
op(stype x,stype y)171     static bool op (stype x, stype y)
172     {
173       return xop::op (x, y);
174     }
175 
op(stype x,utype y)176     static bool op (stype x, utype y)
177     {
178       return (x < 0) ? xop::ltval : xop::op (static_cast<utype> (x), y);
179     }
180 
op(utype x,stype y)181     static bool op (utype x, stype y)
182     {
183       return (y < 0) ? xop::gtval : xop::op (x, static_cast<utype> (y));
184     }
185   };
186 
187 public:
188 
189   // Rationale: Comparators have a single static method, rel(), that
190   // returns the result of the binary relation.  They also have two
191   // static boolean fields: ltval, gtval determine the value of x OP y
192   // if x < y, x > y, respectively.
193 
194 #define OCTAVE_REGISTER_INT_CMP_OP(NM, OP)              \
195   class NM                                              \
196   {                                                     \
197   public:                                               \
198                                                         \
199     static const bool ltval = (0 OP 1);                 \
200     static const bool gtval = (1 OP 0);                 \
201                                                         \
202     template <typename T>                               \
203     static bool op (T x, T y) { return x OP y; }        \
204   }
205 
206   OCTAVE_REGISTER_INT_CMP_OP (lt, <);
207   OCTAVE_REGISTER_INT_CMP_OP (le, <=);
208   OCTAVE_REGISTER_INT_CMP_OP (gt, >);
209   OCTAVE_REGISTER_INT_CMP_OP (ge, >=);
210   OCTAVE_REGISTER_INT_CMP_OP (eq, ==);
211   OCTAVE_REGISTER_INT_CMP_OP (ne, !=);
212 
213 #undef OCTAVE_REGISTER_INT_CMP_OP
214 
215   // We also provide two special relations: ct, yielding always true,
216   // and cf, yielding always false.
217 
218 #define OCTAVE_REGISTER_INT_CONST_OP(NM, VALUE) \
219   class NM                                      \
220   {                                             \
221   public:                                       \
222                                                 \
223     static const bool ltval = VALUE;            \
224     static const bool gtval = VALUE;            \
225                                                 \
226     template <typename T>                       \
227       static bool op (T, T) { return VALUE; }   \
228   }
229 
230   OCTAVE_REGISTER_INT_CONST_OP (ct, true);
231   OCTAVE_REGISTER_INT_CONST_OP (cf, false);
232 
233 #undef OCTAVE_REGISTER_INT_CONST_OP
234 
235   // Universal comparison operation.
236 
237   template <typename xop, typename T1, typename T2>
238   static bool
op(T1 x,T2 y)239   op (T1 x, T2 y)
240   {
241     typedef typename prom<T1, T2>::type PT1;
242     typedef typename prom<T2, T1>::type PT2;
243 
244     return uiop<xop, sizeof (PT1)>::op (static_cast<PT1> (x),
245                                         static_cast<PT2> (y));
246   }
247 
248 public:
249 
250   // Mixed comparisons.
251 
252   template <typename xop, typename T>
mop(T x,double y)253   static bool mop (T x, double y)
254   {
255     return xop::op (static_cast<double> (x), y);
256   }
257 
258   template <typename xop, typename T>
mop(double x,T y)259   static bool mop (double x, T y)
260   {
261     return xop::op (x, static_cast<double> (y));
262   }
263 
264 #if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
265 
266 #  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS(T)    \
267   template <typename xop>                                       \
268   static OCTAVE_API bool external_mop (double, T);              \
269                                                                 \
270   template <typename xop>                                       \
271   static OCTAVE_API bool external_mop (T, double)
272 
273   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (int64_t);
274   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_CMP_OPS (uint64_t);
275 
276 #endif
277 
278   // Typecasting to doubles won't work properly for 64-bit integers --
279   // they lose precision.  If we have long doubles, use them...
280 
281 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
282 
283 #  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
284 
285 #    define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)     \
286   template <typename xop>                               \
287   static bool mop (double x, T y)                       \
288   {                                                     \
289     return external_mop<xop> (x, y);                    \
290   }                                                     \
291                                                         \
292   template <typename xop>                               \
293   static bool mop (T x, double y)                       \
294   {                                                     \
295     return external_mop<xop> (x, y);                    \
296   }
297 
298 #  else
299 
300 #    define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)     \
301   template <typename xop>                               \
302   static bool mop (double x, T y)                       \
303   {                                                     \
304     return xop::op (static_cast<long double> (x),       \
305                     static_cast<long double> (y));      \
306   }                                                     \
307                                                         \
308   template <typename xop>                               \
309   static bool mop (T x, double y)                       \
310   {                                                     \
311     return xop::op (static_cast<long double> (x),       \
312                     static_cast<long double> (y));      \
313   }
314 
315 #  endif
316 
317 #else
318 
319   // ... otherwise, use external handlers
320 
321   // FIXME: We could declare directly the mop methods as external, but
322   // we can't do this because bugs in gcc (<= 4.3) prevent explicit
323   // instantiations later in that case.
324 
325 #  define OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP(T)       \
326   template <typename xop>                               \
327   static OCTAVE_API bool emulate_mop (double, T);       \
328                                                         \
329   template <typename xop>                               \
330   static bool mop (double x, T y)                       \
331   {                                                     \
332     return emulate_mop<xop> (x, y);                     \
333   }                                                     \
334                                                         \
335   template <typename xop>                               \
336   static OCTAVE_API bool emulate_mop (T, double);       \
337                                                         \
338   template <typename xop>                               \
339   static bool mop (T x, double y)                       \
340   {                                                     \
341     return emulate_mop<xop> (x, y);                     \
342   }
343 
344 #endif
345 
346   OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP (int64_t)
347   OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP (uint64_t)
348 
349 #undef OCTAVE_DEFINE_LONG_DOUBLE_INT_CMP_OP
350 };
351 
352 // Base integer class.  No data, just conversion methods and exception
353 // flags.
354 
355 template <typename T>
356 class octave_int_base
357 {
358 public:
359 
min_val(void)360   static T min_val (void) { return std::numeric_limits<T>::min (); }
max_val(void)361   static T max_val (void) { return std::numeric_limits<T>::max (); }
362 
363   // Convert integer value.
364 
365   template <typename S>
truncate_int(const S & value)366   static T truncate_int (const S& value)
367   {
368     // An exhaustive test whether the max and/or min check can be
369     // omitted.
370 
371     static const bool t_is_signed = std::numeric_limits<T>::is_signed;
372     static const bool s_is_signed = std::numeric_limits<S>::is_signed;
373 
374     static const int t_size = sizeof (T);
375     static const int s_size = sizeof (S);
376 
377     static const bool omit_chk_min
378       = (! s_is_signed || (t_is_signed && t_size >= s_size));
379 
380     static const bool omit_chk_max
381       = (t_size > s_size
382          || (t_size == s_size && (! t_is_signed || s_is_signed)));
383 
384     // If the check can be omitted, substitute constant false
385     // relation.
386 
387     typedef octave_int_cmp_op::cf cf;
388     typedef octave_int_cmp_op::lt lt;
389     typedef octave_int_cmp_op::gt gt;
390     typedef typename if_then_else<omit_chk_min, cf, lt>::result chk_min;
391     typedef typename if_then_else<omit_chk_max, cf, gt>::result chk_max;
392 
393     // Efficiency of the following depends on inlining and dead code
394     // elimination, but that should be a piece of cake for most
395     // compilers.
396 
397     if (chk_min::op (value, static_cast<S> (min_val ())))
398       return min_val ();
399     else if (chk_max::op (value, static_cast<S> (max_val ())))
400       return max_val ();
401     else
402       return static_cast<T> (value);
403   }
404 
405 private:
406 
407   // Compute a real-valued threshold for a max/min check.
408 
409   template <typename S>
compute_threshold(S val,T orig_val)410   static S compute_threshold (S val, T orig_val)
411   {
412     // Fool optimizations (maybe redundant).
413 
414     val = octave::math::round (val);
415 
416     // If val is even, but orig_val is odd, we're one unit off.
417 
418     if (orig_val % 2 && val / 2 == octave::math::round (val / 2))
419       // FIXME: is this always correct?
420       val *= (static_cast<S> (1) - (std::numeric_limits<S>::epsilon () / 2));
421 
422     return val;
423   }
424 
425 public:
426 
427   // Convert a real number (check NaN and non-int).
428 
429   template <typename S>
430   static T convert_real (const S& value);
431 };
432 
433 // Saturated (homogeneous) integer arithmetics.  The signed and
434 // unsigned implementations are significantly different, so we
435 // implement another layer and completely specialize.  Arithmetics
436 // inherits from octave_int_base so that it can use its exceptions and
437 // truncation functions.
438 
439 template <typename T, bool is_signed>
440 class octave_int_arith_base
441 { };
442 
443 // Unsigned arithmetics.  C++ standard requires it to be modular, so
444 // the overflows can be handled efficiently and reliably.
445 
446 template <typename T>
447 class octave_int_arith_base<T, false> : octave_int_base<T>
448 {
449 public:
450 
abs(T x)451   static T abs (T x) { return x; }
452 
signum(T x)453   static T signum (T x) { return x ? static_cast<T> (1) : static_cast<T> (0); }
454 
455   // Shifts do not overflow.
456 
rshift(T x,int n)457   static T rshift (T x, int n) { return x >> n; }
458 
lshift(T x,int n)459   static T lshift (T x, int n) { return x << n; }
460 
minus(T)461   static T minus (T) { return static_cast<T> (0); }
462 
463   // The overflow behavior for unsigned integers is guaranteed by
464   // C and C++, so the following should always work.
465 
add(T x,T y)466   static T add (T x, T y)
467   {
468     T u = x + y;
469 
470     if (u < x)
471       u = octave_int_base<T>::max_val ();
472 
473     return u;
474   }
475 
sub(T x,T y)476   static T sub (T x, T y)
477   {
478     T u = x - y;
479 
480     if (u > x)
481       u = 0;
482 
483     return u;
484   }
485 
486   // Multiplication is done using promotion to wider integer type.  If
487   // there is no suitable promotion type, this operation *MUST* be
488   // specialized.
489 
mul(T x,T y)490   static T mul (T x, T y) { return mul_internal (x, y); }
491 
mul_internal(T x,T y)492   static T mul_internal (T x, T y)
493   {
494     // Promotion type for multiplication (if exists).
495 
496     typedef typename query_integer_type<2*sizeof (T), false>::type mptype;
497 
498     return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
499                                              * static_cast<mptype> (y));
500   }
501 
502   // Division with rounding to nearest.  Note that / and % are
503   // probably computed by a single instruction.
504 
div(T x,T y)505   static T div (T x, T y)
506   {
507     if (y != 0)
508       {
509         T z = x / y;
510         T w = x % y;
511 
512         if (w >= y-w)
513           z += 1;
514 
515         return z;
516       }
517     else
518       return x ? octave_int_base<T>::max_val () : 0;
519   }
520 
521   // Remainder.
522 
rem(T x,T y)523   static T rem (T x, T y) { return y != 0 ? x % y : 0; }
524 
525   // Modulus.  Note the weird y = 0 case for Matlab compatibility.
526 
mod(T x,T y)527   static T mod (T x, T y) { return y != 0 ? x % y : x; }
528 };
529 
530 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
531 
532 // Handle 64-bit multiply using long double.
533 
534 #  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
535 
536 extern OCTAVE_API uint64_t
537 octave_external_uint64_uint64_mul (uint64_t, uint64_t);
538 
539 #  endif
540 
541 template <>
542 inline uint64_t
mul_internal(uint64_t x,uint64_t y)543 octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t x, uint64_t y)
544 {
545   uint64_t retval;
546 
547   long double p = static_cast<long double> (x) * static_cast<long double> (y);
548 
549   if (p > static_cast<long double> (octave_int_base<uint64_t>::max_val ()))
550     retval = octave_int_base<uint64_t>::max_val ();
551   else
552     retval = static_cast<uint64_t> (p);
553 
554   return retval;
555 }
556 
557 template <>
558 inline uint64_t
mul(uint64_t x,uint64_t y)559 octave_int_arith_base<uint64_t, false>::mul (uint64_t x, uint64_t y)
560 {
561 #  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
562   return octave_external_uint64_uint64_mul (x, y);
563 #  else
564   return mul_internal (x, y);
565 #  endif
566 }
567 
568 #else
569 
570 // Special handler for 64-bit integer multiply.
571 
572 template <>
573 OCTAVE_API uint64_t
574 octave_int_arith_base<uint64_t, false>::mul_internal (uint64_t, uint64_t);
575 
576 #endif
577 
578 template <typename T>
579 class octave_int_arith_base<T, true> : octave_int_base<T>
580 {
581   // The corresponding unsigned type.
582   typedef typename query_integer_type<sizeof (T), false>::type UT;
583 
584 public:
585 
586   // Returns 1 for negative number, 0 otherwise.
587 
__signbit(T x)588   static T __signbit (T x) { return (x < 0) ? 1 : 0; }
589 
abs(T x)590   static T abs (T x)
591   {
592     // -INT_MAX is safe because C++ actually allows only three
593     // implementations of integers: sign & magnitude, ones complement
594     // and twos complement.  The first test will, with modest
595     // optimizations, evaluate at compile time, and maybe eliminate
596     // the branch completely.
597 
598     return ((octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
599              && x == octave_int_base<T>::min_val ())
600             ? octave_int_base<T>::max_val ()
601             : ((x < 0) ? -x : x));
602   }
603 
signum(T x)604   static T signum (T x)
605   {
606     // With modest optimizations, this will compile without a jump.
607 
608     return ((x > 0) ? 1 : 0) - __signbit (x);
609   }
610 
611   // FIXME: we do not have an authority what signed shifts should
612   // exactly do, so we define them the easy way.  Note that Matlab
613   // does not define signed shifts.
614 
rshift(T x,int n)615   static T rshift (T x, int n) { return x >> n; }
616 
lshift(T x,int n)617   static T lshift (T x, int n) { return x << n; }
618 
619   // Minus has problems similar to abs.
620 
minus(T x)621   static T minus (T x)
622   {
623     return ((octave_int_base<T>::min_val () < -octave_int_base<T>::max_val ()
624              && x == octave_int_base<T>::min_val ())
625             ? octave_int_base<T>::max_val ()
626             : -x);
627   }
628 
add(T x,T y)629   static T add (T x, T y)
630   {
631     // Avoid anything that may overflow.
632 
633     return (y < 0
634             ? (x < octave_int_base<T>::min_val () - y
635                ? octave_int_base<T>::min_val ()
636                : x + y)
637             : (x > octave_int_base<T>::max_val () - y
638                ? octave_int_base<T>::max_val ()
639                : x + y));
640   }
641 
sub(T x,T y)642   static T sub (T x, T y)
643   {
644     // Avoid anything that may overflow.
645 
646     return (y < 0
647             ? (x > octave_int_base<T>::max_val () + y
648                ? octave_int_base<T>::max_val ()
649                : x - y)
650             : (x < octave_int_base<T>::min_val () + y
651                ? octave_int_base<T>::min_val ()
652                : x - y));
653   }
654 
655   // Multiplication is done using promotion to wider integer type.  If
656   // there is no suitable promotion type, this operation *MUST* be
657   // specialized.
658 
mul(T x,T y)659   static T mul (T x, T y) { return mul_internal (x, y); }
660 
mul_internal(T x,T y)661   static T mul_internal (T x, T y)
662   {
663     // Promotion type for multiplication (if exists).
664 
665     typedef typename query_integer_type<2*sizeof (T), true>::type mptype;
666 
667     return octave_int_base<T>::truncate_int (static_cast<mptype> (x)
668            * static_cast<mptype> (y));
669   }
670 
671   // Division.
672 
div(T x,T y)673   static T div (T x, T y)
674   {
675     T z;
676 
677     if (y == 0)
678       {
679         if (x < 0)
680           z = octave_int_base<T>::min_val ();
681         else if (x != 0)
682           z = octave_int_base<T>::max_val ();
683         else
684           z = 0;
685       }
686     else if (y < 0)
687       {
688         // This is a special case that overflows as well.
689         if (y == -1 && x == octave_int_base<T>::min_val ())
690           z = octave_int_base<T>::max_val ();
691         else
692           {
693             z = x / y;
694             // Can't overflow, but std::abs (x) can!
695             T w = -octave_int_abs (x % y);
696             if (w <= y - w)
697               z -= 1 - (__signbit (x) << 1);
698           }
699       }
700     else
701       {
702         z = x / y;
703 
704         // FIXME: this is a workaround due to MSVC's absence of
705         // std::abs (int64_t).  The call to octave_int_abs can't
706         // overflow, but std::abs (x) can!
707         T w = octave_int_abs (x % y);
708 
709         if (w >= y - w)
710           z += 1 - (__signbit (x) << 1);
711       }
712     return z;
713   }
714 
715   // Remainder.
716 
rem(T x,T y)717   static T rem (T x, T y)
718   {
719     return y != 0 ? x % y : 0;
720   }
721 
722   // Modulus.  Note the weird y = 0 case for Matlab compatibility.
723 
mod(T x,T y)724   static T mod (T x, T y)
725   {
726     if (y != 0)
727       {
728         T r = x % y;
729         return (r == 0) ? 0 : (((r < 0) != (y < 0)) ? r + y : r);
730       }
731     else
732       return x;
733   }
734 };
735 
736 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
737 
738 // Handle 64-bit multiply using long double
739 
740 #  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
741 
742 extern OCTAVE_API int64_t
743 octave_external_int64_int64_mul (int64_t, int64_t);
744 
745 #  endif
746 
747 template <>
748 inline int64_t
mul_internal(int64_t x,int64_t y)749 octave_int_arith_base<int64_t, true>::mul_internal (int64_t x, int64_t y)
750 {
751   int64_t retval;
752 
753   long double p = static_cast<long double> (x) * static_cast<long double> (y);
754 
755   if (p > static_cast<long double> (octave_int_base<int64_t>::max_val ()))
756     retval = octave_int_base<int64_t>::max_val ();
757   else if (p < static_cast<long double> (octave_int_base<int64_t>::min_val ()))
758     retval = octave_int_base<int64_t>::min_val ();
759   else
760     retval = static_cast<int64_t> (p);
761 
762   return retval;
763 }
764 
765 template <>
766 inline int64_t
mul(int64_t x,int64_t y)767 octave_int_arith_base<int64_t, true>::mul (int64_t x, int64_t y)
768 {
769 #  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
770   return octave_external_int64_int64_mul (x, y);
771 #  else
772   return mul_internal (x, y);
773 #  endif
774 }
775 
776 #else
777 
778 // Special handler for 64-bit integer multiply.
779 
780 template <>
781 OCTAVE_API int64_t
782 octave_int_arith_base<int64_t, true>::mul_internal (int64_t, int64_t);
783 
784 #endif
785 
786 // This class simply selects the proper arithmetics.
787 template <typename T>
788 class octave_int_arith
789 : public octave_int_arith_base<T, std::numeric_limits<T>::is_signed>
790 { };
791 
792 template <typename T>
793 class
794 octave_int : public octave_int_base<T>
795 {
796 public:
797 
798   typedef T val_type;
799 
octave_int(void)800   octave_int (void) : m_ival () { }
801 
octave_int(T i)802   octave_int (T i) : m_ival (i) { }
803 
804 #if defined (OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES)
805 
806   // Always treat characters as unsigned.
octave_int(char c)807   octave_int (char c)
808     : m_ival (octave_int_base<T>::truncate_int (static_cast<unsigned char> (c)))
809   { }
810 
811 #endif
812 
octave_int(double d)813   octave_int (double d)
814     : m_ival (octave_int_base<T>::convert_real (d)) { }
815 
octave_int(float d)816   octave_int (float d)
817     : m_ival (octave_int_base<T>::convert_real (d)) { }
818 
819 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
820 
octave_int(long double d)821   octave_int (long double d)
822     : m_ival (octave_int_base<T>::convert_real (d)) { }
823 
824 #endif
825 
octave_int(bool b)826   octave_int (bool b) : m_ival (b) { }
827 
828   template <typename U>
octave_int(const U & i)829   octave_int (const U& i)
830     : m_ival(octave_int_base<T>::truncate_int (i)) { }
831 
832   template <typename U>
octave_int(const octave_int<U> & i)833   octave_int (const octave_int<U>& i)
834     : m_ival (octave_int_base<T>::truncate_int (i.value ())) { }
835 
836   octave_int (const octave_int<T>&) = default;
837 
838   octave_int& operator = (const octave_int<T>&) = default;
839 
840   ~octave_int (void) = default;
841 
value(void)842   T value (void) const { return m_ival; }
843 
iptr(void)844   const unsigned char * iptr (void) const
845   {
846     return reinterpret_cast<const unsigned char *> (& m_ival);
847   }
848 
849   bool operator ! (void) const { return ! m_ival; }
850 
bool_value(void)851   bool bool_value (void) const { return static_cast<bool> (value ()); }
852 
char_value(void)853   char char_value (void) const { return static_cast<char> (value ()); }
854 
double_value(void)855   double double_value (void) const { return static_cast<double> (value ()); }
856 
float_value(void)857   float float_value (void) const { return static_cast<float> (value ()); }
858 
T(void)859   operator T (void) const { return value (); }
860 
861   octave_int<T> operator + () const { return *this; }
862 
863   // unary operators & mappers
864 #define OCTAVE_INT_UN_OP(OPNAME, NAME)          \
865   inline octave_int<T>                          \
866   OPNAME () const                               \
867   {                                             \
868     return octave_int_arith<T>::NAME (m_ival);  \
869   }
870 
871   OCTAVE_INT_UN_OP (operator -, minus)
OCTAVE_INT_UN_OP(abs,abs)872   OCTAVE_INT_UN_OP (abs, abs)
873   OCTAVE_INT_UN_OP (signum, signum)
874 
875 #undef OCTAVE_INT_UN_OP
876 
877   // Homogeneous binary integer operations.
878 #define OCTAVE_INT_BIN_OP(OP, NAME, ARGT)               \
879   inline octave_int<T>                                  \
880   operator OP (const ARGT& y) const                     \
881   {                                                     \
882     return octave_int_arith<T>::NAME (m_ival, y);       \
883   }                                                     \
884                                                         \
885   inline octave_int<T>&                                 \
886   operator OP##= (const ARGT& y)                        \
887   {                                                     \
888     m_ival = octave_int_arith<T>::NAME (m_ival, y);     \
889     return *this;                                       \
890   }
891 
892   OCTAVE_INT_BIN_OP (+, add, octave_int<T>)
893   OCTAVE_INT_BIN_OP (-, sub, octave_int<T>)
894   OCTAVE_INT_BIN_OP (*, mul, octave_int<T>)
895   OCTAVE_INT_BIN_OP (/, div, octave_int<T>)
896   OCTAVE_INT_BIN_OP (%, rem, octave_int<T>)
897   OCTAVE_INT_BIN_OP (<<, lshift, int)
898   OCTAVE_INT_BIN_OP (>>, rshift, int)
899 
900 #undef OCTAVE_INT_BIN_OP
901 
902   static octave_int<T> min (void) { return std::numeric_limits<T>::min (); }
max(void)903   static octave_int<T> max (void) { return std::numeric_limits<T>::max (); }
904 
nbits(void)905   static int nbits (void) { return std::numeric_limits<T>::digits; }
906 
byte_size(void)907   static int byte_size (void) { return sizeof (T); }
908 
909   static const char * type_name ();
910 
911   // The following are provided for convenience.
912   static const octave_int zero, one;
913 
914   // Unsafe.  This function exists to support the MEX interface.
915   // You should not use it anywhere else.
mex_get_data(void)916   void * mex_get_data (void) const { return const_cast<T *> (&m_ival); }
917 
918 private:
919 
920   T m_ival;
921 };
922 
923 template <typename T>
924 inline octave_int<T>
rem(const octave_int<T> & x,const octave_int<T> & y)925 rem (const octave_int<T>& x, const octave_int<T>& y)
926 {
927   return octave_int_arith<T>::rem (x.value (), y.value ());
928 }
929 
930 template <typename T>
931 inline octave_int<T>
mod(const octave_int<T> & x,const octave_int<T> & y)932 mod (const octave_int<T>& x, const octave_int<T>& y)
933 {
934   return octave_int_arith<T>::mod (x.value (), y.value ());
935 }
936 
937 // No mixed integer binary operations!
938 
939 namespace octave
940 {
941   namespace math
942   {
943     template <typename T>
944     bool
isnan(const octave_int<T> &)945     isnan (const octave_int<T>&)
946     {
947       return false;
948     }
949   }
950 }
951 
952 // FIXME: can/should any of these be inline?
953 
954 template <typename T>
955 extern OCTAVE_API octave_int<T>
956 pow (const octave_int<T>&, const octave_int<T>&);
957 
958 template <typename T>
959 extern OCTAVE_API octave_int<T>
960 pow (const double& a, const octave_int<T>& b);
961 
962 template <typename T>
963 extern OCTAVE_API octave_int<T>
964 pow (const octave_int<T>& a, const double& b);
965 
966 template <typename T>
967 extern OCTAVE_API octave_int<T>
968 pow (const float& a, const octave_int<T>& b);
969 
970 template <typename T>
971 extern OCTAVE_API octave_int<T>
972 pow (const octave_int<T>& a, const float& b);
973 
974 // FIXME: Do we really need a differently named single-precision
975 //        function integer power function here instead of an overloaded
976 //        one?
977 
978 template <typename T>
979 extern OCTAVE_API octave_int<T>
980 powf (const float& a, const octave_int<T>& b);
981 
982 template <typename T>
983 extern OCTAVE_API octave_int<T>
984 powf (const octave_int<T>& a, const float& b);
985 
986 // Binary relations
987 
988 #define OCTAVE_INT_CMP_OP(OP, NAME)                                     \
989   template <typename T1, typename T2>                                   \
990   inline bool                                                           \
991   operator OP (const octave_int<T1>& x, const octave_int<T2>& y)        \
992   {                                                                     \
993     return octave_int_cmp_op::op<octave_int_cmp_op::NAME, T1, T2> (x.value (), y.value ()); \
994   }
995 
996 OCTAVE_INT_CMP_OP (<, lt)
997 OCTAVE_INT_CMP_OP (<=, le)
998 OCTAVE_INT_CMP_OP (>, gt)
999 OCTAVE_INT_CMP_OP (>=, ge)
1000 OCTAVE_INT_CMP_OP (==, eq)
1001 OCTAVE_INT_CMP_OP (!=, ne)
1002 
1003 #undef OCTAVE_INT_CMP_OP
1004 
1005 template <typename T>
1006 inline std::ostream&
1007 operator << (std::ostream& os, const octave_int<T>& ival)
1008 {
1009   os << ival.value ();
1010   return os;
1011 }
1012 
1013 template <typename T>
1014 inline std::istream&
1015 operator >> (std::istream& is, octave_int<T>& ival)
1016 {
1017   T tmp = 0;
1018   is >> tmp;
1019   ival = tmp;
1020   return is;
1021 }
1022 
1023 // We need to specialise for char and unsigned char because
1024 // std::operator<< and std::operator>> are overloaded to input and
1025 // output the ASCII character values instead of a representation of
1026 // their numerical value (e.g., os << char(10) outputs a space instead
1027 // of outputting the characters '1' and '0')
1028 
1029 template <>
1030 inline std::ostream&
1031 operator << (std::ostream& os, const octave_int<int8_t>& ival)
1032 {
1033   os << static_cast<int> (ival.value ());
1034 
1035   return os;
1036 }
1037 
1038 template <>
1039 inline std::ostream&
1040 operator << (std::ostream& os, const octave_int<uint8_t>& ival)
1041 {
1042   os << static_cast<unsigned int> (ival.value ());
1043 
1044   return os;
1045 }
1046 
1047 template <>
1048 inline std::istream&
1049 operator >> (std::istream& is, octave_int<int8_t>& ival)
1050 {
1051   int tmp = 0;
1052   is >> tmp;
1053   ival = static_cast<int8_t> (tmp);
1054 
1055   return is;
1056 }
1057 
1058 template <>
1059 inline std::istream&
1060 operator >> (std::istream& is, octave_int<uint8_t>& ival)
1061 {
1062   unsigned int tmp = 0;
1063   is >> tmp;
1064   ival = static_cast<uint8_t> (tmp);
1065 
1066   return is;
1067 }
1068 
1069 // Bitwise operations
1070 
1071 #define OCTAVE_INT_BITCMP_OP(OP)                                \
1072   template <typename T>                                         \
1073   octave_int<T>                                                 \
1074   operator OP (const octave_int<T>& x, const octave_int<T>& y)  \
1075   {                                                             \
1076     return x.value () OP y.value ();                            \
1077   }
1078 
1079 OCTAVE_INT_BITCMP_OP (&)
1080 OCTAVE_INT_BITCMP_OP (|)
1081 OCTAVE_INT_BITCMP_OP (^)
1082 
1083 #undef OCTAVE_INT_BITCMP_OP
1084 
1085 // General bit shift.
1086 template <typename T>
1087 octave_int<T>
1088 bitshift (const octave_int<T>& a, int n,
1089           const octave_int<T>& mask = std::numeric_limits<T>::max ())
1090 {
1091   if (n > 0)
1092     return (a << n) & mask;
1093   else if (n < 0)
1094     return (a >> -n) & mask;
1095   else
1096     return a & mask;
1097 }
1098 
1099 #if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
1100 
1101 #  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP(T, OP)     \
1102   extern OCTAVE_API T                                           \
1103   external_double_ ## T ## _ ## OP (double x, T y);             \
1104                                                                 \
1105   extern OCTAVE_API T                                           \
1106   external_ ## T ## _double_ ## OP (T x, double y)
1107 
1108 #  define OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS(T)        \
1109   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, add);          \
1110   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, sub);          \
1111   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, mul);          \
1112   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP (T, div)
1113 
1114   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_int64);
1115   OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS (octave_uint64);
1116 
1117 #endif
1118 
1119 #define OCTAVE_INT_DOUBLE_BIN_OP0(OP)                           \
1120   template <typename T>                                         \
1121   inline octave_int<T>                                          \
1122   operator OP (const octave_int<T>& x, const double& y)         \
1123   {                                                             \
1124     return octave_int<T> (static_cast<double> (x) OP y);        \
1125   }                                                             \
1126                                                                 \
1127   template <typename T>                                         \
1128   inline octave_int<T>                                          \
1129   operator OP (const double& x, const octave_int<T>& y)         \
1130   {                                                             \
1131     return octave_int<T> (x OP static_cast<double> (y));        \
1132   }
1133 
1134 #if defined (OCTAVE_INT_USE_LONG_DOUBLE)
1135 
1136 // Handle mixed op using long double.
1137 
1138 #  if defined (OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED)
1139 
1140 #    define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)                  \
1141   OCTAVE_INT_DOUBLE_BIN_OP0(OP)                                 \
1142                                                                 \
1143   template <>                                                   \
1144   inline octave_int64                                           \
1145   operator OP (const double& x, const octave_int64& y)          \
1146   {                                                             \
1147     return external_double_octave_int64_ ## NAME (x, y);        \
1148   }                                                             \
1149                                                                 \
1150   template <>                                                   \
1151   inline octave_uint64                                          \
1152   operator OP (const double& x, const octave_uint64& y)         \
1153   {                                                             \
1154     return external_double_octave_uint64_ ## NAME (x, y);       \
1155   }                                                             \
1156                                                                 \
1157   template <>                                                   \
1158   inline octave_int64                                           \
1159   operator OP (const octave_int64& x, const double& y)          \
1160   {                                                             \
1161     return external_octave_int64_double_ ## NAME (x, y);        \
1162   }                                                             \
1163                                                                 \
1164   template <>                                                   \
1165   inline octave_uint64                                          \
1166   operator OP (const octave_uint64& x, const double& y)         \
1167   {                                                             \
1168     return external_octave_uint64_double_ ## NAME (x, y);       \
1169   }
1170 
1171 #  else
1172 
1173 #    define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)                          \
1174   OCTAVE_INT_DOUBLE_BIN_OP0(OP)                                         \
1175                                                                         \
1176   template <>                                                           \
1177   inline octave_int64                                                   \
1178   operator OP (const double& x, const octave_int64& y)                  \
1179   {                                                                     \
1180     return octave_int64 (x OP static_cast<long double> (y.value ()));   \
1181   }                                                                     \
1182                                                                         \
1183   template <>                                                           \
1184   inline octave_uint64                                                  \
1185   operator OP (const double& x, const octave_uint64& y)                 \
1186   {                                                                     \
1187     return octave_uint64 (x OP static_cast<long double> (y.value ()));  \
1188   }                                                                     \
1189                                                                         \
1190   template <>                                                           \
1191   inline octave_int64                                                   \
1192   operator OP (const octave_int64& x, const double& y)                  \
1193   {                                                                     \
1194     return octave_int64 (static_cast<long double> (x.value ()) OP y);   \
1195   }                                                                     \
1196                                                                         \
1197   template <>                                                           \
1198   inline octave_uint64                                                  \
1199   operator OP (const octave_uint64& x, const double& y)                 \
1200   {                                                                     \
1201     return octave_uint64 (static_cast<long double> (x.value ()) OP y);  \
1202   }
1203 
1204 #  endif
1205 
1206 #else
1207 
1208 // External handlers.
1209 
1210 #  define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME)            \
1211   OCTAVE_INT_DOUBLE_BIN_OP0(OP)                         \
1212                                                         \
1213   template <>                                           \
1214   OCTAVE_API octave_int64                               \
1215   operator OP (const double&, const octave_int64&);     \
1216                                                         \
1217   template <>                                           \
1218   OCTAVE_API octave_uint64                              \
1219   operator OP (const double&, const octave_uint64&);    \
1220                                                         \
1221   template <>                                           \
1222   OCTAVE_API octave_int64                               \
1223   operator OP (const octave_int64&, const double&);     \
1224                                                         \
1225   template <>                                           \
1226   OCTAVE_API octave_uint64                              \
1227   operator OP (const octave_uint64&, const double&);
1228 
1229 #endif
1230 
1231 OCTAVE_INT_DOUBLE_BIN_OP (+, add)
1232 OCTAVE_INT_DOUBLE_BIN_OP (-, sub)
1233 OCTAVE_INT_DOUBLE_BIN_OP (*, mul)
1234 OCTAVE_INT_DOUBLE_BIN_OP (/, div)
1235 
1236 #undef OCTAVE_INT_DOUBLE_BIN_OP0
1237 #undef OCTAVE_INT_DOUBLE_BIN_OP
1238 #undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OP
1239 #undef OCTAVE_DECLARE_EXTERNAL_LONG_DOUBLE_INT_OPS
1240 
1241 #define OCTAVE_INT_DOUBLE_CMP_OP(OP, NAME)                              \
1242   template <typename T>                                                 \
1243   inline bool                                                           \
1244   operator OP (const octave_int<T>& x, const double& y)                 \
1245   {                                                                     \
1246     return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x.value (), y); \
1247   }                                                                     \
1248                                                                         \
1249   template <typename T>                                                 \
1250   inline bool                                                           \
1251   operator OP (const double& x, const octave_int<T>& y)                 \
1252   {                                                                     \
1253     return octave_int_cmp_op::mop<octave_int_cmp_op::NAME> (x, y.value ()); \
1254   }
1255 
1256 OCTAVE_INT_DOUBLE_CMP_OP (<, lt)
1257 OCTAVE_INT_DOUBLE_CMP_OP (<=, le)
1258 OCTAVE_INT_DOUBLE_CMP_OP (>=, ge)
1259 OCTAVE_INT_DOUBLE_CMP_OP (>, gt)
1260 OCTAVE_INT_DOUBLE_CMP_OP (==, eq)
1261 OCTAVE_INT_DOUBLE_CMP_OP (!=, ne)
1262 
1263 #undef OCTAVE_INT_DOUBLE_CMP_OP
1264 
1265 // Floats are handled by simply converting to doubles.
1266 
1267 #define OCTAVE_INT_FLOAT_BIN_OP(OP)             \
1268   template <typename T>                         \
1269   inline octave_int<T>                          \
1270   operator OP (const octave_int<T>& x, float y) \
1271   {                                             \
1272     return x OP static_cast<double> (y);        \
1273   }                                             \
1274                                                 \
1275   template <typename T>                         \
1276   inline octave_int<T>                          \
1277   operator OP (float x, const octave_int<T>& y) \
1278   {                                             \
1279     return static_cast<double> (x) OP y;        \
1280   }
1281 
1282 OCTAVE_INT_FLOAT_BIN_OP (+)
1283 OCTAVE_INT_FLOAT_BIN_OP (-)
1284 OCTAVE_INT_FLOAT_BIN_OP (*)
1285 OCTAVE_INT_FLOAT_BIN_OP (/)
1286 
1287 #undef OCTAVE_INT_FLOAT_BIN_OP
1288 
1289 #define OCTAVE_INT_FLOAT_CMP_OP(OP) \
1290   template <typename T>                                 \
1291   inline bool                                           \
1292   operator OP (const octave_int<T>& x, const float& y)  \
1293   {                                                     \
1294     return x OP static_cast<double> (y);                \
1295   }                                                     \
1296                                                         \
1297   template <typename T>                                 \
1298   bool                                                  \
1299   operator OP (const float& x, const octave_int<T>& y)  \
1300   {                                                     \
1301     return static_cast<double> (x) OP y;                \
1302   }
1303 
1304 OCTAVE_INT_FLOAT_CMP_OP (<)
1305 OCTAVE_INT_FLOAT_CMP_OP (<=)
1306 OCTAVE_INT_FLOAT_CMP_OP (>=)
1307 OCTAVE_INT_FLOAT_CMP_OP (>)
1308 OCTAVE_INT_FLOAT_CMP_OP (==)
1309 OCTAVE_INT_FLOAT_CMP_OP (!=)
1310 
1311 #undef OCTAVE_INT_FLOAT_CMP_OP
1312 
1313 template <typename T>
1314 octave_int<T>
xmax(const octave_int<T> & x,const octave_int<T> & y)1315 xmax (const octave_int<T>& x, const octave_int<T>& y)
1316 {
1317   const T xv = x.value ();
1318   const T yv = y.value ();
1319 
1320   return octave_int<T> (xv >= yv ? xv : yv);
1321 }
1322 
1323 template <typename T>
1324 octave_int<T>
xmin(const octave_int<T> & x,const octave_int<T> & y)1325 xmin (const octave_int<T>& x, const octave_int<T>& y)
1326 {
1327   const T xv = x.value ();
1328   const T yv = y.value ();
1329 
1330   return octave_int<T> (xv <= yv ? xv : yv);
1331 }
1332 
1333 #endif
1334