33#if KBLIB_DEF_MACROS and not defined(pFromStr)
34# define pFromStr(type, val) ::kblib::fromStr<type>((val), #type)
37#ifndef KBLIB_CONVERT_H
38# define KBLIB_CONVERT_H
54# if KBLIB_USE_STRING_VIEW
56# include <string_view>
63# if KBLIB_USE_SPANSTREAM
68# pragma GCC diagnostic push
69# pragma GCC diagnostic ignored "-W#warnings"
71# pragma GCC diagnostic pop
82template <
int base,
typename Int>
84 static_assert(base <= 62 and base > 0,
"Supported bases are 1 thru 62.");
86 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
92 }
else if (num == 0) {
96 ret.push_back(digits[num % base]);
97 }
while (num /= base);
101 std::reverse(ret.begin(), ret.end());
105template <
typename Int>
107 assert(base <= 62 and base > 0);
109 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
115 }
else if (num == 0) {
119 ret.push_back(digits[num % base]);
120 }
while (num /= base);
124 std::reverse(ret.begin(), ret.end());
131namespace detail_convert {
133 template <
typename Result,
unsigned variants, std::
size_t N>
135 const char* end,
unsigned base,
136 const char (&digits)[N])
139 throw std::invalid_argument(
"\"\" is not an integer");
142 for (
auto c :
indirect(begin, end)) {
144 if (result >
static_cast<Result
>(
max.
of<Result>() / base)) {
145 throw std::invalid_argument(
"Integer out of range for type");
148 auto pos =
find_in(std::begin(digits),
149 std::begin(digits) + base * variants, c);
150 if (pos != base * variants) {
151 result += pos / variants;
153 throw std::invalid_argument(
"invalid character in integer");
164template <
typename Result>
166 int base = 0) -> Result {
168 throw std::invalid_argument(
"\"\" is not an integer");
169 }
else if (*begin ==
'-') {
170 if (begin + 1 == end) {
171 throw std::invalid_argument(
"\"-\" is not an integer");
173 if (begin[1] ==
'-' or begin[1] ==
'+') {
174 throw std::invalid_argument(
"Too many signs in integer");
176 return -parse_integer<Result>(begin + 1, end, base);
178 if (begin[0] ==
'+') {
179 if (begin + 1 == end) {
180 throw std::invalid_argument(
"\"+\" is not an integer");
182 if (begin[1] ==
'+' or begin[1] ==
'-') {
183 throw std::invalid_argument(
"Too many signs in integer");
189 if (begin + 1 == end) {
191 }
else if (begin[1] ==
'-' or (begin + 2 != end and begin[2] ==
'-')) {
192 throw std::invalid_argument(
"unexpected - in integer");
193 }
else if (begin[1] ==
'+' or (begin + 2 != end and begin[2] ==
'+')) {
194 throw std::invalid_argument(
"unexpected + in integer");
198 return parse_integer<Result>(begin + 2, end, 16);
200 return parse_integer<Result>(begin + 2, end, 2);
202 return parse_integer<Result>(begin + 1, end, 8);
206 return parse_integer<Result>(begin, end, 10);
209 if (base < 2 or base > 62) {
210 throw std::invalid_argument(
211 "base must be either 0 or a positive number between 2 and 62");
212 }
else if (base <= 36) {
213 return detail_convert::read_digits<Result, 2>(
215 "00112233445566778899AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRr"
217 }
else if (base <= 62) {
218 return detail_convert::read_digits<Result, 1>(
220 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
228template <
typename Result, std::
size_t N>
232 return parse_integer<Result>(std::begin(in), std::end(in) - +(t ==
'\0'),
236template <
typename Result>
238 int base = 0) -> Result {
243# if KBLIB_USE_STRING_VIEW
245template <
typename Result>
254template <
typename T, T V>
258 constexpr constant(std::integral_constant<T, V>)
noexcept {}
262inline namespace literals {
264 template <
char... Cs>
266 constexpr char arr[] = {Cs...};
269 template <
char... Cs>
271 constexpr char arr[] = {Cs...};
280 return static_cast<std::underlying_type_t<E>
>(
e);
283template <
int maxBufLen = 4096,
typename clock,
typename duration>
285 const std::string& fmt =
"%F %T")
287 std::time_t time = clock::to_time_t(tp);
288 std::tm* tmb = std::localtime(&time);
289 std::string ret{maxBufLen,
'\0'};
290 std::strftime(&ret.front(), maxBufLen, fmt.c_str(), tmb);
348# if (-1U >> 63) > (1U << 18)
351# if (-1U >> 63) > (1U << 8)
352 constexpr auto name_of(std::zepto) -> prefix {
return prefix{
"zepto",
"z"}; }
374# if (-1U >> 63) > (1U << 8)
375 constexpr auto name_of(std::zetta) -> prefix {
return prefix{
"zetta",
"Z"}; }
377# if (-1U >> 63) > (1U << 18)
378 constexpr auto name_of(std::yotta) -> prefix {
return prefix{
"yotta",
"Y"}; }
382 if (in % 1000 == 0) {
390 if (in / 1000 >= 1) {
400 if (in / 1000 >= 1) {
421 template <
typename R>
424# if (-1U >> 63) > (1U << 18)
428# if (-1U >> 63) > (1U << 8)
430 struct is_si_ratio<
std::zepto> : std::true_type {};
469# if (-1U >> 63) > (1U << 8)
473# if (-1U >> 63) > (1U << 18)
475 struct is_si_ratio<
std::yotta> : std::true_type {};
478 template <
typename M>
485 template <std::
intmax_t Num, std::
intmax_t Den>
490 template <std::
intmax_t Num, std::
intmax_t Den>
493 template <std::
intmax_t Num, std::
intmax_t Den>
498template <
typename Rep,
typename Ratio,
500 typename Ratio::type>
::value>* =
nullptr>
502 std::chrono::duration<Rep, Ratio>& d) -> std::string {
503 using ratio =
typename Ratio::type;
505 return concat(d.count() / (
static_cast<double>(ratio{}.num) / ratio{}.den),
509template <
typename Rep,
typename Ratio,
513 std::chrono::duration<Rep, Ratio>& d) -> std::string {
514 using ratio =
typename Ratio::type;
515 using n_r = detail_units::nearest_ratio_t<ratio::num, ratio::den>;
519 std::chrono::duration<Rep, n_r> n_d = d;
520 return concat(n_d.count(),
' ', u.abbr,
's');
523template <
typename Rep>
525 std::chrono::duration<Rep, std::ratio<60>> d) -> std::string {
526 return concat(d.count(),
" min");
528template <
typename Rep>
530 std::chrono::duration<Rep, std::ratio<3600>> d) -> std::string {
531 return concat(d.count(),
" hr");
534template <
typename string>
536 std::ostringstream escaped;
540 for (
char c :
value) {
542 if (std::isalnum(c) or c ==
'-' or c ==
'_' or c ==
'.' or c ==
'~') {
546 escaped << std::uppercase;
547 escaped <<
'%' << std::setw(2) << int(
to_unsigned(c));
548 escaped << std::nouppercase;
552 return escaped.str();
555template <
typename string>
559 buffer.reserve(data.size() + data.size() / 8);
560 for (
char c : data) {
588 constexpr std::array<char, 16> digits{
590 std::string rc(
"\\x ");
591 rc[2] = digits[
value >> 4u];
592 rc[3] = digits[
value & 15u];
595 return std::string(1,
static_cast<char>(
value));
600template <
typename string>
602 std::ostringstream ret;
603 for (
char c :
value) {
604 if (c < ' ' or c >=
'\x7F') {
615template <
typename string>
619 std::ptrdiff_t counter = 0;
620 for (
auto&& c :
value) {
624 counter += (std::isprint(c)) ? 1 : 4;
633 throw std::invalid_argument(
634 "calculate_translated_index can't take a nullptr");
636 std::ptrdiff_t counter = 0;
641 counter += (std::isprint(*
value)) ? 1 : 4;
646template <
typename character, enable_if_t<is_
character_v<
character>>* =
nullptr>
648 if (c < ' ' or c >=
'\x7F') {
650 }
else if (c ==
'"') {
652 }
else if (c ==
'\\') {
659template <
typename string, enable_if_t<not is_
character_v<
string>>* =
nullptr>
661 std::ostringstream ret;
664 if (c < ' ' or c >=
'\x7F') {
666 }
else if (c ==
'"') {
668 }
else if (c ==
'\\') {
682 const char* type =
typeid(T).name()) -> T {
683 std::stringstream ss(val);
685 if (not (ss >> std::boolalpha >> ret).fail()) {
688 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
699 if (val ==
"1" or val ==
"true") {
701 }
else if (val ==
"0" or val ==
"false") {
704 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
710 const char* type =
typeid(T).name()) -> T {
711 std::stringstream ss(val);
713 if (not (ss >> std::boolalpha >> ret).fail()) {
716 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
722 return std::move(val);
727 if (val ==
"1" or val ==
"true") {
729 }
else if (val ==
"0" or val ==
"false") {
732 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
736# if KBLIB_USE_STRING_VIEW
740 -> std::string_view {
744inline auto fromStr(std::string&&,
const char*) -> std::string_view =
delete;
748 const char* type =
typeid(T).name()) -> T {
749# if KBLIB_USE_SPANSTREAM
750 std::ispanstream ss(std::span<const char>(val.data(), val.size()));
755 if (not (ss >> std::boolalpha >> ret).fail()) {
758 throw std::runtime_error(
kblib::quoted(val) +
" is not a " + type);
763 -> std::string_view {
769 return std::string(val);
774 if (val ==
"1" or val ==
"true") {
776 }
else if (val ==
"0" or val ==
"false") {
779 throw std::runtime_error(
"\"" + std::string(val) +
"\" is not a " + type);
783template <
typename To, std::
size_t N>
785 const char* type =
typeid(To).name())
788 return fromStr<To>(std::string_view(val, N - 1), type);
791template <
typename To,
typename _>
793 const char* type =
typeid(To).name(),
795 return fromStr<To>(std::string_view(val), type);
802 std::stringstream ss;
810template <
typename To,
typename From>
812 static auto cast(
const From& val,
const char* type) -> To {
813 std::stringstream ss;
816 if (not (ss >> ret).fail()) {
819 throw std::runtime_error(
"Cannot convert \"" +
toStr(val) +
"\" to "
825template <
typename Same>
827 static constexpr auto cast(
const Same& val,
const char*) -> Same {
834 static constexpr auto cast(
const std::string& val,
const char*)
840template <
typename From>
842 static constexpr auto cast(
const From& val,
const char*) -> std::string {
847template <
typename To>
849 static constexpr auto cast(
const std::string& val,
const char* type) -> To {
850 return fromStr<To>(val, type);
854# if KBLIB_USE_STRING_VIEW
858 static constexpr auto cast(
const std::string_view& val,
const char*)
859 -> std::string_view {
866 static constexpr auto cast(
const std::string& val,
const char*)
867 -> std::string_view {
872template <
typename From>
875 std::is_convertible_v<From, std::string_view>, std::string_view>
876 cast(
const From& val,
const char*) {
883 auto cast(...) -> std::string_view =
delete;
886template <
typename To>
888 static constexpr auto cast(std::string_view val,
const char* type) -> To {
889 return fromStr<To>(val, type);
895template <
typename To,
typename From>
898 =
typeid(To).name()) -> To {
903template <
typename To,
typename From>
905 const char* type =
typeid(To).name()) -> To {
906 using namespace std::literals;
907 if constexpr (std::is_same_v<std::decay_t<To>, std::decay_t<From>>) {
909 }
else if constexpr (std::is_same_v<std::decay_t<To>, std::string>) {
911 }
else if constexpr (std::is_same_v<std::decay_t<From>, std::string>) {
912 return fromStr<To>(val, type);
914 std::stringstream ss;
917 if (not(ss >> ret).fail())
920 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...
GeneratorWrapper< T > value(T &&value)
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
constexpr auto unit_of(std::chrono::hours) noexcept -> auto
constexpr auto ratio_to_SI() noexcept -> unit_conversion< std::intmax_t >
constexpr auto largest_power_1000(double in) -> int
typename nearest_ratio< Num, Den >::type nearest_ratio_t
constexpr struct kblib::nums::max_t max
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
constexpr 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
constexpr auto html_encode(const string &data) -> std::string
constexpr auto quoted(character c) -> std::string
constexpr auto duration_to_str(std::chrono::duration< Rep, std::ratio< 3600 > > d) -> 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 fromStr(const char *val, const char *type=typeid(To).name(), _=0) -> To
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.
constexpr auto toStr(std::string val) -> std::string
constexpr auto lexical_cast(const From &val, const char *type=typeid(To).name()) -> To
auto escapify(const string &value) -> std::string
constexpr auto etoi(E e) -> auto
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
constexpr auto to_string(Int num, int base) -> std::string
constexpr auto calculate_translated_index(const char *value, const char *p) -> std::ptrdiff_t
Provides numerical and mathematical utilities.
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 constexpr auto cast(const Same &val, const char *) -> Same
static constexpr auto cast(const std::string &val, const char *type) -> To
static constexpr auto cast(std::string_view val, const char *type) -> To
static constexpr auto cast(const From &val, const char *) -> std::string
static constexpr auto cast(const std::string &val, const char *) -> std::string
static constexpr std::enable_if_t< std::is_convertible_v< From, std::string_view >, std::string_view > cast(const From &val, const char *)
auto cast(...) -> std::string_view=delete
static constexpr auto cast(const std::string &val, const char *) -> std::string_view
static constexpr auto cast(const std::string_view &val, const char *) -> std::string_view
static auto cast(const From &val, const char *type) -> To
static constexpr auto of() noexcept(noexcept(std::numeric_limits< T >::max()))
#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.