TrinityCore
Loading...
Searching...
No Matches
StringConvert.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITY_STRINGCONVERT_H
19#define TRINITY_STRINGCONVERT_H
20
21#include "Define.h"
22#include "Errors.h"
23#include "Optional.h"
24#include "Types.h"
25#include <charconv>
26#include <string>
27#include <string_view>
28#include <type_traits>
29
30TC_COMMON_API bool StringEqualI(std::string_view str1, std::string_view str2);
31
33{
34 template <typename T, typename = void> struct For
35 {
36 static_assert(Trinity::dependant_false_v<T>, "Unsupported type used for ToString or StringTo");
37 /*
38 static Optional<T> FromString(std::string_view str, ...);
39 static std::string ToString(T&& val, ...);
40 */
41 };
42
43 template <typename T>
44 struct For<T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>>>
45 {
46 static Optional<T> FromString(std::string_view str, int base = 10)
47 {
48 if (base == 0)
49 {
50 if (StringEqualI(str.substr(0, 2), "0x"))
51 {
52 base = 16;
53 str.remove_prefix(2);
54 }
55 else if (StringEqualI(str.substr(0, 2), "0b"))
56 {
57 base = 2;
58 str.remove_prefix(2);
59 }
60 else
61 base = 10;
62
63 if (str.empty())
64 return std::nullopt;
65 }
66
67 char const* const start = str.data();
68 char const* const end = (start + str.length());
69
70 T val;
71 std::from_chars_result const res = std::from_chars(start, end, val, base);
72 if ((res.ptr == end) && (res.ec == std::errc()))
73 return val;
74 else
75 return std::nullopt;
76 }
77
78 static std::string ToString(T val)
79 {
80 using buffer_size = std::integral_constant<size_t, sizeof(T) < 8 ? 11 : 20>;
81
82 std::string buf(buffer_size::value,'\0'); /* 2^64 is 20 decimal characters, -(2^63) is 20 including the sign */
83 char* const start = buf.data();
84 char* const end = (start + buf.length());
85 std::to_chars_result const res = std::to_chars(start, end, val);
86 ASSERT(res.ec == std::errc());
87 buf.resize(res.ptr - start);
88 return buf;
89 }
90 };
91
92#ifdef TRINITY_NEED_CHARCONV_WORKAROUND
93 /*
94 If this is defined, std::from_chars will cause linkage errors for 64-bit types.
95 (This is a bug in clang-7.)
96
97 If the clang requirement is bumped to >= clang-8, remove this ifdef block and its
98 associated check in cmake/compiler/clang/settings.cmake
99 */
100 template <>
101 struct For<uint64, void>
102 {
103 static Optional<uint64> FromString(std::string_view str, int base = 10)
104 {
105 if (str.empty())
106 return std::nullopt;
107 try
108 {
109 size_t n;
110 uint64 val = std::stoull(std::string(str), &n, base);
111 if (n != str.length())
112 return std::nullopt;
113 return val;
114 }
115 catch (...) { return std::nullopt; }
116 }
117
118 static std::string ToString(uint64 val)
119 {
120 return std::to_string(val);
121 }
122 };
123
124 template <>
125 struct For<int64, void>
126 {
127 static Optional<int64> FromString(std::string_view str, int base = 10)
128 {
129 try {
130 if (str.empty())
131 return std::nullopt;
132 size_t n;
133 int64 val = std::stoll(std::string(str), &n, base);
134 if (n != str.length())
135 return std::nullopt;
136 return val;
137 }
138 catch (...) { return std::nullopt; }
139 }
140
141 static std::string ToString(int64 val)
142 {
143 return std::to_string(val);
144 }
145 };
146#endif
147
148 template <>
149 struct For<bool, void>
150 {
151 static Optional<bool> FromString(std::string_view str, int strict = 0) /* this is int to match the signature for "proper" integral types */
152 {
153 if (strict)
154 {
155 if (str == "1")
156 return true;
157 if (str == "0")
158 return false;
159 return std::nullopt;
160 }
161 else
162 {
163 if ((str == "1") || StringEqualI(str, "y") || StringEqualI(str, "on") || StringEqualI(str, "yes") || StringEqualI(str, "true"))
164 return true;
165 if ((str == "0") || StringEqualI(str, "n") || StringEqualI(str, "off") || StringEqualI(str, "no") || StringEqualI(str, "false"))
166 return false;
167 return std::nullopt;
168 }
169 }
170
171 static std::string ToString(bool val)
172 {
173 return (val ? "1" : "0");
174 }
175 };
176
177#if TRINITY_COMPILER == TRINITY_COMPILER_MICROSOFT
178 template <typename T>
179 struct For<T, std::enable_if_t<std::is_floating_point_v<T>>>
180 {
181 static Optional<T> FromString(std::string_view str, std::chars_format fmt = std::chars_format())
182 {
183 if (str.empty())
184 return std::nullopt;
185
186 if (fmt == std::chars_format())
187 {
188 if (StringEqualI(str.substr(0, 2), "0x"))
189 {
190 fmt = std::chars_format::hex;
191 str.remove_prefix(2);
192 }
193 else
194 fmt = std::chars_format::general;
195
196 if (str.empty())
197 return std::nullopt;
198 }
199
200 char const* const start = str.data();
201 char const* const end = (start + str.length());
202
203 T val;
204 std::from_chars_result const res = std::from_chars(start, end, val, fmt);
205 if ((res.ptr == end) && (res.ec == std::errc()))
206 return val;
207 else
208 return std::nullopt;
209 }
210
211 // this allows generic converters for all numeric types (easier templating!)
212 static Optional<T> FromString(std::string_view str, int base)
213 {
214 if (base == 16)
215 return FromString(str, std::chars_format::hex);
216 else if (base == 10)
217 return FromString(str, std::chars_format::general);
218 else
219 return FromString(str, std::chars_format());
220 }
221
222 static std::string ToString(T val)
223 {
224 return std::to_string(val);
225 }
226 };
227#else
228 // @todo replace this once libc++ supports double args to from_chars
229 template <typename T>
230 struct For<T, std::enable_if_t<std::is_floating_point_v<T>>>
231 {
232 static Optional<T> FromString(std::string_view str, int base = 0)
233 {
234 try {
235 if (str.empty())
236 return std::nullopt;
237
238 if ((base == 10) && StringEqualI(str.substr(0, 2), "0x"))
239 return std::nullopt;
240
241 std::string tmp;
242 if (base == 16)
243 tmp.append("0x");
244 tmp.append(str);
245
246 size_t n;
247 T val = static_cast<T>(std::stold(tmp, &n));
248 if (n != tmp.length())
249 return std::nullopt;
250 return val;
251 }
252 catch (...) { return std::nullopt; }
253 }
254
255 static std::string ToString(T val)
256 {
257 return std::to_string(val);
258 }
259 };
260#endif
261}
262
263namespace Trinity
264{
265 template <typename Result, typename... Params>
266 Optional<Result> StringTo(std::string_view str, Params&&... params)
267 {
268 return Trinity::Impl::StringConvertImpl::For<Result>::FromString(str, std::forward<Params>(params)...);
269 }
270
271 template <typename Type, typename... Params>
272 std::string ToString(Type&& val, Params&&... params)
273 {
274 return Trinity::Impl::StringConvertImpl::For<std::decay_t<Type>>::ToString(std::forward<Type>(val), std::forward<Params>(params)...);
275 }
276}
277
278#endif
int64_t int64
Definition Define.h:149
#define TC_COMMON_API
Definition Define.h:99
uint64_t uint64
Definition Define.h:153
std::unordered_set< uint32 > params[2]
#define ASSERT
Definition Errors.h:80
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
TC_COMMON_API bool StringEqualI(std::string_view str1, std::string_view str2)
Definition Util.cpp:849
std::string ToString(Type &&val, Params &&... params)
Optional< Result > StringTo(std::string_view str, Params &&... params)
STL namespace.
static Optional< T > FromString(std::string_view str, std::chars_format fmt=std::chars_format())
static Optional< bool > FromString(std::string_view str, int strict=0)