checked_integer.hpp 27 KB

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