safe_base_operations.hpp 57 KB

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