z3-z3-4.12.6.src.util.checked_int64.h Maven / Gradle / Ivy
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
checked_int64.h
Abstract:
A class for wrapping checked (and unchecked) int64_t operations.
Note: the mpfx class defines a more general class of fixed-point operations.
A tradeoff is that it relies on a manager.
This class several of the most common operations from rational, so
it can be swapped for rational.
Author:
Nikolaj Bjorner (nbjorner) 2013-03-25.
Revision History:
--*/
#pragma once
#include "util/z3_exception.h"
#include "util/rational.h"
template
class checked_int64 {
int64_t m_value;
typedef checked_int64 ci;
rational r64(int64_t i) { return rational(i, rational::i64()); }
public:
checked_int64(): m_value(0) {}
checked_int64(int64_t v): m_value(v) {}
class overflow_exception : public z3_exception {
char const * msg() const override { return "checked_int64 overflow/underflow";}
};
bool is_zero() const { return m_value == 0; }
bool is_pos() const { return m_value > 0; }
bool is_neg() const { return m_value < 0; }
bool is_one() const { return m_value == 1; }
bool is_minus_one() const { return m_value == -1; }
bool is_nonneg() const { return m_value >= 0; }
bool is_nonpos() const { return m_value <= 0; }
bool is_even() const { return 0 == (m_value ^ 0x1); }
static checked_int64 zero() { return ci(0); }
static checked_int64 one() { return ci(1); }
static checked_int64 minus_one() { return ci(-1);}
int64_t get_int64() const { return m_value; }
checked_int64 abs() const {
if (m_value >= 0) {
return *this;
}
if (CHECK && m_value == INT64_MIN) {
throw overflow_exception();
}
return ci(-m_value);
}
checked_int64& neg() {
if (CHECK && m_value == INT64_MIN) {
throw overflow_exception();
}
m_value = -m_value;
return *this;
}
unsigned hash() const { return static_cast(m_value); }
struct hash_proc { unsigned operator()(checked_int64 const& r) const { return r.hash(); } };
struct eq_proc { bool operator()(checked_int64 const& r1, checked_int64 const& r2) const { return r1 == r2; } };
friend inline std::ostream& operator<<(std::ostream& out, checked_int64 const& i) {
return out << i.m_value;
}
friend inline bool operator==(checked_int64 const& a, checked_int64 const& b) {
return a.m_value == b.m_value;
}
friend inline bool operator<(checked_int64 const& a, checked_int64 const& b) {
return a.m_value < b.m_value;
}
checked_int64 & operator++() {
if (CHECK && INT64_MAX == m_value) {
throw overflow_exception();
}
++m_value;
return *this;
}
const checked_int64 operator++(int) { checked_int64 tmp(*this); ++(*this); return tmp; }
checked_int64 & operator--() {
if (CHECK && m_value == INT64_MIN) {
throw overflow_exception();
}
--m_value;
return *this;
}
const checked_int64 operator--(int) { checked_int64 tmp(*this); --(*this); return tmp; }
checked_int64& operator+=(checked_int64 const& other) {
if (CHECK) {
uint64_t x = static_cast(m_value);
uint64_t y = static_cast(other.m_value);
int64_t r = static_cast(x + y);
if (m_value > 0 && other.m_value > 0 && r <= 0) throw overflow_exception();
if (m_value < 0 && other.m_value < 0 && r >= 0) throw overflow_exception();
m_value = r;
}
else {
m_value += other.m_value;
}
return *this;
}
checked_int64& operator-=(checked_int64 const& other) {
if (CHECK) {
uint64_t x = static_cast(m_value);
uint64_t y = static_cast(other.m_value);
int64_t r = static_cast(x - y);
if (m_value > 0 && other.m_value < 0 && r <= 0) throw overflow_exception();
if (m_value < 0 && other.m_value > 0 && r >= 0) throw overflow_exception();
m_value = r;
}
else {
m_value -= other.m_value;
}
return *this;
}
checked_int64& operator*=(checked_int64 const& other) {
if (CHECK) {
if (INT_MIN < m_value && m_value <= INT_MAX && INT_MIN < other.m_value && other.m_value <= INT_MAX) {
m_value *= other.m_value;
}
// TBD: could be tuned by using known techniques or 128-bit arithmetic.
else {
rational r(r64(m_value) * r64(other.m_value));
if (!r.is_int64()) {
throw overflow_exception();
}
m_value = r.get_int64();
}
}
else {
m_value *= other.m_value;
}
return *this;
}
friend inline checked_int64 abs(checked_int64 const& i) {
return i.abs();
}
};
template
inline bool operator!=(checked_int64 const & i1, checked_int64 const & i2) {
return !operator==(i1, i2);
}
template
inline bool operator>(checked_int64 const & i1, checked_int64 const & i2) {
return operator<(i2, i1);
}
template
inline bool operator<=(checked_int64 const & i1, checked_int64 const & i2) {
return !operator>(i1, i2);
}
template
inline bool operator>=(checked_int64 const & i1, checked_int64 const & i2) {
return !operator<(i1, i2);
}
template
inline checked_int64 operator-(checked_int64 const& i) {
checked_int64 result(i);
return result.neg();
}
template
inline checked_int64 operator+(checked_int64 const& a, checked_int64 const& b) {
checked_int64 result(a);
result += b;
return result;
}
template
inline checked_int64 operator-(checked_int64 const& a, checked_int64 const& b) {
checked_int64 result(a);
result -= b;
return result;
}
template
inline checked_int64 operator*(checked_int64 const& a, checked_int64 const& b) {
checked_int64 result(a);
result *= b;
return result;
}