1 #ifndef _C4_FORMAT_HPP_
2 #define _C4_FORMAT_HPP_
11 #if defined(_MSC_VER) && !defined(__clang__)
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"
268 static_assert(std::is_integral<T>::value,
"range checking only for integral types");
289 typename std::enable_if<std::is_signed<T>::value,
size_t>::type
298 typename std::enable_if<std::is_signed<T>::value,
size_t>::type
308 typename std::enable_if<std::is_unsigned<T>::value,
size_t>::type
317 typename std::enable_if<std::is_unsigned<T>::value,
size_t>::type
328 if(C4_LIKELY(!overflows<T>(s)))
337 if(C4_LIKELY(!overflows<T>(s)))
368 return real_<T>(val, precision, fmt);
402 C4_ALWAYS_INLINE
raw_wrapper_(blob_<T> data,
size_t alignment_) noexcept
521 return left_<T>(val, width, padchar);
574 if(ret >= buf.len || ret >= align.
width)
585 if(ret >= buf.len || ret >= align.
width)
587 size_t rem = align.
width - ret;
589 memmove(buf.str + rem, buf.str, ret);
590 buf.first(rem).fill(align.
padchar);
599 if(ret >= buf.len || ret >= align.
width)
601 size_t first = (align.
width - ret) / 2u;
603 memmove(buf.str + first, buf.str, ret);
604 buf.first(first).fill(align.
padchar);
605 buf.sub(first + ret).fill(align.
padchar);
620 inline size_t cat(substr )
652 template<
class Arg,
class... Args>
653 size_t cat(substr buf, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
656 buf = buf.len >= num ? buf.sub(num) : substr{};
657 num +=
cat(buf, more...);
662 template<
class... Args>
663 substr
cat_sub(substr buf, Args
const& C4_RESTRICT ...args)
665 size_t sz =
cat(buf, args...);
666 C4_CHECK(sz <= buf.len);
667 return {buf.str, sz <= buf.len ? sz : buf.len};
681 inline size_t uncat(csubstr )
693 template<
class Arg,
class... Args>
694 size_t uncat(csubstr buf, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
699 buf = buf.len >= out ? buf.sub(out) : substr{};
700 size_t num =
uncat(buf, more...);
721 C4_ALWAYS_INLINE
size_t catsep_more(substr , Sep
const& C4_RESTRICT )
726 template<
class Sep,
class Arg,
class... Args>
727 size_t catsep_more(substr buf, Sep
const& C4_RESTRICT sep, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
731 buf = buf.len >= ret ? buf.sub(ret) : substr{};
734 buf = buf.len >= ret ? buf.sub(ret) : substr{};
735 ret = catsep_more(buf, sep, more...);
743 size_t catsep(substr , Sep
const& C4_RESTRICT )
777 template<
class Sep,
class Arg,
class... Args>
778 size_t catsep(substr buf, Sep
const& C4_RESTRICT sep, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
781 buf = buf.len >= num ? buf.sub(num) : substr{};
782 num += detail::catsep_more(buf, sep, more...);
789 template<
class... Args>
792 size_t sz =
catsep(buf, std::forward<Args>(args)...);
793 C4_CHECK(sz <= buf.len);
794 return {buf.str, sz <= buf.len ? sz : buf.len};
810 inline size_t uncatsep(csubstr buf, csubstr , Arg &C4_RESTRICT a)
822 template<
class Arg,
class... Args>
823 size_t uncatsep(csubstr buf, csubstr sep, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
825 if(C4_LIKELY(sep.len > 0))
827 size_t pos = buf.find(sep);
833 size_t num =
uncatsep(buf.sub(pos), sep, more...);
854 inline size_t format(substr buf, csubstr fmt)
939 template<
class Arg,
class... Args>
940 size_t format(substr buf, csubstr fmt, Arg
const& C4_RESTRICT a, Args
const& C4_RESTRICT ...more)
942 size_t pos = fmt.find(
"{}");
945 size_t num =
to_chars(buf, fmt.first(pos));
947 buf = buf.len >= num ? buf.sub(num) : substr{};
950 buf = buf.len >= num ? buf.sub(num) : substr{};
951 num =
format(buf, fmt.sub(pos + 2), more...);
959 template<
class... Args>
960 substr
format_sub(substr buf, csubstr fmt, Args
const& C4_RESTRICT ...args)
963 C4_CHECK(sz <= buf.len);
964 return {buf.str, sz <= buf.len ? sz : buf.len};
977 inline size_t unformat(csubstr , csubstr fmt)
990 template<
class Arg,
class... Args>
991 size_t unformat(csubstr buf, csubstr fmt, Arg & C4_RESTRICT a, Args & C4_RESTRICT ...more)
993 const size_t pos = fmt.find(
"{}");
998 buf = buf.len >= num ? buf.sub(num) : substr{};
1003 buf = buf.len >= num ? buf.sub(num) : substr{};
1004 num =
unformat(buf, fmt.sub(pos + 2), more...);
1043 template<
class CharOwningContainer,
class... Args>
1044 inline void catrs(CharOwningContainer * C4_RESTRICT cont, Args
const& C4_RESTRICT ...args)
1046 cont->resize(cont->capacity());
1049 size_t ret =
cat(buf, args...);
1078 template<
class CharOwningContainer,
class... Args>
1079 inline CharOwningContainer
catrs(Args
const& C4_RESTRICT ...args)
1081 CharOwningContainer cont;
1082 catrs(&cont, args...);
1112 template<
class CharOwningContainer,
class... Args>
1113 inline csubstr
catrs_append(CharOwningContainer * C4_RESTRICT cont, Args
const& C4_RESTRICT ...args)
1115 const size_t pos = cont->size();
1116 cont->resize(cont->capacity());
1119 size_t ret =
cat(buf, args...);
1120 cont->resize(pos + ret);
1123 return to_csubstr(*cont).range(pos, cont->size());
1155 template<
class CharOwningContainer,
class Sep,
class... Args>
1156 inline void catseprs(CharOwningContainer * C4_RESTRICT cont, Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
1158 cont->resize(cont->capacity());
1161 size_t ret =
catsep(buf, sep, args...);
1190 template<
class CharOwningContainer,
class Sep,
class... Args>
1191 inline CharOwningContainer
catseprs(Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
1193 CharOwningContainer cont;
1223 template<
class CharOwningContainer,
class Sep,
class... Args>
1224 inline csubstr
catseprs_append(CharOwningContainer * C4_RESTRICT cont, Sep
const& C4_RESTRICT sep, Args
const& C4_RESTRICT ...args)
1226 const size_t pos = cont->size();
1227 cont->resize(cont->capacity());
1230 size_t ret =
catsep(buf, sep, args...);
1231 cont->resize(pos + ret);
1234 return to_csubstr(*cont).range(pos, cont->size());
1266 template<
class CharOwningContainer,
class... Args>
1267 inline void formatrs(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args
const& C4_RESTRICT ...args)
1269 cont->resize(cont->capacity());
1272 size_t ret =
format(buf, fmt, args...);
1301 template<
class CharOwningContainer,
class... Args>
1302 inline CharOwningContainer
formatrs(csubstr fmt, Args
const& C4_RESTRICT ...args)
1304 CharOwningContainer cont;
1333 template<
class CharOwningContainer,
class... Args>
1334 inline csubstr
formatrs_append(CharOwningContainer * C4_RESTRICT cont, csubstr fmt, Args
const& C4_RESTRICT ...args)
1336 const size_t pos = cont->size();
1337 cont->resize(cont->capacity());
1340 size_t ret =
format(buf, fmt, args...);
1341 cont->resize(pos + ret);
1344 return to_csubstr(*cont).range(pos, cont->size());
1353 # pragma warning(pop)
1354 #elif defined(__clang__)
1355 # pragma clang diagnostic pop
1356 #elif defined(__GNUC__)
1357 # pragma GCC diagnostic pop
Lightweight generic type-safe wrappers for converting individual values to/from strings.
center_< T > center(T val, size_t width, char padchar=' ')
tag function to mark an argument to be aligned center
left_< T > left(T val, size_t width, char padchar=' ')
tag type to mark an argument to be aligned left.
right_< T > right(T val, size_t width, char padchar=' ')
tag function to mark an argument to be aligned right
bool atox(csubstr s, uint8_t *v) noexcept
boolalpha_ boolalpha(T const &val=false)
tag function to mark a variable to be written as an alphabetic boolean, ie as either true or false
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.
substr cat_sub(substr buf, Args const &...args)
like c4::cat() but return a substr instead of a size
csubstr catseprs_append(CharOwningContainer *cont, Sep const &sep, Args const &...args)
catsep+resize+append: like c4::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, csubstr sep, Arg &a, Args &...more)
deserialize the arguments from the given buffer, using a separator.
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
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
center_(T v, size_t w, char c) noexcept
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 c) noexcept
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 c) noexcept