The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
lexical_cast.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * New lexcical_cast header.
18  *
19  * For debugging you can include this header _in_ a namespace (to honor ODR)
20  * and have a set of functions that throws exceptions instead of doing the
21  * real job. This is done for the unit tests but should normally not be done.
22  */
23 
24 #ifdef LEXICAL_CAST_DEBUG
25 #undef LEXICAL_CAST_HPP_INCLUDED
26 #endif
27 
28 #ifndef LEXICAL_CAST_HPP_INCLUDED
29 #define LEXICAL_CAST_HPP_INCLUDED
30 
31 #ifdef LEXICAL_CAST_DEBUG
32 
33 #undef DEBUG_THROW
34 /**
35  * Throws an exception for debugging.
36  *
37  * @param id The unique name to identify the function.
38  * @note this name is a user defined string and
39  * should not be modified once used!
40  */
41 #define DEBUG_THROW(id) throw id;
42 #else
43 
44 #ifdef __FreeBSD__
45 #define __LONG_LONG_SUPPORTED
46 #endif
47 
48 #include "global.hpp"
49 
51 
52 #include <cstdlib>
53 #include <limits>
54 #include <string>
55 #include <sstream>
56 #include <type_traits>
57 
58 #include <boost/mpl/set.hpp>
59 #include <boost/optional.hpp>
60 
61 #define DEBUG_THROW(id)
62 #endif
63 
64 /**
65  * @namespace implementation
66  * Contains the implementation details for lexical_cast and shouldn't be used
67  * directly.
68  */
69 namespace implementation {
70 
71  template<
72  typename To
73  , typename From
74  , typename ToEnable = void
75  , typename FromEnable = void
76  >
78 
79 } // namespace implementation
80 
81 /**
82  * Lexical cast converts one type to another.
83  *
84  * @tparam To The type to convert to.
85  * @tparam From The type to convert from.
86  *
87  * @param value The value to convert.
88  *
89  * @returns The converted value.
90  *
91  * @throw bad_lexical_cast if the cast was unsuccessful.
92  */
93 template<typename To, typename From>
94 inline To lexical_cast(From value)
95 {
96  return implementation::lexical_caster<To, From>().operator()(value, boost::none);
97 }
98 
99 /**
100  * Lexical cast converts one type to another with a fallback.
101  *
102  * @tparam To The type to convert to.
103  * @tparam From The type to convert from.
104  *
105  * @param value The value to convert.
106  * @param fallback The fallback value to return if the cast fails.
107  *
108  * @returns The converted value.
109  */
110 template<typename To, typename From>
111 inline To lexical_cast_default(From value, To fallback = To())
112 {
113  return implementation::lexical_caster<To, From>().operator()(value, fallback);
114 }
115 
116 /** Thrown when a lexical_cast fails. */
117 struct bad_lexical_cast : std::exception
118 {
119  const char* what() const NOEXCEPT
120  {
121  return "bad_lexical_cast";
122  }
123 };
124 
125 namespace implementation {
126 
127 /**
128  * Base class for the conversion.
129  *
130  * Since functions can't be partially specialized we use a class, which can be
131  * partially specialized for the conversion.
132  *
133  * @tparam To The type to convert to.
134  * @tparam From The type to convert from.
135  * @tparam ToEnable Filter to enable the To type.
136  * @tparam FromEnable Filter to enable the From type.
137  */
138 template<
139  typename To
140  , typename From
141  , typename ToEnable
142  , typename FromEnable
143 >
144 struct lexical_caster
145 {
146  To operator()(From value, boost::optional<To> fallback) const
147  {
148  DEBUG_THROW("generic");
149 
150  To result = To();
151  std::stringstream sstr;
152 
153  if(!(sstr << value && sstr >> result)) {
154  if(fallback) { return fallback.get(); }
155 
156  throw bad_lexical_cast();
157  } else {
158  return result;
159  }
160  }
161 };
162 
163 /**
164  * Specialized conversion class.
165  *
166  * Specialized for returning strings from an integral type or a pointer to an
167  * integral type.
168  */
169 template <typename From>
171  std::string
172  , From
173  , void
174  , utils::enable_if_t<std::is_integral<utils::remove_pointer_t<From>>::value>
175 >
176 {
177  std::string operator()(From value, boost::optional<std::string>) const
178  {
179  DEBUG_THROW("specialized - To std::string - From integral (pointer)");
180 
181  std::stringstream sstr;
182  sstr << value;
183  return sstr.str();
184  }
185 };
186 
187 /**
188  * Specialized conversion class.
189  *
190  * Specialized for returning a long long from a (const) char*.
191  * @note is separate from the other signed types since a long long has a
192  * performance penalty at 32 bit systems.
193  */
194 template <class From>
196  long long
197  , From
198  , void
199  , utils::enable_if_t<boost::mpl::has_key<boost::mpl::set<char*, const char*> , From>::value>
200  >
201 {
202  long long operator()(From value, boost::optional<long long> fallback) const
203  {
204  DEBUG_THROW("specialized - To long long - From (const) char*");
205 
206  if(fallback) {
207  return lexical_cast_default<long long>(std::string(value), fallback.get());
208  } else {
209  return lexical_cast<long long>(std::string(value));
210  }
211  }
212 };
213 
214 /**
215  * Specialized conversion class.
216  *
217  * Specialized for returning a long long from a std::string.
218  * @note is separate from the other signed types since a long long has a
219  * performance penalty at 32 bit systems.
220  */
221 template <>
223  long long
224  , std::string
225  >
226 {
227  long long operator()(const std::string& value, boost::optional<long long> fallback) const
228  {
229  DEBUG_THROW("specialized - To long long - From std::string");
230 
231  try {
232  return std::stoll(value);
233  } catch(std::invalid_argument&) {
234  } catch(std::out_of_range&) {
235  }
236 
237  if(fallback) {
238  return fallback.get();
239  } else {
240  throw bad_lexical_cast();
241  }
242  }
243 };
244 
245 /**
246  * Specialized conversion class.
247  *
248  * Specialized for returning a signed type from a (const) char*.
249  */
250 template <class To, class From>
252  To
253  , From
254  , utils::enable_if_t<std::is_integral<To>::value && std::is_signed<To>::value && !std::is_same<To, long long>::value>
255  , utils::enable_if_t<boost::mpl::has_key<boost::mpl::set<char*, const char*> , From>::value>
256  >
257 {
258  To operator()(From value, boost::optional<To> fallback) const
259  {
260  DEBUG_THROW("specialized - To signed - From (const) char*");
261 
262  if(fallback) {
263  return lexical_cast_default<To>(std::string(value), fallback.get());
264  } else {
265  return lexical_cast<To>(std::string(value));
266  }
267  }
268 };
269 
270 /**
271  * Specialized conversion class.
272  *
273  * Specialized for returning a signed type from a std::string.
274  */
275 template <class To>
277  To
278  , std::string
279  , utils::enable_if_t<std::is_integral<To>::value && std::is_signed<To>::value && !std::is_same<To, long long>::value>
280  >
281 {
282  To operator()(const std::string& value, boost::optional<To> fallback) const
283  {
284  DEBUG_THROW("specialized - To signed - From std::string");
285 
286  try {
287  long res = std::stol(value);
288  if(std::numeric_limits<To>::lowest() <= res && std::numeric_limits<To>::max() >= res) {
289  return static_cast<To>(res);
290  }
291  } catch(std::invalid_argument&) {
292  } catch(std::out_of_range&) {
293  }
294 
295  if(fallback) {
296  return fallback.get();
297  } else {
298  throw bad_lexical_cast();
299  }
300  }
301 };
302 
303 /**
304  * Specialized conversion class.
305  *
306  * Specialized for returning a floating point type from a (const) char*.
307  */
308 template <class To, class From>
310  To
311  , From
312  , utils::enable_if_t<std::is_floating_point<To>::value>
313  , utils::enable_if_t<boost::mpl::has_key<boost::mpl::set<char*, const char*> , From>::value>
314  >
315 {
316  To operator()(From value, boost::optional<To> fallback) const
317  {
318  DEBUG_THROW("specialized - To floating point - From (const) char*");
319 
320  if(fallback) {
321  return lexical_cast_default<To>(std::string(value), fallback.get());
322  } else {
323  return lexical_cast<To>(std::string(value));
324  }
325  }
326 };
327 
328 /**
329  * Specialized conversion class.
330  *
331  * Specialized for returning a floating point type from a std::string.
332  */
333 template <class To>
335  To
336  , std::string
337  , utils::enable_if_t<std::is_floating_point<To>::value>
338  >
339 {
340  To operator()(const std::string& value, boost::optional<To> fallback) const
341  {
342  DEBUG_THROW("specialized - To floating point - From std::string");
343 
344  // Explicitly reject hexadecimal values. Unit tests of the config class require that.
345  if(value.find_first_of("Xx") != std::string::npos) {
346  if(fallback) {
347  return fallback.get();
348  } else {
349  throw bad_lexical_cast();
350  }
351  }
352 
353  try {
354  long double res = std::stold(value);
355  if((static_cast<long double>(std::numeric_limits<To>::lowest()) <= res) && (static_cast<long double>(std::numeric_limits<To>::max()) >= res)) {
356  return static_cast<To>(res);
357  }
358  } catch(std::invalid_argument&) {
359  } catch(std::out_of_range&) {
360  }
361 
362  if(fallback) {
363  return fallback.get();
364  } else {
365  throw bad_lexical_cast();
366  }
367  }
368 };
369 
370 /**
371  * Specialized conversion class.
372  *
373  * Specialized for returning a unsigned long long from a (const) char*.
374  * @note is separate from the other unsigned types since a unsigned long long
375  * has a performance penalty at 32 bit systems.
376  */
377 template <class From>
379  unsigned long long
380  , From
381  , void
382  , utils::enable_if_t<boost::mpl::has_key<boost::mpl::set<char*, const char*> , From>::value>
383  >
384 {
385  unsigned long long operator()(From value, boost::optional<unsigned long long> fallback) const
386  {
387  DEBUG_THROW(
388  "specialized - To unsigned long long - From (const) char*");
389 
390  if(fallback) {
391  return lexical_cast_default<unsigned long long>(std::string(value), fallback.get());
392  } else {
393  return lexical_cast<unsigned long long>(std::string(value));
394  }
395  }
396 };
397 
398 /**
399  * Specialized conversion class.
400  *
401  * Specialized for returning a unsigned long long from a std::string.
402  * @note is separate from the other unsigned types since a unsigned long long
403  * has a performance penalty at 32 bit systems.
404  */
405 template <>
407  unsigned long long
408  , std::string
409  >
410 {
411  unsigned long long operator()(const std::string& value, boost::optional<unsigned long long> fallback) const
412  {
413  DEBUG_THROW("specialized - To unsigned long long - From std::string");
414 
415  try {
416  return std::stoull(value);
417  } catch(std::invalid_argument&) {
418  } catch(std::out_of_range&) {
419  }
420 
421  if(fallback) {
422  return fallback.get();
423  } else {
424  throw bad_lexical_cast();
425  }
426  }
427 };
428 
429 /**
430  * Specialized conversion class.
431  *
432  * Specialized for returning a unsigned type from a (const) char*.
433  */
434 template <class To, class From>
436  To
437  , From
438  , utils::enable_if_t<std::is_unsigned<To>::value && !std::is_same<To, unsigned long long>::value>
439  , utils::enable_if_t<boost::mpl::has_key<boost::mpl::set<char*, const char*> , From>::value>
440  >
441 {
442  To operator()(From value, boost::optional<To> fallback) const
443  {
444  DEBUG_THROW("specialized - To unsigned - From (const) char*");
445 
446  if(fallback) {
447  return lexical_cast_default<To>(std::string(value), fallback.get());
448  } else {
449  return lexical_cast<To>(std::string(value));
450  }
451  }
452 };
453 
454 /**
455  * Specialized conversion class.
456  *
457  * Specialized for returning a unsigned type from a std::string.
458  */
459 template <class To>
461  To
462  , std::string
463  , utils::enable_if_t<std::is_unsigned<To>::value>
464  >
465 {
466  To operator()(const std::string& value, boost::optional<To> fallback) const
467  {
468  DEBUG_THROW("specialized - To unsigned - From std::string");
469 
470  try {
471  unsigned long res = std::stoul(value);
472  // No need to check the lower bound, it's zero for all unsigned types.
473  if(std::numeric_limits<To>::max() >= res) {
474  return static_cast<To>(res);
475  }
476  } catch(std::invalid_argument&) {
477  } catch(std::out_of_range&) {
478  }
479 
480  if(fallback) {
481  return fallback.get();
482  } else {
483  throw bad_lexical_cast();
484  }
485  }
486 };
487 
488 } // namespace implementation
489 
490 #endif
491 
std::vector< char_t > string
To lexical_cast_default(From value, To fallback=To())
Lexical cast converts one type to another with a fallback.
#define DEBUG_THROW(id)
Throws an exception for debugging.
STL namespace.
Base class for the conversion.
To lexical_cast(From value)
Lexical cast converts one type to another.
const char * what() const NOEXCEPT
long long operator()(const std::string &value, boost::optional< long long > fallback) const
unsigned long long operator()(const std::string &value, boost::optional< unsigned long long > fallback) const
typename std::enable_if< B, T >::type enable_if_t
std::string operator()(From value, boost::optional< std::string >) const
To operator()(From value, boost::optional< To > fallback) const
Thrown when a lexical_cast fails.
Contains the implementation details for lexical_cast and shouldn't be used directly.
To operator()(const std::string &value, boost::optional< To > fallback) const