123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209 |
- #ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
- #define BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
- // 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)
- // Implemenation of arithmetic on "extended" integers.
- // Extended integers are defined in terms of C++ primitive integers as
- // a) an interger range
- // b) extra elements +inf, -inf, indeterminate
- //
- // Integer operations are closed on the set of extended integers
- // but operations are not necessarily associative when they result in the
- // extensions +inf, -inf, and indeterminate
- //
- // in this code, the type "checked_result<T>" where T is some
- // integer type is an "extended" integer.
- #include <cassert>
- #include <boost/logic/tribool.hpp>
- #include "checked_result.hpp"
- #include "checked_integer.hpp"
- //////////////////////////////////////////////////////////////////////////
- // the following idea of "value_type" is used by several of the operations
- // defined by checked_result arithmetic.
- namespace boost {
- namespace safe_numerics {
- template<typename T>
- constexpr inline void display(const boost::safe_numerics::checked_result<T> & c){
- switch(c.m_e){
- case safe_numerics_error::success:
- std::terminate();
- case safe_numerics_error::positive_overflow_error: // result is above representational maximum
- std::terminate();
- case safe_numerics_error::negative_overflow_error: // result is below representational minimum
- std::terminate();
- case safe_numerics_error::domain_error: // one operand is out of valid range
- std::terminate();
- case safe_numerics_error::range_error: // result cannot be produced for this operation
- std::terminate();
- case safe_numerics_error::precision_overflow_error: // result lost precision
- std::terminate();
- case safe_numerics_error::underflow_error: // result is too small to be represented
- std::terminate();
- case safe_numerics_error::negative_value_shift: // negative value in shift operator
- std::terminate();
- case safe_numerics_error::negative_shift: // shift a negative value
- std::terminate();
- case safe_numerics_error::shift_too_large: // l/r shift exceeds variable size
- std::terminate();
- case safe_numerics_error::uninitialized_value: // creating of uninitialized value
- std::terminate();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // implement C++ operators for check_result<T>
- struct sum_value_type {
- // characterization of various values
- const enum flag {
- known_value = 0,
- less_than_min,
- greater_than_max,
- indeterminate,
- count
- } m_flag;
- template<class T>
- constexpr flag to_flag(const checked_result<T> & t) const {
- switch(static_cast<safe_numerics_error>(t)){
- case safe_numerics_error::success:
- return known_value;
- case safe_numerics_error::negative_overflow_error:
- // result is below representational minimum
- return less_than_min;
- case safe_numerics_error::positive_overflow_error:
- // result is above representational maximum
- return greater_than_max;
- default:
- return indeterminate;
- }
- }
- template<class T>
- constexpr sum_value_type(const checked_result<T> & t) :
- m_flag(to_flag(t))
- {}
- constexpr operator std::uint8_t () const {
- return static_cast<std::uint8_t>(m_flag);
- }
- };
- // integers addition
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator+(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = sum_value_type;
- const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- // note major pain. Clang constexpr multi-dimensional array is fine.
- // but gcc doesn't permit a multi-dimensional array to be be constexpr.
- // so we need to some ugly gymnastics to make our system work for all
- // all systems.
- const enum safe_numerics_error result[order * order] = {
- // t == known_value
- //{
- // u == ...
- safe_numerics_error::success, // known_value,
- safe_numerics_error::negative_overflow_error, // less_than_min,
- safe_numerics_error::positive_overflow_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- // t == less_than_min,
- //{
- // u == ...
- safe_numerics_error::negative_overflow_error, // known_value,
- safe_numerics_error::negative_overflow_error, // less_than_min,
- safe_numerics_error::range_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- // t == greater_than_max,
- //{
- // u == ...
- safe_numerics_error::positive_overflow_error, // known_value,
- safe_numerics_error::range_error, // less_than_min,
- safe_numerics_error::positive_overflow_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- // t == indeterminate,
- //{
- // u == ...
- safe_numerics_error::range_error, // known_value,
- safe_numerics_error::range_error, // less_than_min,
- safe_numerics_error::range_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- };
- const value_type tx(t);
- const value_type ux(u);
- const safe_numerics_error e = result[tx * order + ux];
- if(safe_numerics_error::success == e)
- return checked::add<T>(t, u);
- return checked_result<T>(e, "addition result");
- }
- // unary +
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator+(
- const checked_result<T> & t
- ){
- return t;
- }
- // integers subtraction
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator-(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = sum_value_type;
- constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- constexpr const enum safe_numerics_error result[order * order] = {
- // t == known_value
- //{
- // u == ...
- safe_numerics_error::success, // known_value,
- safe_numerics_error::positive_overflow_error, // less_than_min,
- safe_numerics_error::negative_overflow_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- // t == less_than_min,
- //{
- // u == ...
- safe_numerics_error::negative_overflow_error, // known_value,
- safe_numerics_error::range_error, // less_than_min,
- safe_numerics_error::negative_overflow_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- // t == greater_than_max,
- //{
- // u == ...
- safe_numerics_error::positive_overflow_error, // known_value,
- safe_numerics_error::positive_overflow_error, // less_than_min,
- safe_numerics_error::range_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- // t == indeterminate,
- //{
- // u == ...
- safe_numerics_error::range_error, // known_value,
- safe_numerics_error::range_error, // less_than_min,
- safe_numerics_error::range_error, // greater_than_max,
- safe_numerics_error::range_error, // indeterminate,
- //},
- };
- const value_type tx(t);
- const value_type ux(u);
- const safe_numerics_error e = result[tx * order + ux];
- if(safe_numerics_error::success == e)
- return checked::subtract<T>(t, u);
- return checked_result<T>(e, "subtraction result");
- }
- // unary -
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator-(
- const checked_result<T> & t
- ){
- // assert(false);
- return checked_result<T>(0) - t;
- }
- struct product_value_type {
- // characterization of various values
- const enum flag {
- less_than_min = 0,
- less_than_zero,
- zero,
- greater_than_zero,
- greater_than_max,
- indeterminate,
- // count of number of cases for values
- count,
- // temporary values for special cases
- t_value,
- u_value,
- z_value
- } m_flag;
- template<class T>
- constexpr flag to_flag(const checked_result<T> & t) const {
- switch(static_cast<safe_numerics_error>(t)){
- case safe_numerics_error::success:
- return (t < checked_result<T>(0))
- ? less_than_zero
- : (t > checked_result<T>(0))
- ? greater_than_zero
- : zero;
- case safe_numerics_error::negative_overflow_error:
- // result is below representational minimum
- return less_than_min;
- case safe_numerics_error::positive_overflow_error:
- // result is above representational maximum
- return greater_than_max;
- default:
- return indeterminate;
- }
- }
- template<class T>
- constexpr product_value_type(const checked_result<T> & t) :
- m_flag(to_flag(t))
- {}
- constexpr operator std::uint8_t () const {
- return static_cast<std::uint8_t>(m_flag);
- }
- };
- // integers multiplication
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator*(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = product_value_type;
- const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- constexpr const enum value_type::flag result[order * order] = {
- // t == less_than_min
- //{
- // u == ...
- value_type::greater_than_max, // less_than_min,
- value_type::greater_than_max, // less_than_zero,
- value_type::zero, // zero,
- value_type::less_than_min, // greater_than_zero,
- value_type::less_than_min, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == less_than_zero,
- //{
- // u == ...
- value_type::greater_than_max, // less_than_min,
- value_type::greater_than_zero, // less_than_zero,
- value_type::zero, // zero,
- value_type::less_than_zero, // greater_than_zero,
- value_type::less_than_min, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == zero,
- //{
- // u == ...
- value_type::zero, // less_than_min,
- value_type::zero, // less_than_zero,
- value_type::zero, // zero,
- value_type::zero, // greater_than_zero,
- value_type::zero, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_zero,
- //{
- // u == ...
- value_type::less_than_min, // less_than_min,
- value_type::less_than_zero, // less_than_zero,
- value_type::zero, // zero,
- value_type::greater_than_zero, // greater_than_zero,
- value_type::greater_than_max, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_max
- //{
- value_type::less_than_min, // less_than_min,
- value_type::less_than_min, // less_than_zero,
- value_type::zero, // zero,
- value_type::greater_than_max, // greater_than_zero,
- value_type::greater_than_max, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == indeterminate
- //{
- value_type::indeterminate, // less_than_min,
- value_type::indeterminate, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::indeterminate, // greater_than_zero,
- value_type::indeterminate, // greater than max,
- value_type::indeterminate, // indeterminate,
- //}
- };
- const value_type tx(t);
- const value_type ux(u);
- switch(result[tx * order + ux]){
- case value_type::less_than_min:
- return safe_numerics_error::negative_overflow_error;
- case value_type::zero:
- return T(0);
- case value_type::greater_than_max:
- return safe_numerics_error::positive_overflow_error;
- case value_type::less_than_zero:
- case value_type::greater_than_zero:
- return checked::multiply<T>(t, u);
- case value_type::indeterminate:
- return safe_numerics_error::range_error;
- default:
- assert(false);
- }
- return checked_result<T>(0); // to suppress msvc warning
- }
- // integers division
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator/(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = product_value_type;
- const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- constexpr const enum value_type::flag result[order * order] = {
- // t == less_than_min
- //{
- // u == ...
- value_type::indeterminate, // less_than_min,
- value_type::greater_than_max, // less_than_zero,
- value_type::less_than_min, // zero,
- value_type::less_than_min, // greater_than_zero,
- value_type::less_than_min, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == less_than_zero,
- //{
- // u == ...
- value_type::zero, // less_than_min,
- value_type::greater_than_zero, // less_than_zero,
- value_type::less_than_min, // zero,
- value_type::less_than_zero, // greater_than_zero,
- value_type::zero, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == zero,
- //{
- // u == ...
- value_type::zero, // less_than_min,
- value_type::zero, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::zero, // greater_than_zero,
- value_type::zero, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_zero,
- //{
- // u == ...
- value_type::zero, // less_than_min,
- value_type::less_than_zero, // less_than_zero,
- value_type::greater_than_max, // zero,
- value_type::greater_than_zero, // greater_than_zero,
- value_type::zero, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_max
- //{
- value_type::less_than_min, // less_than_min,
- value_type::less_than_min, // less_than_zero,
- value_type::greater_than_max, // zero,
- value_type::greater_than_max, // greater_than_zero,
- value_type::indeterminate, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == indeterminate
- //{
- value_type::indeterminate, // less_than_min,
- value_type::indeterminate, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::indeterminate, // greater_than_zero,
- value_type::indeterminate, // greater than max,
- value_type::indeterminate, // indeterminate,
- //}
- };
- const value_type tx(t);
- const value_type ux(u);
- switch(result[tx * order + ux]){
- case value_type::less_than_min:
- return safe_numerics_error::negative_overflow_error;
- case value_type::zero:
- return 0;
- case value_type::greater_than_max:
- return safe_numerics_error::positive_overflow_error;
- case value_type::less_than_zero:
- case value_type::greater_than_zero:
- return checked::divide<T>(t, u);
- case value_type::indeterminate:
- return safe_numerics_error::range_error;
- default:
- assert(false);
- }
- return checked_result<T>(0); // to suppress msvc warning
- }
- // integers modulus
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator%(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = product_value_type;
- const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- constexpr const enum value_type::flag result[order * order] = {
- // t == less_than_min
- //{
- // u == ...
- value_type::indeterminate, // less_than_min,
- value_type::z_value, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::z_value, // greater_than_zero,
- value_type::indeterminate, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == less_than_zero,
- //{
- // u == ...
- value_type::t_value, // less_than_min,
- value_type::greater_than_zero, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::less_than_zero, // greater_than_zero,
- value_type::t_value, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == zero,
- //{
- // u == ...
- value_type::zero, // less_than_min,
- value_type::zero, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::zero, // greater_than_zero,
- value_type::zero, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_zero,
- //{
- // u == ...
- value_type::t_value, // less_than_min,
- value_type::less_than_zero, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::greater_than_zero, // greater_than_zero,
- value_type::t_value, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_max
- //{
- value_type::indeterminate, // less_than_min,
- value_type::u_value, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::u_value, // greater_than_zero,
- value_type::indeterminate, // greater than max,
- value_type::indeterminate, // indeterminate,
- //},
- // t == indeterminate
- //{
- value_type::indeterminate, // less_than_min,
- value_type::indeterminate, // less_than_zero,
- value_type::indeterminate, // zero,
- value_type::indeterminate, // greater_than_zero,
- value_type::indeterminate, // greater than max,
- value_type::indeterminate, // indeterminate,
- //}
- };
- const value_type tx(t);
- const value_type ux(u);
- switch(result[tx * order + ux]){
- case value_type::zero:
- return 0;
- case value_type::less_than_zero:
- case value_type::greater_than_zero:
- return checked::modulus<T>(t, u);
- case value_type::indeterminate:
- return safe_numerics_error::range_error;
- case value_type::t_value:
- return t;
- case value_type::u_value:
- return checked::subtract<T>(u, 1);
- case value_type::z_value:
- return checked::subtract<T>(1, u);
- case value_type::greater_than_max:
- case value_type::less_than_min:
- default:
- assert(false);
- }
- // suppress msvc warning
- return checked_result<T>(0);
- }
- // comparison operators
- template<class T>
- constexpr boost::logic::tribool operator<(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = sum_value_type;
- constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- // the question arises about how to order values of type greater_than_min.
- // that is: what should greater_than_min < greater_than_min return.
- //
- // a) return indeterminate because we're talking about the "true" values for
- // which greater_than_min is a placholder.
- //
- // b) return false because the two values are "equal"
- //
- // for our purposes, a) seems the better interpretation.
-
- enum class result_type : std::uint8_t {
- runtime,
- false_value,
- true_value,
- indeterminate,
- };
- constexpr const result_type resultx[order * order]{
- // t == known_value
- //{
- // u == ...
- result_type::runtime, // known_value,
- result_type::false_value, // less_than_min,
- result_type::true_value, // greater_than_max,
- result_type::indeterminate, // indeterminate,
- //},
- // t == less_than_min
- //{
- // u == ...
- result_type::true_value, // known_value,
- result_type::indeterminate, // less_than_min, see above argument
- result_type::true_value, // greater_than_max,
- result_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_max
- //{
- // u == ...
- result_type::false_value, // known_value,
- result_type::false_value, // less_than_min,
- result_type::indeterminate, // greater_than_max, see above argument
- result_type::indeterminate, // indeterminate,
- //},
- // t == indeterminate
- //{
- // u == ...
- result_type::indeterminate, // known_value,
- result_type::indeterminate, // less_than_min,
- result_type::indeterminate, // greater_than_max,
- result_type::indeterminate, // indeterminate,
- //},
- };
- const value_type tx(t);
- const value_type ux(u);
- switch(resultx[tx * order + ux]){
- case result_type::runtime:
- return static_cast<const T &>(t) < static_cast<const T &>(u);
- case result_type::false_value:
- return false;
- case result_type::true_value:
- return true;
- case result_type::indeterminate:
- return boost::logic::indeterminate;
- default:
- assert(false);
- }
- return true;
- }
- template<class T>
- constexpr boost::logic::tribool
- operator>=(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- return !(t < u);
- }
- template<class T>
- constexpr boost::logic::tribool
- operator>(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- return u < t;
- }
- template<class T>
- constexpr boost::logic::tribool
- operator<=(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- return !(u < t);
- }
- template<class T>
- constexpr boost::logic::tribool
- operator==(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = sum_value_type;
- constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- enum class result_type : std::uint8_t {
- runtime,
- false_value,
- true_value,
- indeterminate,
- };
- constexpr const result_type result[order * order]{
- // t == known_value
- //{
- // u == ...
- result_type::runtime, // known_value,
- result_type::false_value, // less_than_min,
- result_type::false_value, // greater_than_max,
- result_type::indeterminate, // indeterminate,
- //},
- // t == less_than_min
- //{
- // u == ...
- result_type::false_value, // known_value,
- result_type::indeterminate, // less_than_min,
- result_type::false_value, // greater_than_max,
- result_type::indeterminate, // indeterminate,
- //},
- // t == greater_than_max
- //{
- // u == ...
- result_type::false_value, // known_value,
- result_type::false_value, // less_than_min,
- result_type::indeterminate, // greater_than_max,
- result_type::indeterminate, // indeterminate,
- //},
- // t == indeterminate
- //{
- // u == ...
- result_type::indeterminate, // known_value,
- result_type::indeterminate, // less_than_min,
- result_type::indeterminate, // greater_than_max,
- result_type::indeterminate, // indeterminate,
- //},
- };
- const value_type tx(t);
- const value_type ux(u);
- switch(result[tx * order + ux]){
- case result_type::runtime:
- return static_cast<const T &>(t) == static_cast<const T &>(u);
- case result_type::false_value:
- return false;
- case result_type::true_value:
- return true;
- case result_type::indeterminate:
- return boost::logic::indeterminate;
- default:
- assert(false);
- }
- // suppress msvc warning - not all control paths return a value
- return false;
- }
- template<class T>
- constexpr boost::logic::tribool
- operator!=(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- return ! (t == u);
- }
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator>>(
- const checked_result<T> & t,
- const checked_result<T> & u
- );
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator~(
- const checked_result<T> & t
- ){
- // assert(false);
- return ~t.m_r;
- }
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator<<(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = product_value_type;
- const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- constexpr const std::uint8_t result[order * order] = {
- // t == less_than_min
- //{
- // u == ...
- 1, // -1, // less_than_min,
- 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
- 2, // safe_numerics_error::negative_overflow_error, // zero,
- 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
- 2, // safe_numerics_error::negative_overflow_error, // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == less_than_zero,
- //{
- // u == ...
- 3, // -1, // less_than_min,
- 4, // - (-t >> -u), // less_than_zero,
- 5, // safe_numerics_error::negative_overflow_error, // zero,
- 6, // - (-t << u), // greater_than_zero,
- 2, // safe_numerics_error::negative_overflow_error, // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == zero,
- //{
- // u == ...
- 3, // 0 // less_than_min,
- 3, // 0 // less_than_zero,
- 3, // 0, // zero,
- 3, // 0, // greater_than_zero,
- 3, // 0, // greater than max,
- 3, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == greater_than_zero,
- //{
- // u == ...
- 3, // 0, // less_than_min,
- 7, // t << -u, // less_than_zero,
- 5, // t, // zero,
- 8, // t << u // greater_than_zero,
- 9, // safe_numerics_error::positive_overflow_error, // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == greater_than_max
- //{
- // u == ...
- 1, // safe_numerics_error::range_error, // less_than_min,
- 9, // safe_numerics_error::positive_overflow_error), // less_than_zero,
- 9, // safe_numerics_error::positive_overflow_error, // zero,
- 9, // safe_numerics_error::positive_overflow_error), // greater_than_zero,
- 9, // safe_numerics_error::positive_overflow_error, // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == indeterminate
- //{
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //}
- };
- const value_type tx(t);
- const value_type ux(u);
- assert(tx * order + ux < order * order);
- // I had a switch(i) statment here - but it results in an ICE
- // on multiple versions of gcc. So make the equivalent in
- // nested if statments - should be the same (more or less)
- // performancewise.
- const unsigned int i = result[tx * order + ux];
- assert(i <= 9);
- if(1 == i){
- return safe_numerics_error::range_error;
- }
- else
- if(2 == i){
- return safe_numerics_error::negative_overflow_error;
- }
- else
- if(3 == i){
- return checked_result<T>(0);
- // the following gymnastics are to handle the case where
- // a value is changed from a negative to a positive number.
- // For example, and 8 bit number t == -128. Then -t also
- // equals -128 since 128 cannot be held in an 8 bit signed
- // integer.
- }
- else
- if(4 == i){ // - (-t >> -u)
- assert(static_cast<bool>(t < checked_result<T>(0)));
- assert(static_cast<bool>(u < checked_result<T>(0)));
- return t >> -u;
- }
- else
- if(5 == i){
- return t;
- }
- else
- if(6 == i){ // - (-t << u)
- assert(static_cast<bool>(t < checked_result<T>(0)));
- assert(static_cast<bool>(u > checked_result<T>(0)));
- const checked_result<T> temp_t = t * checked_result<T>(2);
- const checked_result<T> temp_u = u - checked_result<T>(1);
- return - (-temp_t << temp_u);
- }
- else
- if(7 == i){ // t >> -u
- assert(static_cast<bool>(t > checked_result<T>(0)));
- assert(static_cast<bool>(u < checked_result<T>(0)));
- return t >> -u;
- }
- else
- if(8 == i){ // t << u
- assert(static_cast<bool>(t > checked_result<T>(0)));
- assert(static_cast<bool>(u > checked_result<T>(0)));
- checked_result<T> r = checked::left_shift<T>(t, u);
- return (r.m_e == safe_numerics_error::shift_too_large)
- ? checked_result<T>(safe_numerics_error::positive_overflow_error)
- : r;
- }
- else
- if(9 == i){
- return safe_numerics_error::positive_overflow_error;
- }
- else{
- assert(false);
- };
- return checked_result<T>(0); // to suppress msvc warning
- }
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator>>(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- using value_type = product_value_type;
- const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
- const std::uint8_t result[order * order] = {
- // t == less_than_min
- //{
- // u == ...
- 2, // safe_numerics_error::negative_overflow_error, // less_than_min,
- 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
- 2, // safe_numerics_error::negative_overflow_error, // zero,
- 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
- 1, // safe_numerics_error::range_error, // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == less_than_zero,
- //{
- // u == ...
- 2, // safe_numerics_error::negative_overflow_error // less_than_min,
- 4, // - (-t << -u), // less_than_zero,
- 5, // safe_numerics_error::negative_overflow_error. // zero,
- 6, // - (-t >> u), // greater_than_zero,
- 3, // 0, ? or -1 // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == zero,
- //{
- // u == ...
- 3, // 0 // less_than_min,
- 3, // 0 // less_than_zero,
- 3, // 0, // zero,
- 3, // 0, // greater_than_zero,
- 3, // 0, // greater than max,
- 3, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == greater_than_zero,
- //{
- // u == ...
- 9, // safe_numerics_error::positive_overflow_error // less_than_min,
- 7, // t << -u, // less_than_zero,
- 5, // t, // zero,
- 8, // t >> u // greater_than_zero,
- 3, // 0, // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == greater_than_max
- //{
- // u == ...
- 9, // safe_numerics_error::positive_overflow_error, // less_than_min,
- 9, // safe_numerics_error::positive_overflow_error, // less_than_zero,
- 9, // safe_numerics_error::positive_overflow_error, // zero,
- 9, // safe_numerics_error::positive_overflow_error, // greater_than_zero,
- 1, // safe_numerics_error::range_error, // greater than max,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //},
- // t == indeterminate
- //{
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- 1, // safe_numerics_error::range_error, // indeterminate,
- //}
- };
- const value_type tx(t);
- const value_type ux(u);
- assert(tx * order + ux < order * order);
- // I had a switch(i) statment here - but it results in an ICE
- // on multiple versions of gcc. So make the equivalent in
- // nested if statments - should be the same (more or less)
- // performancewise.
- const unsigned int i = result[tx * order + ux];
- assert(i <= 9);
- if(1 == i){
- return safe_numerics_error::range_error;
- }
- else
- if(2 == i){
- return safe_numerics_error::negative_overflow_error;
- }
- else
- if(3 == i){
- return checked_result<T>(0);
- }
- else
- if(4 == i){ // - (-t << -u)
- assert(static_cast<bool>(t < checked_result<T>(0)));
- assert(static_cast<bool>(u < checked_result<T>(0)));
- return t << -u;
- }
- else
- if(5 == i){
- return t;
- }
- else
- if(6 == i){ // - (-t >> u)
- assert(static_cast<bool>(t < checked_result<T>(0)));
- assert(static_cast<bool>(u > checked_result<T>(0)));
- const checked_result<T> temp_t = t / checked_result<T>(2);
- const checked_result<T> temp_u = u - checked_result<T>(1);
- return - (-temp_t >> temp_u);
- }
- else
- if(7 == i){ // t << -u,
- assert(static_cast<bool>(t > checked_result<T>(0)));
- assert(static_cast<bool>(u < checked_result<T>(0)));
- return t << -u;
- }
- else
- if(8 == i){ // t >> u
- assert(static_cast<bool>(t > checked_result<T>(0)));
- assert(static_cast<bool>(u > checked_result<T>(0)));
- checked_result<T> r = checked::right_shift<T>(t, u);
- return (r.m_e == safe_numerics_error::shift_too_large)
- ? checked_result<T>(0)
- : r;
- }
- else
- if(9 == i){
- return safe_numerics_error::positive_overflow_error;
- }
- else{
- assert(false);
- };
- return checked_result<T>(0); // to suppress msvc warning
- }
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator|(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- return
- t.exception() || u.exception()
- ? checked_result<T>(safe_numerics_error::range_error)
- : checked::bitwise_or<T>(
- static_cast<T>(t),
- static_cast<T>(u)
- );
- }
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator^(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- return
- t.exception() || u.exception()
- ? checked_result<T>(safe_numerics_error::range_error)
- : checked::bitwise_xor<T>(
- static_cast<T>(t),
- static_cast<T>(u)
- );
- }
- template<class T>
- typename std::enable_if<
- std::is_integral<T>::value,
- checked_result<T>
- >::type
- constexpr inline operator&(
- const checked_result<T> & t,
- const checked_result<T> & u
- ){
- return
- t.exception() || u.exception()
- ? checked_result<T>(safe_numerics_error::range_error)
- : checked::bitwise_and<T>(
- static_cast<T>(t),
- static_cast<T>(u)
- );
- }
- } // safe_numerics
- } // boost
- #include <iosfwd>
- namespace std {
- template<typename CharT, typename Traits, typename R>
- inline std::basic_ostream<CharT, Traits> & operator<<(
- std::basic_ostream<CharT, Traits> & os,
- const boost::safe_numerics::checked_result<R> & r
- ){
- bool e = r.exception();
- os << e;
- if(!e)
- os << static_cast<R>(r);
- else
- os << std::error_code(r.m_e).message() << ':' << static_cast<const char * const>(r);
- return os;
- }
- template<typename CharT, typename Traits>
- inline std::basic_ostream<CharT, Traits> & operator<<(
- std::basic_ostream<CharT, Traits> & os,
- const boost::safe_numerics::checked_result<signed char> & r
- ){
- bool e = r.exception();
- os << e;
- if(! e)
- os << static_cast<std::int16_t>(r);
- else
- os << std::error_code(r.m_e).message() << ':' << static_cast<const char * const>(r);
- return os;
- }
- template<typename CharT, typename Traits, typename R>
- inline std::basic_istream<CharT, Traits> & operator>>(
- std::basic_istream<CharT, Traits> & is,
- boost::safe_numerics::checked_result<R> & r
- ){
- bool e;
- is >> e;
- if(!e)
- is >> static_cast<R>(r);
- else
- is >> std::error_code(r.m_e).message() >> ':' >> static_cast<const char * const>(r);
- return is;
- }
- template<typename CharT, typename Traits>
- inline std::basic_istream<CharT, Traits> & operator>>(
- std::basic_istream<CharT, Traits> & is,
- boost::safe_numerics::checked_result<signed char> & r
- ){
- bool e;
- is >> e;
- if(!e){
- std::int16_t i;
- is >> i;
- r.m_contents.m_r = static_cast<signed char>(i);
- }
- else
- is >> std::error_code(r.m_e).message() >> ':' >> static_cast<const char * const>(r);
- return is;
- }
- } // std
- /////////////////////////////////////////////////////////////////
- // numeric limits for checked<R>
- #include <limits>
- namespace std {
- template<class R>
- class numeric_limits<boost::safe_numerics::checked_result<R> >
- : public std::numeric_limits<R>
- {
- using this_type = boost::safe_numerics::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_OPERATIONS
|