checked_result_operations.hpp 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217
  1. #ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
  2. #define BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS
  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. // Implemenation of arithmetic on "extended" integers.
  9. // Extended integers are defined in terms of C++ primitive integers as
  10. // a) an interger range
  11. // b) extra elements +inf, -inf, indeterminate
  12. //
  13. // Integer operations are closed on the set of extended integers
  14. // but operations are not necessarily associative when they result in the
  15. // extensions +inf, -inf, and indeterminate
  16. //
  17. // in this code, the type "checked_result<T>" where T is some
  18. // integer type is an "extended" integer.
  19. #include <cassert>
  20. #include <boost/logic/tribool.hpp>
  21. #include "checked_result.hpp"
  22. #include "checked_integer.hpp"
  23. //////////////////////////////////////////////////////////////////////////
  24. // the following idea of "value_type" is used by several of the operations
  25. // defined by checked_result arithmetic.
  26. namespace boost {
  27. namespace safe_numerics {
  28. template<typename T>
  29. constexpr void display(const boost::safe_numerics::checked_result<T> & c){
  30. switch(c.m_e){
  31. case safe_numerics_error::success:
  32. std::terminate();
  33. case safe_numerics_error::positive_overflow_error: // result is above representational maximum
  34. std::terminate();
  35. case safe_numerics_error::negative_overflow_error: // result is below representational minimum
  36. std::terminate();
  37. case safe_numerics_error::domain_error: // one operand is out of valid range
  38. std::terminate();
  39. case safe_numerics_error::range_error: // result cannot be produced for this operation
  40. std::terminate();
  41. case safe_numerics_error::precision_overflow_error: // result lost precision
  42. std::terminate();
  43. case safe_numerics_error::underflow_error: // result is too small to be represented
  44. std::terminate();
  45. case safe_numerics_error::negative_value_shift: // negative value in shift operator
  46. std::terminate();
  47. case safe_numerics_error::negative_shift: // shift a negative value
  48. std::terminate();
  49. case safe_numerics_error::shift_too_large: // l/r shift exceeds variable size
  50. std::terminate();
  51. case safe_numerics_error::uninitialized_value: // creating of uninitialized value
  52. std::terminate();
  53. }
  54. }
  55. //////////////////////////////////////////////////////////////////////////
  56. // implement C++ operators for check_result<T>
  57. struct sum_value_type {
  58. // characterization of various values
  59. const enum flag {
  60. known_value = 0,
  61. less_than_min,
  62. greater_than_max,
  63. indeterminate,
  64. count
  65. } m_flag;
  66. template<class T>
  67. constexpr flag to_flag(const checked_result<T> & t) const {
  68. switch(static_cast<safe_numerics_error>(t)){
  69. case safe_numerics_error::success:
  70. return known_value;
  71. case safe_numerics_error::negative_overflow_error:
  72. // result is below representational minimum
  73. return less_than_min;
  74. case safe_numerics_error::positive_overflow_error:
  75. // result is above representational maximum
  76. return greater_than_max;
  77. default:
  78. return indeterminate;
  79. }
  80. }
  81. template<class T>
  82. constexpr sum_value_type(const checked_result<T> & t) :
  83. m_flag(to_flag(t))
  84. {}
  85. constexpr operator std::uint8_t () const {
  86. return static_cast<std::uint8_t>(m_flag);
  87. }
  88. };
  89. // integers addition
  90. template<class T>
  91. typename std::enable_if<
  92. std::is_integral<T>::value,
  93. checked_result<T>
  94. >::type
  95. constexpr inline operator+(
  96. const checked_result<T> & t,
  97. const checked_result<T> & u
  98. ){
  99. using value_type = sum_value_type;
  100. const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  101. // note major pain. Clang constexpr multi-dimensional array is fine.
  102. // but gcc doesn't permit a multi-dimensional array to be be constexpr.
  103. // so we need to some ugly gymnastics to make our system work for all
  104. // all systems.
  105. const enum safe_numerics_error result[order * order] = {
  106. // t == known_value
  107. //{
  108. // u == ...
  109. safe_numerics_error::success, // known_value,
  110. safe_numerics_error::negative_overflow_error, // less_than_min,
  111. safe_numerics_error::positive_overflow_error, // greater_than_max,
  112. safe_numerics_error::range_error, // indeterminate,
  113. //},
  114. // t == less_than_min,
  115. //{
  116. // u == ...
  117. safe_numerics_error::negative_overflow_error, // known_value,
  118. safe_numerics_error::negative_overflow_error, // less_than_min,
  119. safe_numerics_error::range_error, // greater_than_max,
  120. safe_numerics_error::range_error, // indeterminate,
  121. //},
  122. // t == greater_than_max,
  123. //{
  124. // u == ...
  125. safe_numerics_error::positive_overflow_error, // known_value,
  126. safe_numerics_error::range_error, // less_than_min,
  127. safe_numerics_error::positive_overflow_error, // greater_than_max,
  128. safe_numerics_error::range_error, // indeterminate,
  129. //},
  130. // t == indeterminate,
  131. //{
  132. // u == ...
  133. safe_numerics_error::range_error, // known_value,
  134. safe_numerics_error::range_error, // less_than_min,
  135. safe_numerics_error::range_error, // greater_than_max,
  136. safe_numerics_error::range_error, // indeterminate,
  137. //},
  138. };
  139. const value_type tx(t);
  140. const value_type ux(u);
  141. const safe_numerics_error e = result[tx * order + ux];
  142. if(safe_numerics_error::success == e)
  143. return checked::add<T>(t, u);
  144. return checked_result<T>(e, "addition result");
  145. }
  146. // unary +
  147. template<class T>
  148. typename std::enable_if<
  149. std::is_integral<T>::value,
  150. checked_result<T>
  151. >::type
  152. constexpr inline operator+(
  153. const checked_result<T> & t
  154. ){
  155. return t;
  156. }
  157. // integers subtraction
  158. template<class T>
  159. typename std::enable_if<
  160. std::is_integral<T>::value,
  161. checked_result<T>
  162. >::type
  163. constexpr inline operator-(
  164. const checked_result<T> & t,
  165. const checked_result<T> & u
  166. ){
  167. using value_type = sum_value_type;
  168. constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  169. constexpr const enum safe_numerics_error result[order * order] = {
  170. // t == known_value
  171. //{
  172. // u == ...
  173. safe_numerics_error::success, // known_value,
  174. safe_numerics_error::positive_overflow_error, // less_than_min,
  175. safe_numerics_error::negative_overflow_error, // greater_than_max,
  176. safe_numerics_error::range_error, // indeterminate,
  177. //},
  178. // t == less_than_min,
  179. //{
  180. // u == ...
  181. safe_numerics_error::negative_overflow_error, // known_value,
  182. safe_numerics_error::range_error, // less_than_min,
  183. safe_numerics_error::negative_overflow_error, // greater_than_max,
  184. safe_numerics_error::range_error, // indeterminate,
  185. //},
  186. // t == greater_than_max,
  187. //{
  188. // u == ...
  189. safe_numerics_error::positive_overflow_error, // known_value,
  190. safe_numerics_error::positive_overflow_error, // less_than_min,
  191. safe_numerics_error::range_error, // greater_than_max,
  192. safe_numerics_error::range_error, // indeterminate,
  193. //},
  194. // t == indeterminate,
  195. //{
  196. // u == ...
  197. safe_numerics_error::range_error, // known_value,
  198. safe_numerics_error::range_error, // less_than_min,
  199. safe_numerics_error::range_error, // greater_than_max,
  200. safe_numerics_error::range_error, // indeterminate,
  201. //},
  202. };
  203. const value_type tx(t);
  204. const value_type ux(u);
  205. const safe_numerics_error e = result[tx * order + ux];
  206. if(safe_numerics_error::success == e)
  207. return checked::subtract<T>(t, u);
  208. return checked_result<T>(e, "subtraction result");
  209. }
  210. // unary -
  211. template<class T>
  212. typename std::enable_if<
  213. std::is_integral<T>::value,
  214. checked_result<T>
  215. >::type
  216. constexpr inline operator-(
  217. const checked_result<T> & t
  218. ){
  219. // assert(false);
  220. return checked_result<T>(0) - t;
  221. }
  222. struct product_value_type {
  223. // characterization of various values
  224. const enum flag {
  225. less_than_min = 0,
  226. less_than_zero,
  227. zero,
  228. greater_than_zero,
  229. greater_than_max,
  230. indeterminate,
  231. // count of number of cases for values
  232. count,
  233. // temporary values for special cases
  234. t_value,
  235. u_value,
  236. z_value
  237. } m_flag;
  238. template<class T>
  239. constexpr flag to_flag(const checked_result<T> & t) const {
  240. switch(static_cast<safe_numerics_error>(t)){
  241. case safe_numerics_error::success:
  242. return (t < checked_result<T>(0))
  243. ? less_than_zero
  244. : (t > checked_result<T>(0))
  245. ? greater_than_zero
  246. : zero;
  247. case safe_numerics_error::negative_overflow_error:
  248. // result is below representational minimum
  249. return less_than_min;
  250. case safe_numerics_error::positive_overflow_error:
  251. // result is above representational maximum
  252. return greater_than_max;
  253. default:
  254. return indeterminate;
  255. }
  256. }
  257. template<class T>
  258. constexpr product_value_type(const checked_result<T> & t) :
  259. m_flag(to_flag(t))
  260. {}
  261. constexpr operator std::uint8_t () const {
  262. return static_cast<std::uint8_t>(m_flag);
  263. }
  264. };
  265. // integers multiplication
  266. template<class T>
  267. typename std::enable_if<
  268. std::is_integral<T>::value,
  269. checked_result<T>
  270. >::type
  271. constexpr inline operator*(
  272. const checked_result<T> & t,
  273. const checked_result<T> & u
  274. ){
  275. using value_type = product_value_type;
  276. const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  277. constexpr const enum value_type::flag result[order * order] = {
  278. // t == less_than_min
  279. //{
  280. // u == ...
  281. value_type::greater_than_max, // less_than_min,
  282. value_type::greater_than_max, // less_than_zero,
  283. value_type::zero, // zero,
  284. value_type::less_than_min, // greater_than_zero,
  285. value_type::less_than_min, // greater than max,
  286. value_type::indeterminate, // indeterminate,
  287. //},
  288. // t == less_than_zero,
  289. //{
  290. // u == ...
  291. value_type::greater_than_max, // less_than_min,
  292. value_type::greater_than_zero, // less_than_zero,
  293. value_type::zero, // zero,
  294. value_type::less_than_zero, // greater_than_zero,
  295. value_type::less_than_min, // greater than max,
  296. value_type::indeterminate, // indeterminate,
  297. //},
  298. // t == zero,
  299. //{
  300. // u == ...
  301. value_type::zero, // less_than_min,
  302. value_type::zero, // less_than_zero,
  303. value_type::zero, // zero,
  304. value_type::zero, // greater_than_zero,
  305. value_type::zero, // greater than max,
  306. value_type::indeterminate, // indeterminate,
  307. //},
  308. // t == greater_than_zero,
  309. //{
  310. // u == ...
  311. value_type::less_than_min, // less_than_min,
  312. value_type::less_than_zero, // less_than_zero,
  313. value_type::zero, // zero,
  314. value_type::greater_than_zero, // greater_than_zero,
  315. value_type::greater_than_max, // greater than max,
  316. value_type::indeterminate, // indeterminate,
  317. //},
  318. // t == greater_than_max
  319. //{
  320. value_type::less_than_min, // less_than_min,
  321. value_type::less_than_min, // less_than_zero,
  322. value_type::zero, // zero,
  323. value_type::greater_than_max, // greater_than_zero,
  324. value_type::greater_than_max, // greater than max,
  325. value_type::indeterminate, // indeterminate,
  326. //},
  327. // t == indeterminate
  328. //{
  329. value_type::indeterminate, // less_than_min,
  330. value_type::indeterminate, // less_than_zero,
  331. value_type::indeterminate, // zero,
  332. value_type::indeterminate, // greater_than_zero,
  333. value_type::indeterminate, // greater than max,
  334. value_type::indeterminate, // indeterminate,
  335. //}
  336. };
  337. const value_type tx(t);
  338. const value_type ux(u);
  339. switch(result[tx * order + ux]){
  340. case value_type::less_than_min:
  341. return safe_numerics_error::negative_overflow_error;
  342. case value_type::zero:
  343. return T(0);
  344. case value_type::greater_than_max:
  345. return safe_numerics_error::positive_overflow_error;
  346. case value_type::less_than_zero:
  347. case value_type::greater_than_zero:
  348. return checked::multiply<T>(t, u);
  349. case value_type::indeterminate:
  350. return safe_numerics_error::range_error;
  351. default:
  352. assert(false);
  353. }
  354. return checked_result<T>(0); // to suppress msvc warning
  355. }
  356. // integers division
  357. template<class T>
  358. typename std::enable_if<
  359. std::is_integral<T>::value,
  360. checked_result<T>
  361. >::type
  362. constexpr inline operator/(
  363. const checked_result<T> & t,
  364. const checked_result<T> & u
  365. ){
  366. using value_type = product_value_type;
  367. const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  368. constexpr const enum value_type::flag result[order * order] = {
  369. // t == less_than_min
  370. //{
  371. // u == ...
  372. value_type::indeterminate, // less_than_min,
  373. value_type::greater_than_max, // less_than_zero,
  374. value_type::less_than_min, // zero,
  375. value_type::less_than_min, // greater_than_zero,
  376. value_type::less_than_min, // greater than max,
  377. value_type::indeterminate, // indeterminate,
  378. //},
  379. // t == less_than_zero,
  380. //{
  381. // u == ...
  382. value_type::zero, // less_than_min,
  383. value_type::greater_than_zero, // less_than_zero,
  384. value_type::less_than_min, // zero,
  385. value_type::less_than_zero, // greater_than_zero,
  386. value_type::zero, // greater than max,
  387. value_type::indeterminate, // indeterminate,
  388. //},
  389. // t == zero,
  390. //{
  391. // u == ...
  392. value_type::zero, // less_than_min,
  393. value_type::zero, // less_than_zero,
  394. value_type::indeterminate, // zero,
  395. value_type::zero, // greater_than_zero,
  396. value_type::zero, // greater than max,
  397. value_type::indeterminate, // indeterminate,
  398. //},
  399. // t == greater_than_zero,
  400. //{
  401. // u == ...
  402. value_type::zero, // less_than_min,
  403. value_type::less_than_zero, // less_than_zero,
  404. value_type::greater_than_max, // zero,
  405. value_type::greater_than_zero, // greater_than_zero,
  406. value_type::zero, // greater than max,
  407. value_type::indeterminate, // indeterminate,
  408. //},
  409. // t == greater_than_max
  410. //{
  411. value_type::less_than_min, // less_than_min,
  412. value_type::less_than_min, // less_than_zero,
  413. value_type::greater_than_max, // zero,
  414. value_type::greater_than_max, // greater_than_zero,
  415. value_type::indeterminate, // greater than max,
  416. value_type::indeterminate, // indeterminate,
  417. //},
  418. // t == indeterminate
  419. //{
  420. value_type::indeterminate, // less_than_min,
  421. value_type::indeterminate, // less_than_zero,
  422. value_type::indeterminate, // zero,
  423. value_type::indeterminate, // greater_than_zero,
  424. value_type::indeterminate, // greater than max,
  425. value_type::indeterminate, // indeterminate,
  426. //}
  427. };
  428. const value_type tx(t);
  429. const value_type ux(u);
  430. switch(result[tx * order + ux]){
  431. case value_type::less_than_min:
  432. return safe_numerics_error::negative_overflow_error;
  433. case value_type::zero:
  434. return 0;
  435. case value_type::greater_than_max:
  436. return safe_numerics_error::positive_overflow_error;
  437. case value_type::less_than_zero:
  438. case value_type::greater_than_zero:
  439. return checked::divide<T>(t, u);
  440. case value_type::indeterminate:
  441. return safe_numerics_error::range_error;
  442. default:
  443. assert(false);
  444. }
  445. return checked_result<T>(0); // to suppress msvc warning
  446. }
  447. // integers modulus
  448. template<class T>
  449. typename std::enable_if<
  450. std::is_integral<T>::value,
  451. checked_result<T>
  452. >::type
  453. constexpr inline operator%(
  454. const checked_result<T> & t,
  455. const checked_result<T> & u
  456. ){
  457. using value_type = product_value_type;
  458. const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  459. constexpr const enum value_type::flag result[order * order] = {
  460. // t == less_than_min
  461. //{
  462. // u == ...
  463. value_type::indeterminate, // less_than_min,
  464. value_type::z_value, // less_than_zero,
  465. value_type::indeterminate, // zero,
  466. value_type::z_value, // greater_than_zero,
  467. value_type::indeterminate, // greater than max,
  468. value_type::indeterminate, // indeterminate,
  469. //},
  470. // t == less_than_zero,
  471. //{
  472. // u == ...
  473. value_type::t_value, // less_than_min,
  474. value_type::greater_than_zero, // less_than_zero,
  475. value_type::indeterminate, // zero,
  476. value_type::less_than_zero, // greater_than_zero,
  477. value_type::t_value, // greater than max,
  478. value_type::indeterminate, // indeterminate,
  479. //},
  480. // t == zero,
  481. //{
  482. // u == ...
  483. value_type::zero, // less_than_min,
  484. value_type::zero, // less_than_zero,
  485. value_type::indeterminate, // zero,
  486. value_type::zero, // greater_than_zero,
  487. value_type::zero, // greater than max,
  488. value_type::indeterminate, // indeterminate,
  489. //},
  490. // t == greater_than_zero,
  491. //{
  492. // u == ...
  493. value_type::t_value, // less_than_min,
  494. value_type::less_than_zero, // less_than_zero,
  495. value_type::indeterminate, // zero,
  496. value_type::greater_than_zero, // greater_than_zero,
  497. value_type::t_value, // greater than max,
  498. value_type::indeterminate, // indeterminate,
  499. //},
  500. // t == greater_than_max
  501. //{
  502. value_type::indeterminate, // less_than_min,
  503. value_type::u_value, // less_than_zero,
  504. value_type::indeterminate, // zero,
  505. value_type::u_value, // greater_than_zero,
  506. value_type::indeterminate, // greater than max,
  507. value_type::indeterminate, // indeterminate,
  508. //},
  509. // t == indeterminate
  510. //{
  511. value_type::indeterminate, // less_than_min,
  512. value_type::indeterminate, // less_than_zero,
  513. value_type::indeterminate, // zero,
  514. value_type::indeterminate, // greater_than_zero,
  515. value_type::indeterminate, // greater than max,
  516. value_type::indeterminate, // indeterminate,
  517. //}
  518. };
  519. const value_type tx(t);
  520. const value_type ux(u);
  521. switch(result[tx * order + ux]){
  522. case value_type::zero:
  523. return 0;
  524. case value_type::less_than_zero:
  525. case value_type::greater_than_zero:
  526. return checked::modulus<T>(t, u);
  527. case value_type::indeterminate:
  528. return safe_numerics_error::range_error;
  529. case value_type::t_value:
  530. return t;
  531. case value_type::u_value:
  532. return checked::subtract<T>(u, 1);
  533. case value_type::z_value:
  534. return checked::subtract<T>(1, u);
  535. case value_type::greater_than_max:
  536. case value_type::less_than_min:
  537. default:
  538. assert(false);
  539. }
  540. // suppress msvc warning
  541. return checked_result<T>(0);
  542. }
  543. // comparison operators
  544. template<class T>
  545. constexpr boost::logic::tribool operator<(
  546. const checked_result<T> & t,
  547. const checked_result<T> & u
  548. ){
  549. using value_type = sum_value_type;
  550. constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  551. // the question arises about how to order values of type greater_than_min.
  552. // that is: what should greater_than_min < greater_than_min return.
  553. //
  554. // a) return indeterminate because we're talking about the "true" values for
  555. // which greater_than_min is a placholder.
  556. //
  557. // b) return false because the two values are "equal"
  558. //
  559. // for our purposes, a) seems the better interpretation.
  560. enum class result_type : std::uint8_t {
  561. runtime,
  562. false_value,
  563. true_value,
  564. indeterminate,
  565. };
  566. constexpr const result_type resultx[order * order]{
  567. // t == known_value
  568. //{
  569. // u == ...
  570. result_type::runtime, // known_value,
  571. result_type::false_value, // less_than_min,
  572. result_type::true_value, // greater_than_max,
  573. result_type::indeterminate, // indeterminate,
  574. //},
  575. // t == less_than_min
  576. //{
  577. // u == ...
  578. result_type::true_value, // known_value,
  579. result_type::indeterminate, // less_than_min, see above argument
  580. result_type::true_value, // greater_than_max,
  581. result_type::indeterminate, // indeterminate,
  582. //},
  583. // t == greater_than_max
  584. //{
  585. // u == ...
  586. result_type::false_value, // known_value,
  587. result_type::false_value, // less_than_min,
  588. result_type::indeterminate, // greater_than_max, see above argument
  589. result_type::indeterminate, // indeterminate,
  590. //},
  591. // t == indeterminate
  592. //{
  593. // u == ...
  594. result_type::indeterminate, // known_value,
  595. result_type::indeterminate, // less_than_min,
  596. result_type::indeterminate, // greater_than_max,
  597. result_type::indeterminate, // indeterminate,
  598. //},
  599. };
  600. const value_type tx(t);
  601. const value_type ux(u);
  602. switch(resultx[tx * order + ux]){
  603. case result_type::runtime:
  604. return static_cast<const T &>(t) < static_cast<const T &>(u);
  605. case result_type::false_value:
  606. return false;
  607. case result_type::true_value:
  608. return true;
  609. case result_type::indeterminate:
  610. return boost::logic::indeterminate;
  611. default:
  612. assert(false);
  613. }
  614. return true;
  615. }
  616. template<class T>
  617. constexpr boost::logic::tribool
  618. operator>=(
  619. const checked_result<T> & t,
  620. const checked_result<T> & u
  621. ){
  622. return !(t < u);
  623. }
  624. template<class T>
  625. constexpr boost::logic::tribool
  626. operator>(
  627. const checked_result<T> & t,
  628. const checked_result<T> & u
  629. ){
  630. return u < t;
  631. }
  632. template<class T>
  633. constexpr boost::logic::tribool
  634. operator<=(
  635. const checked_result<T> & t,
  636. const checked_result<T> & u
  637. ){
  638. return !(u < t);
  639. }
  640. template<class T>
  641. constexpr boost::logic::tribool
  642. operator==(
  643. const checked_result<T> & t,
  644. const checked_result<T> & u
  645. ){
  646. using value_type = sum_value_type;
  647. constexpr const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  648. enum class result_type : std::uint8_t {
  649. runtime,
  650. false_value,
  651. true_value,
  652. indeterminate,
  653. };
  654. constexpr const result_type result[order * order]{
  655. // t == known_value
  656. //{
  657. // u == ...
  658. result_type::runtime, // known_value,
  659. result_type::false_value, // less_than_min,
  660. result_type::false_value, // greater_than_max,
  661. result_type::indeterminate, // indeterminate,
  662. //},
  663. // t == less_than_min
  664. //{
  665. // u == ...
  666. result_type::false_value, // known_value,
  667. result_type::indeterminate, // less_than_min,
  668. result_type::false_value, // greater_than_max,
  669. result_type::indeterminate, // indeterminate,
  670. //},
  671. // t == greater_than_max
  672. //{
  673. // u == ...
  674. result_type::false_value, // known_value,
  675. result_type::false_value, // less_than_min,
  676. result_type::indeterminate, // greater_than_max,
  677. result_type::indeterminate, // indeterminate,
  678. //},
  679. // t == indeterminate
  680. //{
  681. // u == ...
  682. result_type::indeterminate, // known_value,
  683. result_type::indeterminate, // less_than_min,
  684. result_type::indeterminate, // greater_than_max,
  685. result_type::indeterminate, // indeterminate,
  686. //},
  687. };
  688. const value_type tx(t);
  689. const value_type ux(u);
  690. switch(result[tx * order + ux]){
  691. case result_type::runtime:
  692. return static_cast<const T &>(t) == static_cast<const T &>(u);
  693. case result_type::false_value:
  694. return false;
  695. case result_type::true_value:
  696. return true;
  697. case result_type::indeterminate:
  698. return boost::logic::indeterminate;
  699. default:
  700. assert(false);
  701. }
  702. // suppress msvc warning - not all control paths return a value
  703. return false;
  704. }
  705. template<class T>
  706. constexpr boost::logic::tribool
  707. operator!=(
  708. const checked_result<T> & t,
  709. const checked_result<T> & u
  710. ){
  711. return ! (t == u);
  712. }
  713. template<class T>
  714. typename std::enable_if<
  715. std::is_integral<T>::value,
  716. checked_result<T>
  717. >::type
  718. constexpr inline operator>>(
  719. const checked_result<T> & t,
  720. const checked_result<T> & u
  721. );
  722. template<class T>
  723. typename std::enable_if<
  724. std::is_integral<T>::value,
  725. checked_result<T>
  726. >::type
  727. constexpr inline operator~(
  728. const checked_result<T> & t
  729. ){
  730. // assert(false);
  731. return ~t.m_r;
  732. }
  733. template<class T>
  734. typename std::enable_if<
  735. std::is_integral<T>::value,
  736. checked_result<T>
  737. >::type
  738. constexpr inline operator<<(
  739. const checked_result<T> & t,
  740. const checked_result<T> & u
  741. ){
  742. using value_type = product_value_type;
  743. const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  744. constexpr const std::uint8_t result[order * order] = {
  745. // t == less_than_min
  746. //{
  747. // u == ...
  748. 1, // -1, // less_than_min,
  749. 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
  750. 2, // safe_numerics_error::negative_overflow_error, // zero,
  751. 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
  752. 2, // safe_numerics_error::negative_overflow_error, // greater than max,
  753. 1, // safe_numerics_error::range_error, // indeterminate,
  754. //},
  755. // t == less_than_zero,
  756. //{
  757. // u == ...
  758. 3, // -1, // less_than_min,
  759. 4, // - (-t >> -u), // less_than_zero,
  760. 5, // safe_numerics_error::negative_overflow_error, // zero,
  761. 6, // - (-t << u), // greater_than_zero,
  762. 2, // safe_numerics_error::negative_overflow_error, // greater than max,
  763. 1, // safe_numerics_error::range_error, // indeterminate,
  764. //},
  765. // t == zero,
  766. //{
  767. // u == ...
  768. 3, // 0 // less_than_min,
  769. 3, // 0 // less_than_zero,
  770. 3, // 0, // zero,
  771. 3, // 0, // greater_than_zero,
  772. 3, // 0, // greater than max,
  773. 3, // safe_numerics_error::range_error, // indeterminate,
  774. //},
  775. // t == greater_than_zero,
  776. //{
  777. // u == ...
  778. 3, // 0, // less_than_min,
  779. 7, // t << -u, // less_than_zero,
  780. 5, // t, // zero,
  781. 8, // t << u // greater_than_zero,
  782. 9, // safe_numerics_error::positive_overflow_error, // greater than max,
  783. 1, // safe_numerics_error::range_error, // indeterminate,
  784. //},
  785. // t == greater_than_max
  786. //{
  787. // u == ...
  788. 1, // safe_numerics_error::range_error, // less_than_min,
  789. 9, // safe_numerics_error::positive_overflow_error), // less_than_zero,
  790. 9, // safe_numerics_error::positive_overflow_error, // zero,
  791. 9, // safe_numerics_error::positive_overflow_error), // greater_than_zero,
  792. 9, // safe_numerics_error::positive_overflow_error, // greater than max,
  793. 1, // safe_numerics_error::range_error, // indeterminate,
  794. //},
  795. // t == indeterminate
  796. //{
  797. 1, // safe_numerics_error::range_error, // indeterminate,
  798. 1, // safe_numerics_error::range_error, // indeterminate,
  799. 1, // safe_numerics_error::range_error, // indeterminate,
  800. 1, // safe_numerics_error::range_error, // indeterminate,
  801. 1, // safe_numerics_error::range_error, // indeterminate,
  802. 1, // safe_numerics_error::range_error, // indeterminate,
  803. //}
  804. };
  805. const value_type tx(t);
  806. const value_type ux(u);
  807. assert(tx * order + ux < order * order);
  808. // I had a switch(i) statment here - but it results in an ICE
  809. // on multiple versions of gcc. So make the equivalent in
  810. // nested if statments - should be the same (more or less)
  811. // performancewise.
  812. const unsigned int i = result[tx * order + ux];
  813. assert(i <= 9);
  814. if(1 == i){
  815. return safe_numerics_error::range_error;
  816. }
  817. else
  818. if(2 == i){
  819. return safe_numerics_error::negative_overflow_error;
  820. }
  821. else
  822. if(3 == i){
  823. return checked_result<T>(0);
  824. // the following gymnastics are to handle the case where
  825. // a value is changed from a negative to a positive number.
  826. // For example, and 8 bit number t == -128. Then -t also
  827. // equals -128 since 128 cannot be held in an 8 bit signed
  828. // integer.
  829. }
  830. else
  831. if(4 == i){ // - (-t >> -u)
  832. assert(static_cast<bool>(t < checked_result<T>(0)));
  833. assert(static_cast<bool>(u < checked_result<T>(0)));
  834. return t >> -u;
  835. }
  836. else
  837. if(5 == i){
  838. return t;
  839. }
  840. else
  841. if(6 == i){ // - (-t << u)
  842. assert(static_cast<bool>(t < checked_result<T>(0)));
  843. assert(static_cast<bool>(u > checked_result<T>(0)));
  844. const checked_result<T> temp_t = t * checked_result<T>(2);
  845. const checked_result<T> temp_u = u - checked_result<T>(1);
  846. return - (-temp_t << temp_u);
  847. }
  848. else
  849. if(7 == i){ // t >> -u
  850. assert(static_cast<bool>(t > checked_result<T>(0)));
  851. assert(static_cast<bool>(u < checked_result<T>(0)));
  852. return t >> -u;
  853. }
  854. else
  855. if(8 == i){ // t << u
  856. assert(static_cast<bool>(t > checked_result<T>(0)));
  857. assert(static_cast<bool>(u > checked_result<T>(0)));
  858. checked_result<T> r = checked::left_shift<T>(t, u);
  859. return (r.m_e == safe_numerics_error::shift_too_large)
  860. ? checked_result<T>(safe_numerics_error::positive_overflow_error)
  861. : r;
  862. }
  863. else
  864. if(9 == i){
  865. return safe_numerics_error::positive_overflow_error;
  866. }
  867. else{
  868. assert(false);
  869. };
  870. return checked_result<T>(0); // to suppress msvc warning
  871. }
  872. template<class T>
  873. typename std::enable_if<
  874. std::is_integral<T>::value,
  875. checked_result<T>
  876. >::type
  877. constexpr inline operator>>(
  878. const checked_result<T> & t,
  879. const checked_result<T> & u
  880. ){
  881. using value_type = product_value_type;
  882. const std::uint8_t order = static_cast<std::uint8_t>(value_type::count);
  883. const std::uint8_t result[order * order] = {
  884. // t == less_than_min
  885. //{
  886. // u == ...
  887. 2, // safe_numerics_error::negative_overflow_error, // less_than_min,
  888. 2, // safe_numerics_error::negative_overflow_error, // less_than_zero,
  889. 2, // safe_numerics_error::negative_overflow_error, // zero,
  890. 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero,
  891. 1, // safe_numerics_error::range_error, // greater than max,
  892. 1, // safe_numerics_error::range_error, // indeterminate,
  893. //},
  894. // t == less_than_zero,
  895. //{
  896. // u == ...
  897. 2, // safe_numerics_error::negative_overflow_error // less_than_min,
  898. 4, // - (-t << -u), // less_than_zero,
  899. 5, // safe_numerics_error::negative_overflow_error. // zero,
  900. 6, // - (-t >> u), // greater_than_zero,
  901. 3, // 0, ? or -1 // greater than max,
  902. 1, // safe_numerics_error::range_error, // indeterminate,
  903. //},
  904. // t == zero,
  905. //{
  906. // u == ...
  907. 3, // 0 // less_than_min,
  908. 3, // 0 // less_than_zero,
  909. 3, // 0, // zero,
  910. 3, // 0, // greater_than_zero,
  911. 3, // 0, // greater than max,
  912. 3, // safe_numerics_error::range_error, // indeterminate,
  913. //},
  914. // t == greater_than_zero,
  915. //{
  916. // u == ...
  917. 9, // safe_numerics_error::positive_overflow_error // less_than_min,
  918. 7, // t << -u, // less_than_zero,
  919. 5, // t, // zero,
  920. 8, // t >> u // greater_than_zero,
  921. 3, // 0, // greater than max,
  922. 1, // safe_numerics_error::range_error, // indeterminate,
  923. //},
  924. // t == greater_than_max
  925. //{
  926. // u == ...
  927. 9, // safe_numerics_error::positive_overflow_error, // less_than_min,
  928. 9, // safe_numerics_error::positive_overflow_error, // less_than_zero,
  929. 9, // safe_numerics_error::positive_overflow_error, // zero,
  930. 9, // safe_numerics_error::positive_overflow_error, // greater_than_zero,
  931. 1, // safe_numerics_error::range_error, // greater than max,
  932. 1, // safe_numerics_error::range_error, // indeterminate,
  933. //},
  934. // t == indeterminate
  935. //{
  936. 1, // safe_numerics_error::range_error, // indeterminate,
  937. 1, // safe_numerics_error::range_error, // indeterminate,
  938. 1, // safe_numerics_error::range_error, // indeterminate,
  939. 1, // safe_numerics_error::range_error, // indeterminate,
  940. 1, // safe_numerics_error::range_error, // indeterminate,
  941. 1, // safe_numerics_error::range_error, // indeterminate,
  942. //}
  943. };
  944. const value_type tx(t);
  945. const value_type ux(u);
  946. assert(tx * order + ux < order * order);
  947. // I had a switch(i) statment here - but it results in an ICE
  948. // on multiple versions of gcc. So make the equivalent in
  949. // nested if statments - should be the same (more or less)
  950. // performancewise.
  951. const unsigned int i = result[tx * order + ux];
  952. assert(i <= 9);
  953. if(1 == i){
  954. return safe_numerics_error::range_error;
  955. }
  956. else
  957. if(2 == i){
  958. return safe_numerics_error::negative_overflow_error;
  959. }
  960. else
  961. if(3 == i){
  962. return checked_result<T>(0);
  963. }
  964. else
  965. if(4 == i){ // - (-t << -u)
  966. assert(static_cast<bool>(t < checked_result<T>(0)));
  967. assert(static_cast<bool>(u < checked_result<T>(0)));
  968. return t << -u;
  969. }
  970. else
  971. if(5 == i){
  972. return t;
  973. }
  974. else
  975. if(6 == i){ // - (-t >> u)
  976. assert(static_cast<bool>(t < checked_result<T>(0)));
  977. assert(static_cast<bool>(u > checked_result<T>(0)));
  978. const checked_result<T> temp_t = t / checked_result<T>(2);
  979. const checked_result<T> temp_u = u - checked_result<T>(1);
  980. return - (-temp_t >> temp_u);
  981. }
  982. else
  983. if(7 == i){ // t << -u,
  984. assert(static_cast<bool>(t > checked_result<T>(0)));
  985. assert(static_cast<bool>(u < checked_result<T>(0)));
  986. return t << -u;
  987. }
  988. else
  989. if(8 == i){ // t >> u
  990. assert(static_cast<bool>(t > checked_result<T>(0)));
  991. assert(static_cast<bool>(u > checked_result<T>(0)));
  992. checked_result<T> r = checked::right_shift<T>(t, u);
  993. return (r.m_e == safe_numerics_error::shift_too_large)
  994. ? checked_result<T>(0)
  995. : r;
  996. }
  997. else
  998. if(9 == i){
  999. return safe_numerics_error::positive_overflow_error;
  1000. }
  1001. else{
  1002. assert(false);
  1003. };
  1004. return checked_result<T>(0); // to suppress msvc warning
  1005. }
  1006. template<class T>
  1007. typename std::enable_if<
  1008. std::is_integral<T>::value,
  1009. checked_result<T>
  1010. >::type
  1011. constexpr inline operator|(
  1012. const checked_result<T> & t,
  1013. const checked_result<T> & u
  1014. ){
  1015. return
  1016. t.exception() || u.exception()
  1017. ? checked_result<T>(safe_numerics_error::range_error)
  1018. : checked::bitwise_or<T>(
  1019. static_cast<T>(t),
  1020. static_cast<T>(u)
  1021. );
  1022. }
  1023. template<class T>
  1024. typename std::enable_if<
  1025. std::is_integral<T>::value,
  1026. checked_result<T>
  1027. >::type
  1028. constexpr inline operator^(
  1029. const checked_result<T> & t,
  1030. const checked_result<T> & u
  1031. ){
  1032. return
  1033. t.exception() || u.exception()
  1034. ? checked_result<T>(safe_numerics_error::range_error)
  1035. : checked::bitwise_xor<T>(
  1036. static_cast<T>(t),
  1037. static_cast<T>(u)
  1038. );
  1039. }
  1040. template<class T>
  1041. typename std::enable_if<
  1042. std::is_integral<T>::value,
  1043. checked_result<T>
  1044. >::type
  1045. constexpr inline operator&(
  1046. const checked_result<T> & t,
  1047. const checked_result<T> & u
  1048. ){
  1049. return
  1050. t.exception() || u.exception()
  1051. ? checked_result<T>(safe_numerics_error::range_error)
  1052. : checked::bitwise_and<T>(
  1053. static_cast<T>(t),
  1054. static_cast<T>(u)
  1055. );
  1056. }
  1057. } // safe_numerics
  1058. } // boost
  1059. #include <iosfwd>
  1060. namespace std {
  1061. template<typename CharT, typename Traits, typename R>
  1062. inline std::basic_ostream<CharT, Traits> & operator<<(
  1063. std::basic_ostream<CharT, Traits> & os,
  1064. const boost::safe_numerics::checked_result<R> & r
  1065. ){
  1066. if(!r.exception())
  1067. os << static_cast<R>(r);
  1068. else
  1069. os << std::error_code(r.m_e).message() << ':' << r.m_msg;
  1070. return os;
  1071. }
  1072. template<typename CharT, typename Traits>
  1073. inline std::basic_ostream<CharT, Traits> & operator<<(
  1074. std::basic_ostream<CharT, Traits> & os,
  1075. const boost::safe_numerics::checked_result<signed char> & r
  1076. ){
  1077. if(! r.exception())
  1078. os << static_cast<std::int16_t>(r);
  1079. else
  1080. os << std::error_code(r.m_e).message() << ':' << r.m_msg;
  1081. return os;
  1082. }
  1083. template<typename CharT, typename Traits>
  1084. inline std::basic_ostream<CharT, Traits> & operator<<(
  1085. std::basic_ostream<CharT, Traits> & os,
  1086. const boost::safe_numerics::checked_result<unsigned char> & r
  1087. ){
  1088. if(! r.exception())
  1089. os << static_cast<std::uint16_t>(r);
  1090. else
  1091. os << std::error_code(r.m_e).message() << ':' << r.m_msg;
  1092. return os;
  1093. }
  1094. template<typename CharT, typename Traits, typename R>
  1095. inline std::basic_istream<CharT, Traits> & operator>>(
  1096. std::basic_istream<CharT, Traits> & is,
  1097. boost::safe_numerics::checked_result<R> & r
  1098. ){
  1099. is >> r.m_r;
  1100. return is;
  1101. }
  1102. template<typename CharT, typename Traits, typename R>
  1103. inline std::basic_istream<CharT, Traits> & operator>>(
  1104. std::basic_istream<CharT, Traits> & is,
  1105. boost::safe_numerics::checked_result<signed char> & r
  1106. ){
  1107. std::int16_t i;
  1108. is >> i;
  1109. r.m_r = i;
  1110. return is;
  1111. }
  1112. template<typename CharT, typename Traits, typename R>
  1113. inline std::basic_istream<CharT, Traits> & operator>>(
  1114. std::basic_istream<CharT, Traits> & is,
  1115. boost::safe_numerics::checked_result<unsigned char> & r
  1116. ){
  1117. std::uint16_t i;
  1118. is >> i;
  1119. r.m_r = i;
  1120. return is;
  1121. }
  1122. } // std
  1123. /////////////////////////////////////////////////////////////////
  1124. // numeric limits for checked<R>
  1125. #include <limits>
  1126. namespace std {
  1127. template<class R>
  1128. class numeric_limits<boost::safe_numerics::checked_result<R> >
  1129. : public std::numeric_limits<R>
  1130. {
  1131. using this_type = boost::safe_numerics::checked_result<R>;
  1132. public:
  1133. constexpr static this_type min() noexcept {
  1134. return this_type(std::numeric_limits<R>::min());
  1135. }
  1136. constexpr static this_type max() noexcept {
  1137. return this_type(std::numeric_limits<R>::max());
  1138. }
  1139. };
  1140. } // std
  1141. #endif // BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS