123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 |
- #ifndef BOOST_NUMERIC_CHECKED_INTEGER_HPP
- #define BOOST_NUMERIC_CHECKED_INTEGER_HPP
- #include <limits>
- #include <type_traits> // is_integral, make_unsigned, enable_if
- #include <algorithm> // std::max
- #include "checked_result.hpp"
- #include "checked_default.hpp"
- #include "safe_compare.hpp"
- #include "utility.hpp"
- #include "exception.hpp"
- namespace boost {
- namespace safe_numerics {
- template<bool tf>
- using bool_type = typename std::conditional<tf, std::true_type, std::false_type>::type;
- template<
- typename R,
- R Min,
- R Max,
- typename T,
- class F
- >
- struct heterogeneous_checked_operation<
- R,
- Min,
- Max,
- T,
- F,
- typename std::enable_if<
- std::is_integral<R>::value
- && std::is_integral<T>::value
- >::type
- >{
-
-
- struct cast_impl_detail {
- constexpr static checked_result<R>
- cast_impl(
- const T & t,
- std::true_type,
- std::true_type
- ){
-
-
- return
- boost::safe_numerics::safe_compare::greater_than(t, Max) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "converted signed value too large"
- )
- : boost::safe_numerics::safe_compare::less_than(t, Min) ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "converted signed value too small"
- )
- :
- checked_result<R>(static_cast<R>(t))
- ;
- }
- constexpr static checked_result<R>
- cast_impl(
- const T & t,
- std::true_type,
- std::false_type
- ){
-
-
- return
- boost::safe_numerics::safe_compare::greater_than(t, Max) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "converted unsigned value too large"
- )
- :
- boost::safe_numerics::safe_compare::less_than(t, Min) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "converted unsigned value too small"
- )
- :
- checked_result<R>(static_cast<R>(t))
- ;
- }
- constexpr static checked_result<R>
- cast_impl(
- const T & t,
- std::false_type,
- std::false_type
- ){
-
-
- return
- boost::safe_numerics::safe_compare::greater_than(t, Max) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "converted unsigned value too large"
- )
- :
- boost::safe_numerics::safe_compare::less_than(t, Min) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "converted unsigned value too small"
- )
- :
- checked_result<R>(static_cast<R>(t))
- ;
- }
- constexpr static checked_result<R>
- cast_impl(
- const T & t,
- std::false_type,
- std::true_type
- ){
- return
- boost::safe_numerics::safe_compare::less_than(t, Min) ?
- F::template invoke<safe_numerics_error::domain_error>(
- "converted value to low or negative"
- )
- :
- boost::safe_numerics::safe_compare::greater_than(t, Max) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "converted signed value too large"
- )
- :
- checked_result<R>(static_cast<R>(t))
- ;
- }
- };
- constexpr static checked_result<R>
- cast(const T & t){
- return
- cast_impl_detail::cast_impl(
- t,
- std::is_signed<R>(),
- std::is_signed<T>()
- );
- }
- };
- template<
- typename R,
- R Min,
- R Max,
- typename T,
- class F
- >
- struct heterogeneous_checked_operation<
- R,
- Min,
- Max,
- T,
- F,
- typename std::enable_if<
- std::is_integral<R>::value
- && std::is_floating_point<T>::value
- >::type
- >{
- constexpr static checked_result<R>
- cast(const T & t){
- return static_cast<R>(t);
- }
- };
- template<
- typename R,
- R Min,
- R Max,
- typename T,
- class F
- >
- struct heterogeneous_checked_operation<
- R,
- Min,
- Max,
- T,
- F,
- typename std::enable_if<
- std::is_floating_point<R>::value
- && std::is_integral<T>::value
- >::type
- >{
- constexpr static checked_result<R>
- cast(const T & t){
- if(std::numeric_limits<R>::digits < std::numeric_limits<T>::digits){
- if(utility::significant_bits(t) > std::numeric_limits<R>::digits){
- return F::invoke(
- safe_numerics_error::precision_overflow_error,
- "keep precision"
- );
- }
- }
- return t;
- }
- };
- template<
- typename R,
- class F
- >
- struct checked_operation<R, F,
- typename std::enable_if<
- std::is_integral<R>::value
- >::type
- >{
-
-
- struct add_impl_detail {
-
- constexpr static checked_result<R> add(
- const R t,
- const R u,
- std::false_type
- ){
- return
-
- std::numeric_limits<R>::max() - u < t ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "addition result too large"
- )
- :
- checked_result<R>(t + u)
- ;
- }
-
- constexpr static checked_result<R> add(
- const R t,
- const R u,
- std::true_type
- ){
-
- return
-
- ((u > 0) && (t > (std::numeric_limits<R>::max() - u))) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "addition result too large"
- )
- :
- ((u < 0) && (t < (std::numeric_limits<R>::min() - u))) ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "addition result too low"
- )
- :
- checked_result<R>(t + u)
- ;
- }
- };
- constexpr static checked_result<R>
- add(const R & t, const R & u){
- return add_impl_detail::add(t, u, std::is_signed<R>());
- }
-
-
- struct subtract_impl_detail {
-
- constexpr static checked_result<R> subtract(
- const R t,
- const R u,
- std::false_type
- ){
-
- return
- t < u ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "subtraction result cannot be negative"
- )
- :
- checked_result<R>(t - u)
- ;
- }
-
- constexpr static checked_result<R> subtract(
- const R t,
- const R u,
- std::true_type
- ){
- return
-
- ((u > 0) && (t < (std::numeric_limits<R>::min() + u))) ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "subtraction result overflows result type"
- )
- :
- ((u < 0) && (t > (std::numeric_limits<R>::max() + u))) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "subtraction result overflows result type"
- )
- :
- checked_result<R>(t - u)
- ;
- }
- };
- constexpr static checked_result<R> subtract(const R & t, const R & u){
- return subtract_impl_detail::subtract(t, u, std::is_signed<R>());
- }
-
-
- struct minus_impl_detail {
-
- constexpr static checked_result<R> minus(
- const R t,
- std::false_type
- ){
- return t > 0 ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "minus unsigned would be negative"
- )
- :
-
- checked_result<R>(0)
- ;
- }
-
- constexpr static checked_result<R> minus(
- const R t,
- std::true_type
- ){
- return t == std::numeric_limits<R>::min() ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "subtraction result overflows result type"
- )
- :
- checked_result<R>(-t)
- ;
- }
- };
- constexpr static checked_result<R> minus(const R & t){
- return minus_impl_detail::minus(t, std::is_signed<R>());
- }
-
-
- struct multiply_impl_detail {
-
- constexpr static checked_result<R> multiply(
- const R t,
- const R u,
- std::false_type,
- std::false_type
- ){
-
-
-
- using i_type = std::uintmax_t;
- return
- static_cast<i_type>(t) * static_cast<i_type>(u)
- > std::numeric_limits<R>::max() ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "multiplication overflow"
- )
- :
- checked_result<R>(t * u)
- ;
- }
- constexpr static checked_result<R> multiply(
- const R t,
- const R u,
- std::false_type,
- std::true_type
- ){
-
- return
- u > 0 && t > std::numeric_limits<R>::max() / u ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "multiplication overflow"
- )
- :
- checked_result<R>(t * u)
- ;
- }
-
- constexpr static checked_result<R> multiply(
- const R t,
- const R u,
- std::true_type,
- std::false_type
- ){
-
-
-
- using i_type = std::intmax_t;
- return
- (
- static_cast<i_type>(t) * static_cast<i_type>(u)
- > static_cast<i_type>(std::numeric_limits<R>::max())
- ) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "multiplication overflow"
- )
- :
- (
- static_cast<i_type>(t) * static_cast<i_type>(u)
- < static_cast<i_type>(std::numeric_limits<R>::min())
- ) ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "multiplication overflow"
- )
- :
- checked_result<R>(t * u)
- ;
- }
- constexpr static checked_result<R> multiply(
- const R t,
- const R u,
- std::true_type,
- std::true_type
- ){
- return t > 0 ?
- u > 0 ?
- t > std::numeric_limits<R>::max() / u ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "multiplication overflow"
- )
- :
- checked_result<R>(t * u)
- :
- u < std::numeric_limits<R>::min() / t ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "multiplication overflow"
- )
- :
- checked_result<R>(t * u)
- :
- u > 0 ?
- t < std::numeric_limits<R>::min() / u ?
- F::template invoke<safe_numerics_error::negative_overflow_error>(
- "multiplication overflow"
- )
- :
- checked_result<R>(t * u)
- :
- t != 0 && u < std::numeric_limits<R>::max() / t ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "multiplication overflow"
- )
- :
- checked_result<R>(t * u)
- ;
- }
- };
- constexpr static checked_result<R> multiply(const R & t, const R & u){
- return multiply_impl_detail::multiply(
- t,
- u,
- std::is_signed<R>(),
- std::integral_constant<
- bool,
- (sizeof(R) > sizeof(std::uintmax_t) / 2)
- >()
- );
- }
-
-
- struct divide_impl_detail {
- constexpr static checked_result<R> divide(
- const R & t,
- const R & u,
- std::false_type
- ){
- return t / u;
- }
- constexpr static checked_result<R> divide(
- const R & t,
- const R & u,
- std::true_type
- ){
- return
- (u == -1 && t == std::numeric_limits<R>::min()) ?
- F::template invoke<safe_numerics_error::positive_overflow_error>(
- "result cannot be represented"
- )
- :
- checked_result<R>(t / u)
- ;
- }
- };
-
- constexpr static checked_result<R> divide(const R & t, const R & u){
- if(u == 0){
- return F::template invoke<safe_numerics_error::domain_error>(
- "divide by zero"
- );
- }
- return divide_impl_detail::divide(t, u, std::is_signed<R>());
- }
-
-
- struct modulus_impl_detail {
- constexpr static checked_result<R> modulus(
- const R & t,
- const R & u,
- std::false_type
- ){
- return t % u;
- }
- constexpr static checked_result<R> modulus(
- const R & t,
- const R & u,
- std::true_type
- ){
- if(u >= 0)
- return t % u;
- checked_result<R> ux = checked::minus(u);
- if(ux.exception())
- return t;
- return t % static_cast<R>(ux);
- }
- };
- constexpr static checked_result<R> modulus(const R & t, const R & u){
- if(0 == u)
- return F::template invoke<safe_numerics_error::domain_error>(
- "denominator is zero"
- );
-
-
-
-
-
-
-
- return modulus_impl_detail::modulus(t, u, typename std::is_signed<R>::type());
- }
-
-
- struct left_shift_integer_detail {
- #if 0
-
-
- #ifndef __has_feature
- #define __has_feature(x) 0
- #endif
- template<typename T>
- constexpr unsigned int leading_zeros(const T & t){
- if(0 == t)
- return 0;
- #if __has_feature(builtin_clz)
- return __builtin_clz(t);
- #else
- #endif
- }
- #endif
-
-
-
-
- constexpr static checked_result<R> left_shift(
- const R & t,
- const R & u,
- std::false_type
- ){
-
-
-
-
-
- if(
- safe_compare::greater_than(
- u,
- std::numeric_limits<R>::digits - utility::significant_bits(t)
- )
- ){
-
- return F::template invoke<safe_numerics_error::shift_too_large>(
- "shifting left more bits than available is undefined behavior"
- );
- }
- return t << u;
- }
- constexpr static checked_result<R> left_shift(
- const R & t,
- const R & u,
- std::true_type
- ){
-
- if(t >= 0){
-
-
-
-
-
- if(
- safe_compare::greater_than(
- u,
- std::numeric_limits<R>::digits - utility::significant_bits(t)
- )
- ){
-
- return F::template invoke<safe_numerics_error::shift_too_large>(
- "shifting left more bits than available"
- );
- }
- else{
- return t << u;
- }
- }
-
- return F::template invoke<safe_numerics_error::negative_shift>(
- "shifting a negative value"
- );
- }
- };
- constexpr static checked_result<R> left_shift(
- const R & t,
- const R & u
- ){
-
-
-
- if(u == 0){
- return t;
- }
- if(u < 0){
- return F::template invoke<safe_numerics_error::negative_shift>(
- "shifting negative amount"
- );
- }
- if(u > std::numeric_limits<R>::digits){
-
- return F::template invoke<safe_numerics_error::shift_too_large>(
- "shifting more bits than available"
- );
- }
- return left_shift_integer_detail::left_shift(t, u, std::is_signed<R>());
- }
-
- struct right_shift_integer_detail {
-
-
-
-
- constexpr static checked_result<R> right_shift(
- const R & t,
- const R & u,
- std::false_type
- ){
-
-
- return t >> u;
- }
- constexpr static checked_result<R> right_shift(
- const R & t,
- const R & u,
- std::true_type
- ){
- if(t < 0){
-
-
- return F::template invoke<safe_numerics_error::negative_value_shift>(
- "shifting a negative value"
- );
- }
-
- return t >> u;
- }
- };
- constexpr static checked_result<R> right_shift(
- const R & t,
- const R & u
- ){
-
-
-
- if(u < 0){
- return F::template invoke<safe_numerics_error::negative_shift>(
- "shifting negative amount"
- );
- }
- if(u > std::numeric_limits<R>::digits){
-
- return F::template invoke<safe_numerics_error::shift_too_large>(
- "shifting more bits than available"
- );
- }
- return right_shift_integer_detail::right_shift(t, u ,std::is_signed<R>());
- }
-
-
-
-
-
- constexpr static checked_result<R> bitwise_or(const R & t, const R & u){
- using namespace boost::safe_numerics::utility;
- const unsigned int result_size
- = std::max(significant_bits(t), significant_bits(u));
- if(result_size > bits_type<R>::value){
- return F::template invoke<safe_numerics_error::positive_overflow_error>(
- "result type too small to hold bitwise or"
- );
- }
- return t | u;
- }
- constexpr static checked_result<R> bitwise_xor(const R & t, const R & u){
- using namespace boost::safe_numerics::utility;
- const unsigned int result_size
- = std::max(significant_bits(t), significant_bits(u));
- if(result_size > bits_type<R>::value){
- return F::template invoke<safe_numerics_error::positive_overflow_error>(
- "result type too small to hold bitwise or"
- );
- }
- return t ^ u;
- }
- constexpr static checked_result<R> bitwise_and(const R & t, const R & u){
- using namespace boost::safe_numerics::utility;
- const unsigned int result_size
- = std::min(significant_bits(t), significant_bits(u));
- if(result_size > bits_type<R>::value){
- return F::template invoke<safe_numerics_error::positive_overflow_error>(
- "result type too small to hold bitwise and"
- );
- }
- return t & u;
- }
- constexpr static checked_result<R> bitwise_not(const R & t){
- using namespace boost::safe_numerics::utility;
- if(significant_bits(t) > bits_type<R>::value){
- return F::template invoke<safe_numerics_error::positive_overflow_error>(
- "result type too small to hold bitwise inverse"
- );
- }
- return ~t;
- }
- };
- }
- }
- #endif
|