mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-22 15:42:30 +00:00
228 lines
5.5 KiB
C++
228 lines
5.5 KiB
C++
#ifndef BOOST_NUMERIC_CHECKED_RESULT
|
|
#define BOOST_NUMERIC_CHECKED_RESULT
|
|
|
|
// MS compatible compilers support #pragma once
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
|
# pragma once
|
|
#endif
|
|
|
|
// Copyright (c) 2012 Robert Ramey
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
// contains operations for doing checked aritmetic on NATIVE
|
|
// C++ types.
|
|
|
|
#include <cassert>
|
|
#include <boost/logic/tribool.hpp>
|
|
|
|
#include "safe_common.hpp"
|
|
#include "safe_compare.hpp"
|
|
#include "exception.hpp"
|
|
|
|
namespace boost {
|
|
namespace numeric {
|
|
|
|
template<typename R>
|
|
struct checked_result {
|
|
exception_type m_e;
|
|
union {
|
|
R m_r;
|
|
char const * m_msg;
|
|
};
|
|
// constructors
|
|
// can't select constructor based on the current status of another
|
|
// checked_result object. So no copy constructor
|
|
/*
|
|
constexpr checked_result(const checked_result<R> & r) :
|
|
m_e(r.m_e)
|
|
{
|
|
(no_exception()) ?
|
|
(m_r = r.m_r), 0
|
|
:
|
|
(m_msg = r.m_msg), 0
|
|
;
|
|
}
|
|
*/
|
|
// don't permit construction without initial value;
|
|
checked_result() = delete;
|
|
|
|
constexpr /*explicit*/ checked_result(const R & r) :
|
|
m_e(exception_type::no_exception),
|
|
m_r(r)
|
|
{}
|
|
|
|
constexpr /*explicit*/ checked_result(
|
|
exception_type e,
|
|
const char * msg
|
|
) :
|
|
m_e(e),
|
|
m_msg(msg)
|
|
{}
|
|
|
|
// accesors
|
|
constexpr operator R() const {
|
|
//assert(no_exception());
|
|
return m_r;
|
|
}
|
|
|
|
constexpr operator const char *() const {
|
|
assert(! no_exception());
|
|
return m_msg;
|
|
}
|
|
|
|
template<class T>
|
|
constexpr boost::logic::tribool operator<(const checked_result<T> & t) const {
|
|
return
|
|
(this->no_exception() && t.no_exception()) ?
|
|
safe_compare::less_than(m_r, t.m_r)
|
|
:
|
|
boost::logic::tribool::indeterminate_value
|
|
;
|
|
}
|
|
template<class T>
|
|
constexpr boost::logic::tribool operator>=(const checked_result<T> & t) const {
|
|
return ! operator<(t);
|
|
}
|
|
template<class T>
|
|
constexpr boost::logic::tribool operator>(const checked_result<T> & t) const {
|
|
return
|
|
(this->no_exception() && t.no_exception()) ?
|
|
safe_compare::greater_than(m_r, t.m_r)
|
|
:
|
|
boost::logic::tribool::indeterminate_value
|
|
;
|
|
}
|
|
template<class T>
|
|
constexpr boost::logic::tribool operator<=(const checked_result<T> & t) const {
|
|
return ! operator>(t) && ! operator<(t);
|
|
}
|
|
template<class T>
|
|
constexpr boost::logic::tribool operator!=(const checked_result<T> & t) const {
|
|
return operator<(t) || operator>(t);
|
|
}
|
|
template<class T>
|
|
constexpr boost::logic::tribool operator==(const checked_result<T> & t) const {
|
|
return ! operator!=(t);
|
|
}
|
|
constexpr bool no_exception() const {
|
|
return m_e == exception_type::no_exception;
|
|
}
|
|
constexpr bool exception() const {
|
|
return m_e != exception_type::no_exception;
|
|
}
|
|
};
|
|
|
|
template<class EP, typename R>
|
|
void
|
|
dispatch(const checked_result<R> & cr){
|
|
if(cr.no_exception())
|
|
dispatch<EP>(exception_type::no_exception, "");
|
|
else
|
|
dispatch<EP>(cr.m_e, cr.m_msg);
|
|
}
|
|
|
|
// C++ does not (yet) permit constexpr lambdas. So create some
|
|
// constexpr predicates to be used by constexpr algorthms.
|
|
template<typename R>
|
|
constexpr bool no_exception(const checked_result<R> & cr){
|
|
return cr.no_exception();
|
|
}
|
|
|
|
} // numeric
|
|
} // boost
|
|
|
|
#include <ostream>
|
|
#include <istream>
|
|
|
|
namespace std {
|
|
|
|
template<typename R>
|
|
std::ostream & operator<<(
|
|
std::ostream & os,
|
|
const boost::numeric::checked_result<R> & r
|
|
){
|
|
if(r.no_exception())
|
|
os << static_cast<R>(r);
|
|
else
|
|
os << r.m_msg; //static_cast<const char *>(r);
|
|
return os;
|
|
}
|
|
|
|
template<>
|
|
std::ostream & operator<<(
|
|
std::ostream & os,
|
|
const boost::numeric::checked_result<std::int8_t> & r
|
|
){
|
|
if(r.no_exception())
|
|
os << static_cast<std::int16_t>(r);
|
|
else
|
|
os << r.m_msg; //static_cast<const char *>(r);
|
|
return os;
|
|
}
|
|
|
|
template<>
|
|
std::ostream & operator<<(
|
|
std::ostream & os,
|
|
const boost::numeric::checked_result<std::uint8_t> & r
|
|
){
|
|
if(r.no_exception())
|
|
os << static_cast<std::uint16_t>(r);
|
|
else
|
|
os << r.m_msg; //static_cast<const char *>(r);
|
|
return os;
|
|
}
|
|
|
|
/*
|
|
template<typename R>
|
|
std::istream & operator>>(std::istream & is, const boost::numeric::checked_result<R> & r){
|
|
is >> r.m_r;
|
|
return is;
|
|
}
|
|
|
|
template<typename R>
|
|
std::istream & operator>>(std::istream & is, const boost::numeric::checked_result<std::int8_t> & r){
|
|
std::int16_t i;
|
|
is >> i;
|
|
r.m_r = i;
|
|
return is;
|
|
}
|
|
|
|
template<typename R>
|
|
std::istream & operator>>(std::istream & is, const boost::numeric::checked_result<std::uint8_t> & r){
|
|
std::uint16_t i;
|
|
is >> i;
|
|
r.m_r = i;
|
|
return is;
|
|
}
|
|
*/
|
|
|
|
} // std
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
// numeric limits for checked<R>
|
|
|
|
#include <limits>
|
|
|
|
namespace std {
|
|
|
|
template<class R>
|
|
class numeric_limits<boost::numeric::checked_result<R> >
|
|
: public std::numeric_limits<R>
|
|
{
|
|
using this_type = boost::numeric::checked_result<R>;
|
|
public:
|
|
constexpr static this_type min() noexcept {
|
|
return this_type(std::numeric_limits<R>::min());
|
|
}
|
|
constexpr static this_type max() noexcept {
|
|
return this_type(std::numeric_limits<R>::max());
|
|
}
|
|
};
|
|
|
|
} // std
|
|
|
|
#endif // BOOST_NUMERIC_CHECKED_RESULT
|