more formatter work, type traits fixes, formatting on all streams

master
Daniel Kolesa 2015-07-01 18:51:39 +01:00
parent b5748267d9
commit ea1325543d
5 changed files with 187 additions and 67 deletions

View File

@ -17,47 +17,107 @@
namespace octa { namespace octa {
namespace detail { namespace detail {
template<typename R> /* C string */
static inline void write_val(R &writer, const char *val) {
while (*val) writer.put(*val++);
}
template<typename R> template<typename R>
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<typename R>
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]); for (octa::Size i = 0; i < val.size(); ++i) writer.put(val[i]);
return val.size();
}
/* A character */
template<typename R>
static inline octa::Size write_val(R &writer, char val) {
writer.put(val);
return 1;
}
/* Integer helpers */
template<typename R>
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<typename R> template<typename R>
static inline void write_val(R &writer, char val) { static inline octa::Size write_i(R &writer, octa::Intmax val) {
writer.put(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<typename R, typename T, bool = octa::IsIntegral<T>::value,
bool = octa::IsSigned<T>::value>
struct WriteIntVal {
static inline octa::Size write(R &writer, const T &val) {
return octa::detail::write_val(writer, octa::to_string(val));
}
};
template<typename R, typename T> struct WriteIntVal<R, T, true, true> {
static inline octa::Size write(R &writer, T val) {
return octa::detail::write_i(writer, val);
}
};
template<typename R, typename T> struct WriteIntVal<R, T, true, false> {
static inline octa::Size write(R &writer, T val) {
return octa::detail::write_u(writer, val);
}
};
/* Integers or generic value */
template<typename R, typename T> template<typename R, typename T>
static inline void write_val(R &writer, const T &val) { static inline octa::Size write_val(R &writer, const T &val) {
write_val(writer, octa::to_string(val)); return octa::detail::WriteIntVal<R, T>::write(writer, val);
} }
/* Writer entry point */
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
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"); if (idx) assert(false && "not enough format args");
write_val(writer, v); return octa::detail::write_val(writer, v);
} }
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
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,
A &&...args) { const A &...args) {
if (idx) { if (idx)
write_idx(writer, idx - 1, octa::forward<A>(args)...); return octa::detail::write_idx(writer, idx - 1, args...);
return; return octa::detail::write_val(writer, v);
}
write_val(writer, v);
} }
} /* namespace detail */ } /* namespace detail */
template<typename R, typename ...A> template<typename R, typename ...A>
static inline octa::Size formatted_write(R writer, const char *fmt, static inline octa::Size formatted_write(R writer, octa::Size &fmtn,
A &&...args) { const char *fmt, const A &...args) {
octa::Size argidx = 0, retn = 0; octa::Size argidx = 0, written = 0, retn = 0;
while (*fmt) { while (*fmt) {
if (*fmt == '{') { if (*fmt == '{') {
octa::Size needidx = argidx; octa::Size needidx = argidx;
@ -70,18 +130,34 @@ static inline octa::Size formatted_write(R writer, const char *fmt,
} else ++argidx; } else ++argidx;
++fmt; ++fmt;
retn = octa::max(needidx, retn); retn = octa::max(needidx, retn);
octa::detail::write_idx(writer, needidx, written += octa::detail::write_idx(writer, needidx,
octa::forward<A>(args)...); args...);
continue; continue;
} }
writer.put(*fmt++); writer.put(*fmt++);
++written;
} }
return retn + 1; fmtn = retn + 1;
return written;
} }
template<typename R, typename ...A> template<typename R, typename ...A>
octa::Size formatted_write(R writer, const octa::String &fmt, A &&...args) { octa::Size formatted_write(R writer, octa::Size &fmtn, const octa::String &fmt,
return formatted_write(writer, fmt.data(), octa::forward<A>(args)...); const A &...args) {
return formatted_write(writer, fmtn, fmt.data(), args...);
}
template<typename R, typename ...A>
octa::Size formatted_write(R writer, const char *fmt, const A &...args) {
octa::Size fmtn = 0;
return formatted_write(writer, fmtn, fmt, args...);
}
template<typename R, typename ...A>
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 */ } /* namespace octa */

View File

@ -152,49 +152,36 @@ static inline void writeln(const T &v, const A &...args) {
putc('\n', ::stdout); putc('\n', ::stdout);
} }
namespace detail {
struct FormatOutRange: octa::OutputRange<char> {
FormatOutRange(): needed(0) {}
octa::Size needed;
char buf[512];
void put(char v) {
if (needed < sizeof(buf))
buf[needed] = v;
++needed;
}
};
}
template<typename ...A> template<typename ...A>
static inline void writef(const char *fmt, A &&...args) { static inline void writef(const char *fmt, const A &...args) {
octa::detail::FormatOutRange writer1; char buf[512];
octa::formatted_write<octa::detail::FormatOutRange &>(writer1, fmt, octa::Size need = octa::formatted_write(octa::detail::FormatOutRange<
octa::forward<A>(args)...); sizeof(buf)>(buf), fmt, args...);
if (writer1.needed < sizeof(writer1.buf)) { if (need < sizeof(buf)) {
fwrite(writer1.buf, 1, writer1.needed, ::stdout); fwrite(buf, 1, need, ::stdout);
return; return;
} }
octa::String s; octa::String s;
s.reserve(writer1.needed); s.reserve(need);
s[writer1.needed] = '\0'; s[need] = '\0';
octa::formatted_write(s.iter(), fmt, octa::forward<A>(args)...); octa::formatted_write(s.iter(), fmt, args...);
fwrite(s.data(), 1, writer1.needed, ::stdout); fwrite(s.data(), 1, need, ::stdout);
} }
template<typename ...A> template<typename ...A>
static inline void writef(const octa::String &fmt, A &&...args) { static inline void writef(const octa::String &fmt, const A &...args) {
writef(fmt.data(), octa::forward<A>(args)...); writef(fmt.data(), args...);
} }
template<typename ...A> template<typename ...A>
static inline void writefln(const char *fmt, A &&...args) { static inline void writefln(const char *fmt, const A &...args) {
writef(fmt, octa::forward<A>(args)...); writef(fmt, args...);
putc('\n', ::stdout); putc('\n', ::stdout);
} }
template<typename ...A> template<typename ...A>
static inline void writefln(const octa::String &fmt, A &&...args) { static inline void writefln(const octa::String &fmt, const A &...args) {
writef(fmt, octa::forward<A>(args)...); writef(fmt, args...);
putc('\n', ::stdout); putc('\n', ::stdout);
} }

