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)))
362 return real_<T>(val, precision, fmt);
396 C4_ALWAYS_INLINE
raw_wrapper_(blob_<T> data,
size_t alignment_) noexcept
517 return left_<T>(val, width, padchar);
539 if(ret >= buf.len || ret >= align.
width)
541 buf.first(align.
width).sub(ret).fill(align.
pad);
551 if(ret >= buf.len || ret >= align.
width)
553 size_t rem =
static_cast<size_t>(align.
width - ret);
554 buf.first(rem).fill(align.
pad);
569 inline size_t cat(substr )
583 template<
class Arg,
class... Args>
584 size_t cat(substr buf, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
587 buf = buf.len >= num ? buf.sub(num) : substr{};
588 num +=
cat(buf, more...);
593 template<
class... Args>
596 size_t sz =
cat(buf, std::forward<Args>(args)...);
597 C4_CHECK(sz <= buf.len);
598 return {buf.str, sz <= buf.len ? sz : buf.len};
612 inline size_t uncat(csubstr )
624 template<
class Arg,
class... Args>
625 size_t uncat(csubstr buf, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
630 buf = buf.len >= out ? buf.sub(out) : substr{};
631 size_t num =
uncat(buf, more...);
652 C4_ALWAYS_INLINE
size_t catsep_more(substr , Sep
const& C4_RESTRICT )
657 template<
class Sep,
class Arg,
class... Args>
658 size_t catsep_more(substr buf, Sep
const& C4_RESTRICT sep, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
662 buf = buf.len >= ret ? buf.sub(ret) : substr{};
665 buf = buf.len >= ret ? buf.sub(ret) : substr{};
666 ret = catsep_more(buf, sep, more...);
673 inline size_t uncatsep_more(csubstr , Sep & )
678 template<
class Sep,
class Arg,
class... Args>
679 size_t uncatsep_more(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
685 buf = buf.len >= ret ? buf.sub(ret) : substr{};
690 buf = buf.len >= ret ? buf.sub(ret) : substr{};
691 ret = uncatsep_more(buf, sep, more...);
701 size_t catsep(substr , Sep
const& C4_RESTRICT )
716 template<
class Sep,
class Arg,
class... Args>
717 size_t catsep(substr buf, Sep
const& C4_RESTRICT sep, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
720 buf = buf.len >= num ? buf.sub(num) : substr{};
721 num += detail::catsep_more(buf, sep, more...);
727 template<
class... Args>
730 size_t sz =
catsep(buf, std::forward<Args>(args)...);
731 C4_CHECK(sz <= buf.len);
732 return {buf.str, sz <= buf.len ? sz : buf.len};
757 template<
class Sep,
class Arg,
class... Args>
758 size_t uncatsep(csubstr buf, Sep & C4_RESTRICT sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
763 buf = buf.len >= ret ? buf.sub(ret) : substr{};
764 ret = detail::uncatsep_more(buf, sep, more...);
783 inline size_t format(substr buf, csubstr fmt)
805 template<
class Arg,
class... Args>
806 size_t format(substr buf, csubstr fmt, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
808 size_t pos = fmt.find(
"{}");
811 size_t num =
to_chars(buf, fmt.sub(0, pos));
813 buf = buf.len >= num ? buf.sub(num) : substr{};
816 buf = buf.len >= num ? buf.sub(num) : substr{};
817 num =
format(buf, fmt.sub(pos + 2), more...);
825 template<
class... Args>
826 substr
format_sub(substr buf, csubstr fmt, Args
const& C4_RESTRICT ...args)
829 C4_CHECK(sz <= buf.len);
830 return {buf.str, sz <= buf.len ? sz : buf.len};
843 inline size_t unformat(csubstr , csubstr fmt)
854 template<
class Arg,
class... Args>
855 size_t unformat(csubstr buf, csubstr fmt, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
857 const size_t pos = fmt.find(
"{}");
862 buf = buf.len >= num ? buf.sub(num) : substr{};
867 buf = buf.len >= num ? buf.sub(num) : substr{};
868 num =
unformat(buf, fmt.sub(pos + 2), more...);
887 template<
class CharOwningContainer,
class... Args>
888 inline void catrs(CharOwningContainer * C4_RESTRICT cont, Args
const& C4_RESTRICT ...args)
892 size_t ret =
cat(buf, args...);
902 template<
class CharOwningContainer,
class... Args>
903 inline CharOwningContainer
catrs(Args
const& C4_RESTRICT ...args)
905 CharOwningContainer cont;
906 catrs(&cont, args...);
918 template<
class CharOwningContainer,
class... Args>
919 inline csubstr
catrs_append(CharOwningContainer * C4_RESTRICT cont, Args
const& C4_RESTRICT ...args)
921 const size_t pos = cont->size();
924 size_t ret =
cat(buf, args...);
925 cont->resize(pos + ret);
928 return to_csubstr(*cont).range(pos, cont->size());
940 template<
class CharOwningContainer,
class Sep,
class... Args>
941 inline void catseprs(CharOwningContainer * C4_RESTRICT cont, Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
945 size_t ret =
catsep(buf, sep, args...);
956 template<
class CharOwningContainer,
class Sep,
class... Args>
957 inline CharOwningContainer
catseprs(Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
959 CharOwningContainer cont;
972 template<
class CharOwningContainer,
class Sep,
class... Args>
973 inline csubstr
catseprs_append(CharOwningContainer * C4_RESTRICT cont, Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
975 const size_t pos = cont->size();
978 size_t ret =
catsep(buf, sep, args...);
979 cont->resize(pos + ret);
982 return to_csubstr(*cont).range(pos, cont->size());
994 template<
class CharOwningContainer,
class... Args>
995 inline void formatrs(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args
const& C4_RESTRICT ...args)
999 size_t ret =
format(buf, fmt, args...);
1010 template<
class CharOwningContainer,
class... Args>
1011 inline CharOwningContainer
formatrs(csubstr fmt, Args
const& C4_RESTRICT ...args)
1013 CharOwningContainer cont;
1024 template<
class CharOwningContainer,
class... Args>
1025 inline csubstr
formatrs_append(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args
const& C4_RESTRICT ...args)
1027 const size_t pos = cont->size();
1030 size_t ret =
format(buf, fmt, args...);
1031 cont->resize(pos + ret);
1034 return to_csubstr(*cont).range(pos, cont->size());
1042 # pragma warning(pop)
1043 #elif defined(__clang__)
1044 # pragma clang diagnostic pop
1045 #elif defined(__GNUC__)
1046 # 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)