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