checked_result_operations.hpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  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 inline 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. bool e = r.exception();
  1067. os << e;
  1068. if(!e)
  1069. os << static_cast<R>(r);
  1070. else
  1071. os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
  1072. return os;
  1073. }
  1074. template<typename CharT, typename Traits>
  1075. inline std::basic_ostream<CharT, Traits> & operator<<(
  1076. std::basic_ostream<CharT, Traits> & os,
  1077. const boost::safe_numerics::checked_result<signed char> & r
  1078. ){
  1079. bool e = r.exception();
  1080. os << e;
  1081. if(! e)
  1082. os << static_cast<std::int16_t>(r);
  1083. else
  1084. os << std::error_code(r.m_e).message() << ':' << static_cast<char const *>(r);
  1085. return os;
  1086. }
  1087. template<typename CharT, typename Traits, typename R>
  1088. inline std::basic_istream<CharT, Traits> & operator>>(
  1089. std::basic_istream<CharT, Traits> & is,
  1090. boost::safe_numerics::checked_result<R> & r
  1091. ){
  1092. bool e;
  1093. is >> e;
  1094. if(!e)
  1095. is >> static_cast<R>(r);
  1096. else
  1097. is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
  1098. return is;
  1099. }
  1100. template<typename CharT, typename Traits>
  1101. inline std::basic_istream<CharT, Traits> & operator>>(
  1102. std::basic_istream<CharT, Traits> & is,
  1103. boost::safe_numerics::checked_result<signed char> & r
  1104. ){
  1105. bool e;
  1106. is >> e;
  1107. if(!e){
  1108. std::int16_t i;
  1109. is >> i;
  1110. r.m_contents.m_r = static_cast<signed char>(i);
  1111. }
  1112. else
  1113. is >> std::error_code(r.m_e).message() >> ':' >> static_cast<char const *>(r);
  1114. return is;
  1115. }
  1116. } // std
  1117. /////////////////////////////////////////////////////////////////
  1118. // numeric limits for checked<R>
  1119. #include <limits>
  1120. namespace std {
  1121. template<class R>
  1122. class numeric_limits<boost::safe_numerics::checked_result<R> >
  1123. : public std::numeric_limits<R>
  1124. {
  1125. using this_type = boost::safe_numerics::checked_result<R>;
  1126. public:
  1127. constexpr static this_type min() noexcept {
  1128. return this_type(std::numeric_limits<R>::min());
  1129. }
  1130. constexpr static this_type max() noexcept {
  1131. return this_type(std::numeric_limits<R>::max());
  1132. }
  1133. };
  1134. } // std
  1135. #endif // BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS