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