1 // Copyright (C) 2009 Codership Oy <info@codership.com> 2 3 /** 4 * @file Routines for safe integer conversion 5 * 6 * $Id$ 7 */ 8 9 #ifndef _gu_convert_hpp_ 10 #define _gu_convert_hpp_ 11 12 #include "gu_macros.h" 13 #include "gu_throw.hpp" 14 #include <limits> 15 16 namespace gu 17 { 18 /*! 19 * Converts from type FROM to type TO with range checking. 20 * Generic template is for the case sizeof(FROM) > sizeof(TO). 21 * 22 * @param from value to convert 23 * @param to destination (provides type TO for template instantiation) 24 * @return value cast to TO 25 */ 26 template <typename FROM, typename TO> inline convert(const FROM & from,const TO & to)27 TO convert (const FROM& from, const TO& to) 28 { 29 if (gu_unlikely(from > std::numeric_limits<TO>::max() || 30 from < std::numeric_limits<TO>::min())) 31 { 32 // @todo: figure out how to print type name without RTTI 33 gu_throw_error (ERANGE) << from << " is unrepresentable with " 34 << (std::numeric_limits<TO>::is_signed ? 35 "signed" : "unsigned") << " " 36 << sizeof(TO) << " bytes (" 37 << "min " << std::numeric_limits<TO>::min() 38 << " max " << std::numeric_limits<TO>::max() 39 << ")"; 40 } 41 42 return static_cast<TO>(from); 43 } 44 45 /* Specialized templates are for signed conversion */ 46 47 template <> inline convert(const unsigned long long & from,const long long & to)48 long long convert (const unsigned long long& from, const long long& to) 49 { 50 if (gu_unlikely(from > static_cast<unsigned long long> 51 (std::numeric_limits<long long>::max()))) 52 { 53 gu_throw_error (ERANGE) << from 54 << " is unrepresentable with 'long long'"; 55 } 56 57 return static_cast<long long>(from); 58 } 59 60 template <> inline convert(const long long & from,const unsigned long long & to)61 unsigned long long convert (const long long& from, 62 const unsigned long long& to) 63 { 64 if (gu_unlikely(from < 0)) 65 { 66 gu_throw_error (ERANGE) << from 67 << " is unrepresentable with 'unsigned long long'"; 68 } 69 70 return static_cast<unsigned long long>(from); 71 } 72 73 template <> inline convert(const unsigned long & from,const long & to)74 long convert (const unsigned long& from, const long& to) 75 { 76 if (gu_unlikely(from > static_cast<unsigned long> 77 (std::numeric_limits<long>::max()))) 78 { 79 gu_throw_error (ERANGE) << from 80 << " is unrepresentable with 'long'"; 81 } 82 83 return static_cast<long long>(from); 84 } 85 86 template <> inline convert(const long & from,const unsigned long & to)87 unsigned long convert (const long& from, const unsigned long& to) 88 { 89 if (gu_unlikely(from < 0)) 90 { 91 gu_throw_error (ERANGE) << from 92 << " is unrepresentable with 'unsigned long'"; 93 } 94 95 return static_cast<unsigned long>(from); 96 } 97 98 template <> inline convert(const unsigned int & from,const int & to)99 int convert (const unsigned int& from, const int& to) 100 { 101 if (gu_unlikely(from > static_cast<unsigned int> 102 (std::numeric_limits<int>::max()))) 103 { 104 gu_throw_error (ERANGE) << from 105 << " is unrepresentable with 'long'"; 106 } 107 108 return static_cast<int>(from); 109 } 110 111 template <> inline convert(const int & from,const unsigned int & to)112 unsigned int convert (const int& from, const unsigned int& to) 113 { 114 if (gu_unlikely(from < 0)) 115 { 116 gu_throw_error (ERANGE) << from 117 << " is unrepresentable with 'unsigned long'"; 118 } 119 120 return static_cast<unsigned int>(from); 121 } 122 } 123 124 #endif /* _gu_convert_hpp_ */ 125