piranha  0.10
safe_cast.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_SAFE_CAST_HPP
30 #define PIRANHA_SAFE_CAST_HPP
31 
32 #include <boost/numeric/conversion/cast.hpp>
33 #include <cmath>
34 #include <stdexcept>
35 #include <string>
36 #include <type_traits>
37 #include <utility>
38 
39 #include <piranha/detail/demangle.hpp>
40 #include <piranha/exceptions.hpp>
41 #include <piranha/type_traits.hpp>
42 
43 namespace piranha
44 {
45 
47 
53 struct safe_cast_failure final : std::invalid_argument {
54  using std::invalid_argument::invalid_argument;
55 };
56 
58 
62 template <typename To, typename From, typename = void>
64 private:
65  template <typename T>
66  using enabler
67  = enable_if_t<conjunction<std::is_same<To, T>, std::is_same<From, T>, std::is_copy_constructible<T>>::value,
68  int>;
69 
70 public:
72 
84  template <typename T, enabler<T> = 0>
85  To operator()(const T &f) const
86  {
87  return f;
88  }
89 };
90 
91 inline namespace impl
92 {
93 
94 template <typename To, typename From>
95 using sc_int_int_enabler = enable_if_t<conjunction<std::is_integral<To>, std::is_integral<From>>::value>;
96 }
97 
99 
102 template <typename To, typename From>
103 struct safe_cast_impl<To, From, sc_int_int_enabler<To, From>> {
105 
115  To operator()(const From &f) const
116  {
117  try {
118  return boost::numeric_cast<To>(f);
119  } catch (...) {
120  piranha_throw(safe_cast_failure, "the integral value " + std::to_string(f)
121  + " cannot be converted to the type '" + detail::demangle<To>()
122  + "', as the conversion cannot preserve the original value");
123  }
124  }
125 };
126 
127 inline namespace impl
128 {
129 
130 template <typename To, typename From>
131 using sc_float_to_int_enabler = enable_if_t<conjunction<std::is_integral<To>, std::is_floating_point<From>>::value>;
132 }
133 
135 
139 template <typename To, typename From>
140 struct safe_cast_impl<To, From, sc_float_to_int_enabler<To, From>> {
142 
154  To operator()(const From &f) const
155  {
156  if (unlikely(!std::isfinite(f))) {
157  piranha_throw(safe_cast_failure, "the non-finite floating-point value " + std::to_string(f)
158  + " cannot be converted to the integral type '"
159  + detail::demangle<To>() + "'");
160  }
161  if (std::trunc(f) != f) {
162  piranha_throw(safe_cast_failure, "the floating-point value with nonzero fractional part "
163  + std::to_string(f) + " cannot be converted to the integral type '"
164  + detail::demangle<To>()
165  + "', as the conversion cannot preserve the original value");
166  }
167  try {
168  return boost::numeric_cast<To>(f);
169  } catch (...) {
170  piranha_throw(safe_cast_failure, "the floating-point value " + std::to_string(f)
171  + " cannot be converted to the integral type '"
172  + detail::demangle<To>()
173  + "', as the conversion cannot preserve the original value");
174  }
175  }
176 };
177 
178 inline namespace impl
179 {
180 
181 template <typename To, typename From>
182 using safe_cast_t_ = decltype(safe_cast_impl<uncvref_t<To>, From>{}(std::declval<const From &>()));
183 
184 template <typename To, typename From>
185 using safe_cast_type
186  = enable_if_t<conjunction<std::is_same<safe_cast_t_<To, From>, uncvref_t<To>>, is_returnable<uncvref_t<To>>>::value,
187  uncvref_t<To>>;
188 }
189 
191 
218 template <typename To, typename From>
219 inline safe_cast_type<To, From> safe_cast(const From &x)
220 {
221  return safe_cast_impl<uncvref_t<To>, From>{}(x);
222 }
223 
224 inline namespace impl
225 {
226 
227 template <typename To, typename From>
228 using safe_cast_t = decltype(safe_cast<To>(std::declval<From>()));
229 }
230 
232 
236 template <typename To, typename From>
238 {
239  static const bool implementation_defined = is_detected<safe_cast_t, To, From>::value;
240 
241 public:
243  static const bool value = implementation_defined;
244 };
245 
246 // Static init.
247 template <typename To, typename From>
248 const bool has_safe_cast<To, From>::value;
249 }
250 
251 #endif
Exceptions.
#define piranha_throw(exception_type,...)
Exception-throwing macro.
Definition: exceptions.hpp:118
Default implementation of piranha::safe_cast().
Definition: safe_cast.hpp:63
Root piranha namespace.
Definition: array_key.hpp:52
Type traits.
To operator()(const T &f) const
Call operator.
Definition: safe_cast.hpp:85
static const bool value
Value of the type trait.
Definition: safe_cast.hpp:243
Type trait to detect piranha::safe_cast().
Definition: safe_cast.hpp:237
Exception to signal failure in piranha::safe_cast().
Definition: safe_cast.hpp:53
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
Definition: safe_cast.hpp:219