Files
safe_numerics/examples/example7.cpp
Robert Ramey 0a5822c14d working version of automatic promotion policy.
(right now - only working in addition!)
More examples
More complete documentation
pending issue  - compile time trap
2015-07-29 13:55:57 -07:00

113 lines
3.6 KiB
C++

#include <cassert>
#include <stdexcept>
#include <sstream>
#include <iostream>
#include "../include/safe_range.hpp"
// return total number of minutes
unsigned int convert(
const unsigned int & hours,
const unsigned int & minutes
) {
// check that parameters are within required limits
// invokes a runtime cost EVERYTIME the function is called
// and the overhead of supporting an interrupt.
// note high runtime cost!
if(minutes > 59)
throw std::domain_error("minutes exceeded 59");
if(hours > 23)
throw std::domain_error("hours exceeded 23");
return hours * 60 + minutes;
}
// define convient typenames for hours and minutes hh:mm
using hours_t = boost::numeric::safe_unsigned_range<0, 23>;
using minutes_t = boost::numeric::safe_unsigned_range<0, 59>;
// return total number of minutes
// type returned is safe_unsigned_range<0, 24*60 - 1>
auto safe_convert(const hours_t & hours, const minutes_t & minutes) {
// no need for checking as parameters are guaranteed to be within limits
// expression below cannot throw ! zero runtime overhead
return hours * 60 + minutes;
}
int main(int argc, const char * argv[]){
std::cout << "example 7: ";
std::cout << "enforce contracts with zero runtime cost" << std::endl;
std::cout << "Not using safe numerics" << std::endl;
// problem: checking of externally produced value can be expensive
try {
convert(10, 83); // invalid parameters - detected - but at a heavy cost
}
catch(std::exception e){
std::cout << "exception thrown for parameter error" << std::endl;
}
// solution: use safe range to restrict parameters
std::cout << "Using safe numerics" << std::endl;
try {
// parameters are guarenteed to meet requirements
hours_t hours(10);
minutes_t minutes(83); // interrupt thrown here
// so the following will never throw
safe_convert(hours, minutes);
}
catch(std::exception e){
std::cout
<< "exception thrown when invalid arguments are constructed"
<< std::endl;
}
try {
// parameters are guarenteed to meet requirements when
// constructed on the stack
safe_convert(hours_t(10), minutes_t(83));
}
catch(std::exception e){
std::cout
<< "exception thrown when invalid arguments are constructed on the stack"
<< std::endl;
}
try {
// parameters are guarenteed to meet requirements when
// implicitly constructed to safe types to match function signature
safe_convert(10, 83);
}
catch(std::exception e){
std::cout
<< "exception thrown when invalid arguments are implicitly constructed"
<< std::endl;
}
try {
// the following will never throw as the values meet requirements.
hours_t hours(10);
minutes_t minutes(17);
// the following will never throw because it cannot be called with
// invalid parameters
safe_convert(hours, minutes);
// since safe types can be converted to their underlying unsafe types
// we can still call an unsafe function with safe types
convert(hours, minutes);
// since unsafe types can be implicitly converted to corresponding
// safe types we can just pass the unsafe types. checkin will occur
// when the safe type is constructed.
safe_convert(10, 17);
// note zero runtime overhead once values are constructed
}
catch(std::exception e){
assert(false); // can never arrive here !!!
}
return 0;
}