struct FHexU {};
constexpr PrintfFlags(PrintfFlags x, FHexU _): width(x.width), precision(x.precision), flags(x.flags | 0x800) {}
- PrintfFlags():
+ constexpr PrintfFlags():
width(0), precision(0), flags(0)
{
}
typedef ::std::function<void(const char*,size_t)> cprintf_cb;
template <typename Arg> size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags &fmt, Arg arg);
+template <typename Arg> constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, Arg arg);
+constexpr bool cprintf_val_chk(const _bits::PrintfFlags fmt, const char* arg) {
+ return true;
+}
size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* arg) {
unsigned int len;
for(len = 0; arg[len]; len ++)
puts(arg, len);
return len;
}
+constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, int arg) {
+ return true;
+}
size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) {
size_t len = ::std::snprintf(nullptr, 0, "%i", arg);
char buf[len+1];
puts(buf, len);
return len;
}
+constexpr bool cprintf_val_chk(const _bits::PrintfFlags& fmt, unsigned int arg) {
+ return true;
+}
size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, unsigned int arg) {
size_t len = ::std::snprintf(nullptr, 0, "%u", arg);
char buf[len+1];
{
namespace _printf
{
+ template <unsigned N>
+ class _str
+ {
+ const char m_buf[N];
+ unsigned m_ofs;
+ public:
+ constexpr _str(const char buf[N]):
+ m_buf(buf),
+ m_ofs(0)
+ {
+ }
+ constexpr _str(const char buf[N], unsigned ofs):
+ m_buf(buf),
+ m_ofs(ofs)
+ {
+ }
+ constexpr _str<N> operator+(const unsigned o) {
+ return _str(m_buf, m_ofs+o);
+ }
+ constexpr char operator*() {
+ return m_buf[m_ofs];
+ }
+ };
+
+ template <typename... Args>
+ constexpr bool val(const char* fmt, Args... args);
+
+ template <typename Fmt>
+ constexpr bool val_fmt_done(const char * fmt, PrintfFlags item, Fmt fmtcode)
+ {
+ return false ? false : throw "Too few arguments";
+ }
+ template <typename Fmt, typename Arg, typename... Args>
+ constexpr bool val_fmt_done(const char* fmt, PrintfFlags item, Fmt fmtcode, Arg arg, Args... args)
+ {
+ return cprintf_val_chk(item, arg) && val(fmt+1, args...);
+ }
+ // --- Format code
+ template <typename ...Args>
+ constexpr bool val_fmt_fmt(const char * fmt, PrintfFlags item, Args... args)
+ {
+ return *fmt == '\0' ? throw "ERROR: NUL byte in format specifier"
+ : *fmt == '?' ? val_fmt_done(fmt, item, PrintfFlags::FAuto(), args...)
+ : *fmt == 's' ? val_fmt_done(fmt, item, PrintfFlags::FString(),args...)
+ : *fmt == 'B' ? val_fmt_done(fmt, item, PrintfFlags::FBool(), args...)
+ : *fmt == 'b' ? val_fmt_done(fmt, item, PrintfFlags::FBinary(),args...)
+ : *fmt == 'o' ? val_fmt_done(fmt, item, PrintfFlags::FOct(), args...)
+ : *fmt == 'i' ? val_fmt_done(fmt, item, PrintfFlags::FSDec(), args...)
+ : *fmt == 'u' ? val_fmt_done(fmt, item, PrintfFlags::FUDec(), args...)
+ : *fmt == 'x' ? val_fmt_done(fmt, item, PrintfFlags::FHexL(), args...)
+ : *fmt == 'X' ? val_fmt_done(fmt, item, PrintfFlags::FHexU(), args...)
+ : throw cprintf_badformat("Unknown character in format string");
+ }
+ // --- Size modifier (not implemented, not needed?)
+ template <typename ...Args>
+ constexpr bool val_fmt_size(const char * fmt, PrintfFlags item, Args... args)
+ {
+ // TODO: Size characters?
+ return val_fmt_fmt(fmt, item, args...);
+ }
+ // --- Precision
+ template <typename ...Args>
+ constexpr bool val_fmt_prec_val(const char * fmt, unsigned int value, PrintfFlags item, Args... args)
+ {
+ return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, value*10+_bits::todigit(*fmt), item, args...)
+ : val_fmt_size(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), value), args...);
+ }
+ template <typename ...Args>
+ constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args)
+ {
+ return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgPrec(), size), args...);
+ }
+ template <typename Arg, typename ...Args>
+ constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item, Arg size, Args... args)
+ {
+ //static_assert(false, "Invalid type for precision modifier, must be 'unsigned int'");
+ return false ? false : throw "Invalid type for precision modifier, must be 'unsigned int'";
+ }
+ constexpr bool val_fmt_prec_arg(const char *fmt, PrintfFlags item)
+ {
+ //static_assert(false, "Too few arguments when getting precision modifier");
+ return false ? false : throw "Too few arguments when getting precision modifier";
+ }
+ template <typename ...Args>
+ constexpr bool val_fmt_prec(const char * fmt, PrintfFlags item, Args... args)
+ {
+ return _bits::isdigit_s(*fmt) ? val_fmt_prec_val(fmt+1, _bits::todigit(*fmt), item, args...)
+ : *fmt == '*' ? val_fmt_prec_arg(fmt+1, item, args...)
+ : val_fmt_size(fmt, item, args...);
+ }
+ template <typename ...Args>
+ constexpr bool val_fmt_prec_opt(const char * fmt, PrintfFlags item, Args... args)
+ {
+ return *fmt == '.' ? val_fmt_prec(fmt+1, item, args...)
+ : val_fmt_size(fmt, item, args...);
+ }
+ // --- Field Width ---
+ template <typename ...Args>
+ constexpr bool val_fmt_width_val(const char* fmt, unsigned int size, PrintfFlags item, Args... args)
+ {
+ return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, size*10+_bits::todigit(*fmt), item, args...)
+ : val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
+ }
+ template <typename ...Args>
+ constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, unsigned int size, Args... args)
+ {
+ return val_fmt_prec_opt(fmt, PrintfFlags(item, PrintfFlags::ArgWidth(), size), args...);
+ }
+ template <typename Arg, typename ...Args>
+ constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item, Arg size, Args... args)
+ {
+ //static_assert(false, "Invalid type for width modifier, must be 'unsigned int'");
+ return false ? false : throw "Invalid type for width modifier, must be 'unsigned int'";
+ }
+ constexpr bool val_fmt_width_arg(const char *fmt, PrintfFlags item)
+ {
+ //static_assert(false, "Too few arguments when reading width for width modifier");
+ return false ? false : throw "Too few arguments when reading width for width modifier";
+ }
+ template <typename ...Args>
+ constexpr bool val_fmt_width(const char * fmt, PrintfFlags item, Args... args)
+ {
+ return _bits::isdigit_s(*fmt) ? val_fmt_width_val(fmt+1, _bits::todigit(*fmt), item, args...)
+ : *fmt == '*' ? val_fmt_width_arg(fmt+1, item, args...)
+ : val_fmt_prec_opt(fmt, item, args...);
+ }
+ // --- Flags
+ template <typename ...Args>
+ constexpr bool val_fmt_flags(const char * fmt, PrintfFlags item, Args... args)
+ {
+ return
+ *fmt == '-' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Left()) , args...)
+ : *fmt == '+' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Sign()) , args...)
+ : *fmt == ' ' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Space()), args...)
+ : *fmt == '#' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Alt()) , args...)
+ : *fmt == '0' ? val_fmt_flags(fmt+1, PrintfFlags(item, PrintfFlags::Zero()) , args...)
+ : val_fmt_width(fmt, item, args...);
+ }
+ // --- Literal '%'
+ template <typename ...Args>
+ constexpr bool val_fmt_start(const char* fmt, Args... args)
+ {
+ return *fmt == '%' ? val(fmt+1, args...) : val_fmt_flags(fmt, PrintfFlags(), args...);
+ }
+ template <typename... Args>
+ constexpr bool val(const char* fmt, Args... args)
+ {
+ return *fmt == '\0' ? true
+ : *fmt == '%' ? val_fmt_start(fmt+1, args...)
+ : val(fmt+1, args...);
+ }
+
size_t run(cprintf_cb puts, const char *fmt);
template <typename... Args> size_t run(cprintf_cb puts, const char * fmt, Args... args);
}; // namespace _bits
-template <typename ... Args>
-size_t cprintf(cprintf_cb puts, const char *fmt, Args... args)
-{
- _bits::_printf::run(nullptr, fmt, args...);
- return _bits::_printf::run(puts, fmt, args...);
-}
+#define cprintf(puts, fmt, ...) static_assert(::cxxextras::_bits::_printf::val(fmt, __VA_ARGS__),"");::cxxextras::_bits::_printf::run(puts, fmt, __VA_ARGS__)
+
+//template <typename ... Args>
+//size_t cprintf(cprintf_cb puts, const char *fmt, Args... args)
+//{
+// _bits::_printf::run(nullptr, fmt, args...);
+// return _bits::_printf::run(puts, fmt, args...);
+//}
};