1 #ifndef _C4_FORMAT_HPP_
2 #define _C4_FORMAT_HPP_
12 # pragma warning(push)
13 # if C4_MSVC_VERSION != C4_MSVC_VERSION_2017
14 # pragma warning(disable: 4800)
16 # pragma warning(disable: 4996)
17 #elif defined(__clang__)
18 # pragma clang diagnostic push
19 #elif defined(__GNUC__)
20 # pragma GCC diagnostic push
21 # pragma GCC diagnostic ignored "-Wuseless-cast"
271 static_assert(std::is_integral<T>::value,
"range checking only for integral types");
292 typename std::enable_if<std::is_signed<T>::value,
size_t>::type
301 typename std::enable_if<std::is_signed<T>::value,
size_t>::type
311 typename std::enable_if<std::is_unsigned<T>::value,
size_t>::type
320 typename std::enable_if<std::is_unsigned<T>::value,
size_t>::type
331 if(C4_LIKELY(!overflows<T>(s)))
340 if(C4_LIKELY(!overflows<T>(s)))
371 return real_<T>(val, precision, fmt);
405 C4_ALWAYS_INLINE
raw_wrapper_(blob_<T> data,
size_t alignment_) noexcept
526 return left_<T>(val, width, padchar);
548 if(ret >= buf.len || ret >= align.
width)
550 buf.first(align.
width).sub(ret).fill(align.
pad);
560 if(ret >= buf.len || ret >= align.
width)
562 size_t rem =
static_cast<size_t>(align.
width - ret);
563 buf.first(rem).fill(align.
pad);
578 inline size_t cat(substr )
592 template<
class Arg,
class... Args>
593 size_t cat(substr buf, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
596 buf = buf.len >= num ? buf.sub(num) : substr{};
597 num +=
cat(buf, more...);
602 template<
class... Args>
605 size_t sz =
cat(buf, std::forward<Args>(args)...);
606 C4_CHECK(sz <= buf.len);
607 return {buf.str, sz <= buf.len ? sz : buf.len};
621 inline size_t uncat(csubstr )
633 template<
class Arg,
class... Args>
634 size_t uncat(csubstr buf, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
639 buf = buf.len >= out ? buf.sub(out) : substr{};
640 size_t num =
uncat(buf, more...);
661 C4_ALWAYS_INLINE
size_t catsep_more(substr , Sep
const& C4_RESTRICT )
666 template<
class Sep,
class Arg,
class... Args>
667 size_t catsep_more(substr buf, Sep
const& C4_RESTRICT sep, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
671 buf = buf.len >= ret ? buf.sub(ret) : substr{};
674 buf = buf.len >= ret ? buf.sub(ret) : substr{};
675 ret = catsep_more(buf, sep, more...);
682 inline size_t uncatsep_more(csubstr , Sep & )
687 template<
class Sep,
class Arg,
class... Args>
688 size_t uncatsep_more(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
694 buf = buf.len >= ret ? buf.sub(ret) : substr{};
699 buf = buf.len >= ret ? buf.sub(ret) : substr{};
700 ret = uncatsep_more(buf, sep, more...);
710 size_t catsep(substr , Sep
const& C4_RESTRICT )
725 template<
class Sep,
class Arg,
class... Args>
726 size_t catsep(substr buf, Sep
const& C4_RESTRICT sep, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
729 buf = buf.len >= num ? buf.sub(num) : substr{};
730 num += detail::catsep_more(buf, sep, more...);
736 template<
class... Args>
739 size_t sz =
catsep(buf, std::forward<Args>(args)...);
740 C4_CHECK(sz <= buf.len);
741 return {buf.str, sz <= buf.len ? sz : buf.len};
766 template<
class Sep,
class Arg,
class... Args>
767 size_t uncatsep(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
772 buf = buf.len >= ret ? buf.sub(ret) : substr{};
773 ret = detail::uncatsep_more(buf, sep, more...);
792 inline size_t format(substr buf, csubstr fmt)
814 template<
class Arg,
class... Args>
815 size_t format(substr buf, csubstr fmt, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
817 size_t pos = fmt.find(
"{}");
820 size_t num =
to_chars(buf, fmt.sub(0, pos));
822 buf = buf.len >= num ? buf.sub(num) : substr{};
825 buf = buf.len >= num ? buf.sub(num) : substr{};
826 num =
format(buf, fmt.sub(pos + 2), more...);
834 template<
class... Args>
835 substr
format_sub(substr buf, csubstr fmt, Args
const& C4_RESTRICT ...args)
838 C4_CHECK(sz <= buf.len);
839 return {buf.str, sz <= buf.len ? sz : buf.len};
852 inline size_t unformat(csubstr , csubstr fmt)
863 template<
class Arg,
class... Args>
864 size_t unformat(csubstr buf, csubstr fmt, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
866 const size_t pos = fmt.find(
"{}");
871 buf = buf.len >= num ? buf.sub(num) : substr{};
876 buf = buf.len >= num ? buf.sub(num) : substr{};
877 num =
unformat(buf, fmt.sub(pos + 2), more...);
896 template<
class CharOwningContainer,
class... Args>
897 inline void catrs(CharOwningContainer * C4_RESTRICT cont, Args
const& C4_RESTRICT ...args)
901 size_t ret =
cat(buf, args...);
911 template<
class CharOwningContainer,
class... Args>
912 inline CharOwningContainer
catrs(Args
const& C4_RESTRICT ...args)
914 CharOwningContainer cont;
915 catrs(&cont, args...);
927 template<
class CharOwningContainer,
class... Args>
928 inline csubstr
catrs_append(CharOwningContainer * C4_RESTRICT cont, Args
const& C4_RESTRICT ...args)
930 const size_t pos = cont->size();
933 size_t ret =
cat(buf, args...);
934 cont->resize(pos + ret);
937 return to_csubstr(*cont).range(pos, cont->size());
949 template<
class CharOwningContainer,
class Sep,
class... Args>
950 inline void catseprs(CharOwningContainer * C4_RESTRICT cont, Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
954 size_t ret =
catsep(buf, sep, args...);
965 template<
class CharOwningContainer,
class Sep,
class... Args>
966 inline CharOwningContainer
catseprs(Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
968 CharOwningContainer cont;
981 template<
class CharOwningContainer,
class Sep,
class... Args>
982 inline csubstr
catseprs_append(CharOwningContainer * C4_RESTRICT cont, Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
984 const size_t pos = cont->size();
987 size_t ret =
catsep(buf, sep, args...);
988 cont->resize(pos + ret);
991 return to_csubstr(*cont).range(pos, cont->size());
1003 template<
class CharOwningContainer,
class... Args>
1004 inline void formatrs(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args
const& C4_RESTRICT ...args)
1008 size_t ret =
format(buf, fmt, args...);
1019 template<
class CharOwningContainer,
class... Args>
1020 inline CharOwningContainer
formatrs(csubstr fmt, Args
const& C4_RESTRICT ...args)
1022 CharOwningContainer cont;
1033 template<
class CharOwningContainer,
class... Args>
1034 inline csubstr
formatrs_append(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args
const& C4_RESTRICT ...args)
1036 const size_t pos = cont->size();
1039 size_t ret =
format(buf, fmt, args...);
1040 cont->resize(pos + ret);
1043 return to_csubstr(*cont).range(pos, cont->size());
1051 # pragma warning(pop)
1052 #elif defined(__clang__)
1053 # pragma clang diagnostic pop
1054 #elif defined(__GNUC__)
1055 # pragma GCC diagnostic pop
Lightweight generic type-safe wrappers for converting individual values to/from strings.
left_< T > left(T val, size_t width, char padchar=' ')
mark an argument to be aligned left
right_< T > right(T val, size_t width, char padchar=' ')
mark an argument to be aligned right
bool atox(csubstr s, uint8_t *v) noexcept
boolalpha_< T > boolalpha(T const &val, bool strict_read=false)
substr cat_sub(substr buf, Args &&...args)
like c4::cat() but return a substr instead of a size
csubstr catrs_append(CharOwningContainer *cont, Args const &...args)
cat+resize+append: like c4::cat(), but receives a container, and appends to it instead of overwriting...
size_t cat(substr buf, Arg const &a, Args const &...more)
serialize the arguments, concatenating them to the given fixed-size buffer.
void catrs(CharOwningContainer *cont, Args const &...args)
cat+resize: like c4::cat(), but receives a container, and resizes it as needed to contain the result.
csubstr catseprs_append(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize+append: like catsep(), but receives a container, and appends the arguments,...
void catseprs(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize: like c4::catsep(), but receives a container, and resizes it as needed to contain the r...
size_t catsep(substr buf, Sep const &sep, Arg const &a, Args const &...more)
serialize the arguments, concatenating them to the given fixed-size buffer, using a separator between...
substr catsep_sub(substr buf, Args &&...args)
like c4::catsep() but return a substr instead of a size
@ FTOA_FLOAT
print the real number in floating point format (like f)
size_t dtoa(substr str, double v, int precision=-1, RealFormat_e formatting=FTOA_FLEX) noexcept
Convert a double-precision real number to string.
size_t from_chars_first(csubstr buf, uint8_t *v) noexcept
bool from_chars(csubstr buf, uint8_t *v) noexcept
size_t ftoa(substr str, float v, int precision=-1, RealFormat_e formatting=FTOA_FLEX) noexcept
Convert a single-precision real number to string.
integral_< intptr_t > hex(std::nullptr_t)
format null as an hexadecimal value
integral_< T > integral(T val, T radix=10)
format an integral type with a custom radix
integral_< intptr_t > bin(std::nullptr_t)
format null as a binary 0-1 value
integral_< intptr_t > oct(std::nullptr_t)
format null as an octal value
size_t itoa(substr buf, T v) noexcept
convert an integral signed decimal to a string.
overflow_checked_< T > overflow_checked(T &val)
const_raw_wrapper raw(cblob data, size_t alignment=alignof(max_align_t))
mark a variable to be written in raw binary format, using memcpy
raw_wrapper_< byte > raw_wrapper
raw_wrapper_< cbyte > const_raw_wrapper
const_raw_wrapper craw(cblob data, size_t alignment=alignof(max_align_t))
mark a variable to be written in raw binary format, using memcpy
real_< T > real(T val, int precision, RealFormat_e fmt=FTOA_FLOAT)
csubstr to_csubstr(substr s) noexcept
neutral version for use in generic code
substr to_substr(substr s) noexcept
neutral version for use in generic code
size_t to_chars(substr buf, uint8_t v) noexcept
size_t uncat(csubstr buf, Arg &a, Args &...more)
deserialize the arguments from the given buffer.
size_t uncatsep(csubstr buf, Sep &sep, Arg &a, Args &...more)
deserialize the arguments from the given buffer.
size_t utoa(substr buf, T v) noexcept
convert an integral unsigned decimal to a string.
integral_padded_< T > zpad(T val, size_t num_digits)
pad the argument with zeroes on the left, with decimal radix
@ npos
a null string position
write a variable as an alphabetic boolean, ie as either true or false
boolalpha_(T val_, bool strict_read_=false)
format an integral type with a custom radix
C4_STATIC_ASSERT(std::is_integral< T >::value)
integral_(T val_, T radix_)
format an integral type with a custom radix, and pad with zeroes on the left
integral_padded_(T val_, T radix_, size_t nd)
C4_STATIC_ASSERT(std::is_integral< T >::value)
left_(T v, size_t w, char p)
overflow_checked_(T &val_)
raw_wrapper_(blob_< T > data, size_t alignment_) noexcept
real_(T v, int prec=-1, RealFormat_e f=FTOA_FLOAT)
right_(T v, size_t w, char p)