diff --git a/octa/format.hh b/octa/format.hh index 410d179..09462a9 100644 --- a/octa/format.hh +++ b/octa/format.hh @@ -17,47 +17,107 @@ namespace octa { namespace detail { - template - static inline void write_val(R &writer, const char *val) { - while (*val) writer.put(*val++); - } + /* C string */ template - static inline void write_val(R &writer, const octa::String &val) { + static inline octa::Size write_val(R &writer, const char *val) { + octa::Size n = 0; + while (*val) { + writer.put(*val++); + ++n; + } + return n; + } + + /* OctaSTD string */ + + template + static inline octa::Size write_val(R &writer, const octa::String &val) { for (octa::Size i = 0; i < val.size(); ++i) writer.put(val[i]); + return val.size(); + } + + /* A character */ + + template + static inline octa::Size write_val(R &writer, char val) { + writer.put(val); + return 1; + } + + /* Integer helpers */ + + template + static inline octa::Size write_u(R &writer, octa::Uintmax val) { + char buf[20]; + octa::Size n = 0; + for (; val; val /= 10) buf[n++] = '0' + val % 10; + for (int i = int(n - 1); i >= 0; --i) { + writer.put(buf[i]); + } + return n; } template - static inline void write_val(R &writer, char val) { - writer.put(val); + static inline octa::Size write_i(R &writer, octa::Intmax val) { + octa::Uintmax uv; + int neg = 0; + if (val < 0) { + uv = -val; + writer.put('-'); + neg = 1; + } else uv = val; + return octa::detail::write_u(writer, uv) + neg; } + template::value, + bool = octa::IsSigned::value> + struct WriteIntVal { + static inline octa::Size write(R &writer, const T &val) { + return octa::detail::write_val(writer, octa::to_string(val)); + } + }; + + template struct WriteIntVal { + static inline octa::Size write(R &writer, T val) { + return octa::detail::write_i(writer, val); + } + }; + + template struct WriteIntVal { + static inline octa::Size write(R &writer, T val) { + return octa::detail::write_u(writer, val); + } + }; + + /* Integers or generic value */ + template - static inline void write_val(R &writer, const T &val) { - write_val(writer, octa::to_string(val)); + static inline octa::Size write_val(R &writer, const T &val) { + return octa::detail::WriteIntVal::write(writer, val); } + /* Writer entry point */ + template - static inline void write_idx(R &writer, octa::Size idx, const T &v) { + static inline octa::Size write_idx(R &writer, octa::Size idx, const T &v) { if (idx) assert(false && "not enough format args"); - write_val(writer, v); + return octa::detail::write_val(writer, v); } template - static inline void write_idx(R &writer, octa::Size idx, const T &v, - A &&...args) { - if (idx) { - write_idx(writer, idx - 1, octa::forward(args)...); - return; - } - write_val(writer, v); + static inline octa::Size write_idx(R &writer, octa::Size idx, const T &v, + const A &...args) { + if (idx) + return octa::detail::write_idx(writer, idx - 1, args...); + return octa::detail::write_val(writer, v); } } /* namespace detail */ template -static inline octa::Size formatted_write(R writer, const char *fmt, - A &&...args) { - octa::Size argidx = 0, retn = 0; +static inline octa::Size formatted_write(R writer, octa::Size &fmtn, + const char *fmt, const A &...args) { + octa::Size argidx = 0, written = 0, retn = 0; while (*fmt) { if (*fmt == '{') { octa::Size needidx = argidx; @@ -70,18 +130,34 @@ static inline octa::Size formatted_write(R writer, const char *fmt, } else ++argidx; ++fmt; retn = octa::max(needidx, retn); - octa::detail::write_idx(writer, needidx, - octa::forward(args)...); + written += octa::detail::write_idx(writer, needidx, + args...); continue; } writer.put(*fmt++); + ++written; } - return retn + 1; + fmtn = retn + 1; + return written; } template -octa::Size formatted_write(R writer, const octa::String &fmt, A &&...args) { - return formatted_write(writer, fmt.data(), octa::forward(args)...); +octa::Size formatted_write(R writer, octa::Size &fmtn, const octa::String &fmt, + const A &...args) { + return formatted_write(writer, fmtn, fmt.data(), args...); +} + +template +octa::Size formatted_write(R writer, const char *fmt, const A &...args) { + octa::Size fmtn = 0; + return formatted_write(writer, fmtn, fmt, args...); +} + +template +octa::Size formatted_write(R writer, const octa::String &fmt, + const A &...args) { + octa::Size fmtn = 0; + return formatted_write(writer, fmtn, fmt.data(), args...); } } /* namespace octa */ diff --git a/octa/io.hh b/octa/io.hh index 7d93f8a..2ea5d3f 100644 --- a/octa/io.hh +++ b/octa/io.hh @@ -152,49 +152,36 @@ static inline void writeln(const T &v, const A &...args) { putc('\n', ::stdout); } -namespace detail { - struct FormatOutRange: octa::OutputRange { - FormatOutRange(): needed(0) {} - octa::Size needed; - char buf[512]; - void put(char v) { - if (needed < sizeof(buf)) - buf[needed] = v; - ++needed; - } - }; -} - template -static inline void writef(const char *fmt, A &&...args) { - octa::detail::FormatOutRange writer1; - octa::formatted_write(writer1, fmt, - octa::forward(args)...); - if (writer1.needed < sizeof(writer1.buf)) { - fwrite(writer1.buf, 1, writer1.needed, ::stdout); +static inline void writef(const char *fmt, const A &...args) { + char buf[512]; + octa::Size need = octa::formatted_write(octa::detail::FormatOutRange< + sizeof(buf)>(buf), fmt, args...); + if (need < sizeof(buf)) { + fwrite(buf, 1, need, ::stdout); return; } octa::String s; - s.reserve(writer1.needed); - s[writer1.needed] = '\0'; - octa::formatted_write(s.iter(), fmt, octa::forward(args)...); - fwrite(s.data(), 1, writer1.needed, ::stdout); + s.reserve(need); + s[need] = '\0'; + octa::formatted_write(s.iter(), fmt, args...); + fwrite(s.data(), 1, need, ::stdout); } template -static inline void writef(const octa::String &fmt, A &&...args) { - writef(fmt.data(), octa::forward(args)...); +static inline void writef(const octa::String &fmt, const A &...args) { + writef(fmt.data(), args...); } template -static inline void writefln(const char *fmt, A &&...args) { - writef(fmt, octa::forward(args)...); +static inline void writefln(const char *fmt, const A &...args) { + writef(fmt, args...); putc('\n', ::stdout); } template -static inline void writefln(const octa::String &fmt, A &&...args) { - writef(fmt, octa::forward(args)...); +static inline void writefln(const octa::String &fmt, const A &...args) { + writef(fmt, args...); putc('\n', ::stdout); } diff --git a/octa/stream.hh b/octa/stream.hh index 3d9ede5..9bb286b 100644 --- a/octa/stream.hh +++ b/octa/stream.hh @@ -13,6 +13,7 @@ #include "octa/type_traits.hh" #include "octa/string.hh" #include "octa/utility.hh" +#include "octa/format.hh" namespace octa { @@ -28,6 +29,17 @@ enum class StreamSeek { template::value> struct StreamRange; +namespace detail { + template + struct FormatOutRange: octa::OutputRange { + FormatOutRange(char *buf): buf(buf), idx(0) {} + FormatOutRange(const FormatOutRange &r): buf(r.buf), idx(r.idx) {} + char *buf; + octa::Size idx; + void put(char v) { if (idx < N) buf[idx++] = v; } + }; +} + struct Stream { using Offset = StreamOffset; @@ -84,20 +96,49 @@ struct Stream { } virtual bool writeln(const octa::String &s) { - return write(s) && write('\n'); + return write(s) && putchar('\n'); } virtual bool writeln(const char *s) { - return write(s) && write('\n'); + return write(s) && putchar('\n'); } template bool writeln(const T &v) { - return writeln(octa::to_string(v)); + return write(v) && putchar('\n'); } template bool writeln(const T &v, const A &...args) { - return write(v) && write(args...) && write('\n'); + return write(v) && write(args...) && putchar('\n'); + } + + template + bool writef(const char *fmt, const A &...args) { + char buf[512]; + octa::Size need = octa::formatted_write(octa::detail::FormatOutRange< + sizeof(buf)>(buf), fmt, args...); + if (need < sizeof(buf)) + return write_bytes(buf, need) == need; + octa::String s; + s.reserve(need); + s[need] = '\0'; + octa::formatted_write(s.iter(), fmt, args...); + return write_bytes(s.data(), need) == need; + } + + template + bool writef(const octa::String &fmt, const A &...args) { + return writef(fmt.data(), args...); + } + + template + bool writefln(const char *fmt, const A &...args) { + return writef(fmt, args...) && putchar('\n'); + } + + template + bool writefln(const octa::String &fmt, const A &...args) { + return writefln(fmt.data(), args...); } template diff --git a/octa/string.hh b/octa/string.hh index 2eedd78..c8f0ffa 100644 --- a/octa/string.hh +++ b/octa/string.hh @@ -517,25 +517,25 @@ template struct ToString { }; template<> struct ToString { - using Argument = const String &; + using Argument = String; using Result = String; - String operator()(Argument s) { + String operator()(const Argument &s) { return s; } }; template<> struct ToString { - using Argument = const StringRange &; + using Argument = StringRange; using Result = String; - String operator()(Argument s) { + String operator()(const Argument &s) { return String(s); } }; template struct ToString> { - using Argument = const octa::Pair &; + using Argument = octa::Pair; using Result = String; - String operator()(Argument v) { + String operator()(const Argument &v) { String ret("{"); ret += ToString>>() (v.first); diff --git a/octa/type_traits.hh b/octa/type_traits.hh index 4180803..12f0b11 100644 --- a/octa/type_traits.hh +++ b/octa/type_traits.hh @@ -303,13 +303,29 @@ struct IsPolymorphic: IntegralConstant {}; /* is signed */ +namespace detail { + template + struct IsSignedBase: IntegralConstant {}; +} + +template::value> +struct IsSigned: False {}; + template -struct IsSigned: IntegralConstant {}; +struct IsSigned: octa::detail::IsSignedBase {}; /* is unsigned */ +namespace detail { + template + struct IsUnsignedBase: IntegralConstant {}; +} + +template::value> +struct IsUnsigned: False {}; + template -struct IsUnsigned: IntegralConstant {}; +struct IsUnsigned: octa::detail::IsUnsignedBase {}; /* is standard layout */