35 #ifndef VARIANT_IMPL_H
36 #define VARIANT_IMPL_H
38 #include <type_traits>
54 template <
typename BoolCondition>
55 using EnableIf = Invoke<std::enable_if<BoolCondition::value>>;
58 struct is_integer : std::integral_constant<bool, std::is_integral<T>::value &&
59 !std::is_same<T, bool>::value &&
60 !std::is_same<T, char>::value>
64 template <
typename From,
typename To>
65 struct is_same_real : std::integral_constant<bool, std::is_same<From, To>::value &&
66 std::is_floating_point<To>::value>
70 template <
typename From,
typename To>
71 struct is_safe_integer_conversion
72 : std::integral_constant<bool,
73 is_integer<From>::value && is_integer<To>::value &&
74 sizeof(From) <= sizeof(To) &&
75 std::is_signed<From>::value == std::is_signed<To>::value>
79 template <typename From, typename To>
80 struct float_conversion
81 : std::integral_constant<bool, std::is_floating_point<From>::value &&
82 std::is_floating_point<To>::value &&
83 !std::is_same<From, To>::value>
87 template <typename From, typename To>
88 struct unsigned_to_smaller_conversion
89 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
90 (sizeof(From) > sizeof(To)) &&
91 !std::is_signed<From>::value &&
92 !std::is_signed<To>::value>
96 template <
typename From,
typename To>
97 struct signed_to_smaller_conversion
98 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
99 (sizeof(From) > sizeof(To)) &&
106 template <
typename From,
typename To>
107 struct signed_to_smaller_unsigned_conversion
108 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
109 sizeof(From) >= sizeof(To) &&
115 template <
typename From,
typename To>
116 struct signed_to_larger_unsigned_conversion
117 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
118 sizeof(From) < sizeof(To) &&
119 std::is_signed<From>::value &&
120 !std::is_signed<To>::value>
124 template <typename From, typename To>
125 struct unsigned_to_smaller_signed_conversion
126 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
127 (sizeof(From) >= sizeof(To)) &&
128 !std::is_signed<From>::value &&
129 std::is_signed<To>::value>
133 template <
typename From,
typename To>
134 struct unsigned_to_larger_signed_conversion
135 : std::integral_constant<bool, is_integer<From>::value && is_integer<To>::value &&
136 sizeof(From) < sizeof(To) &&
137 !std::is_signed<From>::value &&
138 std::is_signed<To>::value>
142 template <typename From, typename To>
143 struct floating_to_signed_conversion
144 : std::integral_constant<bool, std::is_floating_point<From>::value &&
145 is_integer<To>::value && std::is_signed<To>::value>
149 template <typename From, typename To>
150 struct floating_to_unsigned_conversion
151 : std::integral_constant<bool, std::is_floating_point<From>::value &&
152 is_integer<To>::value && !std::is_signed<To>::value>
156 template <typename From, typename To>
157 struct integer_to_floating_conversion
158 : std::integral_constant<bool,
159 is_integer<From>::value && std::is_floating_point<To>::value>
163 template <typename From, typename To>
164 inline void checkUpperLimit(const From& from)
166 if ((sizeof(To) < sizeof(From)) &&
167 (from > static_cast<From>(std::numeric_limits<To>::max())))
169 throw RangeException("Value too large.");
171 else if (static_cast<To>(from) > std::numeric_limits<To>::max())
177 template <
typename From,
typename To>
178 inline void checkUpperLimitFloat(
const From& from)
180 if (from > std::numeric_limits<To>::max())
186 template <
typename From,
typename To>
187 inline void checkLowerLimitFloat(
const From& from)
189 if (from < -std::numeric_limits<To>::max())
191 throw RangeException(
"Value too small.");
195 template <
typename From,
typename To>
196 inline void checkLowerLimit(
const From& from)
198 if (from < std::numeric_limits<To>::min())
200 throw RangeException(
"Value too small.");
204 template <
typename From,
typename To>
205 inline void checkTruncation(
const From& from)
207 if (from !=
static_cast<From
>(
static_cast<To
>(from)))
209 throw RangeException(
"Floating point truncated");
215 template <
typename SRC,
typename DST,
216 typename details::EnableIf<details::is_same_real<SRC, DST>>* =
nullptr>
217 inline void convert_impl(
const SRC& from, DST& target)
223 typename SRC,
typename DST,
224 typename details::EnableIf<details::is_safe_integer_conversion<SRC, DST>>* =
nullptr>
225 inline void convert_impl(
const SRC& from, DST& target)
227 target =
static_cast<DST
>(from);
230 template <
typename SRC,
typename DST,
231 typename details::EnableIf<details::float_conversion<SRC, DST>>* =
nullptr>
232 inline void convert_impl(
const SRC& from, DST& target)
236 checkTruncation<SRC, DST>(from);
238 target =
static_cast<DST
>(from);
241 template <
typename SRC,
typename DST,
242 typename details::EnableIf<details::unsigned_to_smaller_conversion<SRC, DST>>* =
244 inline void convert_impl(
const SRC& from, DST& target)
246 checkUpperLimit<SRC, DST>(from);
247 target =
static_cast<DST
>(from);
250 template <
typename SRC,
typename DST,
251 typename details::EnableIf<details::signed_to_smaller_conversion<SRC, DST>>* =
253 inline void convert_impl(
const SRC& from, DST& target)
255 checkLowerLimit<SRC, DST>(from);
256 checkUpperLimit<SRC, DST>(from);
257 target =
static_cast<DST
>(from);
260 template <
typename SRC,
typename DST,
262 details::signed_to_smaller_unsigned_conversion<SRC, DST>>* =
nullptr>
263 inline void convert_impl(
const SRC& from, DST& target)
267 throw RangeException(
"Value is negative and can't be converted to signed");
270 checkUpperLimit<SRC, DST>(from);
271 target =
static_cast<DST
>(from);
274 template <
typename SRC,
typename DST,
276 details::signed_to_larger_unsigned_conversion<SRC, DST>>* =
nullptr>
277 inline void convert_impl(
const SRC& from, DST& target)
281 throw RangeException(
"Value is negative and can't be converted to signed");
284 target =
static_cast<DST
>(from);
287 template <
typename SRC,
typename DST,
289 details::unsigned_to_larger_signed_conversion<SRC, DST>>* =
nullptr>
290 inline void convert_impl(
const SRC& from, DST& target)
292 target =
static_cast<DST
>(from);
295 template <
typename SRC,
typename DST,
297 details::unsigned_to_smaller_signed_conversion<SRC, DST>>* =
nullptr>
298 inline void convert_impl(
const SRC& from, DST& target)
300 checkUpperLimit<SRC, DST>(from);
301 target =
static_cast<DST
>(from);
304 template <
typename SRC,
typename DST,
305 typename details::EnableIf<details::floating_to_signed_conversion<SRC, DST>>* =
307 inline void convert_impl(
const SRC& from, DST& target)
309 checkLowerLimitFloat<SRC, DST>(from);
310 checkUpperLimitFloat<SRC, DST>(from);
312 if (from !=
static_cast<SRC
>(
static_cast<DST
>(from)))
314 throw RangeException(
"Floating point truncated");
317 target =
static_cast<DST
>(from);
320 template <
typename SRC,
typename DST,
322 details::floating_to_unsigned_conversion<SRC, DST>>* =
nullptr>
323 inline void convert_impl(
const SRC& from, DST& target)
327 throw RangeException(
"Value is negative and can't be converted to signed");
330 checkLowerLimitFloat<SRC, DST>(from);
332 if (from !=
static_cast<SRC
>(
static_cast<DST
>(from)))
334 throw RangeException(
"Floating point truncated");
337 target =
static_cast<DST
>(from);
340 template <
typename SRC,
typename DST,
341 typename details::EnableIf<details::integer_to_floating_conversion<SRC, DST>>* =
343 inline void convert_impl(
const SRC& from, DST& target)
345 checkTruncation<SRC, DST>(from);
346 target =
static_cast<DST
>(from);