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 
68 namespace kblib {
69 
70 template <int base, typename Int>
71 KBLIB_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 
93 template <typename Int>
94 KBLIB_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 
119 namespace 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 
147 template <typename Result>
148 KBLIB_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 
193 template <typename Result, std::size_t N>
194 KBLIB_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 
201 template <typename Result>
202 KBLIB_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 
210 template <typename Result>
211 KBLIB_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 
219 template <typename T, T V>
220 struct 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 
227 inline 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 
242 template <typename E,
243  typename = typename std::enable_if<std::is_enum<E>::value>::type>
244 KBLIB_NODISCARD constexpr auto etoi(E e) -> auto {
245  return static_cast<std::underlying_type_t<E>>(e);
246 }
247 
248 template <int maxBufLen = 4096, typename clock, typename duration>
249 KBLIB_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 
263 namespace 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 
463 template <
464  typename Rep, typename Ratio,
466 KBLIB_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 
473 template <typename Rep, typename Ratio,
474  enable_if_t<std::is_floating_point<Rep>::value>* = 0>
475 KBLIB_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 
486 template <typename Rep>
488  std::chrono::duration<Rep, std::ratio<60>> d) -> std::string {
489  return concat(d.count(), " min");
490 }
491 template <typename Rep>
493  std::chrono::duration<Rep, std::ratio<3600>> d) -> std::string {
494  return concat(d.count(), " hr");
495 }
496 
497 template <typename string>
498 KBLIB_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 
518 template <typename string>
519 KBLIB_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 
548 KBLIB_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
563 template <typename string>
564 KBLIB_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)
578 template <typename string>
579 KBLIB_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 
591 KBLIB_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 
608 template <typename string>
609 KBLIB_NODISCARD auto quoted(string&& in) -> std::string {
610  std::ostringstream ret;
611  ret << '"';
612  for (char c : in) {
613  if (c < ' ' or c >= '\x7F') {
614  ret << escapify(c);
615  } else if (c == '"') {
616  ret << "\\\"";
617  } else if (c == '\\') {
618  ret << "\\\\";
619  } else {
620  ret << c;
621  }
622  }
623  ret << '"';
624  return ret.str();
625 }
626 
627 // This only uses RTTI because C++ has no other means to get "int" from a
628 // template parameter.
629 template <typename T>
630 KBLIB_NODISCARD auto fromStr(const std::string& val,
631  const char* type = typeid(T).name()) -> T {
632  std::stringstream ss(val);
633  T ret{};
634  if (not (ss >> std::boolalpha >> ret).fail()) {
635  return ret;
636  } else {
637  throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
638  }
639 }
640 template <>
641 KBLIB_NODISCARD inline auto fromStr(const std::string& val, const char*)
642  -> std::string {
643  return val;
644 }
645 template <>
646 KBLIB_NODISCARD inline auto fromStr(const std::string& val, const char* type)
647  -> bool {
648  if (val == "1" or val == "true") {
649  return true;
650  } else if (val == "0" or val == "false") {
651  return false;
652  } else {
653  throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
654  }
655 }
656 
657 template <typename T>
658 KBLIB_NODISCARD auto fromStr(std::string&& val,
659  const char* type = typeid(T).name()) -> T {
660  std::stringstream ss(val);
661  T ret;
662  if (not (ss >> std::boolalpha >> ret).fail()) {
663  return ret;
664  } else {
665  throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
666  }
667 }
668 template <>
669 KBLIB_NODISCARD inline auto fromStr(std::string&& val, const char*)
670  -> std::string {
671  return std::move(val);
672 }
673 template <>
674 KBLIB_NODISCARD inline auto fromStr(std::string&& val, const char* type)
675  -> bool {
676  if (val == "1" or val == "true") {
677  return true;
678  } else if (val == "0" or val == "false") {
679  return false;
680  } else {
681  throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
682  }
683 }
684 
685 # if KBLIB_USE_STRING_VIEW
686 
687 template <>
688 KBLIB_NODISCARD inline auto fromStr(const std::string& val, const char*)
689  -> std::string_view {
690  return val;
691 }
692 template <>
693 inline auto fromStr(std::string&&, const char*) -> std::string_view = delete;
694 
695 template <typename T>
696 KBLIB_NODISCARD auto fromStr(std::string_view val,
697  const char* type = typeid(T).name()) -> T {
698  std::istrstream ss(val.data(), kblib::to_signed(val.size()));
699  T ret;
700  if (not (ss >> std::boolalpha >> ret).fail()) {
701  return ret;
702  } else {
703  throw std::runtime_error(kblib::quoted(val) + " is not a " + type);
704  }
705 }
706 template <>
707 KBLIB_NODISCARD inline auto fromStr(std::string_view val, const char*)
708  -> std::string_view {
709  return val;
710 }
711 template <>
712 KBLIB_NODISCARD inline auto fromStr(std::string_view val, const char*)
713  -> std::string {
714  return std::string(val);
715 }
716 template <>
717 KBLIB_NODISCARD inline auto fromStr(std::string_view val, const char* type)
718  -> bool {
719  if (val == "1" or val == "true") {
720  return true;
721  } else if (val == "0" or val == "false") {
722  return false;
723  } else {
724  throw std::runtime_error("\"" + std::string(val) + "\" is not a " + type);
725  }
726 }
727 
728 template <typename To, std::size_t N>
729 KBLIB_NODISCARD auto fromStr(const char (&val)[N],
730  const char* type = typeid(To).name()) -> To {
731  // N - 1: remove null terminator
732  return fromStr<To>(std::string_view(val, N - 1), type);
733 }
734 
735 template <typename To, typename _>
736 KBLIB_NODISCARD auto fromStr(const char* val,
737  const char* type = typeid(To).name(), _ = 0)
738  -> To {
739  return fromStr<To>(std::string_view(val), type);
740 }
741 
742 # endif
743 
744 template <typename T>
745 KBLIB_NODISCARD auto toStr(T val) -> std::string {
746  std::stringstream ss;
747  ss << val;
748  return ss.str();
749 }
750 KBLIB_NODISCARD inline auto toStr(std::string val) -> std::string {
751  return val;
752 }
753 
754 template <typename To, typename From>
756  static auto cast(const From& val, const char* type) -> To {
757  std::stringstream ss;
758  ss << val;
759  To ret;
760  if (not (ss >> ret).fail()) {
761  return ret;
762  } else {
763  throw std::runtime_error("Cannot convert \"" + toStr(val) + "\" to "
764  + type);
765  }
766  }
767 };
768 
769 template <typename Same>
770 struct lexical_caster<Same, Same> {
771  static auto cast(const Same& val, const char*) -> Same { return val; }
772 };
773 
774 template <>
775 struct lexical_caster<std::string, std::string> {
776  static auto cast(const std::string& val, const char*) -> std::string {
777  return val;
778  }
779 };
780 
781 template <typename From>
782 struct lexical_caster<std::string, From> {
783  static auto cast(const From& val, const char*) -> std::string {
784  return toStr(val);
785  }
786 };
787 
788 template <typename To>
789 struct lexical_caster<To, std::string> {
790  static auto cast(const std::string& val, const char* type) -> To {
791  return fromStr<To>(val, type);
792  }
793 };
794 
795 # if KBLIB_USE_STRING_VIEW
796 
797 template <>
798 struct lexical_caster<std::string_view, std::string_view> {
799  static auto cast(const std::string_view& val, const char*)
800  -> std::string_view {
801  return val;
802  }
803 };
804 
805 template <>
806 struct lexical_caster<std::string_view, std::string> {
807  static auto cast(const std::string& val, const char*) -> std::string_view {
808  return val;
809  }
810 };
811 
812 template <typename From>
813 struct lexical_caster<std::string_view, From> {
814  static std::enable_if_t<std::is_convertible_v<From, std::string_view>,
815  std::string_view>
816  cast(const From& val, const char*) {
817  return From(val);
818  }
819 
820  // DCL50-CPP-EX2:
821  // As stated in the normative text, C-style variadic functions that are
822  // declared but never defined are permitted.
823  auto cast(...) -> std::string_view = delete;
824 };
825 
826 template <typename To>
827 struct lexical_caster<To, std::string_view> {
828  static auto cast(std::string_view val, const char* type) -> To {
829  return fromStr<To>(val, type);
830  }
831 };
832 
833 # endif
834 
835 template <typename To, typename From>
836 KBLIB_NODISCARD auto lexical_cast(const From& val,
837  const char* type = typeid(To).name()) -> To {
838  return lexical_caster<To, From>::cast(val, type);
839 }
840 
841 # if 0
842 template <typename To, typename From>
843 KBLIB_NODISCARD auto lexical_cast(const From& val,
844  const char* type = typeid(To).name()) -> To {
845  using namespace std::literals;
846  if constexpr (std::is_same_v<std::decay_t<To>, std::decay_t<From>>) {
847  return val;
848  } else if constexpr (std::is_same_v<std::decay_t<To>, std::string>) {
849  return toStr(val);
850  } else if constexpr (std::is_same_v<std::decay_t<From>, std::string>) {
851  return fromStr<To>(val, type);
852  } else {
853  std::stringstream ss;
854  ss << val;
855  To ret;
856  if (not(ss >> ret).fail())
857  return ret;
858  else
859  throw std::runtime_error("Cannot convert \""s + toStr(val) + "\" to " +
860  type);
861  }
862 }
863 # endif
864 
865 } // namespace kblib
866 
867 #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 unit_of(std::chrono::nanoseconds) noexcept -> auto
Definition: convert.h:265
auto ratio_to_SI() noexcept -> unit_conversion< std::intmax_t >
Definition: convert.h:451
constexpr auto name_of(std::atto) -> prefix
Definition: convert.h:319
typename nearest_ratio< Num, Den >::type nearest_ratio_t
Definition: convert.h:459
constexpr auto largest_power_1000(std::intmax_t in) -> int
Definition: convert.h:346
The main namespace in which all entities from kblib are defined.
Definition: algorithm.h:44
constexpr auto to_signed(I x) -> std::make_signed_t< I >
Cast integral argument to corresponding signed type.
Definition: fakestd.h:592
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:71
auto time_to_str(std::chrono::time_point< clock, duration > &tp, const std::string &fmt="%F %T") -> std::string
Definition: convert.h:249
constexpr auto parse_integer(const char *begin, const char *end, int base=0) -> Result
Definition: convert.h:148
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:54
auto html_encode(const string &data) -> std::string
Definition: convert.h:519
constexpr auto e() -> T
Definition: stats.h:465
auto toStr(T val) -> std::string
Definition: convert.h:745
auto quoted(string &&in) -> std::string
Definition: convert.h:609
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:1059
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 to_string(Int num) -> std::string
Definition: convert.h:71
auto escapify(char c) -> std::string
Definition: convert.h:548
constexpr auto etoi(E e) -> auto
Definition: convert.h:244
auto fromStr(const std::string &val, const char *type=typeid(T).name()) -> T
Definition: convert.h:630
auto lexical_cast(const From &val, const char *type=typeid(To).name()) -> To
Definition: convert.h:836
auto duration_to_str(std::chrono::duration< Rep, Ratio > &d) -> std::string
Definition: convert.h:466
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
Definition: fakestd.h:585
auto calculate_translated_index(string &&value, const char *p) -> std::ptrdiff_t
Definition: convert.h:579
Definition: bits.h:714
Provides utilities for performing common operations on strings.
Definition: bits.cpp:73
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:771
static auto cast(const std::string &val, const char *type) -> To
Definition: convert.h:790
static auto cast(const From &val, const char *) -> std::string
Definition: convert.h:783
static auto cast(const std::string &val, const char *) -> std::string
Definition: convert.h:776
static auto cast(const From &val, const char *type) -> To
Definition: convert.h:756
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:81
Contains some type traits not in the standard library that are useful in the implementation of kblib.