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