12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217 |
- #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 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
- ){
- if(!r.exception())
- os << static_cast<R>(r);
- else
- os << std::error_code(r.m_e).message() << ':' << r.m_msg;
- 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
- ){
- if(! r.exception())
- os << static_cast<std::int16_t>(r);
- else
- os << std::error_code(r.m_e).message() << ':' << r.m_msg;
- 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<unsigned char> & r
- ){
- if(! r.exception())
- os << static_cast<std::uint16_t>(r);
- else
- os << std::error_code(r.m_e).message() << ':' << r.m_msg;
- 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
- ){
- is >> r.m_r;
- return is;
- }
- 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<signed char> & r
- ){
- std::int16_t i;
- is >> i;
- r.m_r = i;
- return is;
- }
- 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<unsigned char> & 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::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
|