kblib 0.2.3
General utilities library for modern C++
convert.h
Go to the documentation of this file.
1/* *****************************************************************************
2 * kblib is a general utility library for C++14 and C++17, intended to provide
3 * performant high-level abstractions and more expressive ways to do simple
4 * things.
5 *
6 * Copyright (c) 2021 killerbee
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * ****************************************************************************/
21
32#if KBLIB_DEF_MACROS and not defined(pFromStr)
33# define pFromStr(type, val) ::kblib::fromStr<type>((val), # type)
34#endif
35
36#ifndef KBLIB_CONVERT_H
37# define KBLIB_CONVERT_H
38
39# include <algorithm>
40# include <array>
41# include <cassert>
42# include <chrono>
43# include <exception>
44# include <iomanip>
45# include <sstream>
46# include <stdexcept>
47# include <string>
48# include <typeinfo>
49
50# include "algorithm.h"
51# include "iterators.h"
52# include "traits.h"
53
54# if KBLIB_USE_STRING_VIEW
55
56# include <string_view>
57# pragma GCC diagnostic push
58# pragma GCC diagnostic ignored "-W#warnings"
59# include <strstream>
60# pragma GCC diagnostic pop
61
62# include "stringops.h"
63
64# endif
65
66# include <iostream>
67
68namespace KBLIB_NS {
69
70template <int base, typename Int>
71KBLIB_NODISCARD auto to_string(Int num) -> std::string {
72 static_assert(base <= 62 and base > 0, "Supported bases are 1 thru 62.");
73 constexpr auto digits = remove_null_terminator(
74 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
75 std::string ret;
76 bool neg = false;
77 if (num < 0) {
78 neg = true;
79 num *= -1;
80 } else if (num == 0) {
81 return "0";
82 }
83 do {
84 ret.push_back(digits[num % base]);
85 } while (num /= base);
86 if (neg) {
87 ret.push_back('-');
88 }
89 std::reverse(ret.begin(), ret.end());
90 return ret;
91}
92
93template <typename Int>
94KBLIB_NODISCARD auto to_string(Int num, int base) -> std::string {
95 assert(base <= 62 and base > 0);
96 constexpr auto digits = remove_null_terminator(
97 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
98 std::string ret;
99 bool neg = false;
100 if (num < 0) {
101 neg = true;
102 num *= -1;
103 } else if (num == 0) {
104 return "0";
105 }
106 do {
107 ret.push_back(digits[num % base]);
108 } while (num /= base);
109 if (neg) {
110 ret.push_back('-');
111 }
112 std::reverse(ret.begin(), ret.end());
113 return ret;
114}
115
119namespace detail_convert {
120
121 template <typename Result, unsigned variants, std::size_t N>
122 KBLIB_NODISCARD constexpr auto read_digits(const char* begin,
123 const char* end, unsigned base,
124 const char (&digits)[N])
125 -> Result {
126 if (begin == end) {
127 throw std::invalid_argument("\"\" is not an integer");
128 }
129 Result result{};
130 for (auto c : indirect(begin, end)) {
131 if (c != '\'') {
132 result *= base;
133 auto pos = find_in(std::begin(digits),
134 std::begin(digits) + base * variants, c);
135 if (pos != base * variants) {
136 result += pos / variants;
137 } else {
138 throw std::invalid_argument("invalid character in integer");
139 }
140 }
141 }
142 return result;
143 }
144
145} // namespace detail_convert
146
147template <typename Result>
148KBLIB_NODISCARD constexpr auto parse_integer(const char* begin, const char* end,
149 int base = 0) -> Result {
150 if (begin == end) {
151 throw std::invalid_argument("\"\" is not an integer");
152 } else if (*begin == '-') {
153 return -parse_integer<Result>(begin + 1, end, base);
154 } else if (base == 0) {
155 if (*begin == '0') {
156 if (begin + 1 == end) {
157 return 0;
158 } else if (begin[1] == '-' or (begin + 2 != end and begin[2] == '-')) {
159 throw std::invalid_argument("unexpected - in integer");
160 } else {
161 switch (begin[1]) {
162 case 'x':
163 return parse_integer<Result>(begin + 2, end, 16);
164 case 'b':
165 return parse_integer<Result>(begin + 2, end, 2);
166 default:
167 return parse_integer<Result>(begin + 1, end, 8);
168 }
169 }
170 } else {
171 return parse_integer<Result>(begin, end, 10);
172 }
173 } else {
174 if (base < 2 or base > 62) {
175 throw std::invalid_argument(
176 "base must be either 0 or a positive number between 2 and 62");
177 } else if (base <= 36) {
178 return detail_convert::read_digits<Result, 2>(
179 begin, end, to_unsigned(base),
180 "00112233445566778899AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRr"
181 "SsTtUuVvWwXxYyZz");
182 } else if (base <= 62) {
183 return detail_convert::read_digits<Result, 1>(
184 begin, end, to_unsigned(base),
185 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
186 }
187 }
188 // silence warning that control may flow off the end even though all paths
189 // return or throw
190 return 0;
191}
192
193template <typename Result, std::size_t N>
194KBLIB_NODISCARD constexpr auto parse_integer(const char (&in)[N], int base = 0)
195 -> Result {
196 char t = in[N - 1];
197 return parse_integer<Result>(std::begin(in), std::end(in) - +(t == '\0'),
198 base);
199}
200
201template <typename Result>
202KBLIB_NODISCARD constexpr auto parse_integer(const std::string& in,
203 int base = 0) -> Result {
204 return parse_integer<Result>(to_pointer(begin(in)), to_pointer(end(in)),
205 base);
206}
207
208# if KBLIB_USE_STRING_VIEW
209
210template <typename Result>
211KBLIB_NODISCARD constexpr auto parse_integer(std::string_view in, int base = 0)
212 -> Result {
213 return parse_integer<Result>(to_pointer(begin(in)), to_pointer(end(in)),
214 base);
215}
216
217# endif
218
219template <typename T, T V>
220struct constant : std::integral_constant<T, V> {
221 constexpr auto operator-() -> constant<T, -V> { return {}; }
222 constexpr constant() = default;
223 constexpr /* implicit */ constant(std::integral_constant<T, V>) noexcept {}
224 // reverse conversion handled by slicing
225};
226
227inline namespace literals {
228
229 template <char... Cs>
230 KBLIB_NODISCARD constexpr auto operator""_c() {
231 constexpr char arr[] = {Cs...};
233 }
234 template <char... Cs>
235 KBLIB_NODISCARD constexpr auto operator""_cu() {
236 constexpr char arr[] = {Cs...};
238 }
239
240} // namespace literals
241
242template <typename E,
243 typename = typename std::enable_if<std::is_enum<E>::value>::type>
244KBLIB_NODISCARD constexpr auto etoi(E e) -> auto {
245 return static_cast<std::underlying_type_t<E>>(e);
246}
247
248template <int maxBufLen = 4096, typename clock, typename duration>
249KBLIB_NODISCARD auto time_to_str(std::chrono::time_point<clock, duration>& tp,
250 const std::string& fmt = "%F %T")
251 -> std::string {
252 std::time_t time = clock::to_time_t(tp);
253 std::tm* tmb = std::localtime(&time);
254 std::string ret{maxBufLen, '\0'};
255 std::strftime(&ret.front(), maxBufLen, fmt.c_str(), tmb);
256 return ret;
257}
258
263namespace detail_units {
264
265 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::nanoseconds) noexcept
266 -> auto {
267 return "ns";
268 }
269 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::microseconds) noexcept
270 -> auto {
271 return "us";
272 }
273 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::milliseconds) noexcept
274 -> auto {
275 return "ms";
276 }
277
278 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::seconds) noexcept
279 -> auto {
280 return "s";
281 }
282 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::minutes) noexcept
283 -> auto {
284 return "min";
285 }
286 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::hours) noexcept -> auto {
287 return "hr";
288 }
289
290# if KBLIB_USE_CXX20
291
292 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::days) noexcept -> auto {
293 return "ns";
294 }
295 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::weeks) noexcept -> auto {
296 return "ns";
297 }
298 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::months) noexcept
299 -> auto {
300 return "ns";
301 }
302 KBLIB_NODISCARD constexpr auto unit_of(std::chrono::years) noexcept -> auto {
303 return "ns";
304 }
305
306# endif
307
309 char name[16];
310 char abbr[4];
311 };
312// if std::intmax_t can represent the denominator
313# if (-1U >> 63) > (1U << 18)
314 constexpr auto name_of(std::yocto) -> prefix { return prefix{"yocto", "y"}; }
315# endif
316# if (-1U >> 63) > (1U << 8)
317 constexpr auto name_of(std::zepto) -> prefix { return prefix{"zepto", "z"}; }
318# endif
319 constexpr auto name_of(std::atto) -> prefix { return prefix{"atto", "a"}; }
320 constexpr auto name_of(std::femto) -> prefix { return prefix{"femto", "f"}; }
321 constexpr auto name_of(std::pico) -> prefix { return prefix{"pico", "p"}; }
322 constexpr auto name_of(std::nano) -> prefix { return prefix{"nano", "n"}; }
323 constexpr auto name_of(std::micro) -> prefix { return prefix{"micro", "u"}; }
324 constexpr auto name_of(std::milli) -> prefix { return prefix{"milli", "m"}; }
325 constexpr auto name_of(std::centi) -> prefix { return prefix{"centi", "c"}; }
326 constexpr auto name_of(std::deci) -> prefix { return prefix{"deci", "d"}; }
327
328 constexpr auto name_of(std::ratio<1, 1>) -> prefix { return prefix{"", ""}; }
329
330 constexpr auto name_of(std::deca) -> prefix { return prefix{"deca", "da"}; }
331 constexpr auto name_of(std::hecto) -> prefix { return prefix{"hecto", "h"}; }
332 constexpr auto name_of(std::kilo) -> prefix { return prefix{"kilo", "k"}; }
333 constexpr auto name_of(std::mega) -> prefix { return prefix{"mega", "M"}; }
334 constexpr auto name_of(std::giga) -> prefix { return prefix{"giga", "G"}; }
335 constexpr auto name_of(std::tera) -> prefix { return prefix{"tera", "T"}; }
336 constexpr auto name_of(std::peta) -> prefix { return prefix{"peta", "P"}; }
337 constexpr auto name_of(std::exa) -> prefix { return prefix{"exa", "E"}; }
338// if std::intmax_t can represent the numerator
339# if (-1U >> 63) > (1U << 8)
340 constexpr auto name_of(std::zetta) -> prefix { return prefix{"zetta", "Z"}; }
341# endif
342# if (-1U >> 63) > (1U << 18)
343 constexpr auto name_of(std::yotta) -> prefix { return prefix{"yotta", "Y"}; }
344# endif
345
346 KBLIB_NODISCARD constexpr auto largest_power_1000(std::intmax_t in) -> int {
347 if (in % 1000 == 0) {
348 return 1 + largest_power_1000(in / 1000);
349 } else {
350 return 0;
351 }
352 }
353
354 KBLIB_NODISCARD constexpr auto largest_power_1000_p(double in) -> int {
355 if (in / 1000 >= 1) {
356 return 1 + largest_power_1000_p(in / 1000.);
357 } else {
358 return 0;
359 }
360 }
361 KBLIB_NODISCARD constexpr auto largest_power_1000(double in) -> int {
362 if (in < 1) {
363 return -largest_power_1000_p(1 / in);
364 }
365 if (in / 1000 >= 1) {
366 return 1 + largest_power_1000_p(in / 1000.);
367 } else {
368 return 0;
369 }
370 }
371
372 KBLIB_NODISCARD constexpr auto pow1000(int p) -> double {
373 auto r = 1.0;
374 if (p >= 0) {
375 while (p--) {
376 r *= 1000.;
377 }
378 } else {
379 while (p++) {
380 r /= 1000.;
381 }
382 }
383 return r;
384 }
385
386 template <typename R>
387 struct is_si_ratio : std::false_type {};
388// if std::intmax_t can represent the denominator
389# if (-1U >> 63) > (1U << 18)
390 template <>
391 struct is_si_ratio<std::yocto> : std::true_type {};
392# endif
393# if (-1U >> 63) > (1U << 8)
394 template <>
395 struct is_si_ratio<std::zepto> : std::true_type {};
396# endif
397 template <>
398 struct is_si_ratio<std::atto> : std::true_type {};
399 template <>
400 struct is_si_ratio<std::femto> : std::true_type {};
401 template <>
402 struct is_si_ratio<std::pico> : std::true_type {};
403 template <>
404 struct is_si_ratio<std::nano> : std::true_type {};
405 template <>
406 struct is_si_ratio<std::micro> : std::true_type {};
407 template <>
408 struct is_si_ratio<std::milli> : std::true_type {};
409 template <>
410 struct is_si_ratio<std::centi> : std::true_type {};
411 template <>
412 struct is_si_ratio<std::deci> : std::true_type {};
413
414 template <>
415 struct is_si_ratio<std::ratio<1>> : std::true_type {};
416
417 template <>
418 struct is_si_ratio<std::deca> : std::true_type {};
419 template <>
420 struct is_si_ratio<std::hecto> : std::true_type {};
421 template <>
422 struct is_si_ratio<std::kilo> : std::true_type {};
423 template <>
424 struct is_si_ratio<std::mega> : std::true_type {};
425 template <>
426 struct is_si_ratio<std::giga> : std::true_type {};
427 template <>
428 struct is_si_ratio<std::tera> : std::true_type {};
429 template <>
430 struct is_si_ratio<std::peta> : std::true_type {};
431 template <>
432 struct is_si_ratio<std::exa> : std::true_type {};
433// if std::intmax_t can represent the numerator
434# if (-1U >> 63) > (1U << 8)
435 template <>
436 struct is_si_ratio<std::zetta> : std::true_type {};
437# endif
438# if (-1U >> 63) > (1U << 18)
439 template <>
440 struct is_si_ratio<std::yotta> : std::true_type {};
441# endif
442
443 template <typename M>
445 const char* scale_prefix;
446 char abbr[6];
448 };
449
450 template <std::intmax_t Num, std::intmax_t Den>
451 auto ratio_to_SI() noexcept -> unit_conversion<std::intmax_t> {
452 return {};
453 }
454
455 template <std::intmax_t Num, std::intmax_t Den>
456 struct nearest_ratio {};
457
458 template <std::intmax_t Num, std::intmax_t Den>
460
461} // namespace detail_units
462
463template <
464 typename Rep, typename Ratio,
466KBLIB_NODISCARD auto duration_to_str(std::chrono::duration<Rep, Ratio>& d)
467 -> std::string {
468 using ratio = typename Ratio::type;
469 auto cv = detail_units::ratio_to_SI<ratio::num, ratio::den>();
470 return concat(d.count() * cv.multiplier, ' ', cv.abbr, 's');
471}
472
473template <typename Rep, typename Ratio,
474 enable_if_t<std::is_floating_point<Rep>::value>* = 0>
475KBLIB_NODISCARD auto duration_to_str(std::chrono::duration<Rep, Ratio>& d)
476 -> std::string {
477 using ratio = typename Ratio::type;
478 using n_r = detail_units::nearest_ratio_t<ratio::num, ratio::den>;
479 auto u = detail_units::name_of(n_r{});
480
481 // require an implicit cast
482 std::chrono::duration<Rep, n_r> n_d = d;
483 return concat(n_d.count(), ' ', u.abbr, 's');
484}
485
486template <typename Rep>
488 std::chrono::duration<Rep, std::ratio<60>> d) -> std::string {
489 return concat(d.count(), " min");
490}
491template <typename Rep>
493 std::chrono::duration<Rep, std::ratio<3600>> d) -> std::string {
494 return concat(d.count(), " hr");
495}
496
497template <typename string>
498KBLIB_NODISCARD auto url_encode(const string& value) -> std::string {
499 std::ostringstream escaped;
500 escaped.fill('0');
501 escaped << std::hex;
502
503 for (char c : value) {
504 // Keep alphanumeric and other accepted characters intact
505 if (std::isalnum(c) or c == '-' or c == '_' or c == '.' or c == '~') {
506 escaped << c;
507 } else {
508 // Any other characters are percent-encoded
509 escaped << std::uppercase;
510 escaped << '%' << std::setw(2) << int(to_unsigned(c));
511 escaped << std::nouppercase;
512 }
513 }
514
515 return escaped.str();
516}
517
518template <typename string>
519KBLIB_NODISCARD auto html_encode(const string& data) -> std::string {
520 std::string buffer;
521 // Arbitrary estimate for amount of growth caused by the escaping is 12.5%.
522 buffer.reserve(data.size() + data.size() / 8);
523 for (char c : data) {
524 switch (c) {
525 case '&':
526 buffer.append("&amp;");
527 break;
528 case '\"':
529 buffer.append("&quot;");
530 break;
531 case '\'':
532 buffer.append("&apos;");
533 break;
534 case '<':
535 buffer.append("&lt;");
536 break;
537 case '>':
538 buffer.append("&gt;");
539 break;
540 default:
541 buffer.push_back(c);
542 break;
543 }
544 }
545 return buffer;
546}
547
548KBLIB_NODISCARD inline auto escapify(char c) -> std::string {
549 auto value = to_unsigned(c);
550 if (value < ' ' or value == '\x7F' or value & to_unsigned('\x80')) {
551 constexpr std::array<char, 16> digits{
552 remove_null_terminator("0123456789ABCDEF")};
553 std::string rc("\\x ");
554 rc[2] = digits[value >> 4u];
555 rc[3] = digits[value & 15u];
556 return rc;
557 } else {
558 return std::string(1, static_cast<char>(value));
559 }
560}
561
562// Accepts any sequence of char, returns printable string
563template <typename string>
564KBLIB_NODISCARD auto escapify(const string& value) -> std::string {
565 std::ostringstream ret;
566 for (char c : value) {
567 if (c < ' ' or c >= '\x7F') {
568 ret << escapify(c);
569 } else {
570 ret << c;
571 }
572 }
573 return ret.str();
574}
575
576// Given a string and a pointer into it, calculate the effective index of that
577// pointer into a string such as created by kblib::escapify(value)
578template <typename string>
579KBLIB_NODISCARD auto calculate_translated_index(string&& value, const char* p)
580 -> std::ptrdiff_t {
581 std::ptrdiff_t counter = 0;
582 for (auto&& c : value) {
583 if (&c == p) {
584 return counter;
585 }
586 counter += (std::isprint(c)) ? 1 : 4;
587 }
588 return counter;
589}
590
591KBLIB_NODISCARD inline auto calculate_translated_index(const char* value,
592 const char* p)
593 -> std::ptrdiff_t {
594 if (not value) {
595 throw std::invalid_argument(
596 "calculate_translated_index can't take a nullptr");
597 }
598 std::ptrdiff_t counter = 0;
599 while (*value) {
600 if (value == p) {
601 return counter;
602 }
603 counter += (std::isprint(*value)) ? 1 : 4;
604 }
605 return counter;
606}
607
608template <typename character, enable_if_t<is_character_v<character>>* = nullptr>
609KBLIB_NODISCARD auto quoted(character c) -> std::string {
610 if (c < ' ' or c >= '\x7F') {
611 return escapify(c);
612 } else if (c == '"') {
613 return "\\\"";
614 } else if (c == '\\') {
615 return "\\\\";
616 } else {
617 return {1, c};
618 }
619}
620
621template <typename string, enable_if_t<not is_character_v<string>>* = nullptr>
622KBLIB_NODISCARD auto quoted(string&& in) -> std::string {
623 std::ostringstream ret;
624 ret << '"';
625 for (char c : in) {
626 if (c < ' ' or c >= '\x7F') {
627 ret << escapify(c);
628 } else if (c == '"') {
629 ret << "\\\"";
630 } else if (c == '\\') {
631 ret << "\\\\";
632 } else {
633 ret << c;
634 }
635 }
636 ret << '"';
637 return ret.str();
638}
639
640// This only uses RTTI because C++ has no other means to get "int" from a
641// template parameter.
642template <typename T>
643KBLIB_NODISCARD auto fromStr(const std::string& val,
644 const char* type = typeid(T).name()) -> T {
645 std::stringstream ss(val);
646 T ret{};
647 if (not (ss >> std::boolalpha >> ret).fail()) {
648 return ret;
649 } else {
650 throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
651 }
652}
653template <>
654KBLIB_NODISCARD inline auto fromStr(const std::string& val, const char*)
655 -> std::string {
656 return val;
657}
658template <>
659KBLIB_NODISCARD inline auto fromStr(const std::string& val, const char* type)
660 -> bool {
661 if (val == "1" or val == "true") {
662 return true;
663 } else if (val == "0" or val == "false") {
664 return false;
665 } else {
666 throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
667 }
668}
669
670template <typename T>
671KBLIB_NODISCARD auto fromStr(std::string&& val,
672 const char* type = typeid(T).name()) -> T {
673 std::stringstream ss(val);
674 T ret;
675 if (not (ss >> std::boolalpha >> ret).fail()) {
676 return ret;
677 } else {
678 throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
679 }
680}
681template <>
682KBLIB_NODISCARD inline auto fromStr(std::string&& val, const char*)
683 -> std::string {
684 return std::move(val);
685}
686template <>
687KBLIB_NODISCARD inline auto fromStr(std::string&& val, const char* type)
688 -> bool {
689 if (val == "1" or val == "true") {
690 return true;
691 } else if (val == "0" or val == "false") {
692 return false;
693 } else {
694 throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
695 }
696}
697
698# if KBLIB_USE_STRING_VIEW
699
700template <>
701KBLIB_NODISCARD inline auto fromStr(const std::string& val, const char*)
702 -> std::string_view {
703 return val;
704}
705template <>
706inline auto fromStr(std::string&&, const char*) -> std::string_view = delete;
707
708template <typename T>
709KBLIB_NODISCARD auto fromStr(std::string_view val,
710 const char* type = typeid(T).name()) -> T {
711 std::istrstream ss(val.data(), kblib::to_signed(val.size()));
712 T ret;
713 if (not (ss >> std::boolalpha >> ret).fail()) {
714 return ret;
715 } else {
716 throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
717 }
718}
719template <>
720KBLIB_NODISCARD inline auto fromStr(std::string_view val, const char*)
721 -> std::string_view {
722 return val;
723}
724template <>
725KBLIB_NODISCARD inline auto fromStr(std::string_view val, const char*)
726 -> std::string {
727 return std::string(val);
728}
729template <>
730KBLIB_NODISCARD inline auto fromStr(std::string_view val, const char* type)
731 -> bool {
732 if (val == "1" or val == "true") {
733 return true;
734 } else if (val == "0" or val == "false") {
735 return false;
736 } else {
737 throw std::runtime_error("\"" + std::string(val) + "\" is not a " + type);
738 }
739}
740
741template <typename To, std::size_t N>
742KBLIB_NODISCARD auto fromStr(const char (&val)[N],
743 const char* type = typeid(To).name()) -> To {
744 // N - 1: remove null terminator
745 return fromStr<To>(std::string_view(val, N - 1), type);
746}
747
748template <typename To, typename _>
749KBLIB_NODISCARD auto fromStr(const char* val,
750 const char* type = typeid(To).name(), _ = 0)
751 -> To {
752 return fromStr<To>(std::string_view(val), type);
753}
754
755# endif
756
757template <typename T>
758KBLIB_NODISCARD auto toStr(T val) -> std::string {
759 std::stringstream ss;
760 ss << val;
761 return ss.str();
762}
763KBLIB_NODISCARD inline auto toStr(std::string val) -> std::string {
764 return val;
765}
766
767template <typename To, typename From>
769 static auto cast(const From& val, const char* type) -> To {
770 std::stringstream ss;
771 ss << val;
772 To ret;
773 if (not (ss >> ret).fail()) {
774 return ret;
775 } else {
776 throw std::runtime_error("Cannot convert \"" + toStr(val) + "\" to "
777 + type);
778 }
779 }
780};
781
782template <typename Same>
783struct lexical_caster<Same, Same> {
784 static auto cast(const Same& val, const char*) -> Same { return val; }
785};
786
787template <>
788struct lexical_caster<std::string, std::string> {
789 static auto cast(const std::string& val, const char*) -> std::string {
790 return val;
791 }
792};
793
794template <typename From>
795struct lexical_caster<std::string, From> {
796 static auto cast(const From& val, const char*) -> std::string {
797 return toStr(val);
798 }
799};
800
801template <typename To>
802struct lexical_caster<To, std::string> {
803 static auto cast(const std::string& val, const char* type) -> To {
804 return fromStr<To>(val, type);
805 }
806};
807
808# if KBLIB_USE_STRING_VIEW
809
810template <>
811struct lexical_caster<std::string_view, std::string_view> {
812 static auto cast(const std::string_view& val, const char*)
813 -> std::string_view {
814 return val;
815 }
816};
817
818template <>
819struct lexical_caster<std::string_view, std::string> {
820 static auto cast(const std::string& val, const char*) -> std::string_view {
821 return val;
822 }
823};
824
825template <typename From>
826struct lexical_caster<std::string_view, From> {
827 static std::enable_if_t<std::is_convertible_v<From, std::string_view>,
828 std::string_view>
829 cast(const From& val, const char*) {
830 return From(val);
831 }
832
833 // DCL50-CPP-EX2:
834 // As stated in the normative text, C-style variadic functions that are
835 // declared but never defined are permitted.
836 auto cast(...) -> std::string_view = delete;
837};
838
839template <typename To>
840struct lexical_caster<To, std::string_view> {
841 static auto cast(std::string_view val, const char* type) -> To {
842 return fromStr<To>(val, type);
843 }
844};
845
846# endif
847
848template <typename To, typename From>
849KBLIB_NODISCARD auto lexical_cast(const From& val,
850 const char* type = typeid(To).name()) -> To {
851 return lexical_caster<To, From>::cast(val, type);
852}
853
854# if 0
855template <typename To, typename From>
856KBLIB_NODISCARD auto lexical_cast(const From& val,
857 const char* type = typeid(To).name()) -> To {
858 using namespace std::literals;
859 if constexpr (std::is_same_v<std::decay_t<To>, std::decay_t<From>>) {
860 return val;
861 } else if constexpr (std::is_same_v<std::decay_t<To>, std::string>) {
862 return toStr(val);
863 } else if constexpr (std::is_same_v<std::decay_t<From>, std::string>) {
864 return fromStr<To>(val, type);
865 } else {
866 std::stringstream ss;
867 ss << val;
868 To ret;
869 if (not(ss >> ret).fail())
870 return ret;
871 else
872 throw std::runtime_error("Cannot convert \""s + toStr(val) + "\" to " +
873 type);
874 }
875}
876# endif
877
878} // namespace KBLIB_NS
879
880#endif // KBLIB_CONVERT_H
Provides general-purpose algorithms, similar to the <algorithms> header.
This file provides some iterators, ranges, iterator/range adapters, and operations that can be perfor...
constexpr auto read_digits(const char *begin, const char *end, unsigned base, const char(&digits)[N]) -> Result
Definition: convert.h:122
constexpr auto pow1000(int p) -> double
Definition: convert.h:372
constexpr auto largest_power_1000_p(double in) -> int
Definition: convert.h:354
constexpr auto name_of(std::exa) -> prefix
Definition: convert.h:337
auto ratio_to_SI() noexcept -> unit_conversion< std::intmax_t >
Definition: convert.h:451
constexpr auto unit_of(std::chrono::hours) noexcept -> auto
Definition: convert.h:286
constexpr auto largest_power_1000(double in) -> int
Definition: convert.h:361
typename nearest_ratio< Num, Den >::type nearest_ratio_t
Definition: convert.h:459
constexpr auto to_signed(I x) -> std::make_signed_t< I >
Cast integral argument to corresponding signed type.
Definition: fakestd.h:599
constexpr auto to_pointer(P &&p) noexcept -> auto *
Gets a raw pointer out of any smart pointer or iterator you might pass in, without dereferencing it o...
Definition: iterators.h:72
auto time_to_str(std::chrono::time_point< clock, duration > &tp, const std::string &fmt="%F %T") -> std::string
Definition: convert.h:249
auto quoted(string &&in) -> std::string
Definition: convert.h:622
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:61
auto html_encode(const string &data) -> std::string
Definition: convert.h:519
constexpr auto e() -> T
Definition: stats.h:468
auto concat(F &&f, S &&... ins) -> string
Returns a string consisting of the concatenation of all arguments.
Definition: stringops.h:305
constexpr auto parse_integer(std::string_view in, int base=0) -> Result
Definition: convert.h:211
auto toStr(std::string val) -> std::string
Definition: convert.h:763
constexpr auto find_in(ForwardIt begin, EndIt end, const Elem &value) noexcept(noexcept(*begin==value)) -> size_t
Find the offset of the first ocurrence of v in a range from the beginning. It also allows for a senti...
Definition: algorithm.h:458
constexpr auto indirect(Iter1 begin, Iter2 end) noexcept(noexcept(indirect_range< Iter1, Iter2 >{begin, end})) -> indirect_range< Iter1, Iter2 >
Create a range from an iterator pair. Primarily useful for range-for loops.
Definition: iterators.h:1060
auto quoted(character c) -> std::string
Definition: convert.h:609
auto url_encode(const string &value) -> std::string
Definition: convert.h:498
constexpr auto remove_null_terminator(const char(&arr)[N]) -> std::array< char, N - 1 >
Creates an array of only the meaningful characters in a string literal, and not the null terminator.
Definition: traits.h:135
auto fromStr(const char *val, const char *type=typeid(To).name(), _=0) -> To
Definition: convert.h:749
auto to_string(Int num, int base) -> std::string
Definition: convert.h:94
auto duration_to_str(std::chrono::duration< Rep, std::ratio< 3600 > > d) -> std::string
Definition: convert.h:492
auto escapify(const string &value) -> std::string
Definition: convert.h:564
constexpr auto etoi(E e) -> auto
Definition: convert.h:244
auto calculate_translated_index(const char *value, const char *p) -> std::ptrdiff_t
Definition: convert.h:591
auto lexical_cast(const From &val, const char *type=typeid(To).name()) -> To
Definition: convert.h:849
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
Definition: fakestd.h:592
Definition: bits.h:721
Provides utilities for performing common operations on strings.
Definition: bits.cpp:75
constexpr constant(std::integral_constant< T, V >) noexcept
Definition: convert.h:223
constexpr constant()=default
constexpr auto operator-() -> constant< T, -V >
Definition: convert.h:221
static auto cast(const Same &val, const char *) -> Same
Definition: convert.h:784
static auto cast(const std::string &val, const char *type) -> To
Definition: convert.h:803
static auto cast(std::string_view val, const char *type) -> To
Definition: convert.h:841
static auto cast(const From &val, const char *) -> std::string
Definition: convert.h:796
static auto cast(const std::string &val, const char *) -> std::string
Definition: convert.h:789
auto cast(...) -> std::string_view=delete
static std::enable_if_t< std::is_convertible_v< From, std::string_view >, std::string_view > cast(const From &val, const char *)
Definition: convert.h:829
static auto cast(const std::string &val, const char *) -> std::string_view
Definition: convert.h:820
static auto cast(const std::string_view &val, const char *) -> std::string_view
Definition: convert.h:812
static auto cast(const From &val, const char *type) -> To
Definition: convert.h:769
#define KBLIB_NS
Definition: tdecl.h:113
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:129
Contains some type traits not in the standard library that are useful in the implementation of kblib.