safe_base_operations.hpp 52 KB

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