safe_base_operations.hpp 52 KB

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