forked from OctaForge/libostd
more formatter work, type traits fixes, formatting on all streams
This commit is contained in:
parent
b5748267d9
commit
ea1325543d
128
octa/format.hh
128
octa/format.hh
|
@ -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 */
|
||||||
|
|
45
octa/io.hh
45
octa/io.hh
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -303,13 +303,29 @@ struct IsPolymorphic: IntegralConstant<bool, __is_polymorphic(T)> {};
|
||||||
|
|
||||||
/* is signed */
|
/* is signed */
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<typename T>
|
||||||
|
struct IsSignedBase: IntegralConstant<bool, T(-1) < T(0)> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, bool = octa::IsArithmetic<T>::value>
|
||||||
|
struct IsSigned: False {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsSigned: IntegralConstant<bool, T(-1) < T(0)> {};
|
struct IsSigned<T, true>: octa::detail::IsSignedBase<T> {};
|
||||||
|
|
||||||
/* is unsigned */
|
/* is unsigned */
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template<typename T>
|
||||||
|
struct IsUnsignedBase: IntegralConstant<bool, T(0) < T(-1)> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, bool = octa::IsArithmetic<T>::value>
|
||||||
|
struct IsUnsigned: False {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsUnsigned: IntegralConstant<bool, T(0) < T(-1)> {};
|
struct IsUnsigned<T, true>: octa::detail::IsUnsignedBase<T> {};
|
||||||
|
|
||||||
/* is standard layout */
|
/* is standard layout */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue