The Battle for Wesnoth  1.15.0-dev
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 https://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 
50 #include <cstdlib>
51 #include <limits>
52 #include <string>
53 #include <sstream>
54 #include <type_traits>
55 
56 #include <boost/optional.hpp>
57 
58 #define DEBUG_THROW(id)
59 #endif
60 
61 /**
62  * @namespace implementation
63  * Contains the implementation details for lexical_cast and shouldn't be used
64  * directly.
65  */
66 namespace implementation {
67 
68  template<
69  typename To
70  , typename From
71  , typename ToEnable = void
72  , typename FromEnable = void
73  >
75 
76 } // namespace implementation
77 
78 /**
79  * Lexical cast converts one type to another.
80  *
81  * @tparam To The type to convert to.
82  * @tparam From The type to convert from.
83  *
84  * @param value The value to convert.
85  *
86  * @returns The converted value.
87  *
88  * @throw bad_lexical_cast if the cast was unsuccessful.
89  */
90 template<typename To, typename From>
91 inline To lexical_cast(From value)
92 {
93  return implementation::lexical_caster<To, From>().operator()(value, boost::none);
94 }
95 
96 /**
97  * Lexical cast converts one type to another with a fallback.
98  *
99  * @tparam To The type to convert to.
100  * @tparam From The type to convert from.
101  *
102  * @param value The value to convert.
103  * @param fallback The fallback value to return if the cast fails.
104  *
105  * @returns The converted value.
106  */
107 template<typename To, typename From>
108 inline To lexical_cast_default(From value, To fallback = To())
109 {
110  return implementation::lexical_caster<To, From>().operator()(value, fallback);
111 }
112 
113 /** Thrown when a lexical_cast fails. */
114 struct bad_lexical_cast : std::exception
115 {
116  const char* what() const noexcept
117  {
118  return "bad_lexical_cast";
119  }
120 };
121 
122 namespace implementation {
123 
124 /**
125  * Base class for the conversion.
126  *
127  * Since functions can't be partially specialized we use a class, which can be
128  * partially specialized for the conversion.
129  *
130  * @tparam To The type to convert to.
131  * @tparam From The type to convert from.
132  * @tparam ToEnable Filter to enable the To type.
133  * @tparam FromEnable Filter to enable the From type.
134  */
135 template<
136  typename To
137  , typename From
138  , typename ToEnable
139  , typename FromEnable
140 >
141 struct lexical_caster
142 {
143  To operator()(From value, boost::optional<To> fallback) const
144  {
145  DEBUG_THROW("generic");
146 
147  To result = To();
148  std::stringstream sstr;
149 
150  if(!(sstr << value && sstr >> result)) {
151  if(fallback) { return fallback.get(); }
152 
153  throw bad_lexical_cast();
154  } else {
155  return result;
156  }
157  }
158 };
159 
160 /**
161  * Specialized conversion class.
162  *
163  * Specialized for returning strings from an integral type or a pointer to an
164  * integral type.
165  */
166 template <typename From>
168  std::string
169  , From
170  , void
171  , std::enable_if_t<std::is_integral<std::remove_pointer_t<From>>::value>
172 >
173 {
174  std::string operator()(From value, boost::optional<std::string>) const
175  {
176  DEBUG_THROW("specialized - To std::string - From integral (pointer)");
177 
178  std::stringstream sstr;
179  sstr << value;
180  return sstr.str();
181  }
182 };
183 
184 /**
185  * Specialized conversion class.
186  *
187  * Specialized for returning a long long from a (const) char*.
188  * @note is separate from the other signed types since a long long has a
189  * performance penalty at 32 bit systems.
190  */
191 template <class From>
193  long long
194  , From
195  , void
196  , std::enable_if_t<std::is_same<char, std::remove_const_t<std::remove_pointer_t<From>>>::value>
197  >
198 {
199  long long operator()(From value, boost::optional<long long> fallback) const
200  {
201  DEBUG_THROW("specialized - To long long - From (const) char*");
202 
203  if(fallback) {
204  return lexical_cast_default<long long>(std::string(value), fallback.get());
205  } else {
206  return lexical_cast<long long>(std::string(value));
207  }
208  }
209 };
210 
211 /**
212  * Specialized conversion class.
213  *
214  * Specialized for returning a long long from a std::string.
215  * @note is separate from the other signed types since a long long has a
216  * performance penalty at 32 bit systems.
217  */
218 template <>
220  long long
221  , std::string
222  >
223 {
224  long long operator()(const std::string& value, boost::optional<long long> fallback) const
225  {
226  DEBUG_THROW("specialized - To long long - From std::string");
227 
228  try {
229  return std::stoll(value);
230  } catch(const std::invalid_argument&) {
231  } catch(const std::out_of_range&) {
232  }
233 
234  if(fallback) {
235  return fallback.get();
236  } else {
237  throw bad_lexical_cast();
238  }
239  }
240 };
241 
242 /**
243  * Specialized conversion class.
244  *
245  * Specialized for returning a signed type from a (const) char*.
246  */
247 template <class To, class From>
249  To
250  , From
251  , std::enable_if_t<std::is_integral<To>::value && std::is_signed<To>::value && !std::is_same<To, long long>::value>
252  , std::enable_if_t<std::is_same<char, std::remove_const_t<std::remove_pointer_t<From>>>::value>
253  >
254 {
255  To operator()(From value, boost::optional<To> fallback) const
256  {
257  DEBUG_THROW("specialized - To signed - From (const) char*");
258 
259  if(fallback) {
260  return lexical_cast_default<To>(std::string(value), fallback.get());
261  } else {
262  return lexical_cast<To>(std::string(value));
263  }
264  }
265 };
266 
267 /**
268  * Specialized conversion class.
269  *
270  * Specialized for returning a signed type from a std::string.
271  */
272 template <class To>
274  To
275  , std::string
276  , std::enable_if_t<std::is_integral<To>::value && std::is_signed<To>::value && !std::is_same<To, long long>::value>
277  >
278 {
279  To operator()(const std::string& value, boost::optional<To> fallback) const
280  {
281  DEBUG_THROW("specialized - To signed - From std::string");
282 
283  try {
284  long res = std::stol(value);
285  if(std::numeric_limits<To>::lowest() <= res && std::numeric_limits<To>::max() >= res) {
286  return static_cast<To>(res);
287  }
288  } catch(const std::invalid_argument&) {
289  } catch(const std::out_of_range&) {
290  }
291 
292  if(fallback) {
293  return fallback.get();
294  } else {
295  throw bad_lexical_cast();
296  }
297  }
298 };
299 
300 /**
301  * Specialized conversion class.
302  *
303  * Specialized for returning a floating point type from a (const) char*.
304  */
305 template <class To, class From>
307  To
308  , From
309  , std::enable_if_t<std::is_floating_point<To>::value>
310  , std::enable_if_t<std::is_same<char, std::remove_const_t<std::remove_pointer_t<From>>>::value>
311  >
312 {
313  To operator()(From value, boost::optional<To> fallback) const
314  {
315  DEBUG_THROW("specialized - To floating point - From (const) char*");
316 
317  if(fallback) {
318  return lexical_cast_default<To>(std::string(value), fallback.get());
319  } else {
320  return lexical_cast<To>(std::string(value));
321  }
322  }
323 };
324 
325 /**
326  * Specialized conversion class.
327  *
328  * Specialized for returning a floating point type from a std::string.
329  */
330 template <class To>
332  To
333  , std::string
334  , std::enable_if_t<std::is_floating_point<To>::value>
335  >
336 {
337  To operator()(const std::string& value, boost::optional<To> fallback) const
338  {
339  DEBUG_THROW("specialized - To floating point - From std::string");
340 
341  // Explicitly reject hexadecimal values. Unit tests of the config class require that.
342  if(value.find_first_of("Xx") != std::string::npos) {
343  if(fallback) {
344  return fallback.get();
345  } else {
346  throw bad_lexical_cast();
347  }
348  }
349 
350  try {
351  long double res = std::stold(value);
352  if((static_cast<long double>(std::numeric_limits<To>::lowest()) <= res) && (static_cast<long double>(std::numeric_limits<To>::max()) >= res)) {
353  return static_cast<To>(res);
354  }
355  } catch(const std::invalid_argument&) {
356  } catch(const std::out_of_range&) {
357  }
358 
359  if(fallback) {
360  return fallback.get();
361  } else {
362  throw bad_lexical_cast();
363  }
364  }
365 };
366 
367 /**
368  * Specialized conversion class.
369  *
370  * Specialized for returning a unsigned long long from a (const) char*.
371  * @note is separate from the other unsigned types since a unsigned long long
372  * has a performance penalty at 32 bit systems.
373  */
374 template <class From>
376  unsigned long long
377  , From
378  , void
379  , std::enable_if_t<std::is_same<char, std::remove_const_t<std::remove_pointer_t<From>>>::value>
380  >
381 {
382  unsigned long long operator()(From value, boost::optional<unsigned long long> fallback) const
383  {
384  DEBUG_THROW(
385  "specialized - To unsigned long long - From (const) char*");
386 
387  if(fallback) {
388  return lexical_cast_default<unsigned long long>(std::string(value), fallback.get());
389  } else {
390  return lexical_cast<unsigned long long>(std::string(value));
391  }
392  }
393 };
394 
395 /**
396  * Specialized conversion class.
397  *
398  * Specialized for returning a unsigned long long from a std::string.
399  * @note is separate from the other unsigned types since a unsigned long long
400  * has a performance penalty at 32 bit systems.
401  */
402 template <>
404  unsigned long long
405  , std::string
406  >
407 {
408  unsigned long long operator()(const std::string& value, boost::optional<unsigned long long> fallback) const
409  {
410  DEBUG_THROW("specialized - To unsigned long long - From std::string");
411 
412  try {
413  return std::stoull(value);
414  } catch(const std::invalid_argument&) {
415  } catch(const std::out_of_range&) {
416  }
417 
418  if(fallback) {
419  return fallback.get();
420  } else {
421  throw bad_lexical_cast();
422  }
423  }
424 };
425 
426 /**
427  * Specialized conversion class.
428  *
429  * Specialized for returning a unsigned type from a (const) char*.
430  */
431 template <class To, class From>
433  To
434  , From
435  , std::enable_if_t<std::is_unsigned<To>::value && !std::is_same<To, unsigned long long>::value>
436  , std::enable_if_t<std::is_same<char, std::remove_const_t<std::remove_pointer_t<From>>>::value>
437  >
438 {
439  To operator()(From value, boost::optional<To> fallback) const
440  {
441  DEBUG_THROW("specialized - To unsigned - From (const) char*");
442 
443  if(fallback) {
444  return lexical_cast_default<To>(std::string(value), fallback.get());
445  } else {
446  return lexical_cast<To>(std::string(value));
447  }
448  }
449 };
450 
451 /**
452  * Specialized conversion class.
453  *
454  * Specialized for returning a unsigned type from a std::string.
455  */
456 template <class To>
458  To
459  , std::string
460  , std::enable_if_t<std::is_unsigned<To>::value>
461  >
462 {
463  To operator()(const std::string& value, boost::optional<To> fallback) const
464  {
465  DEBUG_THROW("specialized - To unsigned - From std::string");
466 
467  try {
468  unsigned long res = std::stoul(value);
469  // No need to check the lower bound, it's zero for all unsigned types.
470  if(std::numeric_limits<To>::max() >= res) {
471  return static_cast<To>(res);
472  }
473  } catch(const std::invalid_argument&) {
474  } catch(const std::out_of_range&) {
475  }
476 
477  if(fallback) {
478  return fallback.get();
479  } else {
480  throw bad_lexical_cast();
481  }
482  }
483 };
484 
485 } // namespace implementation
486 
487 #endif
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.
To operator()(From value, boost::optional< To > fallback) const
std::string operator()(From value, boost::optional< std::string >) const
unsigned long long operator()(const std::string &value, boost::optional< unsigned long long > fallback) const
const char * what() const noexcept
To operator()(const std::string &value, boost::optional< To > fallback) const
long long operator()(const std::string &value, boost::optional< long long > fallback) const
Thrown when a lexical_cast fails.
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.