forked from OctaForge/libostd
use size_t for format results
This commit is contained in:
parent
dc640d2c1e
commit
667b2d50ea
|
@ -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);
|
||||||
|
|
13
ostd/io.hh
13
ostd/io.hh
|
@ -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 */
|
||||||
|
|
|
@ -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...);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue