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 character, enable_if_t<is_
character_v<
character>>* =
nullptr>
610 if (c < ' ' or c >=
'\x7F') {
612 }
else if (c ==
'"') {
614 }
else if (c ==
'\\') {
621template <
typename string, enable_if_t<not is_
character_v<
string>>* =
nullptr>
623 std::ostringstream ret;
626 if (c < ' ' or c >=
'\x7F') {
628 }
else if (c ==
'"') {
630 }
else if (c ==
'\\') {
644 const char* type =
typeid(T).name()) -> T {
645 std::stringstream ss(val);
647 if (not (ss >> std::boolalpha >> ret).fail()) {
650 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
661 if (val ==
"1" or val ==
"true") {
663 }
else if (val ==
"0" or val ==
"false") {
666 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
672 const char* type =
typeid(T).name()) -> T {
673 std::stringstream ss(val);
675 if (not (ss >> std::boolalpha >> ret).fail()) {
678 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
684 return std::move(val);
689 if (val ==
"1" or val ==
"true") {
691 }
else if (val ==
"0" or val ==
"false") {
694 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
698# if KBLIB_USE_STRING_VIEW
702 -> std::string_view {
706inline auto fromStr(std::string&&,
const char*) -> std::string_view =
delete;
710 const char* type =
typeid(T).name()) -> T {
713 if (not (ss >> std::boolalpha >> ret).fail()) {
716 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
721 -> std::string_view {
727 return std::string(val);
732 if (val ==
"1" or val ==
"true") {
734 }
else if (val ==
"0" or val ==
"false") {
737 throw std::runtime_error(
"\"" + std::string(val) +
"\" is not a " + type);
741template <
typename To, std::
size_t N>
743 const char* type =
typeid(To).name()) -> To {
745 return fromStr<To>(std::string_view(val, N - 1), type);
748template <
typename To,
typename _>
750 const char* type =
typeid(To).name(), _ = 0)
752 return fromStr<To>(std::string_view(val), type);
759 std::stringstream ss;
767template <
typename To,
typename From>
769 static auto cast(
const From& val,
const char* type) -> To {
770 std::stringstream ss;
773 if (not (ss >> ret).fail()) {
776 throw std::runtime_error(
"Cannot convert \"" +
toStr(val) +
"\" to "
782template <
typename Same>
784 static auto cast(
const Same& val,
const char*) -> Same {
return val; }
789 static auto cast(
const std::string& val,
const char*) -> std::string {
794template <
typename From>
796 static auto cast(
const From& val,
const char*) -> std::string {
801template <
typename To>
803 static auto cast(
const std::string& val,
const char* type) -> To {
804 return fromStr<To>(val, type);
808# if KBLIB_USE_STRING_VIEW
812 static auto cast(
const std::string_view& val,
const char*)
813 -> std::string_view {
820 static auto cast(
const std::string& val,
const char*) -> std::string_view {
825template <
typename From>
827 static std::enable_if_t<std::is_convertible_v<From, std::string_view>,
829 cast(
const From& val,
const char*) {
836 auto cast(...) -> std::string_view =
delete;
839template <
typename To>
841 static auto cast(std::string_view val,
const char* type) -> To {
842 return fromStr<To>(val, type);
848template <
typename To,
typename From>
850 const char* type =
typeid(To).name()) -> To {
855template <
typename To,
typename From>
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>>) {
861 }
else if constexpr (std::is_same_v<std::decay_t<To>, std::string>) {
863 }
else if constexpr (std::is_same_v<std::decay_t<From>, std::string>) {
864 return fromStr<To>(val, type);
866 std::stringstream ss;
869 if (not(ss >> ret).fail())
872 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 name_of(std::exa) -> prefix
auto ratio_to_SI() noexcept -> unit_conversion< std::intmax_t >
constexpr auto unit_of(std::chrono::hours) noexcept -> auto
constexpr auto largest_power_1000(double in) -> int
typename nearest_ratio< Num, Den >::type nearest_ratio_t
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
auto quoted(string &&in) -> std::string
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.
constexpr auto parse_integer(std::string_view in, int base=0) -> Result
auto toStr(std::string val) -> 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 quoted(character c) -> std::string
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 fromStr(const char *val, const char *type=typeid(To).name(), _=0) -> To
auto to_string(Int num, int base) -> std::string
auto duration_to_str(std::chrono::duration< Rep, std::ratio< 3600 > > d) -> std::string
auto escapify(const string &value) -> std::string
constexpr auto etoi(E e) -> auto
auto calculate_translated_index(const char *value, const char *p) -> std::ptrdiff_t
auto lexical_cast(const From &val, const char *type=typeid(To).name()) -> To
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
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(std::string_view 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
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 *)
static auto cast(const std::string &val, const char *) -> std::string_view
static auto cast(const std::string_view &val, const char *) -> std::string_view
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.