The Battle for Wesnoth  1.19.7+dev
lexical_cast.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * New lexcical_cast header.
19  *
20  * For debugging you can include this header _in_ a namespace (to honor ODR)
21  * and have a set of functions that throws exceptions instead of doing the
22  * real job. This is done for the unit tests but should normally not be done.
23  */
24 
25 #ifdef LEXICAL_CAST_DEBUG
26 #undef LEXICAL_CAST_HPP_INCLUDED
27 #endif
28 
29 #ifndef LEXICAL_CAST_HPP_INCLUDED
30 #define LEXICAL_CAST_HPP_INCLUDED
31 
32 #ifdef LEXICAL_CAST_DEBUG
33 
34 #undef DEBUG_THROW
35 /**
36  * Throws an exception for debugging.
37  *
38  * @param id The unique name to identify the function.
39  * @note this name is a user defined string and
40  * should not be modified once used!
41  */
42 #define DEBUG_THROW(id) throw id;
43 #else
44 
45 #include "utils/charconv.hpp"
46 
47 #include "utils/optional_fwd.hpp"
48 
49 #include <cstdlib>
50 #include <limits>
51 #include <string>
52 #include <sstream>
53 #include <type_traits>
54 
55 #define DEBUG_THROW(id)
56 #endif
57 
58 /**
59  * @namespace implementation
60  * Contains the implementation details for lexical_cast and shouldn't be used
61  * directly.
62  */
63 namespace implementation {
64 
65  template<
66  typename To
67  , typename From
68  , typename ToEnable = void
69  , typename FromEnable = void
70  >
71  struct lexical_caster;
72 
73 } // namespace implementation
74 
75 /**
76  * Lexical cast converts one type to another.
77  *
78  * @tparam To The type to convert to.
79  * @tparam From The type to convert from.
80  *
81  * @param value The value to convert.
82  *
83  * @returns The converted value.
84  *
85  * @throw bad_lexical_cast if the cast was unsuccessful.
86  */
87 template<typename To, typename From>
88 inline To lexical_cast(From value)
89 {
90  return implementation::lexical_caster<To, From>().operator()(value, utils::nullopt);
91 }
92 
93 /**
94  * Lexical cast converts one type to another with a fallback.
95  *
96  * @tparam To The type to convert to.
97  * @tparam From The type to convert from.
98  *
99  * @param value The value to convert.
100  * @param fallback The fallback value to return if the cast fails.
101  *
102  * @returns The converted value.
103  */
104 template<typename To, typename From>
105 inline To lexical_cast_default(From value, To fallback = To())
106 {
107  return implementation::lexical_caster<To, From>().operator()(value, fallback);
108 }
109 
110 /** Thrown when a lexical_cast fails. */
111 struct bad_lexical_cast : std::exception
112 {
113  const char* what() const noexcept
114  {
115  return "bad_lexical_cast";
116  }
117 };
118 
119 namespace implementation {
120 
121 /**
122  * Base class for the conversion.
123  *
124  * Since functions can't be partially specialized we use a class, which can be
125  * partially specialized for the conversion.
126  *
127  * @tparam To The type to convert to.
128  * @tparam From The type to convert from.
129  * @tparam ToEnable Filter to enable the To type.
130  * @tparam FromEnable Filter to enable the From type.
131  */
132 template<
133  typename To
134  , typename From
135  , typename ToEnable
136  , typename FromEnable
137 >
139 {
140  To operator()(From value, utils::optional<To> fallback) const
141  {
142  DEBUG_THROW("generic");
143 
144  To result = To();
145  std::stringstream sstr;
146 
147  if(!(sstr << value && sstr >> result)) {
148  if(fallback) { return *fallback; }
149 
150  throw bad_lexical_cast();
151  } else {
152  return result;
153  }
154  }
155 };
156 
157 /**
158  * Specialized conversion class.
159  *
160  * Specialized for returning strings from an integral type or a pointer to an
161  * integral type.
162  */
163 template <typename From>
165  std::string
166  , From
167  , void
168  , std::enable_if_t<std::is_arithmetic_v<From>>
169 >
170 {
171  std::string operator()(From value, utils::optional<std::string>) const
172  {
173  DEBUG_THROW("specialized - To std::string - From arithmetic");
174  if constexpr (std::is_same_v<bool, From>) {
175  return value ? "1" : "0";
176  } else {
177  return utils::charconv_buffer(value).to_string();
178  }
179  }
180 };
181 
182 
183 
184 /**
185  * Specialized conversion class.
186  *
187  * @note is specialized to silence C4804 from MSVC.
188  */
189 template <>
191  bool
192  , std::string_view
193  , void
194  , void
195 >
196 {
197  bool operator()(std::string_view str, utils::optional<bool> fallback) const
198  {
199  DEBUG_THROW("specialized - To bool - From string");
201  if(str == "1") {
202  return true;
203  } else if(str == "0") {
204  return false;
205  } else if (fallback) {
206  return *fallback;
207  } else {
208  throw bad_lexical_cast();
209  }
210  }
211 };
212 
213 /**
214  * Specialized conversion class.
215  *
216  * Specialized for returning arithmetic from a string_view, also used by std::string and (const) char*
217  */
218 template <typename To>
220  To
221  , std::string_view
222  , std::enable_if_t<std::is_arithmetic_v<To>>
223  , void
224 >
225 {
226  To operator()(std::string_view str, utils::optional<To> fallback) const
227  {
228  DEBUG_THROW("specialized - To arithmetic - From string");
229 
230  To res = To();
231 
233 
234  auto [ptr, ec] = utils::charconv::from_chars(str.data(), str.data() + str.size(), res);
235  if(ec == std::errc()) {
236  return res;
237  } else if(fallback){
238  return *fallback;
239  } else {
240  throw bad_lexical_cast();
241  }
242  }
243 };
244 
245 /**
246  * Specialized conversion class.
247  *
248  * Specialized for returning arithmetic from a std::string
249  */
250 template <typename To>
252  To
253  , std::string
254  , std::enable_if_t<std::is_arithmetic_v<To>>
255  , void
256 >
257 {
258  To operator()(const std::string& value, utils::optional<To> fallback) const
259  {
260  // Dont DEBUG_THROW. the test shodul test what actual implementaiton is used in the end, not which specialazion that jsut forwards to another
261  if(fallback) {
262  return lexical_cast_default<To>(std::string_view(value), *fallback);
263  } else {
264  return lexical_cast<To>(std::string_view(value));
265  }
266  }
267 };
268 
269 
270 /**
271  * Specialized conversion class.
272  *
273  * Specialized for returning arithmetic from a (const) char*.
274  */
275 template <class To, class From>
277  To
278  , From
279  , std::enable_if_t<std::is_arithmetic_v<To> >
280  , std::enable_if_t<std::is_same_v<From, const char*> || std::is_same_v<From, char*> >
281 >
282 {
283  To operator()(const std::string& value, utils::optional<To> fallback) const
284  {
285  // Dont DEBUG_THROW. the test shodul test what actual implementaiton is used in the end, not which specialazion that jsut forwards to another
286  if(fallback) {
287  return lexical_cast_default<To>(std::string_view(value), *fallback);
288  } else {
289  return lexical_cast<To>(std::string_view(value));
290  }
291  }
292 };
293 
294 } // namespace implementation
295 
296 #endif
To lexical_cast_default(From value, To fallback=To())
Lexical cast converts one type to another with a fallback.
#define DEBUG_THROW(id)
To lexical_cast(From value)
Lexical cast converts one type to another.
Contains the implementation details for lexical_cast and shouldn't be used directly.
std::enable_if_t< std::is_integral_v< T >, from_chars_result > from_chars(const char *first, const char *last, T &value, int base=10)
Definition: charconv.hpp:61
void trim_for_from_chars(std::string_view &v)
Definition: charconv.hpp:85
Thrown when a lexical_cast fails.
const char * what() const noexcept
To operator()(const std::string &value, utils::optional< To > fallback) const
bool operator()(std::string_view str, utils::optional< bool > fallback) const
std::string operator()(From value, utils::optional< std::string >) const
Base class for the conversion.
To operator()(From value, utils::optional< To > fallback) const
std::string to_string() const
Definition: charconv.hpp:132