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