safe_base_operations.hpp 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743
  1. #ifndef BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
  2. #define BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP
  3. // Copyright (c) 2012 Robert Ramey
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. #include <limits>
  9. #include <type_traits> // is_base_of, is_same, is_floating_point, conditional
  10. #include <algorithm> // max
  11. #include <cassert>
  12. #include <boost/config.hpp>
  13. #include <boost/core/enable_if.hpp> // lazy_enable_if
  14. #include <boost/integer.hpp>
  15. #include <boost/logic/tribool.hpp>
  16. #include "checked_integer.hpp"
  17. #include "checked_result.hpp"
  18. #include "safe_base.hpp"
  19. #include "interval.hpp"
  20. #include "utility.hpp"
  21. namespace boost {
  22. namespace safe_numerics {
  23. /////////////////////////////////////////////////////////////////
  24. // validation
  25. template<typename R, R Min, R Max, typename T, typename E>
  26. struct validate_detail {
  27. using r_type = checked_result<R>;
  28. struct exception_possible {
  29. constexpr static R return_value(
  30. const T & t
  31. ){
  32. // INT08-C
  33. const r_type rx = heterogeneous_checked_operation<
  34. R,
  35. typename base_type<T>::type,
  36. dispatch_and_return<E, R>
  37. >::cast(t);
  38. const R r = rx.exception()
  39. ? static_cast<R>(t)
  40. : rx.m_r;
  41. return r;
  42. }
  43. };
  44. struct exception_not_possible {
  45. constexpr static R return_value(
  46. const T & t
  47. ){
  48. return static_cast<R>(base_value(t));
  49. }
  50. };
  51. constexpr static R return_value(const T & t){
  52. constexpr const interval<r_type> t_interval{
  53. checked::cast<R>(base_value(std::numeric_limits<T>::min())),
  54. checked::cast<R>(base_value(std::numeric_limits<T>::max()))
  55. };
  56. constexpr const interval<r_type> r_interval{r_type(Min), r_type(Max)};
  57. /*
  58. static_assert(
  59. true != r_interval.excludes(t_interval),
  60. "ranges don't overlap: can't cast"
  61. );
  62. */
  63. return std::conditional<
  64. static_cast<bool>(r_interval.includes(t_interval)),
  65. exception_not_possible,
  66. exception_possible
  67. >::type::return_value(t);
  68. }
  69. };
  70. template<class Stored, Stored Min, Stored Max, class P, class E>
  71. template<class T>
  72. constexpr Stored safe_base<Stored, Min, Max, P, E>::
  73. validated_cast(const T & t) const {
  74. return validate_detail<Stored,Min,Max,T,E>::return_value(t);
  75. }
  76. template<class Stored, Stored Min, Stored Max, class P, class E>
  77. template<typename T, T N, class P1, class E1>
  78. constexpr Stored safe_base<Stored, Min, Max, P, E>::
  79. validated_cast(const safe_literal_impl<T, N, P1, E1> &) const {
  80. constexpr const interval<Stored> this_interval{};
  81. // if static values don't overlap, the program can never function
  82. static_assert(
  83. this_interval.includes(N),
  84. "safe type cannot be constructed from this value"
  85. );
  86. return static_cast<Stored>(N);
  87. }
  88. /////////////////////////////////////////////////////////////////
  89. // constructors
  90. template<class Stored, Stored Min, Stored Max, class P, class E>
  91. constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
  92. const Stored & rhs,
  93. skip_validation
  94. ) :
  95. m_t(rhs)
  96. {}
  97. template<class Stored, Stored Min, Stored Max, class P, class E>
  98. constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(){
  99. dispatch<E, safe_numerics_error::uninitialized_value>(
  100. "safe values must be initialized"
  101. );
  102. }
  103. // construct an instance of a safe type
  104. // from an instance of a convertible underlying type.
  105. template<class Stored, Stored Min, Stored Max, class P, class E>
  106. template<class T>
  107. constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
  108. const T & t,
  109. typename std::enable_if<
  110. is_safe<T>::value,
  111. bool
  112. >::type
  113. ) :
  114. m_t(validated_cast(t))
  115. {}
  116. template<class Stored, Stored Min, Stored Max, class P, class E>
  117. template<class T>
  118. constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
  119. const T & t,
  120. typename std::enable_if<
  121. std::is_integral<T>::value,
  122. bool
  123. >::type
  124. ) :
  125. m_t(validated_cast(t))
  126. {}
  127. template<class Stored, Stored Min, Stored Max, class P, class E>
  128. template<class T, T value>
  129. constexpr /*explicit*/ safe_base<Stored, Min, Max, P, E>::safe_base(
  130. const std::integral_constant<T, value> &
  131. ) :
  132. m_t(validated_cast(value))
  133. {}
  134. /////////////////////////////////////////////////////////////////
  135. // casting operators
  136. // cast to a builtin type from a safe type
  137. template< class Stored, Stored Min, Stored Max, class P, class E>
  138. template<
  139. class R,
  140. typename std::enable_if<
  141. ! boost::safe_numerics::is_safe<R>::value,
  142. int
  143. >::type
  144. >
  145. constexpr safe_base<Stored, Min, Max, P, E>::
  146. operator R () const {
  147. // if static values don't overlap, the program can never function
  148. #if 0
  149. constexpr const interval<R> r_interval;
  150. constexpr const interval<Stored> this_interval(Min, Max);
  151. static_assert(
  152. ! r_interval.excludes(this_interval),
  153. "safe type cannot be constructed with this type"
  154. );
  155. #endif
  156. return validate_detail<
  157. R,
  158. std::numeric_limits<R>::min(),
  159. std::numeric_limits<R>::max(),
  160. Stored,
  161. E
  162. >::return_value(m_t);
  163. }
  164. // cast to the underlying builtin type from a safe type
  165. template< class Stored, Stored Min, Stored Max, class P, class E>
  166. constexpr safe_base<Stored, Min, Max, P, E>::
  167. operator Stored () const {
  168. return m_t;
  169. }
  170. /////////////////////////////////////////////////////////////////
  171. // binary operators
  172. template<class T, class U>
  173. struct common_exception_policy {
  174. static_assert(is_safe<T>::value || is_safe<U>::value,
  175. "at least one type must be a safe type"
  176. );
  177. using t_exception_policy = typename get_exception_policy<T>::type;
  178. using u_exception_policy = typename get_exception_policy<U>::type;
  179. static_assert(
  180. std::is_same<t_exception_policy, u_exception_policy>::value
  181. || std::is_same<t_exception_policy, void>::value
  182. || std::is_same<void, u_exception_policy>::value,
  183. "if the exception policies are different, one must be void!"
  184. );
  185. static_assert(
  186. ! (std::is_same<t_exception_policy, void>::value
  187. && std::is_same<void, u_exception_policy>::value),
  188. "at least one exception policy must not be void"
  189. );
  190. using type =
  191. typename std::conditional<
  192. !std::is_same<void, u_exception_policy>::value,
  193. u_exception_policy,
  194. typename std::conditional<
  195. !std::is_same<void, t_exception_policy>::value,
  196. t_exception_policy,
  197. //
  198. void
  199. >::type >::type;
  200. static_assert(
  201. !std::is_same<void, type>::value,
  202. "exception_policy is void"
  203. );
  204. };
  205. template<class T, class U>
  206. struct common_promotion_policy {
  207. static_assert(is_safe<T>::value || is_safe<U>::value,
  208. "at least one type must be a safe type"
  209. );
  210. using t_promotion_policy = typename get_promotion_policy<T>::type;
  211. using u_promotion_policy = typename get_promotion_policy<U>::type;
  212. static_assert(
  213. std::is_same<t_promotion_policy, u_promotion_policy>::value
  214. ||std::is_same<t_promotion_policy, void>::value
  215. ||std::is_same<void, u_promotion_policy>::value,
  216. "if the promotion policies are different, one must be void!"
  217. );
  218. static_assert(
  219. ! (std::is_same<t_promotion_policy, void>::value
  220. && std::is_same<void, u_promotion_policy>::value),
  221. "at least one promotion policy must not be void"
  222. );
  223. using type =
  224. typename std::conditional<
  225. ! std::is_same<void, u_promotion_policy>::value,
  226. u_promotion_policy,
  227. typename std::conditional<
  228. ! std::is_same<void, t_promotion_policy>::value,
  229. t_promotion_policy,
  230. //
  231. void
  232. >::type >::type;
  233. static_assert(
  234. ! std::is_same<void, type>::value,
  235. "promotion_policy is void"
  236. );
  237. };
  238. // give the resultant base type, figure out what the final result
  239. // type will be. Note we currently need this because we support
  240. // return of only safe integer types. Someday ..., we'll support
  241. // all other safe types including float and user defined ones.
  242. //
  243. // helper - cast arguments to binary operators to a specified
  244. // result type
  245. template<class EP, class R, class T, class U>
  246. std::pair<R, R>
  247. constexpr static casting_helper(const T & t, const U & u){
  248. using r_type = checked_result<R>;
  249. const r_type tx = heterogeneous_checked_operation<
  250. R,
  251. typename base_type<T>::type,
  252. dispatch_and_return<EP, R>
  253. >::cast(base_value(t));
  254. const R tr = tx.exception()
  255. ? static_cast<R>(t)
  256. : tx.m_r;
  257. const r_type ux = heterogeneous_checked_operation<
  258. R,
  259. typename base_type<U>::type,
  260. dispatch_and_return<EP, R>
  261. >::cast(base_value(u));
  262. const R ur = ux.exception()
  263. ? static_cast<R>(u)
  264. : ux.m_r;
  265. return std::pair<R, R>(tr, ur);
  266. }
  267. // Note: the following global operators will be found via
  268. // argument dependent lookup.
  269. /////////////////////////////////////////////////////////////////
  270. // addition
  271. template<class T, class U>
  272. struct addition_result {
  273. private:
  274. using promotion_policy = typename common_promotion_policy<T, U>::type;
  275. using result_base_type =
  276. typename promotion_policy::template addition_result<T,U>::type;
  277. // if exception not possible
  278. constexpr static result_base_type
  279. return_value(const T & t, const U & u, std::false_type){
  280. return
  281. static_cast<result_base_type>(base_value(t))
  282. + static_cast<result_base_type>(base_value(u));
  283. }
  284. // if exception possible
  285. using exception_policy = typename common_exception_policy<T, U>::type;
  286. using r_type = checked_result<result_base_type>;
  287. constexpr static result_base_type
  288. return_value(const T & t, const U & u, std::true_type){
  289. const std::pair<result_base_type, result_base_type> r = casting_helper<
  290. exception_policy,
  291. result_base_type
  292. >(t, u);
  293. const r_type rx = checked_operation<
  294. result_base_type,
  295. dispatch_and_return<exception_policy, result_base_type>
  296. >::add(r.first, r.second);
  297. return
  298. rx.exception()
  299. ? r.first + r.second
  300. : rx.m_r;
  301. }
  302. using r_type_interval_t = interval<r_type>;
  303. constexpr static const r_type_interval_t get_r_type_interval(){
  304. constexpr const r_type_interval_t t_interval{
  305. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  306. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  307. };
  308. constexpr const r_type_interval_t u_interval{
  309. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  310. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  311. };
  312. return t_interval + u_interval;
  313. }
  314. constexpr static const r_type_interval_t r_type_interval = get_r_type_interval();
  315. constexpr static const interval<result_base_type> return_interval{
  316. r_type_interval.l.exception()
  317. ? std::numeric_limits<result_base_type>::min()
  318. : static_cast<result_base_type>(r_type_interval.l),
  319. r_type_interval.u.exception()
  320. ? std::numeric_limits<result_base_type>::max()
  321. : static_cast<result_base_type>(r_type_interval.u)
  322. };
  323. constexpr static bool exception_possible(){
  324. if(r_type_interval.l.exception())
  325. return true;
  326. if(r_type_interval.u.exception())
  327. return true;
  328. if(! return_interval.includes(r_type_interval))
  329. return true;
  330. return false;
  331. }
  332. constexpr static auto rl = return_interval.l;
  333. constexpr static auto ru = return_interval.u;
  334. public:
  335. using type =
  336. safe_base<
  337. result_base_type,
  338. rl,
  339. ru,
  340. promotion_policy,
  341. exception_policy
  342. >;
  343. constexpr static type return_value(const T & t, const U & u){
  344. return type(
  345. return_value(
  346. t,
  347. u,
  348. std::integral_constant<bool, exception_possible()>()
  349. ),
  350. typename type::skip_validation()
  351. );
  352. }
  353. };
  354. template<class T, class U>
  355. typename boost::lazy_enable_if_c<
  356. is_safe<T>::value || is_safe<U>::value,
  357. addition_result<T, U>
  358. >::type
  359. constexpr operator+(const T & t, const U & u){
  360. return addition_result<T, U>::return_value(t, u);
  361. }
  362. template<class T, class U>
  363. typename std::enable_if<
  364. is_safe<T>::value || is_safe<U>::value,
  365. T
  366. >::type
  367. constexpr operator+=(T & t, const U & u){
  368. t = static_cast<T>(t + u);
  369. return t;
  370. }
  371. /////////////////////////////////////////////////////////////////
  372. // subtraction
  373. template<class T, class U>
  374. struct subtraction_result {
  375. private:
  376. using promotion_policy = typename common_promotion_policy<T, U>::type;
  377. using result_base_type =
  378. typename promotion_policy::template subtraction_result<T, U>::type;
  379. // if exception not possible
  380. constexpr static result_base_type
  381. return_value(const T & t, const U & u, std::false_type){
  382. return
  383. static_cast<result_base_type>(base_value(t))
  384. - static_cast<result_base_type>(base_value(u));
  385. }
  386. // if exception possible
  387. using exception_policy = typename common_exception_policy<T, U>::type;
  388. using r_type = checked_result<result_base_type>;
  389. constexpr static result_base_type
  390. return_value(const T & t, const U & u, std::true_type){
  391. const std::pair<result_base_type, result_base_type> r = casting_helper<
  392. exception_policy,
  393. result_base_type
  394. >(t, u);
  395. const r_type rx = checked_operation<
  396. result_base_type,
  397. dispatch_and_return<exception_policy, result_base_type>
  398. >::subtract(r.first, r.second);
  399. return
  400. rx.exception()
  401. ? r.first + r.second
  402. : rx.m_r;
  403. }
  404. using r_type_interval_t = interval<r_type>;
  405. constexpr static const r_type_interval_t get_r_type_interval(){
  406. constexpr const r_type_interval_t t_interval{
  407. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  408. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  409. };
  410. constexpr const r_type_interval_t u_interval{
  411. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  412. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  413. };
  414. return t_interval - u_interval;
  415. }
  416. static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
  417. constexpr static const interval<result_base_type> return_interval{
  418. r_type_interval.l.exception()
  419. ? std::numeric_limits<result_base_type>::min()
  420. : static_cast<result_base_type>(r_type_interval.l),
  421. r_type_interval.u.exception()
  422. ? std::numeric_limits<result_base_type>::max()
  423. : static_cast<result_base_type>(r_type_interval.u)
  424. };
  425. constexpr static bool exception_possible(){
  426. if(r_type_interval.l.exception())
  427. return true;
  428. if(r_type_interval.u.exception())
  429. return true;
  430. if(! return_interval.includes(r_type_interval))
  431. return true;
  432. return false;
  433. }
  434. public:
  435. constexpr static auto rl = return_interval.l;
  436. constexpr static auto ru = return_interval.u;
  437. using type =
  438. safe_base<
  439. result_base_type,
  440. rl,
  441. ru,
  442. promotion_policy,
  443. exception_policy
  444. >;
  445. constexpr static type return_value(const T & t, const U & u){
  446. return type(
  447. return_value(
  448. t,
  449. u,
  450. std::integral_constant<bool, exception_possible()>()
  451. ),
  452. typename type::skip_validation()
  453. );
  454. }
  455. };
  456. template<class T, class U>
  457. typename boost::lazy_enable_if_c<
  458. is_safe<T>::value || is_safe<U>::value,
  459. subtraction_result<T, U>
  460. >::type
  461. constexpr operator-(const T & t, const U & u){
  462. return subtraction_result<T, U>::return_value(t, u);
  463. }
  464. template<class T, class U>
  465. typename std::enable_if<
  466. is_safe<T>::value || is_safe<U>::value,
  467. T
  468. >::type
  469. constexpr operator-=(T & t, const U & u){
  470. t = static_cast<T>(t - u);
  471. return t;
  472. }
  473. /////////////////////////////////////////////////////////////////
  474. // multiplication
  475. template<class T, class U>
  476. struct multiplication_result {
  477. private:
  478. using promotion_policy = typename common_promotion_policy<T, U>::type;
  479. using result_base_type =
  480. typename promotion_policy::template multiplication_result<T, U>::type;
  481. // if exception not possible
  482. constexpr static result_base_type
  483. return_value(const T & t, const U & u, std::false_type){
  484. return
  485. static_cast<result_base_type>(base_value(t))
  486. * static_cast<result_base_type>(base_value(u));
  487. }
  488. // if exception possible
  489. using exception_policy = typename common_exception_policy<T, U>::type;
  490. using r_type = checked_result<result_base_type>;
  491. constexpr static result_base_type
  492. return_value(const T & t, const U & u, std::true_type){
  493. const std::pair<result_base_type, result_base_type> r = casting_helper<
  494. exception_policy,
  495. result_base_type
  496. >(t, u);
  497. const r_type rx = checked_operation<
  498. result_base_type,
  499. dispatch_and_return<exception_policy, result_base_type>
  500. >::multiply(r.first, r.second);
  501. return
  502. rx.exception()
  503. ? r.first * r.second
  504. : rx.m_r;
  505. }
  506. using r_type_interval_t = interval<r_type>;
  507. constexpr static r_type_interval_t get_r_type_interval(){
  508. constexpr const r_type_interval_t t_interval{
  509. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  510. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  511. };
  512. constexpr const r_type_interval_t u_interval{
  513. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  514. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  515. };
  516. return t_interval * u_interval;
  517. }
  518. static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
  519. constexpr static const interval<result_base_type> return_interval{
  520. r_type_interval.l.exception()
  521. ? std::numeric_limits<result_base_type>::min()
  522. : static_cast<result_base_type>(r_type_interval.l),
  523. r_type_interval.u.exception()
  524. ? std::numeric_limits<result_base_type>::max()
  525. : static_cast<result_base_type>(r_type_interval.u)
  526. };
  527. constexpr static bool exception_possible(){
  528. if(r_type_interval.l.exception())
  529. return true;
  530. if(r_type_interval.u.exception())
  531. return true;
  532. if(! return_interval.includes(r_type_interval))
  533. return true;
  534. return false;
  535. }
  536. constexpr static auto rl = return_interval.l;
  537. constexpr static auto ru = return_interval.u;
  538. public:
  539. using type =
  540. safe_base<
  541. result_base_type,
  542. rl,
  543. ru,
  544. promotion_policy,
  545. exception_policy
  546. >;
  547. constexpr static type return_value(const T & t, const U & u){
  548. return type(
  549. return_value(
  550. t,
  551. u,
  552. std::integral_constant<bool, exception_possible()>()
  553. ),
  554. typename type::skip_validation()
  555. );
  556. }
  557. };
  558. template<class T, class U>
  559. typename boost::lazy_enable_if_c<
  560. is_safe<T>::value || is_safe<U>::value,
  561. multiplication_result<T, U>
  562. >::type
  563. constexpr operator*(const T & t, const U & u){
  564. // argument dependent lookup should guarentee that we only get here
  565. return multiplication_result<T, U>::return_value(t, u);
  566. }
  567. template<class T, class U>
  568. typename std::enable_if<
  569. is_safe<T>::value || is_safe<U>::value,
  570. T
  571. >::type
  572. constexpr operator*=(T & t, const U & u){
  573. t = static_cast<T>(t * u);
  574. return t;
  575. }
  576. /////////////////////////////////////////////////////////////////
  577. // division
  578. // key idea here - result will never be larger than T
  579. template<class T, class U>
  580. struct division_result {
  581. private:
  582. using promotion_policy = typename common_promotion_policy<T, U>::type;
  583. using result_base_type =
  584. typename promotion_policy::template division_result<T, U>::type;
  585. // if exception not possible
  586. constexpr static result_base_type
  587. return_value(const T & t, const U & u, std::false_type){
  588. return
  589. static_cast<result_base_type>(base_value(t))
  590. / static_cast<result_base_type>(base_value(u));
  591. }
  592. // if exception possible
  593. using exception_policy = typename common_exception_policy<T, U>::type;
  594. constexpr static int bits = std::min(
  595. std::numeric_limits<std::uintmax_t>::digits,
  596. std::max(std::initializer_list<int>{
  597. std::numeric_limits<result_base_type>::digits,
  598. std::numeric_limits<typename base_type<T>::type>::digits,
  599. std::numeric_limits<typename base_type<U>::type>::digits
  600. }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
  601. );
  602. using r_type = checked_result<result_base_type>;
  603. constexpr static result_base_type
  604. return_value(const T & t, const U & u, std::true_type){
  605. using temp_base = typename std::conditional<
  606. std::numeric_limits<result_base_type>::is_signed,
  607. typename boost::int_t<bits>::least,
  608. typename boost::uint_t<bits>::least
  609. >::type;
  610. using t_type = checked_result<temp_base>;
  611. const std::pair<t_type, t_type> r = casting_helper<
  612. exception_policy,
  613. temp_base
  614. >(t, u);
  615. const t_type rx = checked_operation<
  616. temp_base,
  617. dispatch_and_return<exception_policy, temp_base>
  618. >::divide(r.first, r.second);
  619. return
  620. rx.exception()
  621. ? r.first / r.second
  622. : rx;
  623. }
  624. using r_type_interval_t = interval<r_type>;
  625. constexpr static r_type_interval_t t_interval(){
  626. return r_type_interval_t{
  627. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  628. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  629. };
  630. };
  631. constexpr static r_type_interval_t u_interval(){
  632. return r_type_interval_t{
  633. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  634. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  635. };
  636. };
  637. constexpr static r_type_interval_t get_r_type_interval(){
  638. constexpr const r_type_interval_t t = t_interval();
  639. constexpr const r_type_interval_t u = u_interval();
  640. if(u.u < r_type(0) || u.l > r_type(0))
  641. return t / u;
  642. return utility::minmax(
  643. std::initializer_list<r_type> {
  644. t.l / u.l,
  645. t.l / r_type(-1),
  646. t.l / r_type(1),
  647. t.l / u.u,
  648. t.u / u.l,
  649. t.u / r_type(-1),
  650. t.u / r_type(1),
  651. t.u / u.u,
  652. }
  653. );
  654. }
  655. static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
  656. constexpr static const interval<result_base_type> return_interval{
  657. r_type_interval.l.exception()
  658. ? std::numeric_limits<result_base_type>::min()
  659. : static_cast<result_base_type>(r_type_interval.l),
  660. r_type_interval.u.exception()
  661. ? std::numeric_limits<result_base_type>::max()
  662. : static_cast<result_base_type>(r_type_interval.u)
  663. };
  664. constexpr static bool exception_possible(){
  665. constexpr const r_type_interval_t ri = get_r_type_interval();
  666. constexpr const r_type_interval_t ui = u_interval();
  667. return
  668. static_cast<bool>(ui.includes(r_type(0)))
  669. || ri.l.exception()
  670. || ri.u.exception();
  671. }
  672. constexpr static auto rl = return_interval.l;
  673. constexpr static auto ru = return_interval.u;
  674. public:
  675. using type =
  676. safe_base<
  677. result_base_type,
  678. rl,
  679. ru,
  680. promotion_policy,
  681. exception_policy
  682. >;
  683. constexpr static type return_value(const T & t, const U & u){
  684. return type(
  685. return_value(
  686. t,
  687. u,
  688. std::integral_constant<bool, exception_possible()>()
  689. ),
  690. typename type::skip_validation()
  691. );
  692. }
  693. };
  694. template<class T, class U>
  695. typename boost::lazy_enable_if_c<
  696. is_safe<T>::value || is_safe<U>::value,
  697. division_result<T, U>
  698. >::type
  699. constexpr operator/(const T & t, const U & u){
  700. return division_result<T, U>::return_value(t, u);
  701. }
  702. template<class T, class U>
  703. typename std::enable_if<
  704. is_safe<T>::value || is_safe<U>::value,
  705. T
  706. >::type
  707. constexpr operator/=(T & t, const U & u){
  708. t = static_cast<T>(t / u);
  709. return t;
  710. }
  711. /////////////////////////////////////////////////////////////////
  712. // modulus
  713. template<class T, class U>
  714. struct modulus_result {
  715. private:
  716. using promotion_policy = typename common_promotion_policy<T, U>::type;
  717. using result_base_type = typename promotion_policy::template modulus_result<T, U>::type;
  718. // if exception not possible
  719. constexpr static result_base_type
  720. return_value(const T & t, const U & u, std::false_type){
  721. return
  722. static_cast<result_base_type>(base_value(t))
  723. % static_cast<result_base_type>(base_value(u));
  724. }
  725. // if exception possible
  726. using exception_policy = typename common_exception_policy<T, U>::type;
  727. constexpr static int bits = std::min(
  728. std::numeric_limits<std::uintmax_t>::digits,
  729. std::max(std::initializer_list<int>{
  730. std::numeric_limits<result_base_type>::digits,
  731. std::numeric_limits<typename base_type<T>::type>::digits,
  732. std::numeric_limits<typename base_type<U>::type>::digits
  733. }) + (std::numeric_limits<result_base_type>::is_signed ? 1 : 0)
  734. );
  735. using r_type = checked_result<result_base_type>;
  736. constexpr static result_base_type
  737. return_value(const T & t, const U & u, std::true_type){
  738. using temp_base = typename std::conditional<
  739. std::numeric_limits<result_base_type>::is_signed,
  740. typename boost::int_t<bits>::least,
  741. typename boost::uint_t<bits>::least
  742. >::type;
  743. using t_type = checked_result<temp_base>;
  744. const std::pair<t_type, t_type> r = casting_helper<
  745. exception_policy,
  746. temp_base
  747. >(t, u);
  748. const t_type rx = checked_operation<
  749. temp_base,
  750. dispatch_and_return<exception_policy, temp_base>
  751. >::modulus(r.first, r.second);
  752. return
  753. rx.exception()
  754. ? r.first % r.second
  755. : rx;
  756. }
  757. using r_type_interval_t = interval<r_type>;
  758. constexpr static const r_type_interval_t t_interval(){
  759. return r_type_interval_t{
  760. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  761. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  762. };
  763. };
  764. constexpr static const r_type_interval_t u_interval(){
  765. return r_type_interval_t{
  766. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  767. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  768. };
  769. };
  770. constexpr static const r_type_interval_t get_r_type_interval(){
  771. constexpr const r_type_interval_t t = t_interval();
  772. constexpr const r_type_interval_t u = u_interval();
  773. if(u.u < r_type(0)
  774. || u.l > r_type(0))
  775. return t % u;
  776. return utility::minmax(
  777. std::initializer_list<r_type> {
  778. t.l % u.l,
  779. t.l % r_type(-1),
  780. t.l % r_type(1),
  781. t.l % u.u,
  782. t.u % u.l,
  783. t.u % r_type(-1),
  784. t.u % r_type(1),
  785. t.u % u.u,
  786. }
  787. );
  788. }
  789. static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
  790. constexpr static const interval<result_base_type> return_interval{
  791. r_type_interval.l.exception()
  792. ? std::numeric_limits<result_base_type>::min()
  793. : static_cast<result_base_type>(r_type_interval.l),
  794. r_type_interval.u.exception()
  795. ? std::numeric_limits<result_base_type>::max()
  796. : static_cast<result_base_type>(r_type_interval.u)
  797. };
  798. constexpr static bool exception_possible(){
  799. constexpr const r_type_interval_t ri = get_r_type_interval();
  800. constexpr const r_type_interval_t ui = u_interval();
  801. return
  802. static_cast<bool>(ui.includes(r_type(0)))
  803. || ri.l.exception()
  804. || ri.u.exception();
  805. }
  806. constexpr static auto rl = return_interval.l;
  807. constexpr static auto ru = return_interval.u;
  808. public:
  809. using type =
  810. safe_base<
  811. result_base_type,
  812. rl,
  813. ru,
  814. promotion_policy,
  815. exception_policy
  816. >;
  817. constexpr static type return_value(const T & t, const U & u){
  818. return type(
  819. return_value(
  820. t,
  821. u,
  822. std::integral_constant<bool, exception_possible()>()
  823. ),
  824. typename type::skip_validation()
  825. );
  826. }
  827. };
  828. template<class T, class U>
  829. typename boost::lazy_enable_if_c<
  830. is_safe<T>::value || is_safe<U>::value,
  831. modulus_result<T, U>
  832. >::type
  833. constexpr operator%(const T & t, const U & u){
  834. // see https://en.wikipedia.org/wiki/Modulo_operation
  835. return modulus_result<T, U>::return_value(t, u);
  836. }
  837. template<class T, class U>
  838. typename std::enable_if<
  839. is_safe<T>::value || is_safe<U>::value,
  840. T
  841. >::type
  842. constexpr operator%=(T & t, const U & u){
  843. t = static_cast<T>(t % u);
  844. return t;
  845. }
  846. /////////////////////////////////////////////////////////////////
  847. // comparison
  848. // less than
  849. template<class T, class U>
  850. struct less_than_result {
  851. private:
  852. using promotion_policy = typename common_promotion_policy<T, U>::type;
  853. using result_base_type =
  854. typename promotion_policy::template comparison_result<T, U>::type;
  855. // if exception not possible
  856. constexpr static bool
  857. return_value(const T & t, const U & u, std::false_type){
  858. return
  859. static_cast<result_base_type>(base_value(t))
  860. < static_cast<result_base_type>(base_value(u));
  861. }
  862. using exception_policy = typename common_exception_policy<T, U>::type;
  863. using r_type = checked_result<result_base_type>;
  864. // if exception possible
  865. constexpr static bool
  866. return_value(const T & t, const U & u, std::true_type){
  867. const std::pair<result_base_type, result_base_type> r = casting_helper<
  868. exception_policy,
  869. result_base_type
  870. >(t, u);
  871. return safe_compare::less_than(r.first, r.second);
  872. }
  873. using r_type_interval_t = interval<r_type>;
  874. constexpr static bool interval_open(const r_type_interval_t & t){
  875. return t.l.exception() || t.u.exception();
  876. }
  877. public:
  878. constexpr static bool
  879. return_value(const T & t, const U & u){
  880. constexpr const r_type_interval_t t_interval{
  881. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  882. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  883. };
  884. constexpr const r_type_interval_t u_interval{
  885. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  886. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  887. };
  888. if(t_interval < u_interval)
  889. return true;
  890. if(t_interval > u_interval)
  891. return false;
  892. constexpr bool exception_possible
  893. = interval_open(t_interval) || interval_open(u_interval);
  894. return return_value(
  895. t,
  896. u,
  897. std::integral_constant<bool, exception_possible>()
  898. );
  899. }
  900. };
  901. template<class T, class U>
  902. typename std::enable_if<
  903. is_safe<T>::value || is_safe<U>::value,
  904. bool
  905. >::type
  906. constexpr operator<(const T & lhs, const U & rhs) {
  907. return less_than_result<T, U>::return_value(lhs, rhs);
  908. }
  909. template<class T, class U>
  910. typename std::enable_if<
  911. is_safe<T>::value || is_safe<U>::value,
  912. bool
  913. >::type
  914. constexpr operator>(const T & lhs, const U & rhs) {
  915. return rhs < lhs;
  916. }
  917. template<class T, class U>
  918. typename std::enable_if<
  919. is_safe<T>::value || is_safe<U>::value,
  920. bool
  921. >::type
  922. constexpr operator>=(const T & lhs, const U & rhs) {
  923. return ! ( lhs < rhs );
  924. }
  925. template<class T, class U>
  926. typename std::enable_if<
  927. is_safe<T>::value || is_safe<U>::value,
  928. bool
  929. >::type
  930. constexpr operator<=(const T & lhs, const U & rhs) {
  931. return ! ( lhs > rhs );
  932. }
  933. // equal
  934. template<class T, class U>
  935. struct equal_result {
  936. private:
  937. using promotion_policy = typename common_promotion_policy<T, U>::type;
  938. using result_base_type =
  939. typename promotion_policy::template comparison_result<T, U>::type;
  940. // if exception not possible
  941. constexpr static bool
  942. return_value(const T & t, const U & u, std::false_type){
  943. return
  944. static_cast<result_base_type>(base_value(t))
  945. == static_cast<result_base_type>(base_value(u));
  946. }
  947. using exception_policy = typename common_exception_policy<T, U>::type;
  948. using r_type = checked_result<result_base_type>;
  949. // exception possible
  950. constexpr static bool
  951. return_value(const T & t, const U & u, std::true_type){
  952. const std::pair<result_base_type, result_base_type> r = casting_helper<
  953. exception_policy,
  954. result_base_type
  955. >(t, u);
  956. return safe_compare::equal(r.first, r.second);
  957. }
  958. using r_type_interval = interval<r_type>;
  959. constexpr static bool interval_open(const r_type_interval & t){
  960. return t.l.exception() || t.u.exception();
  961. }
  962. public:
  963. constexpr static bool
  964. return_value(const T & t, const U & u){
  965. constexpr const r_type_interval t_interval{
  966. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  967. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  968. };
  969. constexpr const r_type_interval u_interval{
  970. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  971. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  972. };
  973. if(! intersect(t_interval, u_interval))
  974. return false;
  975. constexpr bool exception_possible
  976. = interval_open(t_interval) || interval_open(u_interval);
  977. return return_value(
  978. t,
  979. u,
  980. std::integral_constant<bool, exception_possible>()
  981. );
  982. }
  983. };
  984. template<class T, class U>
  985. typename std::enable_if<
  986. is_safe<T>::value || is_safe<U>::value,
  987. bool
  988. >::type
  989. constexpr operator==(const T & lhs, const U & rhs) {
  990. return equal_result<T, U>::return_value(lhs, rhs);
  991. }
  992. template<class T, class U>
  993. typename std::enable_if<
  994. is_safe<T>::value || is_safe<U>::value,
  995. bool
  996. >::type
  997. constexpr operator!=(const T & lhs, const U & rhs) {
  998. return ! (lhs == rhs);
  999. }
  1000. /////////////////////////////////////////////////////////////////
  1001. // shift operators
  1002. // left shift
  1003. template<class T, class U>
  1004. struct left_shift_result {
  1005. private:
  1006. using promotion_policy = typename common_promotion_policy<T, U>::type;
  1007. using result_base_type =
  1008. typename promotion_policy::template left_shift_result<T, U>::type;
  1009. // if exception not possible
  1010. constexpr static result_base_type
  1011. return_value(const T & t, const U & u, std::false_type){
  1012. return
  1013. static_cast<result_base_type>(base_value(t))
  1014. << static_cast<result_base_type>(base_value(u));
  1015. }
  1016. // exception possible
  1017. using exception_policy = typename common_exception_policy<T, U>::type;
  1018. using r_type = checked_result<result_base_type>;
  1019. constexpr static result_base_type
  1020. return_value(const T & t, const U & u, std::true_type){
  1021. const std::pair<result_base_type, result_base_type> r = casting_helper<
  1022. exception_policy,
  1023. result_base_type
  1024. >(t, u);
  1025. const r_type rx = checked_operation<
  1026. result_base_type,
  1027. dispatch_and_return<exception_policy, result_base_type>
  1028. >::left_shift(r.first, r.second);
  1029. return
  1030. rx.exception()
  1031. ? r.first << r.second
  1032. : rx.m_r;
  1033. }
  1034. using r_type_interval_t = interval<r_type>;
  1035. constexpr static r_type_interval_t get_r_type_interval(){
  1036. constexpr const r_type_interval_t t_interval{
  1037. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  1038. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  1039. };
  1040. constexpr const r_type_interval_t u_interval{
  1041. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  1042. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  1043. };
  1044. return (t_interval << u_interval);
  1045. }
  1046. static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
  1047. constexpr static const interval<result_base_type> return_interval{
  1048. r_type_interval.l.exception()
  1049. ? std::numeric_limits<result_base_type>::min()
  1050. : static_cast<result_base_type>(r_type_interval.l),
  1051. r_type_interval.u.exception()
  1052. ? std::numeric_limits<result_base_type>::max()
  1053. : static_cast<result_base_type>(r_type_interval.u)
  1054. };
  1055. constexpr static bool exception_possible(){
  1056. if(r_type_interval.l.exception())
  1057. return true;
  1058. if(r_type_interval.u.exception())
  1059. return true;
  1060. if(! return_interval.includes(r_type_interval))
  1061. return true;
  1062. return false;
  1063. }
  1064. constexpr static auto rl = return_interval.l;
  1065. constexpr static auto ru = return_interval.u;
  1066. public:
  1067. using type =
  1068. safe_base<
  1069. result_base_type,
  1070. rl,
  1071. ru,
  1072. promotion_policy,
  1073. exception_policy
  1074. >;
  1075. constexpr static type return_value(const T & t, const U & u){
  1076. return type(
  1077. return_value(
  1078. t,
  1079. u,
  1080. std::integral_constant<bool, exception_possible()>()
  1081. ),
  1082. typename type::skip_validation()
  1083. );
  1084. }
  1085. };
  1086. template<class T, class U>
  1087. typename boost::lazy_enable_if_c<
  1088. // handle safe<T> << int, int << safe<U>, safe<T> << safe<U>
  1089. // exclude std::ostream << ...
  1090. (! std::is_base_of<std::ios_base, T>::value)
  1091. && (is_safe<T>::value || is_safe<U>::value),
  1092. left_shift_result<T, U>
  1093. >::type
  1094. constexpr operator<<(const T & t, const U & u){
  1095. // INT13-CPP
  1096. // C++ standards document N4618 & 5.8.2
  1097. static_assert(
  1098. std::numeric_limits<T>::is_integer, "shifted value must be an integer"
  1099. );
  1100. static_assert(
  1101. std::numeric_limits<U>::is_integer, "shift amount must be an integer"
  1102. );
  1103. return left_shift_result<T, U>::return_value(t, u);
  1104. }
  1105. template<class T, class U>
  1106. typename std::enable_if<
  1107. is_safe<T>::value || is_safe<U>::value,
  1108. T
  1109. >::type
  1110. constexpr operator<<=(T & t, const U & u){
  1111. t = static_cast<T>(t << u);
  1112. return t;
  1113. }
  1114. // right shift
  1115. template<class T, class U>
  1116. struct right_shift_result {
  1117. using promotion_policy = typename common_promotion_policy<T, U>::type;
  1118. using result_base_type =
  1119. typename promotion_policy::template right_shift_result<T, U>::type;
  1120. // if exception not possible
  1121. constexpr static result_base_type
  1122. return_value(const T & t, const U & u, std::false_type){
  1123. return
  1124. static_cast<result_base_type>(base_value(t))
  1125. >> static_cast<result_base_type>(base_value(u));
  1126. }
  1127. // exception possible
  1128. using exception_policy = typename common_exception_policy<T, U>::type;
  1129. using r_type = checked_result<result_base_type>;
  1130. constexpr static result_base_type
  1131. return_value(const T & t, const U & u, std::true_type){
  1132. const std::pair<result_base_type, result_base_type> r = casting_helper<
  1133. exception_policy,
  1134. result_base_type
  1135. >(t, u);
  1136. const r_type rx = checked_operation<
  1137. result_base_type,
  1138. dispatch_and_return<exception_policy, result_base_type>
  1139. >::right_shift(r.first, r.second);
  1140. return
  1141. rx.exception()
  1142. ? r.first >> r.second
  1143. : rx.m_r;
  1144. }
  1145. using r_type_interval_t = interval<r_type>;
  1146. constexpr static r_type_interval_t t_interval(){
  1147. return r_type_interval_t(
  1148. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::min())),
  1149. checked::cast<result_base_type>(base_value(std::numeric_limits<T>::max()))
  1150. );
  1151. };
  1152. constexpr static r_type_interval_t u_interval(){
  1153. return r_type_interval_t(
  1154. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::min())),
  1155. checked::cast<result_base_type>(base_value(std::numeric_limits<U>::max()))
  1156. );
  1157. }
  1158. constexpr static r_type_interval_t get_r_type_interval(){;
  1159. return (t_interval() >> u_interval());
  1160. }
  1161. static constexpr const r_type_interval_t r_type_interval = get_r_type_interval();
  1162. constexpr static const interval<result_base_type> return_interval{
  1163. r_type_interval.l.exception()
  1164. ? std::numeric_limits<result_base_type>::min()
  1165. : static_cast<result_base_type>(r_type_interval.l),
  1166. r_type_interval.u.exception()
  1167. ? std::numeric_limits<result_base_type>::max()
  1168. : static_cast<result_base_type>(r_type_interval.u)
  1169. };
  1170. constexpr static bool exception_possible(){
  1171. constexpr const r_type_interval_t ri = r_type_interval;
  1172. constexpr const r_type_interval_t ti = t_interval();
  1173. constexpr const r_type_interval_t ui = u_interval();
  1174. return static_cast<bool>(
  1175. // note undesirable coupling with checked::shift right here !
  1176. ui.u > checked_result<result_base_type>(
  1177. std::numeric_limits<result_base_type>::digits
  1178. )
  1179. || ti.l < checked_result<result_base_type>(0)
  1180. || ui.l < checked_result<result_base_type>(0)
  1181. || ri.l.exception()
  1182. || ri.u.exception()
  1183. );
  1184. }
  1185. constexpr static auto rl = return_interval.l;
  1186. constexpr static auto ru = return_interval.u;
  1187. public:
  1188. using type =
  1189. safe_base<
  1190. result_base_type,
  1191. rl,
  1192. ru,
  1193. promotion_policy,
  1194. exception_policy
  1195. >;
  1196. constexpr static type return_value(const T & t, const U & u){
  1197. return type(
  1198. return_value(
  1199. t,
  1200. u,
  1201. std::integral_constant<bool, exception_possible()>()
  1202. ),
  1203. typename type::skip_validation()
  1204. );
  1205. }
  1206. };
  1207. template<class T, class U>
  1208. typename boost::lazy_enable_if_c<
  1209. (! std::is_base_of<std::ios_base, T>::value)
  1210. && (is_safe<T>::value || is_safe<U>::value),
  1211. right_shift_result<T, U>
  1212. >::type
  1213. constexpr operator>>(const T & t, const U & u){
  1214. // INT13-CPP
  1215. static_assert(
  1216. std::numeric_limits<T>::is_integer, "shifted value must be an integer"
  1217. );
  1218. static_assert(
  1219. std::numeric_limits<U>::is_integer, "shift amount must be an integer"
  1220. );
  1221. return right_shift_result<T, U>::return_value(t, u);
  1222. }
  1223. template<class T, class U>
  1224. typename std::enable_if<
  1225. is_safe<T>::value || is_safe<U>::value,
  1226. T
  1227. >::type
  1228. constexpr operator>>=(T & t, const U & u){
  1229. t = static_cast<T>(t >> u);
  1230. return t;
  1231. }
  1232. /////////////////////////////////////////////////////////////////
  1233. // bitwise operators
  1234. // operator |
  1235. template<class T, class U>
  1236. struct bitwise_or_result {
  1237. private:
  1238. using promotion_policy = typename common_promotion_policy<T, U>::type;
  1239. using result_base_type =
  1240. typename promotion_policy::template bitwise_or_result<T, U>::type;
  1241. // according to the C++ standard, the bitwise operators are executed as if
  1242. // the operands are consider a logical array of bits. That is, there is no
  1243. // sense that these are signed numbers.
  1244. using r_type = typename std::make_unsigned<result_base_type>::type;
  1245. using r_type_interval_t = interval<r_type>;
  1246. #if 0
  1247. // breaks compilation for earlier versions of clant
  1248. constexpr static const r_type_interval_t r_interval{
  1249. r_type(0),
  1250. utility::round_out(
  1251. std::max(
  1252. static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
  1253. static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
  1254. )
  1255. )
  1256. };
  1257. #endif
  1258. using exception_policy = typename common_exception_policy<T, U>::type;
  1259. public:
  1260. // lazy_enable_if_c depends on this
  1261. using type = safe_base<
  1262. result_base_type,
  1263. //r_interval.l,
  1264. r_type(0),
  1265. //r_interval.u,
  1266. utility::round_out(
  1267. std::max(
  1268. static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
  1269. static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
  1270. )
  1271. ),
  1272. promotion_policy,
  1273. exception_policy
  1274. >;
  1275. constexpr static type return_value(const T & t, const U & u){
  1276. return type(
  1277. static_cast<result_base_type>(base_value(t))
  1278. | static_cast<result_base_type>(base_value(u)),
  1279. typename type::skip_validation()
  1280. );
  1281. }
  1282. };
  1283. template<class T, class U>
  1284. typename boost::lazy_enable_if_c<
  1285. is_safe<T>::value || is_safe<U>::value,
  1286. bitwise_or_result<T, U>
  1287. >::type
  1288. constexpr operator|(const T & t, const U & u){
  1289. return bitwise_or_result<T, U>::return_value(t, u);
  1290. }
  1291. template<class T, class U>
  1292. typename std::enable_if<
  1293. is_safe<T>::value || is_safe<U>::value,
  1294. T
  1295. >::type
  1296. constexpr operator|=(T & t, const U & u){
  1297. t = static_cast<T>(t | u);
  1298. return t;
  1299. }
  1300. // operator &
  1301. template<class T, class U>
  1302. struct bitwise_and_result {
  1303. private:
  1304. using promotion_policy = typename common_promotion_policy<T, U>::type;
  1305. using result_base_type =
  1306. typename promotion_policy::template bitwise_and_result<T, U>::type;
  1307. // according to the C++ standard, the bitwise operators are executed as if
  1308. // the operands are consider a logical array of bits. That is, there is no
  1309. // sense that these are signed numbers.
  1310. using r_type = typename std::make_unsigned<result_base_type>::type;
  1311. using r_type_interval_t = interval<r_type>;
  1312. #if 0
  1313. // breaks compilation for earlier versions of clant
  1314. constexpr static const r_type_interval_t r_interval{
  1315. r_type(0),
  1316. utility::round_out(
  1317. std::min(
  1318. static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
  1319. static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
  1320. )
  1321. )
  1322. };
  1323. #endif
  1324. using exception_policy = typename common_exception_policy<T, U>::type;
  1325. public:
  1326. // lazy_enable_if_c depends on this
  1327. using type = safe_base<
  1328. result_base_type,
  1329. //r_interval.l,
  1330. r_type(0),
  1331. //r_interval.u,
  1332. utility::round_out(
  1333. std::min(
  1334. static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
  1335. static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
  1336. )
  1337. ),
  1338. promotion_policy,
  1339. exception_policy
  1340. >;
  1341. constexpr static type return_value(const T & t, const U & u){
  1342. return type(
  1343. static_cast<result_base_type>(base_value(t))
  1344. & static_cast<result_base_type>(base_value(u)),
  1345. typename type::skip_validation()
  1346. );
  1347. }
  1348. };
  1349. template<class T, class U>
  1350. typename boost::lazy_enable_if_c<
  1351. is_safe<T>::value || is_safe<U>::value,
  1352. bitwise_and_result<T, U>
  1353. >::type
  1354. constexpr operator&(const T & t, const U & u){
  1355. return bitwise_and_result<T, U>::return_value(t, u);
  1356. }
  1357. template<class T, class U>
  1358. typename std::enable_if<
  1359. is_safe<T>::value || is_safe<U>::value,
  1360. T
  1361. >::type
  1362. constexpr operator&=(T & t, const U & u){
  1363. t = static_cast<T>(t & u);
  1364. return t;
  1365. }
  1366. // operator ^
  1367. template<class T, class U>
  1368. struct bitwise_xor_result {
  1369. using promotion_policy = typename common_promotion_policy<T, U>::type;
  1370. using result_base_type =
  1371. typename promotion_policy::template bitwise_xor_result<T, U>::type;
  1372. // according to the C++ standard, the bitwise operators are executed as if
  1373. // the operands are consider a logical array of bits. That is, there is no
  1374. // sense that these are signed numbers.
  1375. using r_type = typename std::make_unsigned<result_base_type>::type;
  1376. using r_type_interval_t = interval<r_type>;
  1377. #if 0
  1378. // breaks compilation for earlier versions of clant
  1379. constexpr static const r_type_interval_t r_interval{
  1380. r_type(0),
  1381. utility::round_out(
  1382. std::max(
  1383. static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
  1384. static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
  1385. )
  1386. )
  1387. };
  1388. #endif
  1389. using exception_policy = typename common_exception_policy<T, U>::type;
  1390. public:
  1391. // lazy_enable_if_c depends on this
  1392. using type = safe_base<
  1393. result_base_type,
  1394. //r_interval.l,
  1395. r_type(0),
  1396. //r_interval.u,
  1397. utility::round_out(
  1398. std::max(
  1399. static_cast<r_type>(base_value(std::numeric_limits<T>::max())),
  1400. static_cast<r_type>(base_value(std::numeric_limits<U>::max()))
  1401. )
  1402. ),
  1403. promotion_policy,
  1404. exception_policy
  1405. >;
  1406. constexpr static type return_value(const T & t, const U & u){
  1407. return type(
  1408. static_cast<result_base_type>(base_value(t))
  1409. ^ static_cast<result_base_type>(base_value(u)),
  1410. typename type::skip_validation()
  1411. );
  1412. }
  1413. };
  1414. template<class T, class U>
  1415. typename boost::lazy_enable_if_c<
  1416. is_safe<T>::value || is_safe<U>::value,
  1417. bitwise_xor_result<T, U>
  1418. >::type
  1419. constexpr operator^(const T & t, const U & u){
  1420. return bitwise_xor_result<T, U>::return_value(t, u);
  1421. }
  1422. template<class T, class U>
  1423. typename std::enable_if<
  1424. is_safe<T>::value || is_safe<U>::value,
  1425. T
  1426. >::type
  1427. constexpr operator^=(T & t, const U & u){
  1428. t = static_cast<T>(t ^ u);
  1429. return t;
  1430. }
  1431. /////////////////////////////////////////////////////////////////
  1432. // stream helpers
  1433. template<
  1434. class T,
  1435. T Min,
  1436. T Max,
  1437. class P, // promotion polic
  1438. class E // exception policy
  1439. >
  1440. template<
  1441. class CharT,
  1442. class Traits
  1443. >
  1444. void safe_base<T, Min, Max, P, E>::output(
  1445. std::basic_ostream<CharT, Traits> & os
  1446. ) const {
  1447. os << (
  1448. (std::is_same<T, signed char>::value
  1449. || std::is_same<T, unsigned char>::value
  1450. || std::is_same<T, wchar_t>::value
  1451. ) ?
  1452. static_cast<int>(m_t)
  1453. :
  1454. m_t
  1455. );
  1456. }
  1457. template<
  1458. class T,
  1459. T Min,
  1460. T Max,
  1461. class P, // promotion polic
  1462. class E // exception policy
  1463. >
  1464. template<
  1465. class CharT,
  1466. class Traits
  1467. >
  1468. void safe_base<T, Min, Max, P, E>::input(
  1469. std::basic_istream<CharT, Traits> & is
  1470. ){
  1471. if(std::is_same<T, signed char>::value
  1472. || std::is_same<T, unsigned char>::value
  1473. || std::is_same<T, wchar_t>::value
  1474. ){
  1475. int x;
  1476. is >> x;
  1477. m_t = validated_cast(x);
  1478. }
  1479. else{
  1480. is >> m_t;
  1481. validated_cast(m_t);
  1482. }
  1483. if(is.fail()){
  1484. boost::safe_numerics::dispatch<
  1485. E,
  1486. boost::safe_numerics::safe_numerics_error::domain_error
  1487. >(
  1488. "error in file input"
  1489. );
  1490. }
  1491. }
  1492. } // safe_numerics
  1493. } // boost
  1494. #endif // BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP