The Battle for Wesnoth  1.19.9+dev
charconv.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2024 - 2025
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 #include "utils/charconv.hpp"
16 
17 #include <cassert>
18 #include <cctype>
19 #include <clocale>
20 #include <cstdlib>
21 #include <string>
22 
23 #ifdef USE_FALLBACK_CHARCONV
24 
25 namespace
26 {
27  template<typename T>
28  T string_to_floating_point(const char* str, char** str_end) = delete;
29  template<>
30  float string_to_floating_point(const char* str, char** str_end)
31  {
32  return std::strtof(str, str_end);
33  }
34  template<>
35  double string_to_floating_point(const char* str, char** str_end)
36  {
37  return std::strtod(str, str_end);
38  }
39  template<>
40  long double string_to_floating_point(const char* str, char** str_end)
41  {
42  return std::strtold(str, str_end);
43  }
44 }
45 namespace utils::charconv
46 {
47  template<typename T>
48  std::enable_if_t<std::is_same_v<T, double> || std::is_same_v<T, float> || std::is_same_v<T, long double>, from_chars_result> from_chars(const char* first, const char* last, T& value, chars_format fmt)
49  {
50  // We don't need the other formats.
51  assert(fmt == chars_format::general);
52 
53  // Make a copy to make sure its null terminated.
54  std::string buffer = std::string(first, last);
55  // from_chars doesnt support leading whitespace or plus signs.
56  if(buffer.empty() || std::isspace(buffer.front()) || buffer.front() == '+' ) {
57  return { first, std::errc::invalid_argument };
58  }
59 
60 
61  locale_t l = newlocale(LC_ALL, "C", static_cast<locale_t>(0));
62  locale_t l_prev = uselocale(l);
63 
64  //initilize this to silence a warning.
65  char* str_end = nullptr;
66  value = string_to_floating_point<T>( buffer.data(), &str_end );
67 
68  uselocale(l_prev);
69  freelocale(l);
70 
71  if(str_end == buffer.data()) {
72  return { first, std::errc::invalid_argument };
73  }
74  return { first + (str_end - buffer.data()), std::errc() };
75  }
76  template from_chars_result from_chars(const char* first, const char* last, float& value, chars_format fmt);
77  template from_chars_result from_chars(const char* first, const char* last, double& value, chars_format fmt);
78  template from_chars_result from_chars(const char* first, const char* last, long double& value, chars_format fmt);
79 }
80 
81 #endif
log_domain & general()
Definition: log.cpp:333
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
charconv_impl::from_chars_result from_chars_result
Definition: charconv.hpp:51
charconv_impl::chars_format chars_format
Definition: charconv.hpp:50