32#if KBLIB_DEF_MACROS and not defined(pFromStr)
33# define pFromStr(type, val) ::kblib::fromStr<type>((val), # type)
36#ifndef KBLIB_CONVERT_H
37# define KBLIB_CONVERT_H
54# if KBLIB_USE_STRING_VIEW
56# include <string_view>
57# pragma GCC diagnostic push
58# pragma GCC diagnostic ignored "-W#warnings"
60# pragma GCC diagnostic pop
70template <
int base,
typename Int>
72 static_assert(base <= 62 and base > 0,
"Supported bases are 1 thru 62.");
74 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
80 }
else if (num == 0) {
84 ret.push_back(digits[num % base]);
85 }
while (num /= base);
89 std::reverse(ret.begin(), ret.end());
93template <
typename Int>
95 assert(base <= 62 and base > 0);
97 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
103 }
else if (num == 0) {
107 ret.push_back(digits[num % base]);
108 }
while (num /= base);
112 std::reverse(ret.begin(), ret.end());
119namespace detail_convert {
121 template <
typename Result,
unsigned variants, std::
size_t N>
123 const char* end,
unsigned base,
124 const char (&digits)[N])
127 throw std::invalid_argument(
"\"\" is not an integer");
130 for (
auto c :
indirect(begin, end)) {
133 auto pos =
find_in(std::begin(digits),
134 std::begin(digits) + base * variants, c);
135 if (pos != base * variants) {
136 result += pos / variants;
138 throw std::invalid_argument(
"invalid character in integer");
147template <
typename Result>
149 int base = 0) -> Result {
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) {
156 if (begin + 1 == end) {
158 }
else if (begin[1] ==
'-' or (begin + 2 != end and begin[2] ==
'-')) {
159 throw std::invalid_argument(
"unexpected - in integer");
163 return parse_integer<Result>(begin + 2, end, 16);
165 return parse_integer<Result>(begin + 2, end, 2);
167 return parse_integer<Result>(begin + 1, end, 8);
171 return parse_integer<Result>(begin, end, 10);
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>(
180 "00112233445566778899AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRr"
182 }
else if (base <= 62) {
183 return detail_convert::read_digits<Result, 1>(
185 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
193template <
typename Result, std::
size_t N>
197 return parse_integer<Result>(std::begin(in), std::end(in) - +(t ==
'\0'),
201template <
typename Result>
203 int base = 0) -> Result {
208# if KBLIB_USE_STRING_VIEW
210template <
typename Result>
219template <
typename T, T V>
223 constexpr constant(std::integral_constant<T, V>)
noexcept {}
227inline namespace literals {
229 template <
char... Cs>
231 constexpr char arr[] = {Cs...};
234 template <
char... Cs>
236 constexpr char arr[] = {Cs...};
243 typename =
typename std::enable_if<std::is_enum<E>::value>::type>
245 return static_cast<std::underlying_type_t<E>
>(
e);
248template <
int maxBufLen = 4096,
typename clock,
typename duration>
250 const std::string& fmt =
"%F %T")
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);
313# if (-1U >> 63) > (1U << 18)
316# if (-1U >> 63) > (1U << 8)
317 constexpr auto name_of(std::zepto) -> prefix {
return prefix{
"zepto",
"z"}; }
339# if (-1U >> 63) > (1U << 8)
340 constexpr auto name_of(std::zetta) -> prefix {
return prefix{
"zetta",
"Z"}; }
342# if (-1U >> 63) > (1U << 18)
343 constexpr auto name_of(std::yotta) -> prefix {
return prefix{
"yotta",
"Y"}; }
347 if (in % 1000 == 0) {
355 if (in / 1000 >= 1) {
365 if (in / 1000 >= 1) {
386 template <
typename R>
389# if (-1U >> 63) > (1U << 18)
393# if (-1U >> 63) > (1U << 8)
395 struct is_si_ratio<
std::zepto> : std::true_type {};
434# if (-1U >> 63) > (1U << 8)
438# if (-1U >> 63) > (1U << 18)
440 struct is_si_ratio<
std::yotta> : std::true_type {};
443 template <
typename M>
450 template <std::
intmax_t Num, std::
intmax_t Den>
455 template <std::
intmax_t Num, std::
intmax_t Den>
458 template <std::
intmax_t Num, std::
intmax_t Den>
464 typename Rep,
typename Ratio,
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');
473template <
typename Rep,
typename Ratio,
474 enable_if_t<std::is_floating_point<Rep>::value>* = 0>
477 using ratio =
typename Ratio::type;
478 using n_r = detail_units::nearest_ratio_t<ratio::num, ratio::den>;
482 std::chrono::duration<Rep, n_r> n_d = d;
483 return concat(n_d.count(),
' ', u.abbr,
's');
486template <
typename Rep>
488 std::chrono::duration<Rep, std::ratio<60>> d) -> std::string {
489 return concat(d.count(),
" min");
491template <
typename Rep>
493 std::chrono::duration<Rep, std::ratio<3600>> d) -> std::string {
494 return concat(d.count(),
" hr");
497template <
typename string>
499 std::ostringstream escaped;
503 for (
char c : value) {
505 if (std::isalnum(c) or c ==
'-' or c ==
'_' or c ==
'.' or c ==
'~') {
509 escaped << std::uppercase;
510 escaped <<
'%' << std::setw(2) << int(
to_unsigned(c));
511 escaped << std::nouppercase;
515 return escaped.str();
518template <
typename string>
522 buffer.reserve(data.size() + data.size() / 8);
523 for (
char c : data) {
550 if (value <
' ' or value ==
'\x7F' or value &
to_unsigned(
'\x80')) {
551 constexpr std::array<char, 16> digits{
553 std::string rc(
"\\x ");
554 rc[2] = digits[value >> 4u];
555 rc[3] = digits[value & 15u];
558 return std::string(1,
static_cast<char>(value));
563template <
typename string>
565 std::ostringstream ret;
566 for (
char c : value) {
567 if (c < ' ' or c >=
'\x7F') {
578template <
typename string>
581 std::ptrdiff_t counter = 0;
582 for (
auto&& c : value) {
586 counter += (std::isprint(c)) ? 1 : 4;
595 throw std::invalid_argument(
596 "calculate_translated_index can't take a nullptr");
598 std::ptrdiff_t counter = 0;
603 counter += (std::isprint(*value)) ? 1 : 4;
608template <
typename string>
610 std::ostringstream ret;
613 if (c < ' ' or c >=
'\x7F') {
615 }
else if (c ==
'"') {
617 }
else if (c ==
'\\') {
631 const char* type =
typeid(T).name()) -> T {
632 std::stringstream ss(val);
634 if (not (ss >> std::boolalpha >> ret).fail()) {
637 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
648 if (val ==
"1" or val ==
"true") {
650 }
else if (val ==
"0" or val ==
"false") {
653 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
659 const char* type =
typeid(T).name()) -> T {
660 std::stringstream ss(val);
662 if (not (ss >> std::boolalpha >> ret).fail()) {
665 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
671 return std::move(val);
676 if (val ==
"1" or val ==
"true") {
678 }
else if (val ==
"0" or val ==
"false") {
681 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
685# if KBLIB_USE_STRING_VIEW
689 -> std::string_view {
693inline auto fromStr(std::string&&,
const char*) -> std::string_view =
delete;
697 const char* type =
typeid(T).name()) -> T {
700 if (not (ss >> std::boolalpha >> ret).fail()) {
703 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
708 -> std::string_view {
714 return std::string(val);
719 if (val ==
"1" or val ==
"true") {
721 }
else if (val ==
"0" or val ==
"false") {
724 throw std::runtime_error(
"\"" + std::string(val) +
"\" is not a " + type);
728template <
typename To, std::
size_t N>
730 const char* type =
typeid(To).name()) -> To {
732 return fromStr<To>(std::string_view(val, N - 1), type);
735template <
typename To,
typename _>
737 const char* type =
typeid(To).name(), _ = 0)
739 return fromStr<To>(std::string_view(val), type);
746 std::stringstream ss;
754template <
typename To,
typename From>
756 static auto cast(
const From& val,
const char* type) -> To {
757 std::stringstream ss;
760 if (not (ss >> ret).fail()) {
763 throw std::runtime_error(
"Cannot convert \"" +
toStr(val) +
"\" to "
769template <
typename Same>
771 static auto cast(
const Same& val,
const char*) -> Same {
return val; }
776 static auto cast(
const std::string& val,
const char*) -> std::string {
781template <
typename From>
783 static auto cast(
const From& val,
const char*) -> std::string {
788template <
typename To>
790 static auto cast(
const std::string& val,
const char* type) -> To {
791 return fromStr<To>(val, type);
795# if KBLIB_USE_STRING_VIEW
798struct lexical_caster<
std::string_view, std::string_view> {
799 static auto cast(
const std::string_view& val,
const char*)
800 -> std::string_view {
806struct lexical_caster<
std::string_view, std::string> {
807 static auto cast(
const std::string& val,
const char*) -> std::string_view {
812template <
typename From>
813struct lexical_caster<
std::string_view, From> {
814 static std::enable_if_t<std::is_convertible_v<From, std::string_view>,
816 cast(
const From& val,
const char*) {
823 auto cast(...) -> std::string_view =
delete;
826template <
typename To>
827struct lexical_caster<To,
std::string_view> {
828 static auto cast(std::string_view val,
const char* type) -> To {
829 return fromStr<To>(val, type);
835template <
typename To,
typename From>
837 const char* type =
typeid(To).name()) -> To {
842template <
typename To,
typename From>
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>>) {
848 }
else if constexpr (std::is_same_v<std::decay_t<To>, std::string>) {
850 }
else if constexpr (std::is_same_v<std::decay_t<From>, std::string>) {
851 return fromStr<To>(val, type);
853 std::stringstream ss;
856 if (not(ss >> ret).fail())
859 throw std::runtime_error(
"Cannot convert \""s +
toStr(val) +
"\" to " +
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
constexpr auto pow1000(int p) -> double
constexpr auto largest_power_1000_p(double in) -> int
constexpr auto unit_of(std::chrono::nanoseconds) noexcept -> auto
auto ratio_to_SI() noexcept -> unit_conversion< std::intmax_t >
constexpr auto name_of(std::atto) -> prefix
typename nearest_ratio< Num, Den >::type nearest_ratio_t
constexpr auto largest_power_1000(std::intmax_t in) -> int
The main namespace in which all entities from kblib are defined.
constexpr auto to_signed(I x) -> std::make_signed_t< I >
Cast integral argument to corresponding signed type.
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...
auto time_to_str(std::chrono::time_point< clock, duration > &tp, const std::string &fmt="%F %T") -> std::string
constexpr auto parse_integer(const char *begin, const char *end, int base=0) -> Result
typename std::enable_if< B, T >::type enable_if_t
auto html_encode(const string &data) -> std::string
auto concat(F &&f, S &&... ins) -> string
Returns a string consisting of the concatenation of all arguments.
auto toStr(T val) -> std::string
auto quoted(string &&in) -> std::string
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...
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.
auto url_encode(const string &value) -> std::string
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.
auto to_string(Int num) -> std::string
auto escapify(char c) -> std::string
constexpr auto etoi(E e) -> auto
auto fromStr(const std::string &val, const char *type=typeid(T).name()) -> T
auto lexical_cast(const From &val, const char *type=typeid(To).name()) -> To
auto duration_to_str(std::chrono::duration< Rep, Ratio > &d) -> std::string
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
auto calculate_translated_index(string &&value, const char *p) -> std::ptrdiff_t
Provides utilities for performing common operations on strings.
constexpr constant(std::integral_constant< T, V >) noexcept
constexpr constant()=default
constexpr auto operator-() -> constant< T, -V >
const char * scale_prefix
static auto cast(const Same &val, const char *) -> Same
static auto cast(const std::string &val, const char *type) -> To
static auto cast(const From &val, const char *) -> std::string
static auto cast(const std::string &val, const char *) -> std::string
static auto cast(const From &val, const char *type) -> To
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Contains some type traits not in the standard library that are useful in the implementation of kblib.