00001 #ifndef CONVERT_IMPL_HPP
00002 #define CONVERT_IMPL_HPP
00003
00004 #include <type_traits>
00005 #include <exception>
00006 #include "simple_string.hpp"
00007
00008 namespace SafeAny
00009 {
00010 namespace details
00011 {
00012 template <typename BoolCondition>
00013 using EnableIf = typename std::enable_if<BoolCondition::value, void>::type;
00014
00015 template <typename T>
00016 struct is_integer
00017 : std::integral_constant<bool, std::is_integral<T>::value && !std::is_same<T, bool>::value &&
00018 !std::is_same<T, char>::value>
00019 {
00020 };
00021
00022 template <typename From, typename To>
00023 struct is_same_real
00024 : std::integral_constant<bool, std::is_same<From, To>::value && std::is_floating_point<To>::value>
00025 {
00026 };
00027
00028 template <typename From, typename To>
00029 struct is_safe_integer_conversion
00030 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
00031 sizeof(From) < sizeof(To) &&
00032 std::is_signed<From>::value == std::is_signed<To>::value>
00033 {
00034 };
00035
00036 template <typename T>
00037 struct is_convertible_type
00038 : std::integral_constant<bool, std::is_integral<T>::value || std::is_floating_point<T>::value ||
00039 std::is_same<T, bool>::value || std::is_same<T, char>::value ||
00040 std::is_same<T, std::string>::value ||
00041 std::is_same<T, SimpleString>::value || std::is_enum<T>::value>
00042 {
00043 };
00044
00045 template <typename From, typename To>
00046 struct float_conversion : std::integral_constant<bool, std::is_floating_point<From>::value &&
00047 std::is_floating_point<To>::value &&
00048 !std::is_same<From, To>::value>
00049 {
00050 };
00051
00052 template <typename From, typename To>
00053 struct unsigned_to_smaller_conversion
00054 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
00055 (sizeof(From) > sizeof(To)) && !std::is_signed<From>::value &&
00056 !std::is_signed<To>::value>
00057 {
00058 };
00059
00060 template <typename From, typename To>
00061 struct signed_to_smaller_conversion
00062 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
00063 (sizeof(From) > sizeof(To)) && std::is_signed<From>::value &&
00064 std::is_signed<To>::value>
00065 {
00066 };
00067
00068
00069 template <typename From, typename To>
00070 struct signed_to_smaller_unsigned_conversion
00071 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
00072 sizeof(From) >= sizeof(To) && std::is_signed<From>::value &&
00073 !std::is_signed<To>::value>
00074 {
00075 };
00076
00077 template <typename From, typename To>
00078 struct signed_to_larger_unsigned_conversion
00079 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
00080 sizeof(From) < sizeof(To) && std::is_signed<From>::value &&
00081 !std::is_signed<To>::value>
00082 {
00083 };
00084
00085 template <typename From, typename To>
00086 struct unsigned_to_smaller_signed_conversion
00087 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
00088 (sizeof(From) >= sizeof(To)) && !std::is_signed<From>::value &&
00089 std::is_signed<To>::value>
00090 {
00091 };
00092
00093 template <typename From, typename To>
00094 struct unsigned_to_larger_signed_conversion
00095 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
00096 sizeof(From) < sizeof(To) && !std::is_signed<From>::value &&
00097 std::is_signed<To>::value>
00098 {
00099 };
00100
00101 template <typename From, typename To>
00102 struct floating_to_signed_conversion
00103 : std::integral_constant<bool, std::is_floating_point<From>::value && is_integer<To>::value &&
00104 std::is_signed<To>::value>
00105 {
00106 };
00107
00108 template <typename From, typename To>
00109 struct floating_to_unsigned_conversion
00110 : std::integral_constant<bool, std::is_floating_point<From>::value && is_integer<To>::value &&
00111 !std::is_signed<To>::value>
00112 {
00113 };
00114
00115 template <typename From, typename To>
00116 struct integer_to_floating_conversion
00117 : std::integral_constant<bool, is_integer<From>::value && std::is_floating_point<To>::value>
00118 {
00119 };
00120
00121 template <typename From, typename To>
00122 inline void checkUpperLimit(const From& from)
00123 {
00124 if ((sizeof(To) < sizeof(From)) && (from > static_cast<From>(std::numeric_limits<To>::max())))
00125 {
00126 throw std::runtime_error("Value too large.");
00127 }
00128 else if (static_cast<To>(from) > std::numeric_limits<To>::max())
00129 {
00130 throw std::runtime_error("Value too large.");
00131 }
00132 }
00133
00134 template <typename From, typename To>
00135 inline void checkUpperLimitFloat(const From& from)
00136 {
00137 if (from > std::numeric_limits<To>::max())
00138 {
00139 throw std::runtime_error("Value too large.");
00140 }
00141 }
00142
00143 template <typename From, typename To>
00144 inline void checkLowerLimitFloat(const From& from)
00145 {
00146 if (from < -std::numeric_limits<To>::max())
00147 {
00148 throw std::runtime_error("Value too small.");
00149 }
00150 }
00151
00152 template <typename From, typename To>
00153 inline void checkLowerLimit(const From& from)
00154 {
00155 if (from < std::numeric_limits<To>::min())
00156 {
00157 throw std::runtime_error("Value too small.");
00158 }
00159 }
00160
00161 template <typename From, typename To>
00162 inline void checkTruncation(const From& from)
00163 {
00164 if (from != static_cast<From>(static_cast<To>(from)))
00165 {
00166 throw std::runtime_error("Floating point truncated");
00167 }
00168 }
00169
00170
00171
00172 template <typename SRC, typename DST>
00173 inline typename std::enable_if<!is_convertible_type<DST>::value, void>::type
00174 convertNumber(const SRC&, DST&)
00175 {
00176 static_assert(is_convertible_type<DST>::value, "Not convertible");
00177 }
00178
00179 template <typename SRC, typename DST>
00180 inline EnableIf<std::is_same<bool, DST>> convertNumber(const SRC& from, DST& target)
00181 {
00182 target = (from != 0);
00183 }
00184
00185 template <typename SRC, typename DST>
00186 inline EnableIf<std::is_same<SRC, DST>> convertNumber(const SRC& from, DST& target)
00187 {
00188 target = from;
00189 }
00190
00191 template <typename SRC, typename DST>
00192 inline EnableIf<is_safe_integer_conversion<SRC, DST>> convertNumber(const SRC& from, DST& target)
00193 {
00194 target = static_cast<DST>(from);
00195 }
00196
00197 template <typename SRC, typename DST>
00198 inline EnableIf<float_conversion<SRC, DST>> convertNumber(const SRC& from, DST& target)
00199 {
00200 checkTruncation<SRC, DST>(from);
00201 target = static_cast<DST>(from);
00202 }
00203
00204 template <typename SRC, typename DST>
00205 inline EnableIf<unsigned_to_smaller_conversion<SRC, DST>> convertNumber(const SRC& from,
00206 DST& target)
00207 {
00208 checkUpperLimit<SRC, DST>(from);
00209 target = static_cast<DST>(from);
00210 }
00211
00212 template <typename SRC, typename DST>
00213 inline EnableIf<signed_to_smaller_conversion<SRC, DST>> convertNumber(const SRC& from, DST& target)
00214 {
00215 checkLowerLimit<SRC, DST>(from);
00216 checkUpperLimit<SRC, DST>(from);
00217 target = static_cast<DST>(from);
00218 }
00219
00220 template <typename SRC, typename DST>
00221 inline EnableIf<signed_to_smaller_unsigned_conversion<SRC, DST>> convertNumber(const SRC& from,
00222 DST& target)
00223 {
00224 if (from < 0)
00225 {
00226 throw std::runtime_error("Value is negative and can't be converted to signed");
00227 }
00228
00229 checkUpperLimit<SRC, DST>(from);
00230 target = static_cast<DST>(from);
00231 }
00232
00233 template <typename SRC, typename DST>
00234 inline EnableIf<signed_to_larger_unsigned_conversion<SRC, DST>> convertNumber(const SRC& from,
00235 DST& target)
00236 {
00237 if (from < 0)
00238 {
00239 throw std::runtime_error("Value is negative and can't be converted to signed");
00240 }
00241
00242 target = static_cast<DST>(from);
00243 }
00244
00245 template <typename SRC, typename DST>
00246 inline EnableIf<unsigned_to_larger_signed_conversion<SRC, DST>> convertNumber(const SRC& from,
00247 DST& target)
00248 {
00249 target = static_cast<DST>(from);
00250 }
00251
00252 template <typename SRC, typename DST>
00253 inline EnableIf<unsigned_to_smaller_signed_conversion<SRC, DST>> convertNumber(const SRC& from,
00254 DST& target)
00255 {
00256 checkUpperLimit<SRC, DST>(from);
00257 target = static_cast<DST>(from);
00258 }
00259
00260 template <typename SRC, typename DST>
00261 inline EnableIf<floating_to_signed_conversion<SRC, DST>> convertNumber(const SRC& from, DST& target)
00262 {
00263 checkLowerLimitFloat<SRC, DST>(from);
00264 checkLowerLimitFloat<SRC, DST>(from);
00265
00266 if (from != static_cast<SRC>(static_cast<DST>(from)))
00267 {
00268 throw std::runtime_error("Floating point truncated");
00269 }
00270
00271 target = static_cast<DST>(from);
00272 }
00273
00274 template <typename SRC, typename DST>
00275 inline EnableIf<floating_to_unsigned_conversion<SRC, DST>> convertNumber(const SRC& from,
00276 DST& target)
00277 {
00278 if (from < 0)
00279 {
00280 throw std::runtime_error("Value is negative and can't be converted to signed");
00281 }
00282
00283 checkLowerLimitFloat<SRC, DST>(from);
00284
00285 if (from != static_cast<SRC>(static_cast<DST>(from)))
00286 {
00287 throw std::runtime_error("Floating point truncated");
00288 }
00289
00290 target = static_cast<DST>(from);
00291 }
00292
00293 template <typename SRC, typename DST>
00294 inline EnableIf<integer_to_floating_conversion<SRC, DST>> convertNumber(const SRC& from,
00295 DST& target)
00296 {
00297 checkTruncation<SRC, DST>(from);
00298 target = static_cast<DST>(from);
00299 }
00300
00301 }
00302 }
00303
00304 #endif // CONVERT_IMPL_HPP