View File

@ -13,6 +13,7 @@
#include "octa/type_traits.hh" #include "octa/type_traits.hh"
#include "octa/string.hh" #include "octa/string.hh"
#include "octa/utility.hh" #include "octa/utility.hh"
#include "octa/format.hh"
namespace octa { namespace octa {
@ -28,6 +29,17 @@ enum class StreamSeek {
template<typename T = char, bool = octa::IsPod<T>::value> template<typename T = char, bool = octa::IsPod<T>::value>
struct StreamRange; struct StreamRange;
namespace detail {
template<octa::Size N>
struct FormatOutRange: octa::OutputRange<char> {
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 { struct Stream {
using Offset = StreamOffset; using Offset = StreamOffset;
@ -84,20 +96,49 @@ struct Stream {
} }
virtual bool writeln(const octa::String &s) { virtual bool writeln(const octa::String &s) {
return write(s) && write('\n'); return write(s) && putchar('\n');
} }
virtual bool writeln(const char *s) { virtual bool writeln(const char *s) {
return write(s) && write('\n'); return write(s) && putchar('\n');
} }
template<typename T> bool writeln(const T &v) { template<typename T> bool writeln(const T &v) {
return writeln(octa::to_string(v)); return write(v) && putchar('\n');
} }
template<typename T, typename ...A> template<typename T, typename ...A>
bool writeln(const T &v, const A &...args) { bool writeln(const T &v, const A &...args) {
return write(v) && write(args...) && write('\n'); return write(v) && write(args...) && putchar('\n');
}
template<typename ...A>
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<typename ...A>
bool writef(const octa::String &fmt, const A &...args) {
return writef(fmt.data(), args...);
}
template<typename ...A>
bool writefln(const char *fmt, const A &...args) {
return writef(fmt, args...) && putchar('\n');
}
template<typename ...A>
bool writefln(const octa::String &fmt, const A &...args) {
return writefln(fmt.data(), args...);
} }
template<typename T = char> template<typename T = char>

View File

@ -517,25 +517,25 @@ template<typename T> struct ToString<T *> {
}; };
template<> struct ToString<String> { template<> struct ToString<String> {
using Argument = const String &; using Argument = String;
using Result = String; using Result = String;
String operator()(Argument s) { String operator()(const Argument &s) {
return s; return s;
} }
}; };
template<> struct ToString<StringRange> { template<> struct ToString<StringRange> {
using Argument = const StringRange &; using Argument = StringRange;
using Result = String; using Result = String;
String operator()(Argument s) { String operator()(const Argument &s) {
return String(s); return String(s);
} }
}; };
template<typename T, typename U> struct ToString<octa::Pair<T, U>> { template<typename T, typename U> struct ToString<octa::Pair<T, U>> {
using Argument = const octa::Pair<T, U> &; using Argument = octa::Pair<T, U>;
using Result = String; using Result = String;
String operator()(Argument v) { String operator()(const Argument &v) {
String ret("{"); String ret("{");
ret += ToString<octa::RemoveCv<octa::RemoveReference<T>>>() ret += ToString<octa::RemoveCv<octa::RemoveReference<T>>>()
(v.first); (v.first);

View File

@ -303,13 +303,29 @@ struct IsPolymorphic: IntegralConstant<bool, __is_polymorphic(T)> {};
/* is signed */ /* is signed */
namespace detail {
template<typename T> template<typename T>
struct IsSigned: IntegralConstant<bool, T(-1) < T(0)> {}; struct IsSignedBase: IntegralConstant<bool, T(-1) < T(0)> {};
}
template<typename T, bool = octa::IsArithmetic<T>::value>
struct IsSigned: False {};
template<typename T>
struct IsSigned<T, true>: octa::detail::IsSignedBase<T> {};
/* is unsigned */ /* is unsigned */
namespace detail {
template<typename T> template<typename T>
struct IsUnsigned: IntegralConstant<bool, T(0) < T(-1)> {}; struct IsUnsignedBase: IntegralConstant<bool, T(0) < T(-1)> {};
}
template<typename T, bool = octa::IsArithmetic<T>::value>
struct IsUnsigned: False {};
template<typename T>
struct IsUnsigned<T, true>: octa::detail::IsUnsignedBase<T> {};
/* is standard layout */ /* is standard layout */