example7.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #include <cassert>
  2. #include <stdexcept>
  3. #include <sstream>
  4. #include <iostream>
  5. #include <boost/safe_numerics/safe_integer_range.hpp>
  6. // NOT using safe numerics - enforce program contract explicitly
  7. // return total number of minutes
  8. unsigned int contract_convert(
  9. const unsigned int & hours,
  10. const unsigned int & minutes
  11. ) {
  12. // check that parameters are within required limits
  13. // invokes a runtime cost EVERYTIME the function is called
  14. // and the overhead of supporting an interrupt.
  15. // note high runtime cost!
  16. if(minutes > 59)
  17. throw std::domain_error("minutes exceeded 59");
  18. if(hours > 23)
  19. throw std::domain_error("hours exceeded 23");
  20. return hours * 60 + minutes;
  21. }
  22. // Use safe numerics to enforce program contract automatically
  23. // define convenient typenames for hours and minutes hh:mm
  24. using hours_t = boost::safe_numerics::safe_unsigned_range<0, 23>;
  25. using minutes_t = boost::safe_numerics::safe_unsigned_range<0, 59>;
  26. using minutes_total_t = boost::safe_numerics::safe_unsigned_range<0, 59>;
  27. // return total number of minutes
  28. // type returned is safe_unsigned_range<0, 24*60 - 1>
  29. auto convert(const hours_t & hours, const minutes_t & minutes) {
  30. // no need to test pre-conditions
  31. // input parameters are guaranteed to hold legitimate values
  32. // no need to test post-conditions
  33. // return value guaranteed to hold result
  34. return hours * 60 + minutes;
  35. }
  36. unsigned int test1(unsigned int hours, unsigned int minutes){
  37. // problem: checking of externally produced value can be expensive
  38. // invalid parameters - detected - but at a heavy cost
  39. return contract_convert(hours, minutes);
  40. }
  41. auto test2(unsigned int hours, unsigned int minutes){
  42. // solution: use safe numerics
  43. // safe types can be implicitly constructed base types
  44. // construction guarentees corectness
  45. // return value is known to fit in unsigned int
  46. return convert(hours, minutes);
  47. }
  48. auto test3(unsigned int hours, unsigned int minutes){
  49. // actually we don't even need the convert function any more
  50. return hours_t(hours) * 60 + minutes_t(minutes);
  51. }
  52. int main(int, const char *[]){
  53. std::cout << "example 7: ";
  54. std::cout << "enforce contracts with zero runtime cost" << std::endl;
  55. unsigned int total_minutes;
  56. try {
  57. total_minutes = test3(17, 83);
  58. std::cout << "total minutes = " << total_minutes << std::endl;
  59. }
  60. catch(const std::exception & e){
  61. std::cout << "parameter error detected" << std::endl;
  62. }
  63. try {
  64. total_minutes = test3(17, 10);
  65. std::cout << "total minutes = " << total_minutes << std::endl;
  66. }
  67. catch(const std::exception & e){
  68. // should never arrive here
  69. std::cout << "parameter error erroneously detected" << std::endl;
  70. return 1;
  71. }
  72. return 0;
  73. }