Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:59:41

0001 #ifndef BOOST_NUMERIC_AUTOMATIC_HPP
0002 #define BOOST_NUMERIC_AUTOMATIC_HPP
0003 
0004 //  Copyright (c) 2012 Robert Ramey
0005 //
0006 // Distributed under the Boost Software License, Version 1.0. (See
0007 // accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 // policy which creates expanded results types designed
0011 // to avoid overflows.
0012 
0013 #include <limits>
0014 #include <cstdint>     // (u)intmax_t,
0015 #include <type_traits> // conditional
0016 #include <boost/integer.hpp>
0017 
0018 #include "safe_common.hpp"
0019 #include "checked_result.hpp"
0020 #include "checked_default.hpp"
0021 #include "checked_integer.hpp"
0022 #include "checked_result_operations.hpp"
0023 #include "interval.hpp"
0024 #include "utility.hpp"
0025 
0026 namespace boost {
0027 namespace safe_numerics {
0028 
0029 struct automatic {
0030 private:
0031     // the following returns the "true" type.  After calculating the new max and min
0032     // these return the minimum size type which can hold the expected result.
0033     struct defer_stored_signed_lazily {
0034         template<std::intmax_t Min, std::intmax_t Max>
0035         using type = utility::signed_stored_type<Min, Max>;
0036     };
0037 
0038     struct defer_stored_unsigned_lazily {
0039         template<std::uintmax_t Min, std::uintmax_t Max>
0040         using type = utility::unsigned_stored_type<Min, Max>;
0041     };
0042 
0043     template<typename T, T Min, T Max>
0044     struct result_type {
0045         using type = typename std::conditional<
0046             std::numeric_limits<T>::is_signed,
0047             defer_stored_signed_lazily,
0048             defer_stored_unsigned_lazily
0049         >::type::template type<Min, Max>;
0050     };
0051 
0052 public:
0053     ///////////////////////////////////////////////////////////////////////
0054     template<typename T, typename U>
0055     struct addition_result {
0056         using temp_base_type = typename std::conditional<
0057             // if both arguments are unsigned
0058             ! std::numeric_limits<T>::is_signed
0059             && ! std::numeric_limits<U>::is_signed,
0060             // result is unsigned
0061             std::uintmax_t,
0062             // otherwise result is signed
0063             std::intmax_t
0064         >::type;
0065 
0066         using r_type = checked_result<temp_base_type>;
0067         using r_interval_type = interval<r_type>;
0068 
0069         constexpr static const r_interval_type t_interval{
0070             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0071             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0072         };
0073 
0074         constexpr static const r_interval_type u_interval{
0075             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
0076             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0077         };
0078 
0079         constexpr static const r_interval_type r_interval = t_interval + u_interval;
0080 
0081         constexpr static auto rl = r_interval.l;
0082         constexpr static auto ru = r_interval.u;
0083 
0084         using type = typename result_type<
0085             temp_base_type,
0086             rl.exception()
0087                 ? std::numeric_limits<temp_base_type>::min()
0088                 : static_cast<temp_base_type>(rl),
0089             ru.exception()
0090                 ? std::numeric_limits<temp_base_type>::max()
0091                 : static_cast<temp_base_type>(ru)
0092         >::type;
0093     };
0094 
0095     ///////////////////////////////////////////////////////////////////////
0096     template<typename T, typename U>
0097     struct subtraction_result {
0098         // result of subtraction are always signed.
0099         using temp_base_type = intmax_t;
0100 
0101         using r_type = checked_result<temp_base_type>;
0102         using r_interval_type = interval<r_type>;
0103 
0104         constexpr static const r_interval_type t_interval{
0105             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0106             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0107         };
0108 
0109         constexpr static const r_interval_type u_interval{
0110             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
0111             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0112         };
0113 
0114         constexpr static const r_interval_type r_interval = t_interval - u_interval;
0115 
0116         constexpr static auto rl = r_interval.l;
0117         constexpr static auto ru = r_interval.u;
0118 
0119         using type = typename result_type<
0120             temp_base_type,
0121             rl.exception()
0122                 ? std::numeric_limits<temp_base_type>::min()
0123                 : static_cast<temp_base_type>(rl),
0124             ru.exception()
0125                 ? std::numeric_limits<temp_base_type>::max()
0126                 : static_cast<temp_base_type>(ru)
0127         >::type;
0128     };
0129 
0130     ///////////////////////////////////////////////////////////////////////
0131     template<typename T, typename U>
0132     struct multiplication_result {
0133         using temp_base_type = typename std::conditional<
0134             // if both arguments are unsigned
0135             ! std::numeric_limits<T>::is_signed
0136             && ! std::numeric_limits<U>::is_signed,
0137             // result is unsigned
0138             std::uintmax_t,
0139             // otherwise result is signed
0140             std::intmax_t
0141         >::type;
0142 
0143         using r_type = checked_result<temp_base_type>;
0144         using r_interval_type = interval<r_type>;
0145 
0146         constexpr static const r_interval_type t_interval{
0147             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0148             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0149         };
0150 
0151         constexpr static const r_interval_type u_interval{
0152             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
0153             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0154         };
0155 
0156         constexpr static const r_interval_type r_interval = t_interval * u_interval;
0157 
0158         constexpr static const auto rl = r_interval.l;
0159         constexpr static const auto ru = r_interval.u;
0160 
0161         using type = typename result_type<
0162             temp_base_type,
0163             rl.exception()
0164                 ? std::numeric_limits<temp_base_type>::min()
0165                 : static_cast<temp_base_type>(rl),
0166             ru.exception()
0167                 ? std::numeric_limits<temp_base_type>::max()
0168                 : static_cast<temp_base_type>(ru)
0169         >::type;
0170     };
0171 
0172     ///////////////////////////////////////////////////////////////////////
0173     template<typename T, typename U>
0174     struct division_result {
0175         using temp_base_type = typename std::conditional<
0176             // if both arguments are unsigned
0177             ! std::numeric_limits<T>::is_signed
0178             && ! std::numeric_limits<U>::is_signed,
0179             // result is unsigned
0180             std::uintmax_t,
0181             // otherwise result is signed
0182             std::intmax_t
0183         >::type;
0184 
0185         using r_type = checked_result<temp_base_type>;
0186         using r_interval_type = interval<r_type>;
0187 
0188         constexpr static const r_interval_type t_interval{
0189             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0190             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0191         };
0192 
0193         constexpr static const r_interval_type u_interval{
0194             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
0195             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0196         };
0197 
0198         constexpr static r_interval_type rx(){
0199             if(u_interval.u < r_type(0)
0200             || u_interval.l > r_type(0))
0201                 return t_interval / u_interval;
0202             return utility::minmax(
0203                 std::initializer_list<r_type> {
0204                     t_interval.l / u_interval.l,
0205                     t_interval.l / r_type(-1),
0206                     t_interval.l / r_type(1),
0207                     t_interval.l / u_interval.u,
0208                     t_interval.u / u_interval.l,
0209                     t_interval.u / r_type(-1),
0210                     t_interval.u / r_type(1),
0211                     t_interval.u / u_interval.u,
0212                 }
0213             );
0214         }
0215 
0216         constexpr static const r_interval_type r_interval = rx();
0217 
0218         constexpr static auto rl = r_interval.l;
0219         constexpr static auto ru = r_interval.u;
0220 
0221         using type = typename result_type<
0222             temp_base_type,
0223             rl.exception()
0224                 ? std::numeric_limits<temp_base_type>::min()
0225                 : static_cast<temp_base_type>(rl),
0226             ru.exception()
0227                 ? std::numeric_limits<temp_base_type>::max()
0228                 : static_cast<temp_base_type>(ru)
0229         >::type;
0230     };
0231 
0232     ///////////////////////////////////////////////////////////////////////
0233     template<typename T, typename U>
0234     struct modulus_result {
0235         using temp_base_type = typename std::conditional<
0236             // if both arguments are unsigned
0237             ! std::numeric_limits<T>::is_signed
0238             && ! std::numeric_limits<U>::is_signed,
0239             // result is unsigned
0240             std::uintmax_t,
0241             // otherwise result is signed
0242             std::intmax_t
0243         >::type;
0244 
0245         using r_type = checked_result<temp_base_type>;
0246         using r_interval_type = interval<r_type>;
0247 
0248         constexpr static const r_interval_type t_interval{
0249             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0250             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0251         };
0252 
0253         constexpr static const r_interval_type u_interval{
0254             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
0255             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0256         };
0257 
0258         constexpr static r_interval_type rx(){
0259             if(u_interval.u < r_type(0)
0260             || u_interval.l > r_type(0))
0261                 return t_interval / u_interval;
0262             return utility::minmax(
0263                 std::initializer_list<r_type> {
0264                     t_interval.l % u_interval.l,
0265                     t_interval.l % r_type(-1),
0266                     t_interval.l % r_type(1),
0267                     t_interval.l % u_interval.u,
0268                     t_interval.u % u_interval.l,
0269                     t_interval.u % r_type(-1),
0270                     t_interval.u % r_type(1),
0271                     t_interval.u % u_interval.u,
0272                 }
0273             );
0274         }
0275 
0276         constexpr static const r_interval_type r_interval = rx();
0277 
0278         constexpr static auto rl = r_interval.l;
0279         constexpr static auto ru = r_interval.u;
0280 
0281         using type = typename result_type<
0282             temp_base_type,
0283             rl.exception()
0284                 ? std::numeric_limits<temp_base_type>::min()
0285                 : static_cast<temp_base_type>(rl),
0286             ru.exception()
0287                 ? std::numeric_limits<temp_base_type>::max()
0288                 : static_cast<temp_base_type>(ru)
0289         >::type;
0290     };
0291 
0292     ///////////////////////////////////////////////////////////////////////
0293     // note: comparison_result (<, >, ...) is special.
0294     // The return value is always a bool.  The type returned here is
0295     // the intermediate type applied to make the values comparable.
0296     template<typename T, typename U>
0297     struct comparison_result {
0298         using temp_base_type = typename std::conditional<
0299             // if both arguments are unsigned
0300             ! std::numeric_limits<T>::is_signed
0301             && ! std::numeric_limits<U>::is_signed,
0302             // result is unsigned
0303             std::uintmax_t,
0304             // otherwise result is signed
0305             std::intmax_t
0306         >::type;
0307 
0308         using r_type = checked_result<temp_base_type>;
0309         using r_interval_type = interval<r_type>;
0310 
0311         constexpr static const r_interval_type t_interval{
0312             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0313             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0314         };
0315 
0316         constexpr static const r_interval_type u_interval{
0317             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
0318             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0319         };
0320 
0321         // workaround some microsoft problem
0322         #if 0
0323         constexpr static r_type min(const r_type & t, const r_type & u){
0324             // assert(! u.exception());
0325             // assert(! t.exception());
0326             return static_cast<bool>(t < u) ? t : u;
0327         }
0328 
0329        constexpr static r_type max(const r_type & t, const r_type & u){
0330             // assert(! u.exception());
0331             // assert(! t.exception());
0332             return static_cast<bool>(t < u) ? u : t;
0333         }
0334         #endif
0335 
0336         // union of two intervals
0337         // note: we can't use t_interval | u_interval because it
0338         // depends on max and min which in turn depend on < which in turn
0339         // depends on implicit conversion of tribool to bool
0340         constexpr static r_interval_type union_interval(
0341             const r_interval_type & t,
0342             const r_interval_type & u
0343         ){
0344             //const r_type & rl = min(t.l, u.l);
0345             const r_type & rmin = static_cast<bool>(t.l < u.l) ? t.l : u.l;
0346             //const r_type & ru = max(t.u, u.u);
0347             const r_type & rmax = static_cast<bool>(t.u < u.u) ? u.u : t.u;
0348             return r_interval_type(rmin, rmax);
0349         }
0350 
0351         constexpr static const r_interval_type r_interval =
0352             union_interval(t_interval, u_interval);
0353 
0354         constexpr static auto rl = r_interval.l;
0355         constexpr static auto ru = r_interval.u;
0356 
0357         using type = typename result_type<
0358             temp_base_type,
0359             rl.exception()
0360                 ? std::numeric_limits<temp_base_type>::min()
0361                 : static_cast<temp_base_type>(rl),
0362             ru.exception()
0363                 ? std::numeric_limits<temp_base_type>::max()
0364                 : static_cast<temp_base_type>(ru)
0365         >::type;
0366     };
0367 
0368     ///////////////////////////////////////////////////////////////////////
0369     // shift operations
0370     template<typename T, typename U>
0371     struct left_shift_result {
0372         using temp_base_type = typename std::conditional<
0373             std::numeric_limits<T>::is_signed,
0374             std::intmax_t,
0375             std::uintmax_t
0376         >::type;
0377 
0378         using r_type = checked_result<temp_base_type>;
0379         using r_interval_type = interval<r_type>;
0380 
0381         constexpr static const r_interval_type t_interval{
0382             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0383             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0384         };
0385 
0386         constexpr static const r_interval_type u_interval{
0387             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min())),
0388             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0389         };
0390 
0391         constexpr static const r_interval_type r_interval =
0392             t_interval << u_interval;
0393 
0394         constexpr static auto rl = r_interval.l;
0395         constexpr static auto ru = r_interval.u;
0396 
0397         using type = typename result_type<
0398             temp_base_type,
0399             rl.exception()
0400                 ? std::numeric_limits<temp_base_type>::min()
0401                 : static_cast<temp_base_type>(rl),
0402             ru.exception()
0403                 ? std::numeric_limits<temp_base_type>::max()
0404                 : static_cast<temp_base_type>(ru)
0405         >::type;
0406     };
0407 
0408     ///////////////////////////////////////////////////////////////////////
0409     template<typename T, typename U>
0410     struct right_shift_result {
0411         using temp_base_type = typename std::conditional<
0412             std::numeric_limits<T>::is_signed,
0413             std::intmax_t,
0414             std::uintmax_t
0415         >::type;
0416 
0417         using r_type = checked_result<temp_base_type>;
0418         using r_interval_type = interval<r_type>;
0419 
0420         constexpr static const r_interval_type t_interval{
0421             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::min())),
0422             checked::cast<temp_base_type>(base_value(std::numeric_limits<T>::max()))
0423         };
0424 
0425         constexpr static const r_type u_min
0426             = checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::min()));
0427 
0428         constexpr static const r_interval_type u_interval{
0429             u_min.exception()
0430             ? r_type(0)
0431             : u_min,
0432             checked::cast<temp_base_type>(base_value(std::numeric_limits<U>::max()))
0433         };
0434 
0435         constexpr static const r_interval_type r_interval = t_interval >> u_interval;
0436 
0437         constexpr static auto rl = r_interval.l;
0438         constexpr static auto ru = r_interval.u;
0439 
0440         using type = typename result_type<
0441             temp_base_type,
0442             rl.exception()
0443                 ? std::numeric_limits<temp_base_type>::min()
0444                 : static_cast<temp_base_type>(rl),
0445             ru.exception()
0446                 ? std::numeric_limits<temp_base_type>::max()
0447                 : static_cast<temp_base_type>(ru)
0448         >::type;
0449 
0450     };
0451 
0452     ///////////////////////////////////////////////////////////////////////
0453     template<typename T, typename U>
0454     struct bitwise_and_result {
0455         using type = decltype(
0456             typename base_type<T>::type()
0457             & typename base_type<U>::type()
0458         );
0459     };
0460     template<typename T, typename U>
0461     struct bitwise_or_result {
0462         using type = decltype(
0463             typename base_type<T>::type()
0464             | typename base_type<U>::type()
0465         );
0466     };
0467     template<typename T, typename U>
0468     struct bitwise_xor_result {
0469         using type = decltype(
0470             typename base_type<T>::type()
0471             ^ typename base_type<U>::type()
0472         );
0473     };
0474 };
0475 
0476 } // safe_numerics
0477 } // boost
0478 
0479 #endif // BOOST_NUMERIC_AUTOMATIC_HPP