use size_t for format results

master
Daniel Kolesa 2017-02-11 01:28:14 +01:00
parent dc640d2c1e
commit 667b2d50ea
3 changed files with 69 additions and 52 deletions

View File

@ -447,10 +447,9 @@ inline void to_format(T const &v, R &writer, FormatSpec const &fs) {
namespace detail { namespace detail {
template<typename R, typename T> template<typename R, typename T>
inline ptrdiff_t write_u(R &writer, FormatSpec const *fl, bool neg, T val) { inline size_t write_u(R &writer, FormatSpec const *fl, bool neg, T val) {
char buf[20]; char buf[20];
ptrdiff_t r = 0; size_t r = 0, n = 0;
size_t n = 0;
char spec = fl->spec(); char spec = fl->spec();
if (spec == 's') spec = 'd'; if (spec == 's') spec = 'd';
@ -476,7 +475,7 @@ namespace detail {
r += sign; r += sign;
char const *pfx = nullptr; char const *pfx = nullptr;
int pfxlen = 0; size_t pfxlen = 0;
if (flags & FMT_FLAG_HASH && spec != 'd') { if (flags & FMT_FLAG_HASH && spec != 'd') {
pfx = detail::fmt_intpfx[spec >= 'a'][specn - 3]; pfx = detail::fmt_intpfx[spec >= 'a'][specn - 3];
pfxlen = !!pfx[1] + 1; pfxlen = !!pfx[1] + 1;
@ -502,14 +501,14 @@ namespace detail {
} }
template<typename R, typename ...A> template<typename R, typename ...A>
static ptrdiff_t format_impl( static size_t format_impl(
R &writer, bool escape, ConstCharRange fmt, A const &...args R &writer, bool escape, ConstCharRange fmt, A const &...args
); );
template<size_t I> template<size_t I>
struct FmtTupleUnpacker { struct FmtTupleUnpacker {
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
static inline ptrdiff_t unpack( static inline size_t unpack(
R &writer, bool esc, ConstCharRange fmt, R &writer, bool esc, ConstCharRange fmt,
T const &item, A const &...args T const &item, A const &...args
) { ) {
@ -522,7 +521,7 @@ namespace detail {
template<> template<>
struct FmtTupleUnpacker<0> { struct FmtTupleUnpacker<0> {
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
static inline ptrdiff_t unpack( static inline size_t unpack(
R &writer, bool esc, ConstCharRange fmt, R &writer, bool esc, ConstCharRange fmt,
T const &, A const &...args T const &, A const &...args
) { ) {
@ -543,7 +542,7 @@ namespace detail {
constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value; constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value;
template<typename R, typename T> template<typename R, typename T>
inline ptrdiff_t format_ritem( inline size_t format_ritem(
R &writer, bool esc, bool, ConstCharRange fmt, R &writer, bool esc, bool, ConstCharRange fmt,
T const &item, std::enable_if_t<!is_tuple_like<T>, bool> = true T const &item, std::enable_if_t<!is_tuple_like<T>, bool> = true
) { ) {
@ -551,7 +550,7 @@ namespace detail {
} }
template<typename R, typename T> template<typename R, typename T>
inline ptrdiff_t format_ritem( inline size_t format_ritem(
R &writer, bool esc, bool expandval, ConstCharRange fmt, R &writer, bool esc, bool expandval, ConstCharRange fmt,
T const &item, std::enable_if_t<is_tuple_like<T>, bool> = true T const &item, std::enable_if_t<is_tuple_like<T>, bool> = true
) { ) {
@ -564,7 +563,7 @@ namespace detail {
} }
template<typename R, typename T> template<typename R, typename T>
inline ptrdiff_t write_range( inline size_t write_range(
R &writer, FormatSpec const *fl, bool escape, bool expandval, R &writer, FormatSpec const *fl, bool escape, bool expandval,
ConstCharRange sep, T const &val, ConstCharRange sep, T const &val,
std::enable_if_t<detail::IterableTest<T>, bool> = true std::enable_if_t<detail::IterableTest<T>, bool> = true
@ -574,7 +573,7 @@ namespace detail {
if (range.empty()) { if (range.empty()) {
return 0; return 0;
} }
ptrdiff_t ret = 0; size_t ret = 0;
/* test first item */ /* test first item */
ret += format_ritem( ret += format_ritem(
writer, escape, expandval, fl->rest(), range.front() writer, escape, expandval, fl->rest(), range.front()
@ -591,7 +590,7 @@ namespace detail {
} }
template<typename R, typename T> template<typename R, typename T>
inline ptrdiff_t write_range( inline size_t write_range(
R &, FormatSpec const *, bool, bool, ConstCharRange, R &, FormatSpec const *, bool, bool, ConstCharRange,
T const &, std::enable_if_t<!detail::IterableTest<T>, bool> = true T const &, std::enable_if_t<!detail::IterableTest<T>, bool> = true
) { ) {
@ -663,7 +662,7 @@ namespace detail {
/* string base writer */ /* string base writer */
template<typename R> template<typename R>
ptrdiff_t write_str(R &writer, bool escape, ConstCharRange val) const { size_t write_str(R &writer, bool escape, ConstCharRange val) const {
if (escape) { if (escape) {
return write_str(writer, false, escape_fmt_str(val)); return write_str(writer, false, escape_fmt_str(val));
} }
@ -671,7 +670,7 @@ namespace detail {
if (this->precision()) { if (this->precision()) {
n = this->precision(); n = this->precision();
} }
ptrdiff_t r = n; size_t r = n;
r += this->write_spaces(writer, n, true); r += this->write_spaces(writer, n, true);
writer.put_n(&val[0], n); writer.put_n(&val[0], n);
r += this->write_spaces(writer, n, false); r += this->write_spaces(writer, n, false);
@ -680,7 +679,7 @@ namespace detail {
/* char values */ /* char values */
template<typename R> template<typename R>
ptrdiff_t write_char(R &writer, bool escape, char val) const { size_t write_char(R &writer, bool escape, char val) const {
if (escape) { if (escape) {
char const *esc = escape_fmt_char(val, '\''); char const *esc = escape_fmt_char(val, '\'');
if (esc) { if (esc) {
@ -694,7 +693,7 @@ namespace detail {
}); });
} }
} }
ptrdiff_t r = 1 + escape * 2; size_t r = 1 + escape * 2;
r += this->write_spaces(writer, 1 + escape * 2, true); r += this->write_spaces(writer, 1 + escape * 2, true);
if (escape) { if (escape) {
writer.put('\''); writer.put('\'');
@ -709,7 +708,7 @@ namespace detail {
/* floating point */ /* floating point */
template<typename R, typename T, bool Long = std::is_same_v<T, ldouble>> template<typename R, typename T, bool Long = std::is_same_v<T, ldouble>>
ptrdiff_t write_float(R &writer, bool, T val) const { size_t write_float(R &writer, bool, T val) const {
char buf[16], rbuf[128]; char buf[16], rbuf[128];
char fmtspec[Long + 1]; char fmtspec[Long + 1];
@ -726,10 +725,14 @@ namespace detail {
} }
buf[this->build_spec(iter(buf), fmtspec)] = '\0'; buf[this->build_spec(iter(buf), fmtspec)] = '\0';
ptrdiff_t ret = snprintf( int ret = snprintf(
rbuf, sizeof(rbuf), buf, this->width(), rbuf, sizeof(rbuf), buf, this->width(),
this->has_precision() ? this->precision() : 6, val this->has_precision() ? this->precision() : 6, val
); );
if (ret < 0) {
/* typically unreachable, build_spec creates valid format */
throw format_error{"invalid float format"};
}
char *dbuf = nullptr; char *dbuf = nullptr;
if (size_t(ret) >= sizeof(rbuf)) { if (size_t(ret) >= sizeof(rbuf)) {
@ -739,6 +742,10 @@ namespace detail {
dbuf, ret + 1, buf, this->width(), dbuf, ret + 1, buf, this->width(),
this->has_precision() ? this->precision() : 6, val this->has_precision() ? this->precision() : 6, val
); );
if (ret < 0) {
/* see above */
throw format_error{"invalid float format"};
}
writer.put_n(dbuf, ret); writer.put_n(dbuf, ret);
delete[] dbuf; delete[] dbuf;
} else { } else {
@ -748,7 +755,7 @@ namespace detail {
} }
template<typename R, typename T> template<typename R, typename T>
ptrdiff_t write_val(R &writer, bool escape, T const &val) const { size_t write_val(R &writer, bool escape, T const &val) const {
/* stuff fhat can be custom-formatted goes first */ /* stuff fhat can be custom-formatted goes first */
if constexpr(FmtTofmtTest<T, TostrRange<R>>) { if constexpr(FmtTofmtTest<T, TostrRange<R>>) {
TostrRange<R> sink(writer); TostrRange<R> sink(writer);
@ -820,7 +827,7 @@ namespace detail {
/* actual writer */ /* actual writer */
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
ptrdiff_t write_arg( size_t write_arg(
R &writer, size_t idx, T const &val, A const &...args R &writer, size_t idx, T const &val, A const &...args
) const { ) const {
if (idx) { if (idx) {
@ -836,7 +843,7 @@ namespace detail {
/* range writer */ /* range writer */
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
ptrdiff_t write_range( size_t write_range(
R &writer, size_t idx, bool expandval, ConstCharRange sep, R &writer, size_t idx, bool expandval, ConstCharRange sep,
T const &val, A const &...args T const &val, A const &...args
) const { ) const {
@ -855,11 +862,10 @@ namespace detail {
}; };
template<typename R, typename ...A> template<typename R, typename ...A>
inline ptrdiff_t format_impl( inline size_t format_impl(
R &writer, bool escape, ConstCharRange fmt, A const &...args R &writer, bool escape, ConstCharRange fmt, A const &...args
) { ) {
size_t argidx = 1, twr = 0; size_t argidx = 1, twr = 0, written = 0;
ptrdiff_t written = 0;
detail::WriteSpec spec(fmt, escape); detail::WriteSpec spec(fmt, escape);
while (spec.read_until_spec(writer, &twr)) { while (spec.read_until_spec(writer, &twr)) {
written += twr; written += twr;
@ -870,14 +876,10 @@ namespace detail {
} }
/* FIXME: figure out a better way */ /* FIXME: figure out a better way */
detail::WriteSpec nspec(spec.nested(), spec.nested_escape()); detail::WriteSpec nspec(spec.nested(), spec.nested_escape());
ptrdiff_t sw = nspec.write_range( written += nspec.write_range(
writer, argpos - 1, (spec.flags() & FMT_FLAG_HASH), writer, argpos - 1, (spec.flags() & FMT_FLAG_HASH),
spec.nested_sep(), args... spec.nested_sep(), args...
); );
if (sw < 0) {
return sw;
}
written += sw;
continue; continue;
} }
if (!argpos) { if (!argpos) {
@ -905,11 +907,7 @@ namespace detail {
spec.set_width(argpos - 2 - argprec, args...); spec.set_width(argpos - 2 - argprec, args...);
} }
} }
ptrdiff_t sw = spec.write_arg(writer, argpos - 1, args...); written += spec.write_arg(writer, argpos - 1, args...);
if (sw < 0) {
return sw;
}
written += sw;
} }
written += twr; written += twr;
return written; return written;
@ -917,12 +915,12 @@ namespace detail {
} /* namespace detail */ } /* namespace detail */
template<typename R, typename ...A> template<typename R, typename ...A>
inline ptrdiff_t format(R &&writer, ConstCharRange fmt, A const &...args) { inline size_t format(R &&writer, ConstCharRange fmt, A const &...args) {
return detail::format_impl(writer, false, fmt, args...); return detail::format_impl(writer, false, fmt, args...);
} }
template<typename R, typename T> template<typename R, typename T>
inline ptrdiff_t format(R &&writer, FormatSpec const &fmt, T const &val) { inline size_t format(R &&writer, FormatSpec const &fmt, T const &val) {
/* we can do this as there are no members added... but ugly, FIXME later */ /* we can do this as there are no members added... but ugly, FIXME later */
detail::WriteSpec const &wsp = static_cast<detail::WriteSpec const &>(fmt); detail::WriteSpec const &wsp = static_cast<detail::WriteSpec const &>(fmt);
return wsp.write_arg(writer, 0, val); return wsp.write_arg(writer, 0, val);

View File

@ -177,14 +177,19 @@ inline void write(T const &v, A const &...args) {
template<typename T> template<typename T>
inline void writeln(T const &v) { inline void writeln(T const &v) {
write(v); write(v);
putchar('\n'); if (putchar('\n') == EOF) {
/* consistency with format module */
throw format_error{"stream EOF"};
}
} }
template<typename T, typename ...A> template<typename T, typename ...A>
inline void writeln(T const &v, A const &...args) { inline void writeln(T const &v, A const &...args) {
write(v); write(v);
write(args...); write(args...);
putchar('\n'); if (putchar('\n') == EOF) {
throw format_error{"stream EOF"};
}
} }
template<typename ...A> template<typename ...A>
@ -195,7 +200,9 @@ inline void writef(ConstCharRange fmt, A const &...args) {
template<typename ...A> template<typename ...A>
inline void writefln(ConstCharRange fmt, A const &...args) { inline void writefln(ConstCharRange fmt, A const &...args) {
writef(fmt, args...); writef(fmt, args...);
putchar('\n'); if (putchar('\n') == EOF) {
throw format_error{"stream EOF"};
}
} }
} /* namespace ostd */ } /* namespace ostd */

View File

@ -73,29 +73,41 @@ struct Stream {
} }
template<typename T> template<typename T>
bool write(T const &v); void write(T const &v);
template<typename T, typename ...A> template<typename T, typename ...A>
bool write(T const &v, A const &...args) { void write(T const &v, A const &...args) {
return write(v) && write(args...); write(v);
write(args...);
} }
template<typename T> template<typename T>
bool writeln(T const &v) { void writeln(T const &v) {
return write(v) && putchar('\n'); write(v);
if (!putchar('\n')) {
/* consistency with format module */
throw format_error{"stream EOF"};
}
} }
template<typename T, typename ...A> template<typename T, typename ...A>
bool writeln(T const &v, A const &...args) { bool writeln(T const &v, A const &...args) {
return write(v) && write(args...) && putchar('\n'); write(v);
write(args...);
if (!putchar('\n')) {
throw format_error{"stream EOF"};
}
} }
template<typename ...A> template<typename ...A>
bool writef(ConstCharRange fmt, A const &...args); void writef(ConstCharRange fmt, A const &...args);
template<typename ...A> template<typename ...A>
bool writefln(ConstCharRange fmt, A const &...args) { void writefln(ConstCharRange fmt, A const &...args) {
return writef(fmt, args...) && putchar('\n'); writef(fmt, args...);
if (!putchar('\n')) {
throw format_error{"stream EOF"};
}
} }
template<typename T = char> template<typename T = char>
@ -200,13 +212,13 @@ namespace detail {
} }
template<typename T> template<typename T>
inline bool Stream::write(T const &v) { inline void Stream::write(T const &v) {
return format(detail::FmtStreamRange{*this}, FormatSpec{'s'}, v) >= 0; format(detail::FmtStreamRange{*this}, FormatSpec{'s'}, v);
} }
template<typename ...A> template<typename ...A>
inline bool Stream::writef(ConstCharRange fmt, A const &...args) { inline void Stream::writef(ConstCharRange fmt, A const &...args) {
return format(detail::FmtStreamRange{*this}, fmt, args...) >= 0; format(detail::FmtStreamRange{*this}, fmt, args...);
} }
} }