revamped output ranges and input range pop funcs

This commit is contained in:
q66 2017-02-19 16:45:06 +01:00
parent 2661ba91ae
commit e4dc237f4d
7 changed files with 375 additions and 601 deletions

View file

@ -778,24 +778,24 @@ public:
return p_range.distance_back(r.p_range); return p_range.distance_back(r.p_range);
} }
bool pop_front() { return p_range.pop_front(); } void pop_front() { p_range.pop_front(); }
bool pop_back() { return p_range.pop_back(); } void pop_back() { p_range.pop_back(); }
bool push_front() { return p_range.pop_front(); } void push_front() { p_range.pop_front(); }
bool push_back() { return p_range.push_back(); } void push_back() { p_range.push_back(); }
range_size_t<T> pop_front_n(range_size_t<T> n) { void pop_front_n(range_size_t<T> n) {
p_range.pop_front_n(n); p_range.pop_front_n(n);
} }
range_size_t<T> pop_back_n(range_size_t<T> n) { void pop_back_n(range_size_t<T> n) {
p_range.pop_back_n(n); p_range.pop_back_n(n);
} }
range_size_t<T> push_front_n(range_size_t<T> n) { void push_front_n(range_size_t<T> n) {
return p_range.push_front_n(n); p_range.push_front_n(n);
} }
range_size_t<T> push_back_n(range_size_t<T> n) { void push_back_n(range_size_t<T> n) {
return p_range.push_back_n(n); p_range.push_back_n(n);
} }
R front() const { return p_func(p_range.front()); } R front() const { return p_func(p_range.front()); }
@ -887,10 +887,9 @@ public:
return p_range.equals_front(r.p_range); return p_range.equals_front(r.p_range);
} }
bool pop_front() { void pop_front() {
bool ret = p_range.pop_front(); p_range.pop_front();
advance_valid(); advance_valid();
return ret;
} }
range_reference_t<T> front() const { return p_range.front(); } range_reference_t<T> front() const { return p_range.front(); }

View file

