checked_integer.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. #ifndef BOOST_NUMERIC_CHECKED_INTEGER_HPP
  2. #define BOOST_NUMERIC_CHECKED_INTEGER_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. // contains operations for doing checked aritmetic on NATIVE
  9. // C++ types.
  10. #include <limits>
  11. #include <type_traits> // is_integral, make_unsigned, enable_if
  12. #include <algorithm> // std::max
  13. #include "checked_result.hpp"
  14. #include "checked_default.hpp"
  15. #include "safe_compare.hpp"
  16. #include "utility.hpp"
  17. #include "exception.hpp"
  18. namespace boost {
  19. namespace safe_numerics {
  20. // utility
  21. template<bool tf>
  22. using bool_type = typename std::conditional<tf, std::true_type, std::false_type>::type;
  23. ////////////////////////////////////////////////////
  24. // layer 0 - implement safe operations for intrinsic integers
  25. // Note presumption of twos complement integer arithmetic
  26. // convert an integral value to some other integral type
  27. template<
  28. typename R,
  29. R Min,
  30. R Max,
  31. typename T,
  32. class F
  33. >
  34. struct heterogeneous_checked_operation<
  35. R,
  36. Min,
  37. Max,
  38. T,
  39. F,
  40. typename std::enable_if<
  41. std::is_integral<R>::value
  42. && std::is_integral<T>::value
  43. >::type
  44. >{
  45. ////////////////////////////////////////////////////
  46. // safe casting on primitive types
  47. struct cast_impl_detail {
  48. constexpr static checked_result<R>
  49. cast_impl(
  50. const T & t,
  51. std::true_type, // R is signed
  52. std::true_type // T is signed
  53. ){
  54. // INT32-C Ensure that operations on signed
  55. // integers do not overflow
  56. return
  57. boost::safe_numerics::safe_compare::greater_than(
  58. t,
  59. Max
  60. ) ?
  61. F::template invoke<safe_numerics_error::positive_overflow_error>(
  62. "converted signed value too large"
  63. )
  64. :
  65. boost::safe_numerics::safe_compare::less_than(
  66. t,
  67. Min
  68. ) ?
  69. F::template invoke<safe_numerics_error::negative_overflow_error>(
  70. "converted signed value too small"
  71. )
  72. :
  73. checked_result<R>(static_cast<R>(t))
  74. ;
  75. }
  76. constexpr static checked_result<R>
  77. cast_impl(
  78. const T & t,
  79. std::true_type, // R is signed
  80. std::false_type // T is unsigned
  81. ){
  82. // INT30-C Ensure that unsigned integer operations
  83. // do not wrap
  84. return
  85. boost::safe_numerics::safe_compare::greater_than(
  86. t,
  87. Max
  88. ) ?
  89. F::template invoke<safe_numerics_error::positive_overflow_error>(
  90. "converted unsigned value too large"
  91. )
  92. :
  93. checked_result<R>(static_cast<R>(t))
  94. ;
  95. }
  96. constexpr static checked_result<R>
  97. cast_impl(
  98. const T & t,
  99. std::false_type, // R is unsigned
  100. std::false_type // T is unsigned
  101. ){
  102. // INT32-C Ensure that operations on unsigned
  103. // integers do not overflow
  104. return
  105. boost::safe_numerics::safe_compare::greater_than(
  106. t,
  107. Max
  108. ) ?
  109. F::template invoke<safe_numerics_error::positive_overflow_error>(
  110. "converted unsigned value too large"
  111. )
  112. :
  113. checked_result<R>(static_cast<R>(t))
  114. ;
  115. }
  116. constexpr static checked_result<R>
  117. cast_impl(
  118. const T & t,
  119. std::false_type, // R is unsigned
  120. std::true_type // T is signed
  121. ){
  122. return
  123. boost::safe_numerics::safe_compare::less_than(t, 0) ?
  124. F::template invoke<safe_numerics_error::domain_error>(
  125. "converted negative value to unsigned"
  126. )
  127. :
  128. boost::safe_numerics::safe_compare::greater_than(
  129. t,
  130. Max
  131. ) ?
  132. F::template invoke<safe_numerics_error::positive_overflow_error>(
  133. "converted signed value too large"
  134. )
  135. :
  136. checked_result<R>(static_cast<R>(t))
  137. ;
  138. }
  139. }; // cast_impl_detail
  140. constexpr static checked_result<R>
  141. cast(const T & t){
  142. return
  143. cast_impl_detail::cast_impl(
  144. t,
  145. std::is_signed<R>(),
  146. std::is_signed<T>()
  147. );
  148. }
  149. };
  150. // converting floating point value to integral type
  151. template<
  152. typename R,
  153. R Min,
  154. R Max,
  155. typename T,
  156. class F
  157. >
  158. struct heterogeneous_checked_operation<
  159. R,
  160. Min,
  161. Max,
  162. T,
  163. F,
  164. typename std::enable_if<
  165. std::is_integral<R>::value
  166. && std::is_floating_point<T>::value
  167. >::type
  168. >{
  169. constexpr static checked_result<R>
  170. cast(const T & t){
  171. return static_cast<R>(t);
  172. }
  173. };
  174. // converting integral value to floating point type
  175. // INT35-C. Use correct integer precisions
  176. template<
  177. typename R,
  178. R Min,
  179. R Max,
  180. typename T,
  181. class F
  182. >
  183. struct heterogeneous_checked_operation<
  184. R,
  185. Min,
  186. Max,
  187. T,
  188. F,
  189. typename std::enable_if<
  190. std::is_floating_point<R>::value
  191. && std::is_integral<T>::value
  192. >::type
  193. >{
  194. constexpr static checked_result<R>
  195. cast(const T & t){
  196. if(std::numeric_limits<R>::digits < std::numeric_limits<T>::digits){
  197. if(utility::significant_bits(t) > std::numeric_limits<R>::digits){
  198. return F::invoke(
  199. safe_numerics_error::precision_overflow_error,
  200. "keep precision"
  201. );
  202. }
  203. }
  204. return t;
  205. }
  206. };
  207. // binary operations on primitive integer types
  208. template<
  209. typename R,
  210. class F
  211. >
  212. struct checked_operation<R, F,
  213. typename std::enable_if<
  214. std::is_integral<R>::value
  215. >::type
  216. >{
  217. ////////////////////////////////////////////////////
  218. // safe addition on primitive types
  219. struct add_impl_detail {
  220. // result unsigned
  221. constexpr static checked_result<R> add(
  222. const R t,
  223. const R u,
  224. std::false_type // R unsigned
  225. ){
  226. return
  227. // INT30-C. Ensure that unsigned integer operations do not wrap
  228. std::numeric_limits<R>::max() - u < t ?
  229. F::template invoke<safe_numerics_error::positive_overflow_error>(
  230. "addition result too large"
  231. )
  232. :
  233. checked_result<R>(t + u)
  234. ;
  235. }
  236. // result signed
  237. constexpr static checked_result<R> add(
  238. const R t,
  239. const R u,
  240. std::true_type // R signed
  241. ){
  242. // INT32-C. Ensure that operations on signed integers do not result in overflow
  243. return
  244. // INT32-C. Ensure that operations on signed integers do not result in overflow
  245. ((u > 0) && (t > (std::numeric_limits<R>::max() - u))) ?
  246. F::template invoke<safe_numerics_error::positive_overflow_error>(
  247. "addition result too large"
  248. )
  249. :
  250. ((u < 0) && (t < (std::numeric_limits<R>::min() - u))) ?
  251. F::template invoke<safe_numerics_error::negative_overflow_error>(
  252. "addition result too low"
  253. )
  254. :
  255. checked_result<R>(t + u)
  256. ;
  257. }
  258. }; // add_impl_detail
  259. constexpr static checked_result<R>
  260. add(const R & t, const R & u){
  261. return add_impl_detail::add(t, u, std::is_signed<R>());
  262. }
  263. ////////////////////////////////////////////////////
  264. // safe subtraction on primitive types
  265. struct subtract_impl_detail {
  266. // result unsigned
  267. constexpr static checked_result<R> subtract(
  268. const R t,
  269. const R u,
  270. std::false_type // R is unsigned
  271. ){
  272. // INT30-C. Ensure that unsigned integer operations do not wrap
  273. return
  274. t < u ?
  275. F::template invoke<safe_numerics_error::negative_overflow_error>(
  276. "subtraction result cannot be negative"
  277. )
  278. :
  279. checked_result<R>(t - u)
  280. ;
  281. }
  282. // result signed
  283. constexpr static checked_result<R> subtract(
  284. const R t,
  285. const R u,
  286. std::true_type // R is signed
  287. ){ // INT32-C
  288. return
  289. // INT32-C. Ensure that operations on signed integers do not result in overflow
  290. ((u > 0) && (t < (std::numeric_limits<R>::min() + u))) ?
  291. F::template invoke<safe_numerics_error::negative_overflow_error>(
  292. "subtraction result overflows result type"
  293. )
  294. :
  295. ((u < 0) && (t > (std::numeric_limits<R>::max() + u))) ?
  296. F::template invoke<safe_numerics_error::positive_overflow_error>(
  297. "subtraction result overflows result type"
  298. )
  299. :
  300. checked_result<R>(t - u)
  301. ;
  302. }
  303. }; // subtract_impl_detail
  304. constexpr static checked_result<R> subtract(const R & t, const R & u){
  305. return subtract_impl_detail::subtract(t, u, std::is_signed<R>());
  306. }
  307. ////////////////////////////////////////////////////
  308. // safe minus on primitive types
  309. struct minus_impl_detail {
  310. // result unsigned
  311. constexpr static checked_result<R> minus(
  312. const R t,
  313. std::false_type // R is unsigned
  314. ){
  315. return t > 0 ?
  316. F::template invoke<safe_numerics_error::negative_overflow_error>(
  317. "minus unsigned would be negative"
  318. )
  319. :
  320. // t == 0
  321. checked_result<R>(0)
  322. ;
  323. }
  324. // result signed
  325. constexpr static checked_result<R> minus(
  326. const R t,
  327. std::true_type // R is signed
  328. ){ // INT32-C
  329. return t == std::numeric_limits<R>::min() ?
  330. F::template invoke<safe_numerics_error::positive_overflow_error>(
  331. "subtraction result overflows result type"
  332. )
  333. :
  334. checked_result<R>(-t)
  335. ;
  336. }
  337. }; // minus_impl_detail
  338. constexpr static checked_result<R> minus(const R & t){
  339. return minus_impl_detail::minus(t, std::is_signed<R>());
  340. }
  341. ////////////////////////////////////////////////////
  342. // safe multiplication on primitive types
  343. struct multiply_impl_detail {
  344. // result unsigned
  345. constexpr static checked_result<R> multiply(
  346. const R t,
  347. const R u,
  348. std::false_type, // R is unsigned
  349. std::false_type // !(sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2)
  350. ){
  351. // INT30-C
  352. // fast method using intermediate result guaranteed not to overflow
  353. // todo - replace std::uintmax_t with a size double the size of R
  354. using i_type = std::uintmax_t;
  355. return
  356. static_cast<i_type>(t) * static_cast<i_type>(u)
  357. > std::numeric_limits<R>::max() ?
  358. F::template invoke<safe_numerics_error::positive_overflow_error>(
  359. "multiplication overflow"
  360. )
  361. :
  362. checked_result<R>(t * u)
  363. ;
  364. }
  365. constexpr static checked_result<R> multiply(
  366. const R t,
  367. const R u,
  368. std::false_type, // R is unsigned
  369. std::true_type // (sizeochecked_result<R>R) > sizeochecked_result<R>std::uintmax_t) / 2)
  370. ){
  371. // INT30-C
  372. return
  373. u > 0 && t > std::numeric_limits<R>::max() / u ?
  374. F::template invoke<safe_numerics_error::positive_overflow_error>(
  375. "multiplication overflow"
  376. )
  377. :
  378. checked_result<R>(t * u)
  379. ;
  380. }
  381. // result signed
  382. constexpr static checked_result<R> multiply(
  383. const R t,
  384. const R u,
  385. std::true_type, // R is signed
  386. std::false_type // ! (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2))
  387. ){
  388. // INT30-C
  389. // fast method using intermediate result guaranteed not to overflow
  390. // todo - replace std::intmax_t with a size double the size of R
  391. using i_type = std::intmax_t;
  392. return
  393. (
  394. static_cast<i_type>(t) * static_cast<i_type>(u)
  395. > static_cast<i_type>(std::numeric_limits<R>::max())
  396. ) ?
  397. F::template invoke<safe_numerics_error::positive_overflow_error>(
  398. "multiplication overflow"
  399. )
  400. :
  401. (
  402. static_cast<i_type>(t) * static_cast<i_type>(u)
  403. < static_cast<i_type>(std::numeric_limits<R>::min())
  404. ) ?
  405. F::template invoke<safe_numerics_error::negative_overflow_error>(
  406. "multiplication overflow"
  407. )
  408. :
  409. checked_result<R>(t * u)
  410. ;
  411. }
  412. constexpr static checked_result<R> multiply(
  413. const R t,
  414. const R u,
  415. std::true_type, // R is signed
  416. std::true_type // (sizeochecked_result<R>R) > (sizeochecked_result<R>std::intmax_t) / 2))
  417. ){ // INT32-C
  418. return t > 0 ?
  419. u > 0 ?
  420. t > std::numeric_limits<R>::max() / u ?
  421. F::template invoke<safe_numerics_error::positive_overflow_error>(
  422. "multiplication overflow"
  423. )
  424. :
  425. checked_result<R>(t * u)
  426. : // u <= 0
  427. u < std::numeric_limits<R>::min() / t ?
  428. F::template invoke<safe_numerics_error::negative_overflow_error>(
  429. "multiplication overflow"
  430. )
  431. :
  432. checked_result<R>(t * u)
  433. : // t <= 0
  434. u > 0 ?
  435. t < std::numeric_limits<R>::min() / u ?
  436. F::template invoke<safe_numerics_error::negative_overflow_error>(
  437. "multiplication overflow"
  438. )
  439. :
  440. checked_result<R>(t * u)
  441. : // u <= 0
  442. t != 0 && u < std::numeric_limits<R>::max() / t ?
  443. F::template invoke<safe_numerics_error::positive_overflow_error>(
  444. "multiplication overflow"
  445. )
  446. :
  447. checked_result<R>(t * u)
  448. ;
  449. }
  450. }; // multiply_impl_detail
  451. constexpr static checked_result<R> multiply(const R & t, const R & u){
  452. return multiply_impl_detail::multiply(
  453. t,
  454. u,
  455. std::is_signed<R>(),
  456. std::integral_constant<
  457. bool,
  458. (sizeof(R) > sizeof(std::uintmax_t) / 2)
  459. >()
  460. );
  461. }
  462. ////////////////////////////////
  463. // safe division on unsafe types
  464. struct divide_impl_detail {
  465. constexpr static checked_result<R> divide(
  466. const R & t,
  467. const R & u,
  468. std::false_type // R is unsigned
  469. ){
  470. return t / u;
  471. }
  472. constexpr static checked_result<R> divide(
  473. const R & t,
  474. const R & u,
  475. std::true_type // R is signed
  476. ){
  477. return
  478. (u == -1 && t == std::numeric_limits<R>::min()) ?
  479. F::template invoke<safe_numerics_error::positive_overflow_error>(
  480. "result cannot be represented"
  481. )
  482. :
  483. checked_result<R>(t / u)
  484. ;
  485. }
  486. }; // divide_impl_detail
  487. // note that we presume that the size of R >= size of T
  488. constexpr static checked_result<R> divide(const R & t, const R & u){
  489. if(u == 0){
  490. return F::template invoke<safe_numerics_error::domain_error>(
  491. "divide by zero"
  492. );
  493. }
  494. return divide_impl_detail::divide(t, u, std::is_signed<R>());
  495. }
  496. ////////////////////////////////
  497. // safe modulus on unsafe types
  498. struct modulus_impl_detail {
  499. constexpr static checked_result<R> modulus(
  500. const R & t,
  501. const R & u,
  502. std::false_type // R is unsigned
  503. ){
  504. return t % u;
  505. }
  506. constexpr static checked_result<R> modulus(
  507. const R & t,
  508. const R & u,
  509. std::true_type // R is signed
  510. ){
  511. if(u >= 0)
  512. return t % u;
  513. checked_result<R> ux = checked::minus(u);
  514. if(ux.exception())
  515. return t;
  516. return t % static_cast<R>(ux);
  517. }
  518. }; // modulus_impl_detail
  519. constexpr static checked_result<R> modulus(const R & t, const R & u){
  520. if(0 == u)
  521. return F::template invoke<safe_numerics_error::domain_error>(
  522. "denominator is zero"
  523. );
  524. // why to we need abs here? the sign of the modulus is the sign of the
  525. // dividend. Consider -128 % -1 The result of this operation should be -1
  526. // but if I use t % u the x86 hardware uses the divide instruction
  527. // capturing the modulus as a side effect. When it does this, it
  528. // invokes the operation -128 / -1 -> 128 which overflows a signed type
  529. // and provokes a hardware exception. We can fix this using abs()
  530. // since -128 % -1 = -128 % 1 = 0
  531. return modulus_impl_detail::modulus(t, u, typename std::is_signed<R>::type());
  532. }
  533. ///////////////////////////////////
  534. // shift operations
  535. struct left_shift_integer_detail {
  536. #if 0
  537. // todo - optimize for gcc to exploit builtin
  538. /* for gcc compilers
  539. int __builtin_clz (unsigned int x)
  540. Returns the number of leading 0-bits in x, starting at the
  541. most significant bit position. If x is 0, the result is undefined.
  542. */
  543. #ifndef __has_feature // Optional of course.
  544. #define __has_feature(x) 0 // Compatibility with non-clang compilers.
  545. #endif
  546. template<typename T>
  547. constexpr unsigned int leading_zeros(const T & t){
  548. if(0 == t)
  549. return 0;
  550. #if __has_feature(builtin_clz)
  551. return __builtin_clz(t);
  552. #else
  553. #endif
  554. }
  555. #endif
  556. // INT34-C C++
  557. // standard paragraph 5.8 / 2
  558. // The value of E1 << E2 is E1 left-shifted E2 bit positions;
  559. // vacated bits are zero-filled.
  560. constexpr static checked_result<R> left_shift(
  561. const R & t,
  562. const R & u,
  563. std::false_type // R is unsigned
  564. ){
  565. // the value of the result is E1 x 2^E2, reduced modulo one more than
  566. // the maximum value representable in the result type.
  567. // see 5.8 & 1
  568. // if right operand is
  569. // greater than or equal to the length in bits of the promoted left operand.
  570. if(
  571. safe_compare::greater_than(
  572. u,
  573. std::numeric_limits<R>::digits - utility::significant_bits(t)
  574. )
  575. ){
  576. // behavior is undefined
  577. return F::template invoke<safe_numerics_error::shift_too_large>(
  578. "shifting left more bits than available is undefined behavior"
  579. );
  580. }
  581. return t << u;
  582. }
  583. constexpr static checked_result<R> left_shift(
  584. const R & t,
  585. const R & u,
  586. std::true_type // R is signed
  587. ){
  588. // and [E1] has a non-negative value
  589. if(t >= 0){
  590. // and E1 x 2^E2 is representable in the corresponding
  591. // unsigned type of the result type,
  592. // see 5.8 & 1
  593. // if right operand is
  594. // greater than or equal to the length in bits of the promoted left operand.
  595. if(
  596. safe_compare::greater_than(
  597. u,
  598. std::numeric_limits<R>::digits - utility::significant_bits(t)
  599. )
  600. ){
  601. // behavior is undefined
  602. return F::template invoke<safe_numerics_error::shift_too_large>(
  603. "shifting left more bits than available"
  604. );
  605. }
  606. else{
  607. return t << u;
  608. }
  609. }
  610. // otherwise, the behavior is undefined.
  611. return F::template invoke<safe_numerics_error::negative_shift>(
  612. "shifting a negative value"
  613. );
  614. }
  615. }; // left_shift_integer_detail
  616. constexpr static checked_result<R> left_shift(
  617. const R & t,
  618. const R & u
  619. ){
  620. // INT34-C - Do not shift an expression by a negative number of bits
  621. // standard paragraph 5.8 & 1
  622. // if the right operand is negative
  623. if(u == 0){
  624. return t;
  625. }
  626. if(u < 0){
  627. return F::template invoke<safe_numerics_error::negative_shift>(
  628. "shifting negative amount"
  629. );
  630. }
  631. if(u > std::numeric_limits<R>::digits){
  632. // behavior is undefined
  633. return F::template invoke<safe_numerics_error::shift_too_large>(
  634. "shifting more bits than available"
  635. );
  636. }
  637. return left_shift_integer_detail::left_shift(t, u, std::is_signed<R>());
  638. }
  639. // right shift
  640. struct right_shift_integer_detail {
  641. // INT34-C C++
  642. // standard paragraph 5.8 / 3
  643. // The value of E1 << E2 is E1 left-shifted E2 bit positions;
  644. // vacated bits are zero-filled.
  645. constexpr static checked_result<R> right_shift(
  646. const R & t,
  647. const R & u,
  648. std::false_type // T is unsigned
  649. ){
  650. // the value of the result is the integral part of the
  651. // quotient of E1/2E2
  652. return t >> u;
  653. }
  654. constexpr static checked_result<R> right_shift(
  655. const R & t,
  656. const R & u,
  657. std::true_type // T is signed;
  658. ){
  659. if(t < 0){
  660. // note that the C++ standard considers this case is "implemenation
  661. // defined" rather than "undefined".
  662. return F::template invoke<safe_numerics_error::negative_value_shift>(
  663. "shifting a negative value"
  664. );
  665. }
  666. // the value is the integral part of E1 / 2^E2,
  667. return t >> u;
  668. }
  669. }; // right_shift_integer_detail
  670. constexpr static checked_result<R> right_shift(
  671. const R & t,
  672. const R & u
  673. ){
  674. // INT34-C - Do not shift an expression by a negative number of bits
  675. // standard paragraph 5.8 & 1
  676. // if the right operand is negative
  677. if(u < 0){
  678. return F::template invoke<safe_numerics_error::negative_shift>(
  679. "shifting negative amount"
  680. );
  681. }
  682. if(u > std::numeric_limits<R>::digits){
  683. // behavior is undefined
  684. return F::template invoke<safe_numerics_error::shift_too_large>(
  685. "shifting more bits than available"
  686. );
  687. }
  688. return right_shift_integer_detail::right_shift(t, u ,std::is_signed<R>());
  689. }
  690. ///////////////////////////////////
  691. // bitwise operations
  692. // INT13-C Note: We don't enforce recommendation as acually written
  693. // as it would break too many programs. Specifically, we permit signed
  694. // integer operands.
  695. constexpr static checked_result<R> bitwise_or(const R & t, const R & u){
  696. using namespace boost::safe_numerics::utility;
  697. const unsigned int result_size
  698. = std::max(significant_bits(t), significant_bits(u));
  699. if(result_size > bits_type<R>::value){
  700. return F::template invoke<safe_numerics_error::positive_overflow_error>(
  701. "result type too small to hold bitwise or"
  702. );
  703. }
  704. return t | u;
  705. }
  706. constexpr static checked_result<R> bitwise_xor(const R & t, const R & u){
  707. using namespace boost::safe_numerics::utility;
  708. const unsigned int result_size
  709. = std::max(significant_bits(t), significant_bits(u));
  710. if(result_size > bits_type<R>::value){
  711. return F::template invoke<safe_numerics_error::positive_overflow_error>(
  712. "result type too small to hold bitwise or"
  713. );
  714. }
  715. return t ^ u;
  716. }
  717. constexpr static checked_result<R> bitwise_and(const R & t, const R & u){
  718. using namespace boost::safe_numerics::utility;
  719. const unsigned int result_size
  720. = std::min(significant_bits(t), significant_bits(u));
  721. if(result_size > bits_type<R>::value){
  722. return F::template invoke<safe_numerics_error::positive_overflow_error>(
  723. "result type too small to hold bitwise and"
  724. );
  725. }
  726. return t & u;
  727. }
  728. constexpr static checked_result<R> bitwise_not(const R & t){
  729. using namespace boost::safe_numerics::utility;
  730. if(significant_bits(t) > bits_type<R>::value){
  731. return F::template invoke<safe_numerics_error::positive_overflow_error>(
  732. "result type too small to hold bitwise inverse"
  733. );
  734. }
  735. return ~t;
  736. }
  737. }; // checked_operation
  738. } // safe_numerics
  739. } // boost
  740. #endif // BOOST_NUMERIC_CHECKED_INTEGER_HPP