File indexing completed on 2025-01-30 09:59:41
0001 #ifndef BOOST_NUMERIC_AUTOMATIC_HPP
0002 #define BOOST_NUMERIC_AUTOMATIC_HPP
0003
0004
0005
0006
0007
0008
0009
0010
0011
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
0032
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
0058 ! std::numeric_limits<T>::is_signed
0059 && ! std::numeric_limits<U>::is_signed,
0060
0061 std::uintmax_t,
0062
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
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
0135 ! std::numeric_limits<T>::is_signed
0136 && ! std::numeric_limits<U>::is_signed,
0137
0138 std::uintmax_t,
0139
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
0177 ! std::numeric_limits<T>::is_signed
0178 && ! std::numeric_limits<U>::is_signed,
0179
0180 std::uintmax_t,
0181
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
0237 ! std::numeric_limits<T>::is_signed
0238 && ! std::numeric_limits<U>::is_signed,
0239
0240 std::uintmax_t,
0241
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
0294
0295
0296 template<typename T, typename U>
0297 struct comparison_result {
0298 using temp_base_type = typename std::conditional<
0299
0300 ! std::numeric_limits<T>::is_signed
0301 && ! std::numeric_limits<U>::is_signed,
0302
0303 std::uintmax_t,
0304
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
0322 #if 0
0323 constexpr static r_type min(const r_type & t, const r_type & u){
0324
0325
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
0331
0332 return static_cast<bool>(t < u) ? u : t;
0333 }
0334 #endif
0335
0336
0337
0338
0339
0340 constexpr static r_interval_type union_interval(
0341 const r_interval_type & t,
0342 const r_interval_type & u
0343 ){
0344
0345 const r_type & rmin = static_cast<bool>(t.l < u.l) ? t.l : u.l;
0346
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
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 }
0477 }
0478
0479 #endif