@ -549,8 +549,8 @@ struct directory_range: input_range<directory_range> {
return p_stream->empty(); return p_stream->empty();
} }
bool pop_front() { void pop_front() {
return p_stream->pop_front(); p_stream->pop_front();
} }
file_info front() const { file_info front() const {

View file

@ -147,11 +147,7 @@ struct format_spec {
{} {}
template<typename R> template<typename R>
bool read_until_spec(R &writer, size_t *wret) { bool read_until_spec(R &writer) {
size_t written = 0;
if (wret) {
*wret = 0;
}
if (p_fmt.empty()) { if (p_fmt.empty()) {
return false; return false;
} }
@ -161,34 +157,21 @@ struct format_spec {
if (p_fmt.front() == '%') { if (p_fmt.front() == '%') {
goto plain; goto plain;
} }
bool r = read_spec(); return read_spec();
if (wret) {
*wret = written;
}
return r;
} }
plain: plain:
++written;
writer.put(p_fmt.front()); writer.put(p_fmt.front());
p_fmt.pop_front(); p_fmt.pop_front();
} }
if (wret) {
*wret = written;
}
return false; return false;
} }
template<typename R> template<typename R>
size_t write_spaces(R &writer, size_t n, bool left, char c = ' ') const { void write_spaces(R &writer, size_t n, bool left, char c = ' ') const {
if (left == bool(p_flags & FMT_FLAG_DASH)) { if (left == bool(p_flags & FMT_FLAG_DASH)) {
return 0; return;
} }
int r = p_width - int(n);
for (int w = p_width - int(n); --w >= 0; writer.put(c)); for (int w = p_width - int(n); --w >= 0; writer.put(c));
if (r < 0) {
return 0;
}
return r;
} }
string_range rest() const { string_range rest() const {
@ -196,26 +179,26 @@ struct format_spec {
} }
template<typename R> template<typename R>
size_t build_spec(R &&out, string_range spec) const { R &&build_spec(R &&out, string_range spec) const {
size_t ret = out.put('%'); out.put('%');
if (p_flags & FMT_FLAG_DASH ) { if (p_flags & FMT_FLAG_DASH ) {
ret += out.put('-'); out.put('-');
} }
if (p_flags & FMT_FLAG_ZERO ) { if (p_flags & FMT_FLAG_ZERO ) {
ret += out.put('0'); out.put('0');
} }
if (p_flags & FMT_FLAG_SPACE) { if (p_flags & FMT_FLAG_SPACE) {
ret += out.put(' '); out.put(' ');
} }
if (p_flags & FMT_FLAG_PLUS ) { if (p_flags & FMT_FLAG_PLUS ) {
ret += out.put('+'); out.put('+');
} }
if (p_flags & FMT_FLAG_HASH ) { if (p_flags & FMT_FLAG_HASH ) {
ret += out.put('#'); out.put('#');
} }
ret += range_put_n(out, "*.*", 3); out = ostd::copy(string_range{"*.*"}, out);
ret += range_put_n(out, &spec[0], spec.size()); out = ostd::copy(spec, out);
return ret; return std::forward<R>(out);
} }
int width() const { return p_width; } int width() const { return p_width; }
@ -446,9 +429,9 @@ inline void to_format(T const &v, R &writer, format_spec const &fs) {
namespace detail { namespace detail {
template<typename R, typename T> template<typename R, typename T>
inline size_t write_u(R &writer, format_spec const *fl, bool neg, T val) { inline void write_u(R &writer, format_spec const *fl, bool neg, T val) {
char buf[20]; char buf[20];
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';
@ -464,54 +447,50 @@ namespace detail {
for (; val; val /= base) { for (; val; val /= base) {
buf[n++] = detail::fmt_digits[spec >= 'a'][val % base]; buf[n++] = detail::fmt_digits[spec >= 'a'][val % base];
} }
r = n;
int flags = fl->flags(); int flags = fl->flags();
bool lsgn = flags & FMT_FLAG_PLUS; bool lsgn = flags & FMT_FLAG_PLUS;
bool lsp = flags & FMT_FLAG_SPACE; bool lsp = flags & FMT_FLAG_SPACE;
bool zero = flags & FMT_FLAG_ZERO; bool zero = flags & FMT_FLAG_ZERO;
bool sign = neg + lsgn + lsp; bool sign = neg + lsgn + lsp;
r += sign;
char const *pfx = nullptr; char const *pfx = nullptr;
size_t 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;
r += pfxlen;
} }
if (!zero) { if (!zero) {
r += fl->write_spaces(writer, n + pfxlen + sign, true, ' '); fl->write_spaces(writer, n + pfxlen + sign, true, ' ');
} }
if (sign) { if (sign) {
writer.put(neg ? '-' : *((" \0+") + lsgn * 2)); writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
} }
range_put_n(writer, pfx, pfxlen); writer = ostd::copy(string_range{pfx, pfx + pfxlen}, writer);
if (zero) { if (zero) {
r += fl->write_spaces(writer, n + pfxlen + sign, true, '0'); fl->write_spaces(writer, n + pfxlen + sign, true, '0');
} }
for (int i = int(n - 1); i >= 0; --i) { for (int i = int(n - 1); i >= 0; --i) {
writer.put(buf[i]); writer.put(buf[i]);
} }
r += fl->write_spaces(writer, n + sign + pfxlen, false); fl->write_spaces(writer, n + sign + pfxlen, false);
return r;
} }
template<typename R, typename ...A> template<typename R, typename ...A>
static size_t format_impl( static void format_impl(
R &writer, bool escape, string_range fmt, A const &...args R &writer, bool escape, string_range 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 size_t unpack( static inline void unpack(
R &writer, bool esc, string_range fmt, R &writer, bool esc, string_range fmt,
T const &item, A const &...args T const &item, A const &...args
) { ) {
return FmtTupleUnpacker<I - 1>::unpack( FmtTupleUnpacker<I - 1>::unpack(
writer, esc, fmt, item, std::get<I - 1>(item), args... writer, esc, fmt, item, std::get<I - 1>(item), args...
); );
} }
@ -520,11 +499,11 @@ 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 size_t unpack( static inline void unpack(
R &writer, bool esc, string_range fmt, R &writer, bool esc, string_range fmt,
T const &, A const &...args T const &, A const &...args
) { ) {
return format_impl(writer, esc, fmt, args...); format_impl(writer, esc, fmt, args...);
} }
}; };
@ -541,55 +520,51 @@ 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 size_t format_ritem( inline void format_ritem(
R &writer, bool esc, bool, string_range fmt, R &writer, bool esc, bool, string_range 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
) { ) {
return format_impl(writer, esc, fmt, item); format_impl(writer, esc, fmt, item);
} }
template<typename R, typename T> template<typename R, typename T>
inline size_t format_ritem( inline void format_ritem(
R &writer, bool esc, bool expandval, string_range fmt, R &writer, bool esc, bool expandval, string_range 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
) { ) {
if (expandval) { if (expandval) {
return FmtTupleUnpacker<std::tuple_size<T>::value>::unpack( FmtTupleUnpacker<std::tuple_size<T>::value>::unpack(
writer, esc, fmt, item writer, esc, fmt, item
); );
} else {
format_impl(writer, esc, fmt, item);
} }
return format_impl(writer, esc, fmt, item);
} }
template<typename R, typename T> template<typename R, typename T>
inline size_t write_range( inline void write_range(
R &writer, format_spec const *fl, bool escape, bool expandval, R &writer, format_spec const *fl, bool escape, bool expandval,
string_range sep, T const &val, string_range sep, T const &val,
std::enable_if_t<detail::iterable_test<T>, bool> = true std::enable_if_t<detail::iterable_test<T>, bool> = true
) { ) {
/* XXX: maybe handle error cases? */
auto range = ostd::iter(val); auto range = ostd::iter(val);
if (range.empty()) { if (range.empty()) {
return 0; return;
} }
size_t ret = 0;
/* test first item */ /* test first item */
ret += format_ritem( format_ritem(writer, escape, expandval, fl->rest(), range.front());
writer, escape, expandval, fl->rest(), range.front()
);
range.pop_front(); range.pop_front();
/* write the rest (if any) */ /* write the rest (if any) */
for (; !range.empty(); range.pop_front()) { for (; !range.empty(); range.pop_front()) {
ret += range_put_n(writer, &sep[0], sep.size()); writer = ostd::copy(sep, writer);
ret += format_ritem( format_ritem(
writer, escape, expandval, fl->rest(), range.front() writer, escape, expandval, fl->rest(), range.front()
); );
} }
return ret;
} }
template<typename R, typename T> template<typename R, typename T>
inline size_t write_range( inline void write_range(
R &, format_spec const *, bool, bool, string_range, R &, format_spec const *, bool, bool, string_range,
T const &, std::enable_if_t<!detail::iterable_test<T>, bool> = true T const &, std::enable_if_t<!detail::iterable_test<T>, bool> = true
) { ) {
@ -661,24 +636,23 @@ namespace detail {
/* string base writer */ /* string base writer */
template<typename R> template<typename R>
size_t write_str(R &writer, bool escape, string_range val) const { void write_str(R &writer, bool escape, string_range val) const {
if (escape) { if (escape) {
return write_str(writer, false, escape_fmt_str(val)); write_str(writer, false, escape_fmt_str(val));
return;
} }
size_t n = val.size(); size_t n = val.size();
if (this->precision()) { if (this->precision()) {
n = this->precision(); n = this->precision();
} }
size_t r = n; this->write_spaces(writer, n, true);
r += this->write_spaces(writer, n, true); writer = ostd::copy(val.slice(0, n), writer);
range_put_n(writer, &val[0], n); this->write_spaces(writer, n, false);
r += this->write_spaces(writer, n, false);
return r;
} }
/* char values */ /* char values */
template<typename R> template<typename R>
size_t write_char(R &writer, bool escape, char val) const { void 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) {
@ -687,13 +661,13 @@ namespace detail {
size_t elen = strlen(esc); size_t elen = strlen(esc);
memcpy(buf + 1, esc, elen); memcpy(buf + 1, esc, elen);
buf[elen + 1] = '\''; buf[elen + 1] = '\'';
return write_val(writer, false, ostd::string_range{ write_val(writer, false, ostd::string_range{
buf, buf + elen + 2 buf, buf + elen + 2
}); });
return;
} }
} }
size_t r = 1 + escape * 2; 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('\'');
writer.put(val); writer.put(val);
@ -701,13 +675,12 @@ namespace detail {
} else { } else {
writer.put(val); writer.put(val);
} }
r += this->write_spaces(writer, 1 + escape * 2, false); this->write_spaces(writer, 1 + escape * 2, false);
return r;
} }
/* 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>>
size_t write_float(R &writer, bool, T val) const { void 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];
@ -723,7 +696,7 @@ namespace detail {
fmtspec[0] = 'L'; fmtspec[0] = 'L';
} }
buf[this->build_spec(iter(buf), fmtspec)] = '\0'; this->build_spec(iter(buf), fmtspec).put('\0');
int 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
@ -745,43 +718,45 @@ namespace detail {
/* see above */ /* see above */
throw format_error{"invalid float format"}; throw format_error{"invalid float format"};
} }
range_put_n(writer, dbuf, ret); writer = ostd::copy(string_range{dbuf, dbuf + ret}, writer);
delete[] dbuf; delete[] dbuf;
} else { } else {
range_put_n(writer, rbuf, ret); writer = ostd::copy(string_range{rbuf, rbuf + ret}, writer);
} }
return ret;
} }
template<typename R, typename T> template<typename R, typename T>
size_t write_val(R &writer, bool escape, T const &val) const { void 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(fmt_tofmt_test<T, tostr_range<R>>) { if constexpr(fmt_tofmt_test<T, tostr_range<R>>) {
tostr_range<R> sink(writer); tostr_range<R> sink(writer);
to_format(val, sink, *this); to_format(val, sink, *this);
return sink.get_written(); return;
} }
/* second best, we can convert to string slice */ /* second best, we can convert to string slice */
if constexpr(std::is_constructible_v<string_range, T const &>) { if constexpr(std::is_constructible_v<string_range, T const &>) {
if (this->spec() != 's') { if (this->spec() != 's') {
throw format_error{"strings need the '%s' spec"}; throw format_error{"strings need the '%s' spec"};
} }
return write_str(writer, escape, val); write_str(writer, escape, val);
return;
} }
/* bools, check if printing as string, otherwise convert to int */ /* bools, check if printing as string, otherwise convert to int */
if constexpr(std::is_same_v<T, bool>) { if constexpr(std::is_same_v<T, bool>) {
if (this->spec() == 's') { if (this->spec() == 's') {
return write_val(writer, ("false\0true") + (6 * val)); write_val(writer, ("false\0true") + (6 * val));
} else { } else {
return write_val(writer, int(val)); write_val(writer, int(val));
} }
return;
} }
/* character values */ /* character values */
if constexpr(std::is_same_v<T, char>) { if constexpr(std::is_same_v<T, char>) {
if (this->spec() != 's' && this->spec() != 'c') { if (this->spec() != 's' && this->spec() != 'c') {
throw format_error{"cannot format chars with the given spec"}; throw format_error{"cannot format chars with the given spec"};
} }
return write_char(writer, escape, val); write_char(writer, escape, val);
return;
} }
/* pointers, write as pointer with %s and otherwise as unsigned... /* pointers, write as pointer with %s and otherwise as unsigned...
* char pointers are handled by the string case above * char pointers are handled by the string case above
@ -793,32 +768,36 @@ namespace detail {
has_precision() ? precision() : -1, has_precision() ? precision() : -1,
(spec() == 's') ? (flags() | FMT_FLAG_HASH) : flags() (spec() == 's') ? (flags() | FMT_FLAG_HASH) : flags()
}; };
return detail::write_u(writer, &sp, false, size_t(val)); detail::write_u(writer, &sp, false, size_t(val));
return;
} }
/* integers */ /* integers */
if constexpr(std::is_integral_v<T>) { if constexpr(std::is_integral_v<T>) {
if constexpr(std::is_signed_v<T>) { if constexpr(std::is_signed_v<T>) {
/* signed integers */ /* signed integers */
using UT = std::make_unsigned_t<T>; using UT = std::make_unsigned_t<T>;
return detail::write_u( detail::write_u(
writer, this, val < 0, writer, this, val < 0,
(val < 0) ? static_cast<UT>(-val) : static_cast<UT>(val) (val < 0) ? static_cast<UT>(-val) : static_cast<UT>(val)
); );
} else { } else {
/* unsigned integers */ /* unsigned integers */
return detail::write_u(writer, this, false, val); detail::write_u(writer, this, false, val);
} }
return;
} }
/* floats */ /* floats */
if constexpr(std::is_floating_point_v<T>) { if constexpr(std::is_floating_point_v<T>) {
return write_float(writer, escape, val); write_float(writer, escape, val);
return;
} }
/* stuff that can be to_string'd, worst reliable case, allocates */ /* stuff that can be to_string'd, worst reliable case, allocates */
if constexpr(fmt_tostr_test<T>) { if constexpr(fmt_tostr_test<T>) {
if (this->spec() != 's') { if (this->spec() != 's') {
throw format_error{"custom objects need the '%s' spec"}; throw format_error{"custom objects need the '%s' spec"};
} }
return write_val(writer, false, ostd::to_string<T>{}(val)); write_val(writer, false, ostd::to_string<T>{}(val));
return;
} }
/* we ran out of options, failure */ /* we ran out of options, failure */
throw format_error{"the value cannot be formatted"}; throw format_error{"the value cannot be formatted"};
@ -826,23 +805,23 @@ namespace detail {
/* actual writer */ /* actual writer */
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
size_t write_arg( void 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) {
if constexpr(!sizeof...(A)) { if constexpr(!sizeof...(A)) {
throw format_error{"not enough format arguments"}; throw format_error{"not enough format arguments"};
} else { } else {
return write_arg(writer, idx - 1, args...); write_arg(writer, idx - 1, args...);
} }
} else { } else {
return write_val(writer, this->p_nested_escape, val); write_val(writer, this->p_nested_escape, val);
} }
} }
/* range writer */ /* range writer */
template<typename R, typename T, typename ...A> template<typename R, typename T, typename ...A>
size_t write_range( void write_range(
R &writer, size_t idx, bool expandval, string_range sep, R &writer, size_t idx, bool expandval, string_range sep,
T const &val, A const &...args T const &val, A const &...args
) const { ) const {
@ -850,10 +829,10 @@ namespace detail {
if constexpr(!sizeof...(A)) { if constexpr(!sizeof...(A)) {
throw format_error{"not enough format arguments"}; throw format_error{"not enough format arguments"};
} else { } else {
return write_range(writer, idx - 1, expandval, sep, args...); write_range(writer, idx - 1, expandval, sep, args...);
} }
} else { } else {
return detail::write_range( detail::write_range(
writer, this, this->p_nested_escape, expandval, sep, val writer, this, this->p_nested_escape, expandval, sep, val
); );
} }
@ -861,13 +840,12 @@ namespace detail {
}; };
template<typename R, typename ...A> template<typename R, typename ...A>
inline size_t format_impl( inline void format_impl(
R &writer, bool escape, string_range fmt, A const &...args R &writer, bool escape, string_range fmt, A const &...args
) { ) {
size_t argidx = 1, twr = 0, written = 0; size_t argidx = 1;
detail::write_spec spec(fmt, escape); detail::write_spec spec(fmt, escape);
while (spec.read_until_spec(writer, &twr)) { while (spec.read_until_spec(writer)) {
written += twr;
size_t argpos = spec.index(); size_t argpos = spec.index();
if (spec.is_nested()) { if (spec.is_nested()) {
if (!argpos) { if (!argpos) {
@ -875,7 +853,7 @@ namespace detail {
} }
/* FIXME: figure out a better way */ /* FIXME: figure out a better way */
detail::write_spec nspec(spec.nested(), spec.nested_escape()); detail::write_spec nspec(spec.nested(), spec.nested_escape());
written += nspec.write_range( 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...
); );
@ -906,33 +884,31 @@ namespace detail {
spec.set_width(argpos - 2 - argprec, args...); spec.set_width(argpos - 2 - argprec, args...);
} }
} }
written += spec.write_arg(writer, argpos - 1, args...); spec.write_arg(writer, argpos - 1, args...);
} }
written += twr;
return written;
} }
template<typename R> template<typename R>
inline ptrdiff_t format_impl(R &writer, bool, string_range fmt) { inline void format_impl(R &writer, bool, string_range fmt) {
size_t written = 0;
detail::write_spec spec(fmt, false); detail::write_spec spec(fmt, false);
if (spec.read_until_spec(writer, &written)) { if (spec.read_until_spec(writer)) {
throw format_error{"format spec without format arguments"}; throw format_error{"format spec without format arguments"};
} }
return written;
} }
} /* namespace detail */ } /* namespace detail */
template<typename R, typename ...A> template<typename R, typename ...A>
inline size_t format(R &&writer, string_range fmt, A const &...args) { inline R &&format(R &&writer, string_range fmt, A const &...args) {
return detail::format_impl(writer, false, fmt, args...); detail::format_impl(writer, false, fmt, args...);
return std::forward<R>(writer);
} }
template<typename R, typename T> template<typename R, typename T>
inline size_t format(R &&writer, format_spec const &fmt, T const &val) { inline R &&format(R &&writer, format_spec 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::write_spec const &wsp = static_cast<detail::write_spec const &>(fmt); detail::write_spec const &wsp = static_cast<detail::write_spec const &>(fmt);
return wsp.write_arg(writer, 0, val); wsp.write_arg(writer, 0, val);
return std::forward<R>(writer);
} }
} /* namespace ostd */ } /* namespace ostd */

