/*
Copyright (C) 2004-2013 John W. Eaton
Copyright (C) 2008-2009 Jaroslav Hajek
This file is part of Octave.
Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING. If not, see
.
*/
#if !defined (octave_oct_inttypes_h)
#define octave_oct_inttypes_h 1
#include
#include
#include
#include "lo-traits.h"
#include "lo-math.h"
#include "lo-mappers.h"
#ifdef OCTAVE_INT_USE_LONG_DOUBLE
inline long double xround (long double x) { return roundl (x); }
inline long double xisnan (long double x)
{ return xisnan (static_cast (x)); }
#endif
// FIXME: we define this by our own because some compilers, such as
// MSVC, do not provide std::abs (int64_t) and std::abs (uint64_t). In
// the future, it should go away in favor of std::abs.
template
inline T octave_int_abs (T x) { return x >= 0 ? x : -x; }
// Query for an integer type of certain sizeof, and signedness.
template
struct query_integer_type
{
public:
static const bool registered = false;
typedef void type; // Void shall result in a compile-time error if we
// attempt to use it in computations.
};
#define REGISTER_INT_TYPE(TYPE) \
template <> \
class query_integer_type::is_signed> \
{ \
public: \
static const bool registered = true; \
typedef TYPE type; \
}
// No two registered integers can share sizeof and signedness.
REGISTER_INT_TYPE (int8_t);
REGISTER_INT_TYPE (uint8_t);
REGISTER_INT_TYPE (int16_t);
REGISTER_INT_TYPE (uint16_t);
REGISTER_INT_TYPE (int32_t);
REGISTER_INT_TYPE (uint32_t);
REGISTER_INT_TYPE (int64_t);
REGISTER_INT_TYPE (uint64_t);
// Rationale: Comparators have a single static method, rel(), that returns the
// result of the binary relation. They also have two static boolean fields:
// ltval, gtval determine the value of x OP y if x < y, x > y, respectively.
#define REGISTER_OCTAVE_CMP_OP(NM,OP) \
class NM \
{ \
public: \
static const bool ltval = (0 OP 1), gtval = (1 OP 0); \
template \
static bool op (T x, T y) { return x OP y; } \
}
// We also provide two special relations: ct, yielding always true, and cf,
// yielding always false.
#define REGISTER_OCTAVE_CONST_OP(NM,value) \
class NM \
{ \
public: \
static const bool ltval = value, gtval = value; \
template \
static bool op (T, T) { return value; } \
}
// Handles non-homogeneous integer comparisons. Avoids doing useless tests.
class octave_int_cmp_op
{
// This determines a suitable promotion type for T1 when meeting T2 in a
// binary relation. If promotion to int or T2 is safe, it is used. Otherwise,
// the signedness of T1 is preserved and it is widened if T2 is wider.
// Notice that if this is applied to both types, they must end up with equal
// size.
template
class prom
{
// Promote to int?
static const bool pint = (sizeof (T1) < sizeof (int)
&& sizeof (T2) < sizeof (int));
static const bool t1sig = std::numeric_limits::is_signed;
static const bool t2sig = std::numeric_limits::is_signed;
static const bool psig =
(pint || (sizeof (T2) > sizeof (T1) && t2sig) || t1sig);
static const int psize =
(pint ? sizeof (int) : (sizeof (T2) > sizeof (T1)
? sizeof (T2) : sizeof (T1)));
public:
typedef typename query_integer_type::type type;
};
// Implements comparisons between two types of equal size but
// possibly different signedness.
template
class uiop
{
typedef typename query_integer_type::type utype;
typedef typename query_integer_type::type stype;
public:
static bool op (utype x, utype y)
{ return xop::op (x, y); }
static bool op (stype x, stype y)
{ return xop::op (x, y); }
static bool op (stype x, utype y)
{ return (x < 0) ? xop::ltval : xop::op (static_cast (x), y); }
static bool op (utype x, stype y)
{ return (y < 0) ? xop::gtval : xop::op (x, static_cast (y)); }
};
public:
REGISTER_OCTAVE_CMP_OP (lt, <);
REGISTER_OCTAVE_CMP_OP (le, <=);
REGISTER_OCTAVE_CMP_OP (gt, >);
REGISTER_OCTAVE_CMP_OP (ge, >=);
REGISTER_OCTAVE_CMP_OP (eq, ==);
REGISTER_OCTAVE_CMP_OP (ne, !=);
REGISTER_OCTAVE_CONST_OP (ct, true);
REGISTER_OCTAVE_CONST_OP (cf, false);
// Universal comparison operation.
template
static bool
op (T1 x, T2 y)
{
typedef typename prom::type PT1;
typedef typename prom::type PT2;
return uiop::op (static_cast (x),
static_cast (y));
}
public:
// Mixed comparisons
template
static bool
mop (T x, double y)
{ return xop::op (static_cast (x), y); }
template
static bool
mop (double x, T y)
{ return xop::op (x, static_cast (y)); }
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
#define DECLARE_EXTERNAL_LONG_DOUBLE_CMP_OPS(T) \
template static OCTAVE_API bool \
external_mop (double, T); \
template static OCTAVE_API bool \
external_mop (T, double)
DECLARE_EXTERNAL_LONG_DOUBLE_CMP_OPS (int64_t);
DECLARE_EXTERNAL_LONG_DOUBLE_CMP_OPS (uint64_t);
#endif
// Typecasting to doubles won't work properly for 64-bit integers --
// they lose precision.
// If we have long doubles, use them...
#ifdef OCTAVE_INT_USE_LONG_DOUBLE
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
#define DEFINE_LONG_DOUBLE_CMP_OP(T) \
template \
static bool \
mop (double x, T y) \
{ \
return external_mop (x, y); \
} \
template \
static bool \
mop (T x, double y) \
{ \
return external_mop (x, y); \
}
#else
#define DEFINE_LONG_DOUBLE_CMP_OP(T) \
template \
static bool \
mop (double x, T y) \
{ \
return xop::op (static_cast (x), \
static_cast (y)); \
} \
template \
static bool \
mop (T x, double y) \
{ \
return xop::op (static_cast (x), \
static_cast (y)); \
}
#endif
#else
// ... otherwise, use external handlers
// FIXME: We could declare directly the mop methods as external,
// but we can't do this because bugs in gcc (<= 4.3) prevent
// explicit instantiations later in that case.
#define DEFINE_LONG_DOUBLE_CMP_OP(T) \
template static OCTAVE_API bool \
emulate_mop (double, T); \
template \
static bool \
mop (double x, T y) \
{ \
return emulate_mop (x, y); \
} \
template static OCTAVE_API bool \
emulate_mop (T, double); \
template \
static bool \
mop (T x, double y) \
{ \
return emulate_mop (x, y); \
}
#endif
DEFINE_LONG_DOUBLE_CMP_OP(int64_t)
DEFINE_LONG_DOUBLE_CMP_OP(uint64_t)
#undef DEFINE_LONG_DOUBLE_CMP_OP
};
// Base integer class. No data, just conversion methods and exception flags.
template
class octave_int_base
{
public:
static T min_val () { return std::numeric_limits:: min (); }
static T max_val () { return std::numeric_limits:: max (); }
// Convert integer value.
template
static T
truncate_int (const S& value)
{
// An exhaustive test whether the max and/or min check can be omitted.
static const bool t_is_signed = std::numeric_limits::is_signed;
static const bool s_is_signed = std::numeric_limits::is_signed;
static const int t_size = sizeof (T), s_size = sizeof (S);
static const bool omit_chk_min =
(! s_is_signed || (t_is_signed && t_size >= s_size));
static const bool omit_chk_max =
(t_size > s_size || (t_size == s_size
&& (! t_is_signed || s_is_signed)));
// If the check can be omitted, substitute constant false relation.
typedef octave_int_cmp_op::cf cf;
typedef octave_int_cmp_op::lt lt;
typedef octave_int_cmp_op::gt gt;
typedef typename if_then_else::result chk_min;
typedef typename if_then_else::result chk_max;
// Efficiency of the following depends on inlining and dead code
// elimination, but that should be a piece of cake for most compilers.
if (chk_min::op (value, static_cast (min_val ())))
{
return min_val ();
}
else if (chk_max::op (value, static_cast (max_val ())))
{
return max_val ();
}
else
return static_cast (value);
}
private:
// Computes a real-valued threshold for a max/min check.
template
static S
compute_threshold (S val, T orig_val)
{
val = xround (val); // Fool optimizations (maybe redundant)
// If val is even, but orig_val is odd, we're one unit off.
if (orig_val % 2 && val / 2 == xround (val / 2))
// FIXME: is this always correct?
val *= (static_cast(1) - (std::numeric_limits::epsilon () / 2));
return val;
}
public:
// Convert a real number (check NaN and non-int).
template
static T
convert_real (const S& value)
{
// Compute proper thresholds.
static const S thmin = compute_threshold (static_cast (min_val ()),
min_val ());
static const S thmax = compute_threshold (static_cast (max_val ()),
max_val ());
if (xisnan (value))
{
return static_cast (0);
}
else if (value < thmin)
{
return min_val ();
}
else if (value > thmax)
{
return max_val ();
}
else
{
S rvalue = xround (value);
return static_cast (rvalue);
}
}
};
// Saturated (homogeneous) integer arithmetics. The signed and unsigned
// implementations are significantly different, so we implement another layer
// and completely specialize. Arithmetics inherits from octave_int_base so that
// it can use its exceptions and truncation functions.
template
class octave_int_arith_base
{ };
// Unsigned arithmetics. C++ standard requires it to be modular, so the
// overflows can be handled efficiently and reliably.
template
class octave_int_arith_base : octave_int_base
{
public:
static T
abs (T x) { return x; }
static T
signum (T x) { return x ? static_cast (1) : static_cast (0); }
// Shifts do not overflow.
static T
rshift (T x, int n) { return x >> n; }
static T
lshift (T x, int n) { return x << n; }
static T
minus (T)
{
return static_cast (0);
}
// the overflow behaviour for unsigned integers is guaranteed by C/C++,
// so the following should always work.
static T
add (T x, T y)
{
T u = x + y;
if (u < x)
{
u = octave_int_base::max_val ();
}
return u;
}
static T
sub (T x, T y)
{
T u = x - y;
if (u > x)
{
u = 0;
}
return u;
}
// Multiplication is done using promotion to wider integer type. If there is
// no suitable promotion type, this operation *MUST* be specialized.
static T mul (T x, T y) { return mul_internal (x, y); }
static T
mul_internal (T x, T y)
{
// Promotion type for multiplication (if exists).
typedef typename query_integer_type<2*sizeof (T), false>::type mptype;
return octave_int_base::truncate_int (static_cast (x)
* static_cast (y));
}
// Division with rounding to nearest. Note that / and % are probably
// computed by a single instruction.
static T
div (T x, T y)
{
if (y != 0)
{
T z = x / y, w = x % y;
if (w >= y-w) z += 1;
return z;
}
else
{
return x ? octave_int_base::max_val () : 0;
}
}
// Remainder.
static T
rem (T x, T y)
{
return y != 0 ? x % y : 0;
}
// Modulus. Note the weird y = 0 case for Matlab compatibility.
static T
mod (T x, T y)
{
return y != 0 ? x % y : x;
}
};
#ifdef OCTAVE_INT_USE_LONG_DOUBLE
// Handle 64-bit multiply using long double
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
extern OCTAVE_API uint64_t
octave_external_uint64_uint64_mul (uint64_t, uint64_t);
#endif
template <>
inline uint64_t
octave_int_arith_base::mul_internal (uint64_t x, uint64_t y)
{
uint64_t retval;
long double p = static_cast (x) * static_cast (y);
if (p > static_cast (octave_int_base::max_val ()))
retval = octave_int_base::max_val ();
else
retval = static_cast (p);
return retval;
}
template <>
inline uint64_t
octave_int_arith_base::mul (uint64_t x, uint64_t y)
{
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
return octave_external_uint64_uint64_mul (x, y);
#else
return mul_internal (x, y);
#endif
}
#else
// Special handler for 64-bit integer multiply.
template <>
OCTAVE_API uint64_t
octave_int_arith_base::mul_internal (uint64_t, uint64_t);
#endif
// Signed integer arithmetics.
// Rationale: If HAVE_FAST_INT_OPS is defined, the following conditions
// should hold:
// 1. Signed numbers are represented by twos complement
// (see )
// 2. static_cast to unsigned int counterpart works like interpreting
// the signed bit pattern as unsigned (and is thus zero-cost).
// 3. Signed addition and subtraction yield the same bit results as unsigned.
// (We use casts to prevent optimization interference, so there is no
// need for things like -ftrapv).
// 4. Bit operations on signed integers work like on unsigned integers,
// except for the shifts. Shifts are arithmetic.
//
// The above conditions are satisfied by most modern platforms. If
// HAVE_FAST_INT_OPS is defined, bit tricks and wraparound arithmetics are used
// to avoid conditional jumps as much as possible, thus being friendly to
// modern pipeline processor architectures.
// Otherwise, we fall back to a bullet-proof code that only uses assumptions
// guaranteed by the standard.
template
class octave_int_arith_base : octave_int_base
{
// The corresponding unsigned type.
typedef typename query_integer_type::type UT;
public:
// Returns 1 for negative number, 0 otherwise.
static T
__signbit (T x)
{
#ifdef HAVE_FAST_INT_OPS
return static_cast (x) >> std::numeric_limits::digits;
#else
return (x < 0) ? 1 : 0;
#endif
}
static T
abs (T x)
{
#ifdef HAVE_FAST_INT_OPS
// This is close to how GCC does std::abs, but we can't just use std::abs,
// because its behaviour for INT_MIN is undefined and the compiler could
// discard the following test.
T m = x >> std::numeric_limits::digits;
T y = (x ^ m) - m;
if (y < 0)
{
y = octave_int_base::max_val ();
}
return y;
#else
// -INT_MAX is safe because C++ actually allows only three implementations
// of integers: sign & magnitude, ones complement and twos complement.
// The first test will, with modest optimizations, evaluate at compile
// time, and maybe eliminate the branch completely.
T y;
if (octave_int_base::min_val () < -octave_int_base::max_val ()
&& x == octave_int_base::min_val ())
{
y = octave_int_base::max_val ();
}
else
y = (x < 0) ? -x : x;
return y;
#endif
}
static T
signum (T x)
{
// With modest optimizations, this will compile without a jump.
return ((x > 0) ? 1 : 0) - __signbit (x);
}
// FIXME: we do not have an authority what signed shifts should
// exactly do, so we define them the easy way. Note that Matlab does
// not define signed shifts.
static T
rshift (T x, int n) { return x >> n; }
static T
lshift (T x, int n) { return x << n; }
// Minus has problems similar to abs.
static T
minus (T x)
{
#ifdef HAVE_FAST_INT_OPS
T y = -x;
if (y == octave_int_base::min_val ())
{
--y;
}
return y;
#else
T y;
if (octave_int_base::min_val () < -octave_int_base::max_val ()
&& x == octave_int_base::min_val ())
{
y = octave_int_base::max_val ();
}
else
y = -x;
return y;
#endif
}
static T
add (T x, T y)
{
#ifdef HAVE_FAST_INT_OPS
// The typecasts do nothing, but they are here to prevent an optimizing
// compiler from interfering. Also, the signed operations on small types
// actually return int.
T u = static_cast (x) + static_cast (y);
T ux = u ^ x, uy = u ^ y;
if ((ux & uy) < 0)
{
u = octave_int_base::max_val () + __signbit (~u);
}
return u;
#else
// We shall carefully avoid anything that may overflow.
T u;
if (y < 0)
{
if (x < octave_int_base::min_val () - y)
{
u = octave_int_base::min_val ();
}
else
u = x + y;
}
else
{
if (x > octave_int_base::max_val () - y)
{
u = octave_int_base::max_val ();
}
else
u = x + y;
}
return u;
#endif
}
// This is very similar to addition.
static T
sub (T x, T y)
{
#ifdef HAVE_FAST_INT_OPS
// The typecasts do nothing, but they are here to prevent an optimizing
// compiler from interfering. Also, the signed operations on small types
// actually return int.
T u = static_cast (x) - static_cast (y);
T ux = u ^ x, uy = u ^ ~y;
if ((ux & uy) < 0)
{
u = octave_int_base::max_val () + __signbit (~u);
}
return u;
#else
// We shall carefully avoid anything that may overflow.
T u;
if (y < 0)
{
if (x > octave_int_base::max_val () + y)
{
u = octave_int_base::max_val ();
}
else
u = x - y;
}
else
{
if (x < octave_int_base::min_val () + y)
{
u = octave_int_base::min_val ();
}
else
u = x - y;
}
return u;
#endif
}
// Multiplication is done using promotion to wider integer type. If there is
// no suitable promotion type, this operation *MUST* be specialized.
static T mul (T x, T y) { return mul_internal (x, y); }
static T
mul_internal (T x, T y)
{
// Promotion type for multiplication (if exists).
typedef typename query_integer_type<2*sizeof (T), true>::type mptype;
return octave_int_base::truncate_int (static_cast (x)
* static_cast (y));
}
// Division.
static T
div (T x, T y)
{
T z;
if (y == 0)
{
if (x < 0)
z = octave_int_base::min_val ();
else if (x != 0)
z = octave_int_base::max_val ();
else
z = 0;
}
else if (y < 0)
{
// This is a special case that overflows as well.
if (y == -1 && x == octave_int_base::min_val ())
{
z = octave_int_base::max_val ();
}
else
{
z = x / y;
// Can't overflow, but std::abs (x) can!
T w = -octave_int_abs (x % y);
if (w <= y - w)
z -= 1 - (__signbit (x) << 1);
}
}
else
{
z = x / y;
// FIXME: this is a workaround due to MSVC's absence of
// std::abs (int64_t). The call to octave_int_abs can't
// overflow, but std::abs (x) can!
T w = octave_int_abs (x % y);
if (w >= y - w)
z += 1 - (__signbit (x) << 1);
}
return z;
}
// Remainder.
static T
rem (T x, T y)
{
return y != 0 ? x % y : 0;
}
// Modulus. Note the weird y = 0 case for Matlab compatibility.
static T
mod (T x, T y)
{
if (y != 0)
{
T r = x % y;
return ((r < 0) != (y < 0)) ? r + y : r;
}
else
return x;
}
};
#ifdef OCTAVE_INT_USE_LONG_DOUBLE
// Handle 64-bit multiply using long double
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
extern OCTAVE_API int64_t
octave_external_int64_int64_mul (int64_t, int64_t);
#endif
template <>
inline int64_t
octave_int_arith_base::mul_internal (int64_t x, int64_t y)
{
int64_t retval;
long double p = static_cast (x) * static_cast (y);
// NOTE: We could maybe do it with a single branch if HAVE_FAST_INT_OPS,
// but it would require one more runtime conversion, so the question is
// whether it would really be faster.
if (p > static_cast (octave_int_base::max_val ()))
retval = octave_int_base::max_val ();
else if (p < static_cast (octave_int_base::min_val ()))
retval = octave_int_base::min_val ();
else
retval = static_cast (p);
return retval;
}
template <>
inline int64_t
octave_int_arith_base::mul (int64_t x, int64_t y)
{
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
return octave_external_int64_int64_mul (x, y);
#else
return mul_internal (x, y);
#endif
}
#else
// Special handler for 64-bit integer multiply.
template <>
OCTAVE_API int64_t
octave_int_arith_base::mul_internal (int64_t, int64_t);
#endif
// This class simply selects the proper arithmetics.
template
class octave_int_arith
: public octave_int_arith_base::is_signed>
{ };
template
class
octave_int : public octave_int_base
{
public:
typedef T val_type;
octave_int (void) : ival () { }
octave_int (T i) : ival (i) { }
// Always treat characters as unsigned.
octave_int (char c)
: ival (octave_int_base::truncate_int (static_cast (c)))
{ }
octave_int (double d) : ival (octave_int_base::convert_real (d)) { }
octave_int (float d) : ival (octave_int_base::convert_real (d)) { }
#ifdef OCTAVE_INT_USE_LONG_DOUBLE
octave_int (long double d) : ival (octave_int_base::convert_real (d)) { }
#endif
octave_int (bool b) : ival (b) { }
template
octave_int (const U& i) : ival(octave_int_base::truncate_int (i)) { }
template
octave_int (const octave_int& i)
: ival (octave_int_base::truncate_int (i.value ())) { }
octave_int (const octave_int& i) : ival (i.ival) { }
octave_int& operator = (const octave_int& i)
{
ival = i.ival;
return *this;
}
T value (void) const { return ival; }
const unsigned char * iptr (void) const
{ return reinterpret_cast (& ival); }
bool operator ! (void) const { return ! ival; }
bool bool_value (void) const { return static_cast (value ()); }
char char_value (void) const { return static_cast (value ()); }
double double_value (void) const { return static_cast (value ()); }
float float_value (void) const { return static_cast (value ()); }
operator T (void) const { return value (); }
// char and bool operators intentionally omitted.
operator double (void) const { return double_value (); }
operator float (void) const { return float_value (); }
octave_int
operator + () const
{ return *this; }
// unary operators & mappers
#define OCTAVE_INT_UN_OP(OPNAME,NAME) \
inline octave_int \
OPNAME () const \
{ return octave_int_arith::NAME (ival); }
OCTAVE_INT_UN_OP(operator -, minus)
OCTAVE_INT_UN_OP(abs, abs)
OCTAVE_INT_UN_OP(signum, signum)
#undef OCTAVE_INT_UN_OP
// Homogeneous binary integer operations.
#define OCTAVE_INT_BIN_OP(OP, NAME, ARGT) \
inline octave_int \
operator OP (const ARGT& y) const \
{ return octave_int_arith::NAME (ival, y); } \
inline octave_int& \
operator OP##= (const ARGT& y) \
{ \
ival = octave_int_arith::NAME (ival, y); \
return *this; \
}
OCTAVE_INT_BIN_OP(+, add, octave_int)
OCTAVE_INT_BIN_OP(-, sub, octave_int)
OCTAVE_INT_BIN_OP(*, mul, octave_int)
OCTAVE_INT_BIN_OP(/, div, octave_int)
OCTAVE_INT_BIN_OP(%, rem, octave_int)
OCTAVE_INT_BIN_OP(<<, lshift, int)
OCTAVE_INT_BIN_OP(>>, rshift, int)
#undef OCTAVE_INT_BIN_OP
static octave_int min (void) { return std::numeric_limits::min (); }
static octave_int max (void) { return std::numeric_limits::max (); }
static int nbits (void) { return std::numeric_limits::digits; }
static int byte_size (void) { return sizeof (T); }
static const char *type_name ();
// The following are provided for convenience.
static const octave_int zero, one;
// Unsafe. This function exists to support the MEX interface.
// You should not use it anywhere else.
void *mex_get_data (void) const { return const_cast (&ival); }
private:
T ival;
};
template
inline octave_int
rem (const octave_int& x, const octave_int& y)
{ return octave_int_arith::rem (x.value (), y.value ()); }
template
inline octave_int
mod (const octave_int& x, const octave_int& y)
{ return octave_int_arith::mod (x.value (), y.value ()); }
// No mixed integer binary operations!
template
inline bool
xisnan (const octave_int&)
{ return false; }
// FIXME: can/should any of these be inline?
template
extern OCTAVE_API octave_int
pow (const octave_int&, const octave_int&);
template
extern OCTAVE_API octave_int
pow (const double& a, const octave_int& b);
template
extern OCTAVE_API octave_int
pow (const octave_int& a, const double& b);
template
extern OCTAVE_API octave_int
pow (const float& a, const octave_int& b);
template
extern OCTAVE_API octave_int
pow (const octave_int& a, const float& b);
// FIXME: Do we really need a differently named single-precision
// function integer power function here instead of an overloaded
// one?
template
extern OCTAVE_API octave_int
powf (const float& a, const octave_int& b);
template
extern OCTAVE_API octave_int
powf (const octave_int& a, const float& b);
// Binary relations
#define OCTAVE_INT_CMP_OP(OP, NAME) \
template \
inline bool \
operator OP (const octave_int& x, const octave_int& y) \
{ return octave_int_cmp_op::op \
(x.value (), y.value ()); }
OCTAVE_INT_CMP_OP (<, lt)
OCTAVE_INT_CMP_OP (<=, le)
OCTAVE_INT_CMP_OP (>, gt)
OCTAVE_INT_CMP_OP (>=, ge)
OCTAVE_INT_CMP_OP (==, eq)
OCTAVE_INT_CMP_OP (!=, ne)
#undef OCTAVE_INT_CMP_OP
template
inline std::ostream&
operator << (std::ostream& os, const octave_int& ival)
{
os << ival.value ();
return os;
}
template
inline std::istream&
operator >> (std::istream& is, octave_int& ival)
{
T tmp = 0;
is >> tmp;
ival = tmp;
return is;
}
// We need to specialise for char and unsigned char because
// std::operator<< and std::operator>> are overloaded to input and
// output the ASCII character values instead of a representation of
// their numerical value (e.g. os << char(10) outputs a space instead
// of outputting the characters '1' and '0')
template <>
inline std::ostream&
operator << (std::ostream& os, const octave_int& ival)
{
os << static_cast (ival.value ());
return os;
}
template <>
inline std::ostream&
operator << (std::ostream& os, const octave_int& ival)
{
os << static_cast (ival.value ());
return os;
}
template <>
inline std::istream&
operator >> (std::istream& is, octave_int& ival)
{
int tmp = 0;
is >> tmp;
ival = static_cast (tmp);
return is;
}
template <>
inline std::istream&
operator >> (std::istream& is, octave_int& ival)
{
unsigned int tmp = 0;
is >> tmp;
ival = static_cast (tmp);
return is;
}
// Bitwise operations
#define OCTAVE_INT_BITCMP_OP(OP) \
template \
octave_int \
operator OP (const octave_int& x, const octave_int& y) \
{ return x.value () OP y.value (); }
OCTAVE_INT_BITCMP_OP (&)
OCTAVE_INT_BITCMP_OP (|)
OCTAVE_INT_BITCMP_OP (^)
#undef OCTAVE_INT_BITCMP_OP
// General bit shift.
template
octave_int
bitshift (const octave_int& a, int n,
const octave_int& mask = std::numeric_limits::max ())
{
if (n > 0)
return (a << n) & mask;
else if (n < 0)
return (a >> -n) & mask;
else
return a & mask;
}
typedef octave_int octave_int8;
typedef octave_int octave_int16;
typedef octave_int octave_int32;
typedef octave_int octave_int64;
typedef octave_int octave_uint8;
typedef octave_int octave_uint16;
typedef octave_int octave_uint32;
typedef octave_int octave_uint64;
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
#define DECLARE_EXTERNAL_LONG_DOUBLE_OP(T, OP) \
extern OCTAVE_API T \
external_double_ ## T ## _ ## OP (double x, T y); \
extern OCTAVE_API T \
external_ ## T ## _double_ ## OP (T x, double y)
#define DECLARE_EXTERNAL_LONG_DOUBLE_OPS(T) \
DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, add); \
DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, sub); \
DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, mul); \
DECLARE_EXTERNAL_LONG_DOUBLE_OP (T, div)
DECLARE_EXTERNAL_LONG_DOUBLE_OPS (octave_int64);
DECLARE_EXTERNAL_LONG_DOUBLE_OPS (octave_uint64);
#endif
#define OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
template \
inline octave_int \
operator OP (const octave_int& x, const double& y) \
{ return octave_int (static_cast (x) OP y); } \
template \
inline octave_int \
operator OP (const double& x, const octave_int& y) \
{ return octave_int (x OP static_cast (y)); } \
#ifdef OCTAVE_INT_USE_LONG_DOUBLE
// Handle mixed op using long double
#ifdef OCTAVE_ENSURE_LONG_DOUBLE_OPERATIONS_ARE_NOT_TRUNCATED
#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
template <> \
inline octave_int64 \
operator OP (const double& x, const octave_int64& y) \
{ \
return external_double_octave_int64_ ## NAME (x, y); \
} \
template <> \
inline octave_uint64 \
operator OP (const double& x, const octave_uint64& y) \
{ \
return external_double_octave_uint64_ ## NAME (x, y); \
} \
template <> \
inline octave_int64 \
operator OP (const octave_int64& x, const double& y) \
{ \
return external_octave_int64_double_ ## NAME (x, y); \
} \
template <> \
inline octave_uint64 \
operator OP (const octave_uint64& x, const double& y) \
{ \
return external_octave_uint64_double_ ## NAME (x, y); \
}
#else
#define OCTAVE_INT_DOUBLE_BIN_OP(OP, NAME) \
OCTAVE_INT_DOUBLE_BIN_OP0(OP) \
template <> \
inline octave_int64 \
operator OP (const double& x, const octave_int64& y) \
{ \
return octave_int64 (x OP static_cast (y.value ())); \
} \
template <> \
inline octave_uint64 \
operator OP (const double& x, const octave_uint64& y) \
{ \
return octave_uint64 (x OP static_cast