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

source code of boost/libs/safe_numerics/example/example7.cpp