View file

@ -9,6 +9,8 @@
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
#include <stdexcept>
#include <system_error>
#include "ostd/platform.hh" #include "ostd/platform.hh"
#include "ostd/string.hh" #include "ostd/string.hh"
@ -27,6 +29,11 @@ namespace detail {
}; };
} }
/* TODO: inherit from system_error and come up with the proper infra for it */
struct io_error: std::runtime_error {
using std::runtime_error::runtime_error;
};
struct file_stream: stream { struct file_stream: stream {
file_stream(): p_f(), p_owned(false) {} file_stream(): p_f(), p_owned(false) {}
file_stream(file_stream const &) = delete; file_stream(file_stream const &) = delete;
@ -93,38 +100,59 @@ struct file_stream: stream {
return feof(p_f) != 0; return feof(p_f) != 0;
} }
bool seek(stream_off_t pos, stream_seek whence = stream_seek::SET) { void seek(stream_off_t pos, stream_seek whence = stream_seek::SET) {
#ifndef OSTD_PLATFORM_WIN32 #ifndef OSTD_PLATFORM_WIN32
return fseeko(p_f, pos, int(whence)) >= 0; if (fseeko(p_f, pos, int(whence)))
#else #else
return _fseeki64(p_f, pos, int(whence)) >= 0; if (_fseeki64(p_f, pos, int(whence)))
#endif #endif
{
throw io_error{"file_stream seek error"};
}
} }
stream_off_t tell() const { stream_off_t tell() const {
#ifndef OSTD_PLATFORM_WIN32 #ifndef OSTD_PLATFORM_WIN32
return ftello(p_f); auto ret = ftello(p_f);
#else #else
return _ftelli64(p_f); auto ret = _ftelli64(p_f);
#endif #endif
if (ret < 0) {
throw io_error{"file_stream tell error"};
}
return ret;
} }
bool flush() { return !fflush(p_f); } void flush() {
if (fflush(p_f)) {
size_t read_bytes(void *buf, size_t count) { throw io_error{"file_stream flush error"};
return fread(buf, 1, count, p_f); }
} }
size_t write_bytes(void const *buf, size_t count) { void read_bytes(void *buf, size_t count) {
return fwrite(buf, 1, count, p_f); if (fread(buf, 1, count, p_f) != count) {
throw io_error{"file_stream read error"};
}
}
void write_bytes(void const *buf, size_t count) {
if (fwrite(buf, 1, count, p_f) != count) {
throw io_error{"file_stream write error"};
}
} }
int getchar() { int getchar() {
return fgetc(p_f); int ret = fgetc(p_f);
if (ret == EOF) {
throw io_error{"file_stream EOF"};
}
return ret;
} }
bool putchar(int c) { void putchar(int c) {
return fputc(c, p_f) != EOF; if (fputc(c, p_f) == EOF) {
throw io_error{"file_stream EOF"};
}
} }
void swap(file_stream &s) { void swap(file_stream &s) {
@ -159,14 +187,12 @@ namespace detail {
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
stdout_range() {} stdout_range() {}
bool put(char c) { void put(char c) {
return putchar(c) != EOF; if (putchar(c) == EOF) {
throw io_error{"stdout EOF"};
}
} }
}; };
inline size_t range_put_n(stdout_range &, char const *p, size_t n) {
return fwrite(p, 1, n, stdout);
}
} }
template<typename T> template<typename T>
@ -184,8 +210,7 @@ template<typename T>
inline void writeln(T const &v) { inline void writeln(T const &v) {
write(v); write(v);
if (putchar('\n') == EOF) { if (putchar('\n') == EOF) {
/* consistency with format module */ throw io_error{"stdout EOF"};
throw format_error{"stream EOF"};
} }
} }
@ -194,7 +219,7 @@ inline void writeln(T const &v, A const &...args) {
write(v); write(v);
write(args...); write(args...);
if (putchar('\n') == EOF) { if (putchar('\n') == EOF) {
throw format_error{"stream EOF"}; throw io_error{"stdout EOF"};
} }
} }
@ -207,7 +232,7 @@ template<typename ...A>
inline void writefln(string_range fmt, A const &...args) { inline void writefln(string_range fmt, A const &...args) {
writef(fmt, args...); writef(fmt, args...);
if (putchar('\n') == EOF) { if (putchar('\n') == EOF) {
throw format_error{"stream EOF"}; throw io_error{"stdout EOF"};
} }
} }

