lxgui
utils_string.cpp
1 #include "lxgui/utils_string.hpp"
2 
3 #include "utf8.h"
4 
5 #include <sstream>
6 
9 namespace lxgui::utils {
10 
11 string_view trim(string_view s, char c_pattern) {
12  std::size_t start = s.find_first_not_of(c_pattern);
13  if (start == s.npos)
14  return {};
15 
16  s = s.substr(start);
17 
18  std::size_t end = s.find_last_not_of(c_pattern);
19  if (end != s.npos)
20  s = s.substr(0, end + 1);
21 
22  return s;
23 }
24 
25 string_view trim(string_view s, string_view patterns) {
26  std::size_t start = s.find_first_not_of(patterns);
27  if (start == s.npos)
28  return {};
29 
30  s = s.substr(start);
31 
32  std::size_t end = s.find_last_not_of(patterns);
33  if (end != s.npos)
34  s = s.substr(0, end + 1);
35 
36  return s;
37 }
38 
39 void replace(string& s, string_view pattern, string_view replacement) {
40  std::size_t pos = s.find(pattern);
41 
42  while (pos != s.npos) {
43  s.replace(pos, pattern.length(), replacement);
44  pos = s.find(pattern, pos + replacement.length());
45  }
46 }
47 
48 std::size_t count_occurrences(string_view s, string_view pattern) {
49  std::size_t count = 0;
50  std::size_t pos = s.find(pattern);
51  while (pos != s.npos) {
52  ++count;
53  pos = s.find(pattern, pos + 1);
54  }
55 
56  return count;
57 }
58 
59 template<typename T>
60 std::vector<std::basic_string_view<T>>
61 cut_template(std::basic_string_view<T> s, std::basic_string_view<T> delim) {
62  std::vector<std::basic_string_view<T>> pieces;
63  std::size_t pos = s.find(delim);
64  std::size_t last_pos = 0u;
65  std::size_t cur_size = 0u;
66 
67  while (pos != std::basic_string_view<T>::npos) {
68  cur_size = pos - last_pos;
69  if (cur_size != 0)
70  pieces.push_back(s.substr(last_pos, cur_size));
71  last_pos = pos + delim.size();
72  pos = s.find(delim, last_pos);
73  }
74 
75  pieces.push_back(s.substr(last_pos));
76 
77  return pieces;
78 }
79 
80 std::vector<string_view> cut(string_view s, string_view delim) {
81  return cut_template(s, delim);
82 }
83 
84 std::vector<ustring_view> cut(ustring_view s, ustring_view delim) {
85  return cut_template(s, delim);
86 }
87 
88 template<typename T>
89 std::vector<std::basic_string_view<T>>
90 cut_each_template(std::basic_string_view<T> s, std::basic_string_view<T> delim) {
91  std::vector<std::basic_string_view<T>> pieces;
92  std::size_t pos = s.find(delim);
93  std::size_t last_pos = 0u;
94  std::size_t cur_size = 0u;
95 
96  while (pos != std::basic_string_view<T>::npos) {
97  cur_size = pos - last_pos;
98  pieces.push_back(s.substr(last_pos, cur_size));
99  last_pos = pos + delim.size();
100  pos = s.find(delim, last_pos);
101  }
102 
103  pieces.push_back(s.substr(last_pos));
104 
105  return pieces;
106 }
107 
108 std::vector<string_view> cut_each(string_view s, string_view delim) {
109  return cut_each_template(s, delim);
110 }
111 
112 std::vector<ustring_view> cut_each(ustring_view s, ustring_view delim) {
113  return cut_each_template(s, delim);
114 }
115 
116 template<typename T>
117 std::pair<std::basic_string_view<T>, std::basic_string_view<T>>
118 cut_first_template(std::basic_string_view<T> s, std::basic_string_view<T> delim) {
119  std::size_t pos = s.find(delim);
120  if (pos == std::basic_string_view<T>::npos)
121  return {};
122 
123  return {s.substr(0, pos), s.substr(pos + 1u)};
124 }
125 
126 std::pair<string_view, string_view> cut_first(string_view s, string_view delim) {
127  return cut_first_template(s, delim);
128 }
129 
130 std::pair<ustring_view, ustring_view> cut_first(ustring_view s, ustring_view delim) {
131  return cut_first_template(s, delim);
132 }
133 
134 bool has_no_content(string_view s) {
135  if (s.empty())
136  return true;
137 
138  for (std::size_t i = 0; i < s.length(); ++i) {
139  if (s[i] != ' ' && s[i] != '\t')
140  return false;
141  }
142 
143  return true;
144 }
145 
146 bool starts_with(string_view s, string_view pattern) {
147  std::size_t n = std::min(s.size(), pattern.size());
148  for (std::size_t i = 0; i < n; ++i) {
149  if (s[i] != pattern[i])
150  return false;
151  }
152 
153  return true;
154 }
155 
156 bool ends_with(string_view s, string_view pattern) {
157  std::size_t ss = s.size();
158  std::size_t ps = pattern.size();
159  std::size_t n = std::min(ss, ps);
160  for (std::size_t i = 1; i <= n; ++i) {
161  if (s[ss - i] != pattern[ps - i])
162  return false;
163  }
164 
165  return true;
166 }
167 
168 ustring utf8_to_unicode(string_view s) {
169  return utf8::utf8to32(s);
170 }
171 
172 string unicode_to_utf8(ustring_view s) {
173  return utf8::utf32to8(s);
174 }
175 
176 std::size_t hex_to_uint(string_view s) {
177  std::size_t i = 0;
178  std::istringstream ss{std::string(s)};
179  ss.imbue(std::locale::classic());
180  ss >> std::hex >> i;
181  return i;
182 }
183 
184 namespace impl {
185 
186 template<typename T>
187 std::optional<T> from_string_template(const std::locale& loc, string_view s) {
188  std::istringstream ss{std::string(s)};
189  ss.imbue(loc);
190 
191  T v;
192  ss >> v;
193 
194  if (!ss.fail()) {
195  if (ss.eof())
196  return v;
197 
198  std::string rem;
199  ss >> rem;
200 
201  if (rem.find_first_not_of(" \t") == rem.npos)
202  return v;
203  }
204 
205  return {};
206 }
207 
208 template<typename T>
209 std::optional<T> from_string_template(const std::locale& loc, ustring_view s) {
210  return from_string_template<T>(loc, unicode_to_utf8(s));
211 }
212 
213 // ----- locale, utf8 string
214 
215 template<>
216 std::optional<int> from_string<int>(const std::locale& loc, string_view s) {
217  return from_string_template<int>(loc, s);
218 }
219 
220 template<>
221 std::optional<long> from_string<long>(const std::locale& loc, string_view s) {
222  return from_string_template<long>(loc, s);
223 }
224 
225 template<>
226 std::optional<long long> from_string<long long>(const std::locale& loc, string_view s) {
227  return from_string_template<long long>(loc, s);
228 }
229 
230 template<>
231 std::optional<unsigned> from_string<unsigned>(const std::locale& loc, string_view s) {
232  return from_string_template<unsigned>(loc, s);
233 }
234 
235 template<>
236 std::optional<unsigned long> from_string<unsigned long>(const std::locale& loc, string_view s) {
237  return from_string_template<unsigned long>(loc, s);
238 }
239 
240 template<>
241 std::optional<unsigned long long>
242 from_string<unsigned long long>(const std::locale& loc, string_view s) {
243  return from_string_template<unsigned long long>(loc, s);
244 }
245 
246 template<>
247 std::optional<float> from_string<float>(const std::locale& loc, string_view s) {
248  return from_string_template<float>(loc, s);
249 }
250 
251 template<>
252 std::optional<double> from_string<double>(const std::locale& loc, string_view s) {
253  return from_string_template<double>(loc, s);
254 }
255 
256 // ----- locale, utf32 string
257 
258 template<>
259 std::optional<int> from_string<int>(const std::locale& loc, ustring_view s) {
260  return from_string_template<int>(loc, s);
261 }
262 
263 template<>
264 std::optional<long> from_string<long>(const std::locale& loc, ustring_view s) {
265  return from_string_template<long>(loc, s);
266 }
267 
268 template<>
269 std::optional<long long> from_string<long long>(const std::locale& loc, ustring_view s) {
270  return from_string_template<long long>(loc, s);
271 }
272 
273 template<>
274 std::optional<unsigned> from_string<unsigned>(const std::locale& loc, ustring_view s) {
275  return from_string_template<unsigned>(loc, s);
276 }
277 
278 template<>
279 std::optional<unsigned long> from_string<unsigned long>(const std::locale& loc, ustring_view s) {
280  return from_string_template<unsigned long>(loc, s);
281 }
282 
283 template<>
284 std::optional<unsigned long long>
285 from_string<unsigned long long>(const std::locale& loc, ustring_view s) {
286  return from_string_template<unsigned long long>(loc, s);
287 }
288 
289 template<>
290 std::optional<float> from_string<float>(const std::locale& loc, ustring_view s) {
291  return from_string_template<float>(loc, s);
292 }
293 
294 template<>
295 std::optional<double> from_string<double>(const std::locale& loc, ustring_view s) {
296  return from_string_template<double>(loc, s);
297 }
298 
299 // ----- C locale, utf8 string
300 
301 template<>
302 std::optional<int> from_string<int>(string_view s) {
303  return from_string_template<int>(std::locale::classic(), s);
304 }
305 
306 template<>
307 std::optional<long> from_string<long>(string_view s) {
308  return from_string_template<long>(std::locale::classic(), s);
309 }
310 
311 template<>
312 std::optional<long long> from_string<long long>(string_view s) {
313  return from_string_template<long long>(std::locale::classic(), s);
314 }
315 
316 template<>
317 std::optional<unsigned> from_string<unsigned>(string_view s) {
318  return from_string_template<unsigned>(std::locale::classic(), s);
319 }
320 
321 template<>
322 std::optional<unsigned long> from_string<unsigned long>(string_view s) {
323  return from_string_template<unsigned long>(std::locale::classic(), s);
324 }
325 
326 template<>
327 std::optional<unsigned long long> from_string<unsigned long long>(string_view s) {
328  return from_string_template<unsigned long long>(std::locale::classic(), s);
329 }
330 
331 template<>
332 std::optional<float> from_string<float>(string_view s) {
333  return from_string_template<float>(std::locale::classic(), s);
334 }
335 
336 template<>
337 std::optional<double> from_string<double>(string_view s) {
338  return from_string_template<double>(std::locale::classic(), s);
339 }
340 
341 template<>
342 std::optional<bool> from_string<bool>(string_view s) {
343  if (s == "true")
344  return true;
345  if (s == "false")
346  return false;
347  return {};
348 }
349 
350 template<>
351 std::optional<string> from_string<string>(string_view s) {
352  return string{s};
353 }
354 
355 // ----- C locale, utf32 string
356 
357 template<>
358 std::optional<int> from_string<int>(ustring_view s) {
359  return from_string_template<int>(std::locale::classic(), s);
360 }
361 
362 template<>
363 std::optional<long> from_string<long>(ustring_view s) {
364  return from_string_template<long>(std::locale::classic(), s);
365 }
366 
367 template<>
368 std::optional<long long> from_string<long long>(ustring_view s) {
369  return from_string_template<long long>(std::locale::classic(), s);
370 }
371 
372 template<>
373 std::optional<unsigned> from_string<unsigned>(ustring_view s) {
374  return from_string_template<unsigned>(std::locale::classic(), s);
375 }
376 
377 template<>
378 std::optional<unsigned long> from_string<unsigned long>(ustring_view s) {
379  return from_string_template<unsigned long>(std::locale::classic(), s);
380 }
381 
382 template<>
383 std::optional<unsigned long long> from_string<unsigned long long>(ustring_view s) {
384  return from_string_template<unsigned long long>(std::locale::classic(), s);
385 }
386 
387 template<>
388 std::optional<float> from_string<float>(ustring_view s) {
389  return from_string_template<float>(std::locale::classic(), s);
390 }
391 
392 template<>
393 std::optional<double> from_string<double>(ustring_view s) {
394  return from_string_template<double>(std::locale::classic(), s);
395 }
396 
397 template<>
398 std::optional<bool> from_string<bool>(ustring_view s) {
399  if (s == U"true")
400  return true;
401  if (s == U"false")
402  return false;
403  return {};
404 }
405 
406 template<>
407 std::optional<ustring> from_string<ustring>(ustring_view s) {
408  return ustring{s};
409 }
410 
411 } // namespace impl
412 
413 bool is_number(const std::locale& loc, string_view s) {
414  return impl::from_string<double>(loc, s).has_value();
415 }
416 
417 bool is_number(const std::locale& loc, ustring_view s) {
418  return impl::from_string<double>(loc, s).has_value();
419 }
420 
421 bool is_integer(const std::locale& loc, string_view s) {
422  return impl::from_string<std::int64_t>(loc, s).has_value();
423 }
424 
425 bool is_integer(const std::locale& loc, ustring_view s) {
426  return impl::from_string<std::int64_t>(loc, s).has_value();
427 }
428 
429 bool is_number(string_view s) {
430  return is_number(std::locale::classic(), s);
431 }
432 
433 bool is_number(ustring_view s) {
434  return is_number(std::locale::classic(), s);
435 }
436 
437 bool is_integer(string_view s) {
438  return is_integer(std::locale::classic(), s);
439 }
440 
441 bool is_integer(ustring_view s) {
442  return is_integer(std::locale::classic(), s);
443 }
444 
445 bool is_number(char s) {
446  return '0' <= s && s <= '9';
447 }
448 
449 bool is_number(char32_t s) {
450  return U'0' <= s && s <= U'9';
451 }
452 
453 bool is_integer(char s) {
454  return is_number(s);
455 }
456 
457 bool is_integer(char32_t s) {
458  return is_number(s);
459 }
460 
461 bool is_boolean(string_view s) {
462  return (s == "false") || (s == "true");
463 }
464 
465 bool is_boolean(ustring_view s) {
466  return (s == U"false") || (s == U"true");
467 }
468 
469 bool is_whitespace(char c) {
470  return c == '\n' || c == ' ' || c == '\t' || c == '\r';
471 }
472 
473 bool is_whitespace(char32_t c) {
474  return c == U'\n' || c == U' ' || c == U'\t' || c == '\r';
475 }
476 
477 template<typename T>
478 string to_string_template(T value) {
479  std::ostringstream ss;
480  ss.imbue(std::locale::classic());
481  ss << value;
482  return ss.str();
483 }
484 
485 string to_string(int v) {
486  return to_string_template(v);
487 }
488 
489 string to_string(long v) {
490  return to_string_template(v);
491 }
492 
493 string to_string(long long v) {
494  return to_string_template(v);
495 }
496 
497 string to_string(unsigned v) {
498  return to_string_template(v);
499 }
500 
501 string to_string(unsigned long v) {
502  return to_string_template(v);
503 }
504 
505 string to_string(unsigned long long v) {
506  return to_string_template(v);
507 }
508 
509 string to_string(float v) {
510  return to_string_template(v);
511 }
512 
513 string to_string(double v) {
514  return to_string_template(v);
515 }
516 
517 string to_string(bool b) {
518  return b ? "true" : "false";
519 }
520 
521 string to_string(const void* p) {
522  std::ostringstream stream;
523  stream.imbue(std::locale::classic());
524  stream << p;
525  return stream.str();
526 }
527 
528 string to_string(const utils::variant& value) {
529  return std::visit(
530  [&](const auto& inner_value) -> std::string {
531  using inner_type = std::decay_t<decltype(inner_value)>;
532  if constexpr (std::is_same_v<inner_type, utils::empty>)
533  return "<none>";
534  else
535  return to_string(inner_value);
536  },
537  value);
538 }
539 
540 string to_lower(string str) {
541  for (char& c : str)
542  c = static_cast<char>(std::tolower(c));
543 
544  return str;
545 }
546 
547 } // namespace lxgui::utils
548 
range_impl::value_range< T > value(T &container)
Expose the value rather than the (key,value) pair.
std::variant< empty, bool, std::int64_t, std::int32_t, std::int16_t, std::int8_t, std::uint64_t, std::uint32_t, std::uint16_t, std::uint8_t, double, float, std::string > variant
Type-erased value for passing arguments to events.