checked_integer.hpp 26 KB

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