View file

@ -15,6 +15,7 @@
#include <iterator> #include <iterator>
#include <type_traits> #include <type_traits>
#include <initializer_list> #include <initializer_list>
#include <algorithm>
#include "ostd/types.hh" #include "ostd/types.hh"
@ -198,7 +199,7 @@ template<typename T> constexpr bool is_contiguous_range =
namespace detail { namespace detail {
template<typename R, typename T> template<typename R, typename T>
static std::true_type test_outrange(typename std::is_same< static std::true_type test_outrange(typename std::is_same<
decltype(std::declval<R &>().put(std::declval<T>())), bool decltype(std::declval<R &>().put(std::declval<T>())), void
>::type *); >::type *);
template<typename, typename> template<typename, typename>
@ -392,14 +393,14 @@ public:
return *this; return *this;
} }
bool next() { return p_range.pop_front(); } void next() { p_range.pop_front(); }
bool prev() { return p_range.push_front(); } void prev() { p_range.push_front(); }
range_size_t<T> next_n(range_size_t<T> n) { void next_n(range_size_t<T> n) {
return p_range.pop_front_n(n); p_range.pop_front_n(n);
} }
range_size_t<T> prev_n(range_size_t<T> n) { void prev_n(range_size_t<T> n) {
return p_range.push_front_n(n); p_range.push_front_n(n);
} }
range_difference_t<T> add_n(range_difference_t<T> n) { range_difference_t<T> add_n(range_difference_t<T> n) {
@ -497,43 +498,31 @@ inline range_difference_t<R> operator-(
namespace detail { namespace detail {
template<typename R> template<typename R>
range_size_t<R> pop_front_n(R &range, range_size_t<R> n) { void pop_front_n(R &range, range_size_t<R> n) {
for (range_size_t<R> i = 0; i < n; ++i) { for (range_size_t<R> i = 0; i < n; ++i) {
if (!range.pop_front()) { range.pop_front();
return i;
}
} }
return n;
} }
template<typename R> template<typename R>
range_size_t<R> pop_back_n(R &range, range_size_t<R> n) { void pop_back_n(R &range, range_size_t<R> n) {
for (range_size_t<R> i = 0; i < n; ++i) { for (range_size_t<R> i = 0; i < n; ++i) {
if (!range.pop_back()) { range.pop_back();
return i;
}
} }
return n;
} }
template<typename R> template<typename R>
range_size_t<R> push_front_n(R &range, range_size_t<R> n) { void push_front_n(R &range, range_size_t<R> n) {
for (range_size_t<R> i = 0; i < n; ++i) { for (range_size_t<R> i = 0; i < n; ++i) {
if (!range.push_front()) { range.push_front();
return i;
}
} }
return n;
} }
template<typename R> template<typename R>
range_size_t<R> push_back_n(R &range, range_size_t<R> n) { void push_back_n(R &range, range_size_t<R> n) {
for (range_size_t<R> i = 0; i < n; ++i) { for (range_size_t<R> i = 0; i < n; ++i) {
if (!range.push_back()) { range.push_back();
return i;
}
} }
return n;
} }
} }
@ -562,23 +551,23 @@ struct input_range {
} }
template<typename Size> template<typename Size>
Size pop_front_n(Size n) { void pop_front_n(Size n) {
return detail::pop_front_n<B>(*static_cast<B *>(this), n); detail::pop_front_n<B>(*static_cast<B *>(this), n);
} }
template<typename Size> template<typename Size>
Size pop_back_n(Size n) { void pop_back_n(Size n) {
return detail::pop_back_n<B>(*static_cast<B *>(this), n); detail::pop_back_n<B>(*static_cast<B *>(this), n);
} }
template<typename Size> template<typename Size>
Size push_front_n(Size n) { void push_front_n(Size n) {
return detail::push_front_n<B>(*static_cast<B *>(this), n); detail::push_front_n<B>(*static_cast<B *>(this), n);
} }
template<typename Size> template<typename Size>
Size push_back_n(Size n) { void push_back_n(Size n) {
return detail::push_back_n<B>(*static_cast<B *>(this), n); detail::push_back_n<B>(*static_cast<B *>(this), n);
} }
B iter() const { B iter() const {
@ -621,30 +610,6 @@ struct input_range {
return range_half<B>(iter()); return range_half<B>(iter());
} }
template<typename OR, typename Size>
std::enable_if_t<is_output_range<OR>, Size> copy(OR &&orange, Size n = -1) {
B r(*static_cast<B const *>(this));
Size on = n;
for (; n && !r.empty(); --n) {
if (!orange.put(r.front())) {
break;
}
r.pop_front();
}
return (on - n);
}
template<typename Value, typename Size>
Size copy(Value *p, Size n = -1) {
B r(*static_cast<B const *>(this));
Size on = n;
for (; n && !r.empty(); --n) {
*p++ = r.front();
r.pop_front();
}
return (on - n);
}
/* iterator like interface operating on the front part of the range /* iterator like interface operating on the front part of the range
* this is sometimes convenient as it can be used within expressions */ * this is sometimes convenient as it can be used within expressions */
@ -729,15 +694,6 @@ struct output_range {
using range_category = output_range_tag; using range_category = output_range_tag;
}; };
template<typename R>
inline range_size_t<R> range_put_n(
R &range, range_value_t<R> const *p, range_size_t<R> n
) {
range_size_t<R> on = n;
for (; n && range.put(*p++); --n);
return (on - n);
}
template<typename T> template<typename T>
struct noop_output_range: output_range<noop_output_range<T>> { struct noop_output_range: output_range<noop_output_range<T>> {
using value_type = T; using value_type = T;
@ -745,7 +701,7 @@ struct noop_output_range: output_range<noop_output_range<T>> {
using size_type = size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
bool put(T const &) { return true; } void put(T const &) {}
}; };
template<typename R> template<typename R>
@ -755,13 +711,6 @@ struct counting_output_range: output_range<counting_output_range<R>> {
using size_type = range_size_t<R>; using size_type = range_size_t<R>;
using difference_type = range_difference_t<R>; using difference_type = range_difference_t<R>;
template<typename RR>
friend range_size_t<counting_output_range<RR>> range_put_n(
counting_output_range<RR> &range,
range_value_t<counting_output_range<RR>> *p,
range_size_t<counting_output_range<RR>> n
);
private: private:
R p_range; R p_range;
size_type p_written = 0; size_type p_written = 0;
@ -770,15 +719,13 @@ public:
counting_output_range() = delete; counting_output_range() = delete;
counting_output_range(R const &range): p_range(range) {} counting_output_range(R const &range): p_range(range) {}
bool put(value_type const &v) { void put(value_type const &v) {
bool ret = p_range.put(v); p_range.put(v);
p_written += ret; ++p_written;
return ret;
} }
bool put(value_type &&v) { void put(value_type &&v) {
bool ret = p_range.put(std::move(v)); p_range.put(std::move(v));
p_written += ret; ++p_written;
return ret;
} }
size_type get_written() const { size_type get_written() const {
@ -786,17 +733,6 @@ public:
} }
}; };
template<typename R>
inline range_size_t<counting_output_range<R>> range_put_n(
counting_output_range<R> &range,
range_value_t<counting_output_range<R>> *p,
range_size_t<counting_output_range<R>> n
) {
auto ret = range_put_n(range.p_range, p, n);
range.p_written += ret;
return ret;
}
template<typename R> template<typename R>
inline counting_output_range<R> range_counter(R const &range) { inline counting_output_range<R> range_counter(R const &range) {
return counting_output_range<R>{range}; return counting_output_range<R>{range};
@ -967,23 +903,17 @@ public:
bool empty() const { return p_beg == p_end; } bool empty() const { return p_beg == p_end; }
bool pop_front() { void pop_front() {
if (empty()) { p_beg.next();
return false;
}
return p_beg.next();
} }
bool push_front() { void push_front() {
return p_beg.prev(); p_beg.prev();
} }
bool pop_back() { void pop_back() {
if (empty()) { p_end.prev();
return false;
}
return p_end.prev();
} }
bool push_back() { void push_back() {
return p_end.next(); p_end.next();
} }
reference front() const { return *p_beg; } reference front() const { return *p_beg; }
@ -1013,11 +943,11 @@ public:
return p_beg[idx]; return p_beg[idx];
} }
bool put(value_type const &v) { void put(value_type const &v) {
return p_beg.range().put(v); p_beg.range().put(v);
} }
bool put(value_type &&v) { void put(value_type &&v) {
return p_beg.range().put(std::move(v)); p_beg.range().put(std::move(v));
} }
value_type *data() { return p_beg.data(); } value_type *data() { return p_beg.data(); }
@ -1077,17 +1007,17 @@ public:
return -p_range.distance_front(r.p_range); return -p_range.distance_front(r.p_range);
} }
bool pop_front() { return p_range.pop_back(); } void pop_front() { p_range.pop_back(); }
bool pop_back() { return p_range.pop_front(); } void pop_back() { p_range.pop_front(); }
bool push_front() { return p_range.push_back(); } void push_front() { p_range.push_back(); }
bool push_back() { return p_range.push_front(); } void push_back() { p_range.push_front(); }
size_type pop_front_n(size_type n) { return p_range.pop_front_n(n); } void pop_front_n(size_type n) { p_range.pop_front_n(n); }
size_type pop_back_n(size_type n) { return p_range.pop_back_n(n); } void pop_back_n(size_type n) { p_range.pop_back_n(n); }
size_type push_front_n(size_type n) { return p_range.push_front_n(n); } void push_front_n(size_type n) { p_range.push_front_n(n); }
size_type push_back_n(size_type n) { return p_range.push_back_n(n); } void push_back_n(size_type n) { p_range.push_back_n(n); }
reference front() const { return p_range.back(); } reference front() const { return p_range.back(); }
reference back() const { return p_range.front(); } reference back() const { return p_range.front(); }
@ -1153,17 +1083,17 @@ public:
return p_range.distance_back(r.p_range); return p_range.distance_back(r.p_range);
} }
bool pop_front() { return p_range.pop_front(); } void pop_front() { p_range.pop_front(); }
bool pop_back() { return p_range.pop_back(); } void pop_back() { p_range.pop_back(); }
bool push_front() { return p_range.push_front(); } void push_front() { p_range.push_front(); }
bool push_back() { return p_range.push_back(); } void push_back() { p_range.push_back(); }
size_type pop_front_n(size_type n) { return p_range.pop_front_n(n); } void pop_front_n(size_type n) { p_range.pop_front_n(n); }
size_type pop_back_n(size_type n) { return p_range.pop_back_n(n); } void pop_back_n(size_type n) { p_range.pop_back_n(n); }
size_type push_front_n(size_type n) { return p_range.push_front_n(n); } void push_front_n(size_type n) { p_range.push_front_n(n); }
size_type push_back_n(size_type n) { return p_range.push_back_n(n); } void push_back_n(size_type n) { p_range.push_back_n(n); }
reference front() const { return std::move(p_range.front()); } reference front() const { return std::move(p_range.front()); }
reference back() const { return std::move(p_range.back()); } reference back() const { return std::move(p_range.back()); }
@ -1174,8 +1104,8 @@ public:
return move_range{p_range.slice(start, end)}; return move_range{p_range.slice(start, end)};
} }
bool put(value_type const &v) { return p_range.put(v); } void put(value_type const &v) { p_range.put(v); }
bool put(value_type &&v) { return p_range.put(std::move(v)); } void put(value_type &&v) { p_range.put(std::move(v)); }
}; };
template<typename T> template<typename T>
@ -1198,7 +1128,7 @@ struct number_range: input_range<number_range<T>> {
return p_a == range.p_a; return p_a == range.p_a;
} }
bool pop_front() { p_a += p_step; return true; } void pop_front() { p_a += p_step; }
T front() const { return p_a; } T front() const { return p_a; }
private: private:
@ -1277,18 +1207,14 @@ public:
return p_range.equals_front(r.p_range); return p_range.equals_front(r.p_range);
} }
bool pop_front() { void pop_front() {
if (p_range.pop_front()) { p_range.pop_front();
++p_index; ++p_index;
return true;
}
return false;
} }
size_type pop_front_n(size_type n) { void pop_front_n(size_type n) {
size_type ret = p_range.pop_front_n(n); p_range.pop_front_n(n);
p_index += ret; p_index += n;
return ret;
} }
reference front() const { reference front() const {
@ -1333,18 +1259,16 @@ public:
bool empty() const { return (p_remaining <= 0) || p_range.empty(); } bool empty() const { return (p_remaining <= 0) || p_range.empty(); }
bool pop_front() { void pop_front() {
if (p_range.pop_front()) { p_range.pop_front();
if (p_remaining >= 1) {
--p_remaining; --p_remaining;
return true;
} }
return false;
} }
size_type pop_front_n(size_type n) { void pop_front_n(size_type n) {
size_type ret = p_range.pop_front_n(n); p_range.pop_front_n(n);
p_remaining -= ret; p_remaining -= std::min(n, p_remaining);
return ret;
} }
reference front() const { return p_range.front(); } reference front() const { return p_range.front(); }
@ -1395,9 +1319,9 @@ public:
return p_range.equals_front(r.p_range); return p_range.equals_front(r.p_range);
} }
bool pop_front() { return p_range.pop_front_n(p_chunksize) > 0; } void pop_front() { p_range.pop_front_n(p_chunksize); }
size_type pop_front_n(size_type n) { void pop_front_n(size_type n) {
return p_range.pop_front_n(p_chunksize * n) / p_chunksize; p_range.pop_front_n(p_chunksize * n);
} }
reference front() const { return p_range.take(p_chunksize); } reference front() const { return p_range.take(p_chunksize); }
@ -1405,14 +1329,14 @@ public:
namespace detail { namespace detail {
template<size_t I, size_t N, typename T> template<size_t I, size_t N, typename T>
inline bool join_range_pop(T &tup) { inline void join_range_pop(T &tup) {
if constexpr(I != N) { if constexpr(I != N) {
if (!std::get<I>(tup).empty()) { if (!std::get<I>(tup).empty()) {
return std::get<I>(tup).pop_front(); std::get<I>(tup).pop_front();
return;
} }
return join_range_pop<I + 1, N>(tup); join_range_pop<I + 1, N>(tup);
} }
return false;
} }
template<size_t I, size_t N, typename T> template<size_t I, size_t N, typename T>
@ -1423,6 +1347,7 @@ namespace detail {
} }
return join_range_front<I + 1, N>(tup); return join_range_front<I + 1, N>(tup);
} }
/* fallback, will probably throw */
return std::get<0>(tup).front(); return std::get<0>(tup).front();
} }
} }
@ -1471,8 +1396,8 @@ public:
}, p_ranges); }, p_ranges);
} }
bool pop_front() { void pop_front() {
return detail::join_range_pop<0, sizeof...(R)>(p_ranges); detail::join_range_pop<0, sizeof...(R)>(p_ranges);
} }
reference front() const { reference front() const {
@ -1539,9 +1464,9 @@ public:
}, p_ranges); }, p_ranges);
} }
bool pop_front() { void pop_front() {
return std::apply([](auto &...args) { std::apply([](auto &...args) {
return (... && args.pop_front()); (args.pop_front(), ...);
}, p_ranges); }, p_ranges);
} }
@ -1593,14 +1518,12 @@ struct appender_range: output_range<appender_range<T>> {
size_type size() const { return p_data.size(); } size_type size() const { return p_data.size(); }
size_type capacity() const { return p_data.capacity(); } size_type capacity() const { return p_data.capacity(); }
bool put(typename T::const_reference v) { void put(typename T::const_reference v) {
p_data.push_back(v); p_data.push_back(v);
return true;
} }
bool put(typename T::value_type &&v) { void put(typename T::value_type &&v) {
p_data.push_back(std::move(v)); p_data.push_back(std::move(v));
return true;
} }
T &get() { return p_data; } T &get() { return p_data; }
@ -1691,39 +1614,40 @@ struct iterator_range: input_range<iterator_range<T>> {
/* satisfy input_range / forward_range */ /* satisfy input_range / forward_range */
bool empty() const { return p_beg == p_end; } bool empty() const { return p_beg == p_end; }
bool pop_front() { void pop_front() {
if (p_beg == p_end) {
return false;
}
++p_beg; ++p_beg;
return true; /* rely on iterators to do their own checks */
if constexpr(std::is_pointer_v<T>) {
if (p_beg > p_end) {
throw std::out_of_range{"pop_front on empty range"};
}
}
} }
bool push_front() { void push_front() {
--p_beg; return true; --p_beg;
} }
size_type pop_front_n(size_type n) { void pop_front_n(size_type n) {
using IC = typename std::iterator_traits<T>::iterator_category; using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) { if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
size_type olen = size_type(p_end - p_beg);
p_beg += n; p_beg += n;
if (p_beg > p_end) { /* rely on iterators to do their own checks */
p_beg = p_end; if constexpr(std::is_pointer_v<T>) {
return olen; if (p_beg > p_end) {
throw std::out_of_range{"pop_front_n of too many elements"};
}
} }
return n;
} else { } else {
return detail::pop_front_n(*this, n); detail::pop_front_n(*this, n);
} }
} }
size_type push_front_n(size_type n) { void push_front_n(size_type n) {
using IC = typename std::iterator_traits<T>::iterator_category; using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) { if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
p_beg -= n; p_beg -= n;
return true;
} else { } else {
return detail::push_front_n(*this, n); detail::push_front_n(*this, n);
} }
} }
@ -1738,39 +1662,40 @@ struct iterator_range: input_range<iterator_range<T>> {
} }
/* satisfy bidirectional_range */ /* satisfy bidirectional_range */
bool pop_back() { void pop_back() {
if (p_end == p_beg) { /* rely on iterators to do their own checks */
return false; if constexpr(std::is_pointer_v<T>) {
if (p_end == p_beg) {
throw std::out_of_range{"pop_back on empty range"};
}
} }
--p_end; --p_end;
return true;
} }
bool push_back() { void push_back() {
++p_end; return true; ++p_end;
} }
size_type pop_back_n(size_type n) { void pop_back_n(size_type n) {
using IC = typename std::iterator_traits<T>::iterator_category; using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) { if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
size_type olen = size_type(p_end - p_beg);
p_end -= n; p_end -= n;
if (p_end < p_beg) { /* rely on iterators to do their own checks */
p_end = p_beg; if constexpr(std::is_pointer_v<T>) {
return olen; if (p_end < p_beg) {
throw std::out_of_range{"pop_back_n of too many elements"};
}
} }
return n;
} else { } else {
return detail::pop_back_n(*this, n); detail::pop_back_n(*this, n);
} }
} }
size_type push_back_n(size_type n) { void push_back_n(size_type n) {
using IC = typename std::iterator_traits<T>::iterator_category; using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) { if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
p_end += n; p_end += n;
return true;
} else { } else {
return detail::push_back_n(*this, n); detail::push_back_n(*this, n);
} }
} }
@ -1798,100 +1723,17 @@ struct iterator_range: input_range<iterator_range<T>> {
value_type const *data() const { return p_beg; } value_type const *data() const { return p_beg; }
/* satisfy output_range */ /* satisfy output_range */
bool put(value_type const &v) { void put(value_type const &v) {
if (empty()) {
return false;
}
*(p_beg++) = v; *(p_beg++) = v;
return true;
} }
bool put(value_type &&v) { void put(value_type &&v) {
if (empty()) {
return false;
}
*(p_beg++) = std::move(v); *(p_beg++) = std::move(v);
return true;
} }
template<typename R>
std::enable_if_t<is_output_range<R>, size_type> copy(
R &&orange, size_type n = -1
) {
if constexpr(std::is_pointer_v<T>) {
size_type c = size();
if (n < c) {
c = n;
}
return range_put_n(orange, p_beg, c);
} else {
size_type on = n;
for (; n && !empty(); --n) {
if (!orange.put(front())) {
break;
}
pop_front();
}
return (on - n);
}
}
size_type copy(std::remove_cv_t<value_type> *p, size_type n = -1) {
using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
size_type c = size();
if (n < c) {
c = n;
}
if constexpr(std::is_pointer_v<T> && std::is_pod_v<value_type>) {
memcpy(p, p_beg, c * sizeof(value_type));
return c;
} else {
return copy(iterator_range<
std::remove_cv_t<value_type> *
>(p, p + c), c);
}
} else {
size_type on = n;
for (; n && !empty(); --n) {
*p++ = front();
pop_front();
}
return (on - n);
}
}
private: private:
T p_beg, p_end; T p_beg, p_end;
}; };
template<typename T>
inline auto range_put_n(
iterator_range<T> &range, range_value_t<iterator_range<T>> const *p,
range_size_t<iterator_range<T>> n
) {
using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
using value_type = range_value_t<iterator_range<T>>;
auto ret = range.size();
if (n < ret) {
ret = n;
}
if constexpr(std::is_pointer_v<T> && std::is_pod_v<value_type>) {
memcpy(&range.front(), p, ret * sizeof(value_type));
range.pop_front_n(ret);
} else {
for (auto i = ret; i; --i) {
range.front() = *p++;
range.pop_front();
}
}
return ret;
} else {
auto on = n;
for (; n && range.put(*p++); --n);
return (on - n);
}
}
template<typename T> template<typename T>
iterator_range<T> make_range(T beg, T end) { iterator_range<T> make_range(T beg, T end) {
return iterator_range<T>{beg, end}; return iterator_range<T>{beg, end};

View file

@ -43,32 +43,33 @@ struct stream {
virtual offset_type size() { virtual offset_type size() {
offset_type p = tell(); offset_type p = tell();
if ((p < 0) || !seek(0, stream_seek::END)) { seek(0, stream_seek::END);
return -1;
}
offset_type e = tell(); offset_type e = tell();
return ((p == e) || seek(p, stream_seek::SET)) ? e : -1; if (p == e) {
return e;
}
seek(p, stream_seek::SET);
return e;
} }
virtual bool seek(offset_type, stream_seek = stream_seek::SET) { virtual void seek(offset_type, stream_seek = stream_seek::SET) {}
return false;
}
virtual offset_type tell() const { return -1; } virtual offset_type tell() const { return -1; }
virtual bool flush() { return true; } virtual void flush() {}
virtual size_t read_bytes(void *, size_t) { return 0; } virtual void read_bytes(void *, size_t) {}
virtual size_t write_bytes(void const *, size_t) { return 0; } virtual void write_bytes(void const *, size_t) {}
virtual int getchar() { virtual int getchar() {
byte c; byte c;
return (read_bytes(&c, 1) == 1) ? c : -1; read_bytes(&c, 1);
return c;
} }
virtual bool putchar(int c) { virtual void putchar(int c) {
byte wc = byte(c); byte wc = byte(c);
return write_bytes(&wc, 1) == 1; write_bytes(&wc, 1);
} }
template<typename T> template<typename T>
@ -83,19 +84,14 @@ struct stream {
template<typename T> template<typename T>
void writeln(T const &v) { void writeln(T const &v) {
write(v); write(v);
if (!putchar('\n')) { putchar('\n');
/* consistency with format module */
throw format_error{"stream EOF"};
}
} }
template<typename T, typename ...A> template<typename T, typename ...A>
void writeln(T const &v, A const &...args) { void writeln(T const &v, A const &...args) {
write(v); write(v);
write(args...); write(args...);
if (!putchar('\n')) { putchar('\n');
throw format_error{"stream EOF"};
}
} }
template<typename ...A> template<typename ...A>
@ -104,44 +100,40 @@ struct stream {
template<typename ...A> template<typename ...A>
void writefln(string_range fmt, A const &...args) { void writefln(string_range fmt, A const &...args) {
writef(fmt, args...); writef(fmt, args...);
if (!putchar('\n')) { putchar('\n');
throw format_error{"stream EOF"};
}
} }
template<typename T = char> template<typename T = char>
stream_range<T> iter(); stream_range<T> iter();
template<typename T> template<typename T>
size_t put(T const *v, size_t count) { void put(T const *v, size_t count) {
return write_bytes(v, count * sizeof(T)) / sizeof(T); write_bytes(v, count * sizeof(T));
} }
template<typename T> template<typename T>
bool put(T v) { void put(T v) {
return write_bytes(&v, sizeof(T)) == sizeof(T); write_bytes(&v, sizeof(T));
} }
template<typename T> template<typename T>
size_t get(T *v, size_t count) { void get(T *v, size_t count) {
return read_bytes(v, count * sizeof(T)) / sizeof(T); read_bytes(v, count * sizeof(T));
} }
template<typename T> template<typename T>
bool get(T &v) { void get(T &v) {
return read_bytes(&v, sizeof(T)) == sizeof(T); read_bytes(&v, sizeof(T));
} }
template<typename T> template<typename T>
T get() { T get() {
T r; T r;
return get(r) ? r : T(); get(r);
return r;
} }
}; };
template<typename T>
size_t range_put_n(stream_range<T> &range, T const *p, size_t n);
template<typename T> template<typename T>
struct stream_range<T, true>: input_range<stream_range<T>> { struct stream_range<T, true>: input_range<stream_range<T>> {
using range_category = input_range_tag; using range_category = input_range_tag;
@ -150,28 +142,28 @@ struct stream_range<T, true>: input_range<stream_range<T>> {
using size_type = size_t; using size_type = size_t;
using difference_type = stream_off_t; using difference_type = stream_off_t;
template<typename TT>
friend size_t range_put_n(stream_range<TT> &range, TT const *p, size_t n);
stream_range() = delete; stream_range() = delete;
stream_range(stream &s): p_stream(&s), p_size(s.size()) {} stream_range(stream &s): p_stream(&s), p_size(s.size()) {}
stream_range(stream_range const &r): p_stream(r.p_stream), p_size(r.p_size) {} stream_range(stream_range const &r): p_stream(r.p_stream), p_size(r.p_size) {}
bool empty() const { bool empty() const {
return (p_size - p_stream->tell()) < stream_off_t(sizeof(T)); try {
auto pos = p_stream->tell();
return (p_size - pos) < stream_off_t(sizeof(T));
} catch (...) {
return true;
}
} }
bool pop_front() { void pop_front() {
if (empty()) {
return false;
}
T val; T val;
return !!p_stream->read_bytes(&val, sizeof(T)); p_stream->read_bytes(&val, sizeof(T));
} }
T front() const { T front() const {
T val; T val;
p_stream->seek(-p_stream->read_bytes(&val, sizeof(T)), stream_seek::CUR); p_stream->read_bytes(&val, sizeof(T));
p_stream->seek(-sizeof(T), stream_seek::CUR);
return val; return val;
} }
@ -179,17 +171,9 @@ struct stream_range<T, true>: input_range<stream_range<T>> {
return p_stream->tell() == s.p_stream->tell(); return p_stream->tell() == s.p_stream->tell();
} }
bool put(T val) { void put(T val) {
size_t v = p_stream->write_bytes(&val, sizeof(T)); p_stream->write_bytes(&val, sizeof(T));
p_size += v; p_size += sizeof(T);
return (v == sizeof(T));
}
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
if (n == size_t(-1)) {
n = p_stream->size() / sizeof(T);
}
return p_stream->get(p, n);
} }
private: private:
@ -197,11 +181,6 @@ private:
stream_off_t p_size; stream_off_t p_size;
}; };
template<typename T>
inline size_t range_put_n(stream_range<T> &range, T const *p, size_t n) {
return range.p_stream->put(p, n);
}
template<typename T> template<typename T>
inline stream_range<T> stream::iter() { inline stream_range<T> stream::iter() {
return stream_range<T>(*this); return stream_range<T>(*this);
@ -215,26 +194,22 @@ namespace detail {
using size_type = size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
fmt_stream_range(stream &s): p_s(s) {} fmt_stream_range(stream *s): p_s(s) {}
bool put(char c) { void put(char c) {
return p_s.write_bytes(&c, 1) == 1; p_s->write_bytes(&c, 1);
} }
stream &p_s; stream *p_s;
}; };
inline size_t range_put_n(fmt_stream_range &range, char const *p, size_t n) {
return range.p_s.write_bytes(p, n);
}
} }
template<typename T> template<typename T>
inline void stream::write(T const &v) { inline void stream::write(T const &v) {
format(detail::fmt_stream_range{*this}, format_spec{'s'}, v); format(detail::fmt_stream_range{this}, format_spec{'s'}, v);
} }
template<typename ...A> template<typename ...A>
inline void stream::writef(string_range fmt, A const &...args) { inline void stream::writef(string_range fmt, A const &...args) {
format(detail::fmt_stream_range{*this}, fmt, args...); format(detail::fmt_stream_range{this}, fmt, args...);
} }
} }

