The Battle for Wesnoth  1.19.16+dev
lexical_cast.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2025
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 #include "utils/optional_fwd.hpp"
47 
48 #include <limits>
49 #include <string>
50 #include <sstream>
51 #include <type_traits>
52 
53 #define DEBUG_THROW(id)
54 #endif
55 
56 /**
57  * @namespace implementation
58  * Contains the implementation details for lexical_cast and shouldn't be used
59  * directly.
60  */
61 namespace implementation {
62 
63  template<
64  typename To
65  , typename From
66  , typename ToEnable = void
67  , typename FromEnable = void
68  >
69  struct lexical_caster;
70 
71 } // namespace implementation
72 
73 /**
74  * Lexical cast converts one type to another.
75  *
76  * @tparam To The type to convert to.
77  * @tparam From The type to convert from.
78  *
79  * @param value The value to convert.
80  *
81  * @returns The converted value.
82  *
83  * @throw bad_lexical_cast if the cast was unsuccessful.
84  */
85 template<typename To, typename From>
86 inline To lexical_cast(From value)
87 {
88  return implementation::lexical_caster<To, From>().operator()(value, utils::nullopt);
89 }
90 
91 /**
92  * Lexical cast converts one type to another with a fallback.
93  *
94  * @tparam To The type to convert to.
95  * @tparam From The type to convert from.
96  *
97  * @param value The value to convert.
98  * @param fallback The fallback value to return if the cast fails.
99  *
100  * @returns The converted value.
101  */
102 template<typename To, typename From>
103 inline To lexical_cast_default(From value, To fallback = To())
104 {
105  return implementation::lexical_caster<To, From>().operator()(value, fallback);
106 }
107 
108 /** Thrown when a lexical_cast fails. */
109 struct bad_lexical_cast : std::exception
110 {
111  const char* what() const noexcept
112  {
113  return "bad_lexical_cast";
114  }
115 };
116 
117 namespace implementation {
118 
119 /**
120  * Base class for the conversion.
121  *
122  * Since functions can't be partially specialized we use a class, which can be
123  * partially specialized for the conversion.
124  *
125  * @tparam To The type to convert to.
126  * @tparam From The type to convert from.
127  * @tparam ToEnable Filter to enable the To type.
128  * @tparam FromEnable Filter to enable the From type.
129  */
130 template<
131  typename To
132  , typename From
133  , typename ToEnable
134  , typename FromEnable
135 >
137 {
138  To operator()(From value, utils::optional<To> fallback) const
139  {
140  DEBUG_THROW("generic");
141 
142  To result = To();
143  std::stringstream sstr;
144 
145  if(!(sstr << value && sstr >> result)) {
146  if(fallback) { return *fallback; }
147 
148  throw bad_lexical_cast();
149  } else {
150  return result;
151  }
152  }
153 };
154 
155 /**
156  * Specialized conversion class.
157  *
158  * Specialized for returning strings from an integral type or a pointer to an
159  * integral type.
160  */
161 template <typename From>
163  std::string
164  , From
165  , void
166  , std::enable_if_t<std::is_arithmetic_v<From>>
167 >
168 {
169  std::string operator()(From value, utils::optional<std::string>) const
170  {
171  DEBUG_THROW("specialized - To std::string - From arithmetic");
172  if constexpr (std::is_same_v<bool, From>) {
173  return value ? "1" : "0";
174  } else {
175  return utils::charconv_buffer<From>(value).to_string();
176  }
177  }
178 };
179 
180 
181 
182 /**
183  * Specialized conversion class.
184  *
185  * @note is specialized to silence C4804 from MSVC.
186  */
187 template <>
189  bool
190  , std::string_view
191  , void
192  , void
193 >
194 {
195  bool operator()(std::string_view str, utils::optional<bool> fallback) const
196  {
197  DEBUG_THROW("specialized - To bool - From string");
199  if(str == "1") {
200  return true;
201  } else if(str == "0") {
202  return false;
203  } else if (fallback) {
204  return *fallback;
205  } else {
206  throw bad_lexical_cast();
207  }
208  }
209 };
210 
211 /**
212  * Specialized conversion class.
213  *
214  * Specialized for returning arithmetic from a string_view, also used by std::string and (const) char*
215  */
216 template <typename To>
218  To
219  , std::string_view
220  , std::enable_if_t<std::is_arithmetic_v<To>>
221  , void
222 >
223 {
224  To operator()(std::string_view str, utils::optional<To> fallback) const
225  {
226  DEBUG_THROW("specialized - To arithmetic - From string");
227 
228  To res = To();
229 
231 
232  auto [ptr, ec] = utils::charconv::from_chars(str.data(), str.data() + str.size(), res);
233  if(ec == std::errc()) {
234  return res;
235  } else if(fallback){
236  return *fallback;
237  } else {
238  throw bad_lexical_cast();
239  }
240  }
241 };
242 
243 /**
244  * Specialized conversion class.
245  *
246  * Specialized for returning arithmetic from a std::string
247  */
248 template <typename To>
250  To
251  , std::string
252  , std::enable_if_t<std::is_arithmetic_v<To>>
253  , void
254 >
255 {
256  To operator()(const std::string& value, utils::optional<To> fallback) const
257  {
258  // Dont DEBUG_THROW. the test shodul test what actual implementaiton is used in the end, not which specialazion that jsut forwards to another
259  if(fallback) {
260  return lexical_cast_default<To>(std::string_view(value), *fallback);
261  } else {
262  return lexical_cast<To>(std::string_view(value));
263  }
264  }
265 };
266 
267 
268 /**
269  * Specialized conversion class.
270  *
271  * Specialized for returning arithmetic from a (const) char*.
272  */
273 template <class To, class From>
275  To
276  , From
277  , std::enable_if_t<std::is_arithmetic_v<To> >
278  , std::enable_if_t<std::is_same_v<From, const char*> || std::is_same_v<From, char*> >
279 >
280 {
281  To operator()(const std::string& value, utils::optional<To> fallback) const
282  {
283  // Dont DEBUG_THROW. the test shodul test what actual implementaiton is used in the end, not which specialazion that jsut forwards to another
284  if(fallback) {
285  return lexical_cast_default<To>(std::string_view(value), *fallback);
286  } else {
287  return lexical_cast<To>(std::string_view(value));
288  }
289  }
290 };
291 
292 } // namespace implementation
293 
294 #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 >, std::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