Random work on C++11 printf
authorJohn Hodge <[email protected]>
Sat, 27 Sep 2014 05:34:48 +0000 (13:34 +0800)
committerJohn Hodge <[email protected]>
Sat, 27 Sep 2014 05:34:48 +0000 (13:34 +0800)
Usermode/Libraries/libc++_extras.so_src/Makefile
Usermode/Libraries/libc++_extras.so_src/TEST_cprintf.cpp
Usermode/Libraries/libc++_extras.so_src/include_exp/cxxextras_printf

index a27ba3b..f129b61 100644 (file)
@@ -12,9 +12,8 @@ LIBS     += -lc++
 
 include ../Makefile.tpl
 
-EXP_%.txt: TEST_%.native
-       ./$< > $@
-       rm $<
-
 %.native: %.cpp
        $(NCXX) $< -o $@ -Wall -std=c++11 -I include_exp/
+
+TEST_cprintf.native: include_exp/cxxextras_printf
+
index c99d1a7..b77b004 100644 (file)
@@ -14,15 +14,15 @@ void my_puts(const char *str, size_t len)
 int main()
 {
        printf("Success\n");
-       ::cxxextras::cprintf(my_puts, "%s %i %+#-010x\n", "hello_world", 1337, 0x1234565);
+       cprintf(my_puts, "%s %i %+#-010x\n", "hello_world", 1337, 0x1234565);
        
-       printf("Too Few\n");
-       ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s %i %+#-010x\n"), ::cxxextras::cprintf_toofewargs );
-       printf("Too Many\n");
-       ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s\n", "tst", 12345), ::cxxextras::cprintf_toomanyargs );
-       
-       printf("Bad Format\n");
-       ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%-\n"), ::cxxextras::cprintf_badformat );
+       //printf("Too Few\n");
+       //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s %i %+#-010x\n"), ::cxxextras::cprintf_toofewargs );
+       //printf("Too Many\n");
+       //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%s\n", "tst", 12345), ::cxxextras::cprintf_toomanyargs );
+       //
+       //printf("Bad Format\n");
+       //ASSERT_EXCEPTION( ::cxxextras::cprintf(my_puts, "%-\n"), ::cxxextras::cprintf_badformat );
        
        return 0;
 }
index d9e2722..7d05e21 100644 (file)
@@ -89,7 +89,7 @@ struct PrintfFlags
        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)
        {
        }
@@ -120,7 +120,11 @@ constexpr unsigned todigit(const char ch) {
 
 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 ++)
@@ -128,6 +132,9 @@ size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, const char* a
        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];
@@ -135,6 +142,9 @@ size_t cprintf_val(cprintf_cb puts, const _bits::PrintfFlags& fmt, int arg) {
        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];
@@ -147,6 +157,158 @@ namespace _bits
 {
 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);
 
@@ -294,12 +456,14 @@ namespace _printf
 
 };     // 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...);
+//}
 
 };
 

UCC git Repository :: git.ucc.asn.au