View file

@ -77,26 +77,26 @@ public:
bool empty() const { return p_beg == p_end; } bool empty() const { return p_beg == p_end; }
bool pop_front() { void pop_front() {
if (p_beg == p_end) {
return false;
}
++p_beg; ++p_beg;
return true; if (p_beg > p_end) {
throw std::out_of_range{"pop_front on empty range"};
}
}
void push_front() {
--p_beg;
} }
bool push_front() { --p_beg; return true; }
size_t pop_front_n(size_t n) { void pop_front_n(size_t n) {
size_t olen = p_end - p_beg;
p_beg += n; p_beg += n;
if (p_beg > p_end) { if (p_beg > p_end) {
p_beg = p_end; throw std::out_of_range{"pop_front_n of too many elements"};
return olen;
} }
return n;
} }
size_t push_front_n(size_t n) { p_beg -= n; return true; } void push_front_n(size_t n) {
p_beg -= n;
}
T &front() const { return *p_beg; } T &front() const { return *p_beg; }
@ -108,26 +108,26 @@ public:
return range.p_beg - p_beg; return range.p_beg - p_beg;
} }
bool pop_back() { void pop_back() {
if (p_end == p_beg) { if (p_end == p_beg) {
return false; return;
} }
--p_end; --p_end;
return true;
} }
bool push_back() { ++p_end; return true; } void push_back() {
++p_end;
}
size_t pop_back_n(size_t n) { void pop_back_n(size_t n) {
size_t olen = p_end - p_beg;
p_end -= n; p_end -= n;
if (p_end < p_beg) { if (p_end < p_beg) {
p_end = p_beg; throw std::out_of_range{"pop_back_n of too many elements"};
return olen;
} }
return n;
} }
size_t push_back_n(size_t n) { p_end += n; return true; } void push_back_n(size_t n) {
p_end += n;
}
T &back() const { return *(p_end - 1); } T &back() const { return *(p_end - 1); }
@ -147,12 +147,8 @@ public:
T &operator[](size_t i) const { return p_beg[i]; } T &operator[](size_t i) const { return p_beg[i]; }
bool put(T v) { void put(T v) {
if (empty()) {
return false;
}
*(p_beg++) = v; *(p_beg++) = v;
return true;
} }
T *data() { return p_beg; } T *data() { return p_beg; }
@ -183,17 +179,6 @@ diffsize:
return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0); return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0);
} }
template<typename R>
std::enable_if_t<is_output_range<R>, size_t> copy(R &&orange, size_t n = -1) {
return range_put_n(orange, data(), std::min(n, size()));
}
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
size_t c = std::min(n, size());
TR::copy(p, data(), c);
return c;
}
/* that way we can assign, append etc to std::string */ /* that way we can assign, append etc to std::string */
operator std::basic_string_view<std::remove_cv_t<T>>() const { operator std::basic_string_view<std::remove_cv_t<T>>() const {
return std::basic_string_view<std::remove_cv_t<T>>{data(), size()}; return std::basic_string_view<std::remove_cv_t<T>>{data(), size()};
@ -203,14 +188,6 @@ private:
T *p_beg, *p_end; T *p_beg, *p_end;
}; };
template<typename T, typename TR>
inline size_t range_put_n(basic_char_range<T, TR> &range, T const *p, size_t n) {
size_t an = std::min(n, range.size());
TR::copy(range.data(), p, an);
range.pop_front_n(an);
return an;
}
using char_range = basic_char_range<char>; using char_range = basic_char_range<char>;
using string_range = basic_char_range<char const>; using string_range = basic_char_range<char const>;
@ -461,68 +438,64 @@ namespace detail {
template<typename T, bool B> template<typename T, bool B>
struct ConcatPut<T, true, B> { struct ConcatPut<T, true, B> {
template<typename R> template<typename R>
static bool put(R &sink, string_range v) { static void put(R &sink, string_range v) {
return v.size() && (range_put_n(sink, &v[0], v.size()) == v.size()); sink = ostd::copy(v, sink);
} }
}; };
template<typename T> template<typename T>
struct ConcatPut<T, false, true> { struct ConcatPut<T, false, true> {
template<typename R> template<typename R>
static bool put(R &sink, char v) { static void put(R &sink, char v) {
return sink.put(v); sink.put(v);
} }
}; };
} }
template<typename R, typename T, typename F> template<typename R, typename T, typename F>
bool concat(R &&sink, T const &v, string_range sep, F func) { R &&concat(R &&sink, T const &v, string_range sep, F func) {
auto range = ostd::iter(v); auto range = ostd::iter(v);
if (range.empty()) { if (range.empty()) {
return true; return std::forward<R>(sink);
} }
for (;;) { for (;;) {
if (!detail::ConcatPut< detail::ConcatPut<
decltype(func(range.front())) decltype(func(range.front()))
>::put(sink, func(range.front()))) { >::put(sink, func(range.front()));
return false;
}
range.pop_front(); range.pop_front();
if (range.empty()) { if (range.empty()) {
break; break;
} }
range_put_n(sink, &sep[0], sep.size()); sink = ostd::copy(sep, sink);
} }
return true; return std::forward<R>(sink);
} }
template<typename R, typename T> template<typename R, typename T>
bool concat(R &&sink, T const &v, string_range sep = " ") { R &&concat(R &&sink, T const &v, string_range sep = " ") {
auto range = ostd::iter(v); auto range = ostd::iter(v);
if (range.empty()) { if (range.empty()) {
return true; return std::forward<R>(sink);
} }
for (;;) { for (;;) {
string_range ret = range.front(); string_range ret = range.front();
if (!ret.size() || (range_put_n(sink, &ret[0], ret.size()) != ret.size())) { sink = ostd::copy(ret, sink);
return false;
}
range.pop_front(); range.pop_front();
if (range.empty()) { if (range.empty()) {
break; break;
} }
range_put_n(sink, &sep[0], sep.size()); sink = ostd::copy(sep, sink);
} }
return true; return std::forward<R>(sink);
} }
template<typename R, typename T, typename F> template<typename R, typename T, typename F>
bool concat(R &&sink, std::initializer_list<T> v, string_range sep, F func) { R &&concat(R &&sink, std::initializer_list<T> v, string_range sep, F func) {
return concat(sink, ostd::iter(v), sep, func); return concat(sink, ostd::iter(v), sep, func);
} }
template<typename R, typename T> template<typename R, typename T>
bool concat(R &&sink, std::initializer_list<T> v, string_range sep = " ") { R &&concat(R &&sink, std::initializer_list<T> v, string_range sep = " ") {
return concat(sink, ostd::iter(v), sep); return concat(sink, ostd::iter(v), sep);
} }
@ -534,34 +507,18 @@ namespace detail {
using size_type = size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
template<typename RR>
friend size_t range_put_n(tostr_range<RR> &range, char const *p, size_t n);
tostr_range() = delete; tostr_range() = delete;
tostr_range(R &out): p_out(out), p_written(0) {} tostr_range(R &out): p_out(out) {}
bool put(char v) { void put(char v) {
bool ret = p_out.put(v); p_out.put(v);
p_written += ret;
return ret;
} }
size_t put_string(string_range r) { void put_string(string_range r) {
size_t ret = range_put_n(p_out, r.data(), r.size()); p_out = ostd::copy(r, p_out);
p_written += ret;
return ret;
} }
size_t get_written() const { return p_written; }
private: private:
R &p_out; R &p_out;
size_t p_written;
}; };
template<typename R>
inline size_t range_put_n(tostr_range<R> &range, char const *p, size_t n) {
size_t ret = range_put_n(range.p_out, p, n);
range.p_written += ret;
return ret;
}
template<typename T, typename R> template<typename T, typename R>
static std::true_type test_stringify( static std::true_type test_stringify(
decltype(std::declval<T const &>().to_string(std::declval<R &>())) * decltype(std::declval<T const &>().to_string(std::declval<R &>())) *
@ -590,13 +547,12 @@ struct to_string<T, std::enable_if_t<detail::iterable_test<T>>> {
std::string operator()(T const &v) const { std::string operator()(T const &v) const {
std::string ret("{"); std::string ret("{");
auto x = appender_range<std::string>{}; auto x = appender_range<std::string>{};
if (concat(x, ostd::iter(v), ", ", to_string< concat(x, ostd::iter(v), ", ", to_string<
std::remove_const_t<std::remove_reference_t< std::remove_const_t<std::remove_reference_t<
range_reference_t<decltype(ostd::iter(v))> range_reference_t<decltype(ostd::iter(v))>
>> >>
>())) { >());
ret += x.get(); ret += x.get();
}
ret += "}"; ret += "}";
return ret; return ret;
} }
@ -778,7 +734,8 @@ public:
} else { } else {
p_buf = sbuf; p_buf = sbuf;
} }
p_buf[input.copy(p_buf)] = '\0'; char_range bufr{p_buf, p_buf + input.size()};
ostd::copy(input, bufr).put('\0');
} }
~temp_c_string() { ~temp_c_string() {
if (p_allocated) { if (p_allocated) {