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