From e4dc237f4da8038083d5f4a26e1ee853b31ac7d9 Mon Sep 17 00:00:00 2001 From: q66 Date: Sun, 19 Feb 2017 16:45:06 +0100 Subject: [PATCH] revamped output ranges and input range pop funcs --- ostd/algorithm.hh | 25 ++- ostd/filesystem.hh | 4 +- ostd/format.hh | 204 ++++++++++------------ ostd/io.hh | 73 +++++--- ostd/range.hh | 410 ++++++++++++++------------------------------- ostd/stream.hh | 117 +++++-------- ostd/string.hh | 143 ++++++---------- 7 files changed, 375 insertions(+), 601 deletions(-) diff --git a/ostd/algorithm.hh b/ostd/algorithm.hh index 3f56246..e97256a 100644 --- a/ostd/algorithm.hh +++ b/ostd/algorithm.hh @@ -778,24 +778,24 @@ public: return p_range.distance_back(r.p_range); } - bool pop_front() { return p_range.pop_front(); } - bool pop_back() { return p_range.pop_back(); } + void pop_front() { p_range.pop_front(); } + void pop_back() { p_range.pop_back(); } - bool push_front() { return p_range.pop_front(); } - bool push_back() { return p_range.push_back(); } + void push_front() { p_range.pop_front(); } + void push_back() { p_range.push_back(); } - range_size_t pop_front_n(range_size_t n) { + void pop_front_n(range_size_t n) { p_range.pop_front_n(n); } - range_size_t pop_back_n(range_size_t n) { + void pop_back_n(range_size_t n) { p_range.pop_back_n(n); } - range_size_t push_front_n(range_size_t n) { - return p_range.push_front_n(n); + void push_front_n(range_size_t n) { + p_range.push_front_n(n); } - range_size_t push_back_n(range_size_t n) { - return p_range.push_back_n(n); + void push_back_n(range_size_t n) { + p_range.push_back_n(n); } R front() const { return p_func(p_range.front()); } @@ -887,10 +887,9 @@ public: return p_range.equals_front(r.p_range); } - bool pop_front() { - bool ret = p_range.pop_front(); + void pop_front() { + p_range.pop_front(); advance_valid(); - return ret; } range_reference_t front() const { return p_range.front(); } diff --git a/ostd/filesystem.hh b/ostd/filesystem.hh index 6e66c90..0675611 100644 --- a/ostd/filesystem.hh +++ b/ostd/filesystem.hh @@ -549,8 +549,8 @@ struct directory_range: input_range { return p_stream->empty(); } - bool pop_front() { - return p_stream->pop_front(); + void pop_front() { + p_stream->pop_front(); } file_info front() const { diff --git a/ostd/format.hh b/ostd/format.hh index dae0f99..3372546 100644 --- a/ostd/format.hh +++ b/ostd/format.hh @@ -147,11 +147,7 @@ struct format_spec { {} template - bool read_until_spec(R &writer, size_t *wret) { - size_t written = 0; - if (wret) { - *wret = 0; - } + bool read_until_spec(R &writer) { if (p_fmt.empty()) { return false; } @@ -161,34 +157,21 @@ struct format_spec { if (p_fmt.front() == '%') { goto plain; } - bool r = read_spec(); - if (wret) { - *wret = written; - } - return r; + return read_spec(); } - plain: - ++written; + plain: writer.put(p_fmt.front()); p_fmt.pop_front(); } - if (wret) { - *wret = written; - } return false; } template - 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)) { - return 0; + return; } - int r = p_width - int(n); for (int w = p_width - int(n); --w >= 0; writer.put(c)); - if (r < 0) { - return 0; - } - return r; } string_range rest() const { @@ -196,26 +179,26 @@ struct format_spec { } template - size_t build_spec(R &&out, string_range spec) const { - size_t ret = out.put('%'); + R &&build_spec(R &&out, string_range spec) const { + out.put('%'); if (p_flags & FMT_FLAG_DASH ) { - ret += out.put('-'); + out.put('-'); } if (p_flags & FMT_FLAG_ZERO ) { - ret += out.put('0'); + out.put('0'); } if (p_flags & FMT_FLAG_SPACE) { - ret += out.put(' '); + out.put(' '); } if (p_flags & FMT_FLAG_PLUS ) { - ret += out.put('+'); + out.put('+'); } if (p_flags & FMT_FLAG_HASH ) { - ret += out.put('#'); + out.put('#'); } - ret += range_put_n(out, "*.*", 3); - ret += range_put_n(out, &spec[0], spec.size()); - return ret; + out = ostd::copy(string_range{"*.*"}, out); + out = ostd::copy(spec, out); + return std::forward(out); } 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 { template - 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]; - size_t r = 0, n = 0; + size_t n = 0; char spec = fl->spec(); if (spec == 's') spec = 'd'; @@ -464,54 +447,50 @@ namespace detail { for (; val; val /= base) { buf[n++] = detail::fmt_digits[spec >= 'a'][val % base]; } - r = n; int flags = fl->flags(); bool lsgn = flags & FMT_FLAG_PLUS; bool lsp = flags & FMT_FLAG_SPACE; bool zero = flags & FMT_FLAG_ZERO; bool sign = neg + lsgn + lsp; - r += sign; char const *pfx = nullptr; size_t pfxlen = 0; if (flags & FMT_FLAG_HASH && spec != 'd') { pfx = detail::fmt_intpfx[spec >= 'a'][specn - 3]; pfxlen = !!pfx[1] + 1; - r += pfxlen; } if (!zero) { - r += fl->write_spaces(writer, n + pfxlen + sign, true, ' '); + fl->write_spaces(writer, n + pfxlen + sign, true, ' '); } if (sign) { writer.put(neg ? '-' : *((" \0+") + lsgn * 2)); } - range_put_n(writer, pfx, pfxlen); + writer = ostd::copy(string_range{pfx, pfx + pfxlen}, writer); 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) { writer.put(buf[i]); } - r += fl->write_spaces(writer, n + sign + pfxlen, false); - return r; + fl->write_spaces(writer, n + sign + pfxlen, false); } template - static size_t format_impl( + static void format_impl( R &writer, bool escape, string_range fmt, A const &...args ); template struct FmtTupleUnpacker { template - static inline size_t unpack( + static inline void unpack( R &writer, bool esc, string_range fmt, T const &item, A const &...args ) { - return FmtTupleUnpacker::unpack( + FmtTupleUnpacker::unpack( writer, esc, fmt, item, std::get(item), args... ); } @@ -520,11 +499,11 @@ namespace detail { template<> struct FmtTupleUnpacker<0> { template - static inline size_t unpack( + static inline void unpack( R &writer, bool esc, string_range fmt, 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(0))::value; template - inline size_t format_ritem( + inline void format_ritem( R &writer, bool esc, bool, string_range fmt, T const &item, std::enable_if_t, bool> = true ) { - return format_impl(writer, esc, fmt, item); + format_impl(writer, esc, fmt, item); } template - inline size_t format_ritem( + inline void format_ritem( R &writer, bool esc, bool expandval, string_range fmt, T const &item, std::enable_if_t, bool> = true ) { if (expandval) { - return FmtTupleUnpacker::value>::unpack( + FmtTupleUnpacker::value>::unpack( writer, esc, fmt, item ); + } else { + format_impl(writer, esc, fmt, item); } - return format_impl(writer, esc, fmt, item); } template - inline size_t write_range( + inline void write_range( R &writer, format_spec const *fl, bool escape, bool expandval, string_range sep, T const &val, std::enable_if_t, bool> = true ) { - /* XXX: maybe handle error cases? */ auto range = ostd::iter(val); if (range.empty()) { - return 0; + return; } - size_t ret = 0; /* test first item */ - ret += format_ritem( - writer, escape, expandval, fl->rest(), range.front() - ); + format_ritem(writer, escape, expandval, fl->rest(), range.front()); range.pop_front(); /* write the rest (if any) */ for (; !range.empty(); range.pop_front()) { - ret += range_put_n(writer, &sep[0], sep.size()); - ret += format_ritem( + writer = ostd::copy(sep, writer); + format_ritem( writer, escape, expandval, fl->rest(), range.front() ); } - return ret; } template - inline size_t write_range( + inline void write_range( R &, format_spec const *, bool, bool, string_range, T const &, std::enable_if_t, bool> = true ) { @@ -661,24 +636,23 @@ namespace detail { /* string base writer */ template - 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) { - return write_str(writer, false, escape_fmt_str(val)); + write_str(writer, false, escape_fmt_str(val)); + return; } size_t n = val.size(); if (this->precision()) { n = this->precision(); } - size_t r = n; - r += this->write_spaces(writer, n, true); - range_put_n(writer, &val[0], n); - r += this->write_spaces(writer, n, false); - return r; + this->write_spaces(writer, n, true); + writer = ostd::copy(val.slice(0, n), writer); + this->write_spaces(writer, n, false); } /* char values */ template - size_t write_char(R &writer, bool escape, char val) const { + void write_char(R &writer, bool escape, char val) const { if (escape) { char const *esc = escape_fmt_char(val, '\''); if (esc) { @@ -687,13 +661,13 @@ namespace detail { size_t elen = strlen(esc); memcpy(buf + 1, esc, elen); buf[elen + 1] = '\''; - return write_val(writer, false, ostd::string_range{ + write_val(writer, false, ostd::string_range{ buf, buf + elen + 2 }); + return; } } - size_t r = 1 + escape * 2; - r += this->write_spaces(writer, 1 + escape * 2, true); + this->write_spaces(writer, 1 + escape * 2, true); if (escape) { writer.put('\''); writer.put(val); @@ -701,13 +675,12 @@ namespace detail { } else { writer.put(val); } - r += this->write_spaces(writer, 1 + escape * 2, false); - return r; + this->write_spaces(writer, 1 + escape * 2, false); } /* floating point */ template> - 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 fmtspec[Long + 1]; @@ -723,7 +696,7 @@ namespace detail { fmtspec[0] = 'L'; } - buf[this->build_spec(iter(buf), fmtspec)] = '\0'; + this->build_spec(iter(buf), fmtspec).put('\0'); int ret = snprintf( rbuf, sizeof(rbuf), buf, this->width(), this->has_precision() ? this->precision() : 6, val @@ -745,43 +718,45 @@ namespace detail { /* see above */ throw format_error{"invalid float format"}; } - range_put_n(writer, dbuf, ret); + writer = ostd::copy(string_range{dbuf, dbuf + ret}, writer); delete[] dbuf; } else { - range_put_n(writer, rbuf, ret); + writer = ostd::copy(string_range{rbuf, rbuf + ret}, writer); } - return ret; } template - 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 */ if constexpr(fmt_tofmt_test>) { tostr_range sink(writer); to_format(val, sink, *this); - return sink.get_written(); + return; } /* second best, we can convert to string slice */ if constexpr(std::is_constructible_v) { if (this->spec() != 's') { 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 */ if constexpr(std::is_same_v) { if (this->spec() == 's') { - return write_val(writer, ("false\0true") + (6 * val)); + write_val(writer, ("false\0true") + (6 * val)); } else { - return write_val(writer, int(val)); + write_val(writer, int(val)); } + return; } /* character values */ if constexpr(std::is_same_v) { if (this->spec() != 's' && this->spec() != 'c') { 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... * char pointers are handled by the string case above @@ -793,32 +768,36 @@ namespace detail { has_precision() ? precision() : -1, (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 */ if constexpr(std::is_integral_v) { if constexpr(std::is_signed_v) { /* signed integers */ using UT = std::make_unsigned_t; - return detail::write_u( + detail::write_u( writer, this, val < 0, (val < 0) ? static_cast(-val) : static_cast(val) ); } else { /* unsigned integers */ - return detail::write_u(writer, this, false, val); + detail::write_u(writer, this, false, val); } + return; } /* floats */ if constexpr(std::is_floating_point_v) { - return write_float(writer, escape, val); + write_float(writer, escape, val); + return; } /* stuff that can be to_string'd, worst reliable case, allocates */ if constexpr(fmt_tostr_test) { if (this->spec() != 's') { throw format_error{"custom objects need the '%s' spec"}; } - return write_val(writer, false, ostd::to_string{}(val)); + write_val(writer, false, ostd::to_string{}(val)); + return; } /* we ran out of options, failure */ throw format_error{"the value cannot be formatted"}; @@ -826,23 +805,23 @@ namespace detail { /* actual writer */ template - size_t write_arg( + void write_arg( R &writer, size_t idx, T const &val, A const &...args ) const { if (idx) { if constexpr(!sizeof...(A)) { throw format_error{"not enough format arguments"}; } else { - return write_arg(writer, idx - 1, args...); + write_arg(writer, idx - 1, args...); } } else { - return write_val(writer, this->p_nested_escape, val); + write_val(writer, this->p_nested_escape, val); } } /* range writer */ template - size_t write_range( + void write_range( R &writer, size_t idx, bool expandval, string_range sep, T const &val, A const &...args ) const { @@ -850,10 +829,10 @@ namespace detail { if constexpr(!sizeof...(A)) { throw format_error{"not enough format arguments"}; } else { - return write_range(writer, idx - 1, expandval, sep, args...); + write_range(writer, idx - 1, expandval, sep, args...); } } else { - return detail::write_range( + detail::write_range( writer, this, this->p_nested_escape, expandval, sep, val ); } @@ -861,13 +840,12 @@ namespace detail { }; template - inline size_t format_impl( + inline void format_impl( 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); - while (spec.read_until_spec(writer, &twr)) { - written += twr; + while (spec.read_until_spec(writer)) { size_t argpos = spec.index(); if (spec.is_nested()) { if (!argpos) { @@ -875,7 +853,7 @@ namespace detail { } /* FIXME: figure out a better way */ detail::write_spec nspec(spec.nested(), spec.nested_escape()); - written += nspec.write_range( + nspec.write_range( writer, argpos - 1, (spec.flags() & FMT_FLAG_HASH), spec.nested_sep(), args... ); @@ -906,33 +884,31 @@ namespace detail { 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 - inline ptrdiff_t format_impl(R &writer, bool, string_range fmt) { - size_t written = 0; + inline void format_impl(R &writer, bool, string_range fmt) { 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"}; } - return written; } } /* namespace detail */ template -inline size_t format(R &&writer, string_range fmt, A const &...args) { - return detail::format_impl(writer, false, fmt, args...); +inline R &&format(R &&writer, string_range fmt, A const &...args) { + detail::format_impl(writer, false, fmt, args...); + return std::forward(writer); } template -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 */ detail::write_spec const &wsp = static_cast(fmt); - return wsp.write_arg(writer, 0, val); + wsp.write_arg(writer, 0, val); + return std::forward(writer); } } /* namespace ostd */ diff --git a/ostd/io.hh b/ostd/io.hh index 1f466b8..5ea534b 100644 --- a/ostd/io.hh +++ b/ostd/io.hh @@ -9,6 +9,8 @@ #include #include +#include +#include #include "ostd/platform.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 { file_stream(): p_f(), p_owned(false) {} file_stream(file_stream const &) = delete; @@ -93,38 +100,59 @@ struct file_stream: stream { 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 - return fseeko(p_f, pos, int(whence)) >= 0; + if (fseeko(p_f, pos, int(whence))) #else - return _fseeki64(p_f, pos, int(whence)) >= 0; + if (_fseeki64(p_f, pos, int(whence))) #endif + { + throw io_error{"file_stream seek error"}; + } } stream_off_t tell() const { #ifndef OSTD_PLATFORM_WIN32 - return ftello(p_f); + auto ret = ftello(p_f); #else - return _ftelli64(p_f); + auto ret = _ftelli64(p_f); #endif + if (ret < 0) { + throw io_error{"file_stream tell error"}; + } + return ret; } - bool flush() { return !fflush(p_f); } - - size_t read_bytes(void *buf, size_t count) { - return fread(buf, 1, count, p_f); + void flush() { + if (fflush(p_f)) { + throw io_error{"file_stream flush error"}; + } } - size_t write_bytes(void const *buf, size_t count) { - return fwrite(buf, 1, count, p_f); + void read_bytes(void *buf, size_t count) { + 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() { - return fgetc(p_f); + int ret = fgetc(p_f); + if (ret == EOF) { + throw io_error{"file_stream EOF"}; + } + return ret; } - bool putchar(int c) { - return fputc(c, p_f) != EOF; + void putchar(int c) { + if (fputc(c, p_f) == EOF) { + throw io_error{"file_stream EOF"}; + } } void swap(file_stream &s) { @@ -159,14 +187,12 @@ namespace detail { using difference_type = ptrdiff_t; stdout_range() {} - bool put(char c) { - return putchar(c) != EOF; + void put(char c) { + 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 @@ -184,8 +210,7 @@ template inline void writeln(T const &v) { write(v); if (putchar('\n') == EOF) { - /* consistency with format module */ - throw format_error{"stream EOF"}; + throw io_error{"stdout EOF"}; } } @@ -194,7 +219,7 @@ inline void writeln(T const &v, A const &...args) { write(v); write(args...); if (putchar('\n') == EOF) { - throw format_error{"stream EOF"}; + throw io_error{"stdout EOF"}; } } @@ -207,7 +232,7 @@ template inline void writefln(string_range fmt, A const &...args) { writef(fmt, args...); if (putchar('\n') == EOF) { - throw format_error{"stream EOF"}; + throw io_error{"stdout EOF"}; } } diff --git a/ostd/range.hh b/ostd/range.hh index f14e8c5..0de5fe0 100644 --- a/ostd/range.hh +++ b/ostd/range.hh @@ -15,6 +15,7 @@ #include #include #include +#include #include "ostd/types.hh" @@ -198,7 +199,7 @@ template constexpr bool is_contiguous_range = namespace detail { template static std::true_type test_outrange(typename std::is_same< - decltype(std::declval().put(std::declval())), bool + decltype(std::declval().put(std::declval())), void >::type *); template @@ -392,14 +393,14 @@ public: return *this; } - bool next() { return p_range.pop_front(); } - bool prev() { return p_range.push_front(); } + void next() { p_range.pop_front(); } + void prev() { p_range.push_front(); } - range_size_t next_n(range_size_t n) { - return p_range.pop_front_n(n); + void next_n(range_size_t n) { + p_range.pop_front_n(n); } - range_size_t prev_n(range_size_t n) { - return p_range.push_front_n(n); + void prev_n(range_size_t n) { + p_range.push_front_n(n); } range_difference_t add_n(range_difference_t n) { @@ -497,43 +498,31 @@ inline range_difference_t operator-( namespace detail { template - range_size_t pop_front_n(R &range, range_size_t n) { + void pop_front_n(R &range, range_size_t n) { for (range_size_t i = 0; i < n; ++i) { - if (!range.pop_front()) { - return i; - } + range.pop_front(); } - return n; } template - range_size_t pop_back_n(R &range, range_size_t n) { + void pop_back_n(R &range, range_size_t n) { for (range_size_t i = 0; i < n; ++i) { - if (!range.pop_back()) { - return i; - } + range.pop_back(); } - return n; } template - range_size_t push_front_n(R &range, range_size_t n) { + void push_front_n(R &range, range_size_t n) { for (range_size_t i = 0; i < n; ++i) { - if (!range.push_front()) { - return i; - } + range.push_front(); } - return n; } template - range_size_t push_back_n(R &range, range_size_t n) { + void push_back_n(R &range, range_size_t n) { for (range_size_t i = 0; i < n; ++i) { - if (!range.push_back()) { - return i; - } + range.push_back(); } - return n; } } @@ -562,23 +551,23 @@ struct input_range { } template - Size pop_front_n(Size n) { - return detail::pop_front_n(*static_cast(this), n); + void pop_front_n(Size n) { + detail::pop_front_n(*static_cast(this), n); } template - Size pop_back_n(Size n) { - return detail::pop_back_n(*static_cast(this), n); + void pop_back_n(Size n) { + detail::pop_back_n(*static_cast(this), n); } template - Size push_front_n(Size n) { - return detail::push_front_n(*static_cast(this), n); + void push_front_n(Size n) { + detail::push_front_n(*static_cast(this), n); } template - Size push_back_n(Size n) { - return detail::push_back_n(*static_cast(this), n); + void push_back_n(Size n) { + detail::push_back_n(*static_cast(this), n); } B iter() const { @@ -621,30 +610,6 @@ struct input_range { return range_half(iter()); } - template - std::enable_if_t, Size> copy(OR &&orange, Size n = -1) { - B r(*static_cast(this)); - Size on = n; - for (; n && !r.empty(); --n) { - if (!orange.put(r.front())) { - break; - } - r.pop_front(); - } - return (on - n); - } - - template - Size copy(Value *p, Size n = -1) { - B r(*static_cast(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 * this is sometimes convenient as it can be used within expressions */ @@ -729,15 +694,6 @@ struct output_range { using range_category = output_range_tag; }; -template -inline range_size_t range_put_n( - R &range, range_value_t const *p, range_size_t n -) { - range_size_t on = n; - for (; n && range.put(*p++); --n); - return (on - n); -} - template struct noop_output_range: output_range> { using value_type = T; @@ -745,7 +701,7 @@ struct noop_output_range: output_range> { using size_type = size_t; using difference_type = ptrdiff_t; - bool put(T const &) { return true; } + void put(T const &) {} }; template @@ -755,13 +711,6 @@ struct counting_output_range: output_range> { using size_type = range_size_t; using difference_type = range_difference_t; - template - friend range_size_t> range_put_n( - counting_output_range &range, - range_value_t> *p, - range_size_t> n - ); - private: R p_range; size_type p_written = 0; @@ -770,15 +719,13 @@ public: counting_output_range() = delete; counting_output_range(R const &range): p_range(range) {} - bool put(value_type const &v) { - bool ret = p_range.put(v); - p_written += ret; - return ret; + void put(value_type const &v) { + p_range.put(v); + ++p_written; } - bool put(value_type &&v) { - bool ret = p_range.put(std::move(v)); - p_written += ret; - return ret; + void put(value_type &&v) { + p_range.put(std::move(v)); + ++p_written; } size_type get_written() const { @@ -786,17 +733,6 @@ public: } }; -template -inline range_size_t> range_put_n( - counting_output_range &range, - range_value_t> *p, - range_size_t> n -) { - auto ret = range_put_n(range.p_range, p, n); - range.p_written += ret; - return ret; -} - template inline counting_output_range range_counter(R const &range) { return counting_output_range{range}; @@ -967,23 +903,17 @@ public: bool empty() const { return p_beg == p_end; } - bool pop_front() { - if (empty()) { - return false; - } - return p_beg.next(); + void pop_front() { + p_beg.next(); } - bool push_front() { - return p_beg.prev(); + void push_front() { + p_beg.prev(); } - bool pop_back() { - if (empty()) { - return false; - } - return p_end.prev(); + void pop_back() { + p_end.prev(); } - bool push_back() { - return p_end.next(); + void push_back() { + p_end.next(); } reference front() const { return *p_beg; } @@ -1013,11 +943,11 @@ public: return p_beg[idx]; } - bool put(value_type const &v) { - return p_beg.range().put(v); + void put(value_type const &v) { + p_beg.range().put(v); } - bool put(value_type &&v) { - return p_beg.range().put(std::move(v)); + void put(value_type &&v) { + p_beg.range().put(std::move(v)); } value_type *data() { return p_beg.data(); } @@ -1077,17 +1007,17 @@ public: return -p_range.distance_front(r.p_range); } - bool pop_front() { return p_range.pop_back(); } - bool pop_back() { return p_range.pop_front(); } + void pop_front() { p_range.pop_back(); } + void pop_back() { p_range.pop_front(); } - bool push_front() { return p_range.push_back(); } - bool push_back() { return p_range.push_front(); } + void push_front() { p_range.push_back(); } + void push_back() { p_range.push_front(); } - size_type pop_front_n(size_type n) { return p_range.pop_front_n(n); } - size_type pop_back_n(size_type n) { return p_range.pop_back_n(n); } + void pop_front_n(size_type n) { p_range.pop_front_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); } - size_type push_back_n(size_type n) { return p_range.push_back_n(n); } + void push_front_n(size_type n) { p_range.push_front_n(n); } + void push_back_n(size_type n) { p_range.push_back_n(n); } reference front() const { return p_range.back(); } reference back() const { return p_range.front(); } @@ -1153,17 +1083,17 @@ public: return p_range.distance_back(r.p_range); } - bool pop_front() { return p_range.pop_front(); } - bool pop_back() { return p_range.pop_back(); } + void pop_front() { p_range.pop_front(); } + void pop_back() { p_range.pop_back(); } - bool push_front() { return p_range.push_front(); } - bool push_back() { return p_range.push_back(); } + void push_front() { p_range.push_front(); } + void push_back() { p_range.push_back(); } - size_type pop_front_n(size_type n) { return p_range.pop_front_n(n); } - size_type pop_back_n(size_type n) { return p_range.pop_back_n(n); } + void pop_front_n(size_type n) { p_range.pop_front_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); } - size_type push_back_n(size_type n) { return p_range.push_back_n(n); } + void push_front_n(size_type n) { p_range.push_front_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 back() const { return std::move(p_range.back()); } @@ -1174,8 +1104,8 @@ public: return move_range{p_range.slice(start, end)}; } - bool put(value_type const &v) { return p_range.put(v); } - bool put(value_type &&v) { return p_range.put(std::move(v)); } + void put(value_type const &v) { p_range.put(v); } + void put(value_type &&v) { p_range.put(std::move(v)); } }; template @@ -1198,7 +1128,7 @@ struct number_range: input_range> { 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; } private: @@ -1277,18 +1207,14 @@ public: return p_range.equals_front(r.p_range); } - bool pop_front() { - if (p_range.pop_front()) { - ++p_index; - return true; - } - return false; + void pop_front() { + p_range.pop_front(); + ++p_index; } - size_type pop_front_n(size_type n) { - size_type ret = p_range.pop_front_n(n); - p_index += ret; - return ret; + void pop_front_n(size_type n) { + p_range.pop_front_n(n); + p_index += n; } reference front() const { @@ -1333,18 +1259,16 @@ public: bool empty() const { return (p_remaining <= 0) || p_range.empty(); } - bool pop_front() { - if (p_range.pop_front()) { + void pop_front() { + p_range.pop_front(); + if (p_remaining >= 1) { --p_remaining; - return true; } - return false; } - size_type pop_front_n(size_type n) { - size_type ret = p_range.pop_front_n(n); - p_remaining -= ret; - return ret; + void pop_front_n(size_type n) { + p_range.pop_front_n(n); + p_remaining -= std::min(n, p_remaining); } reference front() const { return p_range.front(); } @@ -1395,9 +1319,9 @@ public: return p_range.equals_front(r.p_range); } - bool pop_front() { return p_range.pop_front_n(p_chunksize) > 0; } - size_type pop_front_n(size_type n) { - return p_range.pop_front_n(p_chunksize * n) / p_chunksize; + void pop_front() { p_range.pop_front_n(p_chunksize); } + void pop_front_n(size_type n) { + p_range.pop_front_n(p_chunksize * n); } reference front() const { return p_range.take(p_chunksize); } @@ -1405,14 +1329,14 @@ public: namespace detail { template - inline bool join_range_pop(T &tup) { + inline void join_range_pop(T &tup) { if constexpr(I != N) { if (!std::get(tup).empty()) { - return std::get(tup).pop_front(); + std::get(tup).pop_front(); + return; } - return join_range_pop(tup); + join_range_pop(tup); } - return false; } template @@ -1423,6 +1347,7 @@ namespace detail { } return join_range_front(tup); } + /* fallback, will probably throw */ return std::get<0>(tup).front(); } } @@ -1471,8 +1396,8 @@ public: }, p_ranges); } - bool pop_front() { - return detail::join_range_pop<0, sizeof...(R)>(p_ranges); + void pop_front() { + detail::join_range_pop<0, sizeof...(R)>(p_ranges); } reference front() const { @@ -1539,9 +1464,9 @@ public: }, p_ranges); } - bool pop_front() { - return std::apply([](auto &...args) { - return (... && args.pop_front()); + void pop_front() { + std::apply([](auto &...args) { + (args.pop_front(), ...); }, p_ranges); } @@ -1593,14 +1518,12 @@ struct appender_range: output_range> { size_type size() const { return p_data.size(); } 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); - return true; } - bool put(typename T::value_type &&v) { + void put(typename T::value_type &&v) { p_data.push_back(std::move(v)); - return true; } T &get() { return p_data; } @@ -1691,39 +1614,40 @@ struct iterator_range: input_range> { /* satisfy input_range / forward_range */ bool empty() const { return p_beg == p_end; } - bool pop_front() { - if (p_beg == p_end) { - return false; - } + void pop_front() { ++p_beg; - return true; + /* rely on iterators to do their own checks */ + if constexpr(std::is_pointer_v) { + if (p_beg > p_end) { + throw std::out_of_range{"pop_front on empty range"}; + } + } } - bool push_front() { - --p_beg; return true; + void push_front() { + --p_beg; } - size_type pop_front_n(size_type n) { + void pop_front_n(size_type n) { using IC = typename std::iterator_traits::iterator_category; if constexpr(std::is_convertible_v) { - size_type olen = size_type(p_end - p_beg); p_beg += n; - if (p_beg > p_end) { - p_beg = p_end; - return olen; + /* rely on iterators to do their own checks */ + if constexpr(std::is_pointer_v) { + if (p_beg > p_end) { + throw std::out_of_range{"pop_front_n of too many elements"}; + } } - return n; } 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::iterator_category; if constexpr(std::is_convertible_v) { p_beg -= n; - return true; } else { - return detail::push_front_n(*this, n); + detail::push_front_n(*this, n); } } @@ -1738,39 +1662,40 @@ struct iterator_range: input_range> { } /* satisfy bidirectional_range */ - bool pop_back() { - if (p_end == p_beg) { - return false; + void pop_back() { + /* rely on iterators to do their own checks */ + if constexpr(std::is_pointer_v) { + if (p_end == p_beg) { + throw std::out_of_range{"pop_back on empty range"}; + } } --p_end; - return true; } - bool push_back() { - ++p_end; return true; + void push_back() { + ++p_end; } - size_type pop_back_n(size_type n) { + void pop_back_n(size_type n) { using IC = typename std::iterator_traits::iterator_category; if constexpr(std::is_convertible_v) { - size_type olen = size_type(p_end - p_beg); p_end -= n; - if (p_end < p_beg) { - p_end = p_beg; - return olen; + /* rely on iterators to do their own checks */ + if constexpr(std::is_pointer_v) { + if (p_end < p_beg) { + throw std::out_of_range{"pop_back_n of too many elements"}; + } } - return n; } 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::iterator_category; if constexpr(std::is_convertible_v) { p_end += n; - return true; } else { - return detail::push_back_n(*this, n); + detail::push_back_n(*this, n); } } @@ -1798,100 +1723,17 @@ struct iterator_range: input_range> { value_type const *data() const { return p_beg; } /* satisfy output_range */ - bool put(value_type const &v) { - if (empty()) { - return false; - } + void put(value_type const &v) { *(p_beg++) = v; - return true; } - bool put(value_type &&v) { - if (empty()) { - return false; - } + void put(value_type &&v) { *(p_beg++) = std::move(v); - return true; } - template - std::enable_if_t, size_type> copy( - R &&orange, size_type n = -1 - ) { - if constexpr(std::is_pointer_v) { - 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 *p, size_type n = -1) { - using IC = typename std::iterator_traits::iterator_category; - if constexpr(std::is_convertible_v) { - size_type c = size(); - if (n < c) { - c = n; - } - if constexpr(std::is_pointer_v && std::is_pod_v) { - memcpy(p, p_beg, c * sizeof(value_type)); - return c; - } else { - return copy(iterator_range< - std::remove_cv_t * - >(p, p + c), c); - } - } else { - size_type on = n; - for (; n && !empty(); --n) { - *p++ = front(); - pop_front(); - } - return (on - n); - } - } private: T p_beg, p_end; }; -template -inline auto range_put_n( - iterator_range &range, range_value_t> const *p, - range_size_t> n -) { - using IC = typename std::iterator_traits::iterator_category; - if constexpr(std::is_convertible_v) { - using value_type = range_value_t>; - auto ret = range.size(); - if (n < ret) { - ret = n; - } - if constexpr(std::is_pointer_v && std::is_pod_v) { - 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 iterator_range make_range(T beg, T end) { return iterator_range{beg, end}; diff --git a/ostd/stream.hh b/ostd/stream.hh index 29bb4f2..d303796 100644 --- a/ostd/stream.hh +++ b/ostd/stream.hh @@ -43,32 +43,33 @@ struct stream { virtual offset_type size() { offset_type p = tell(); - if ((p < 0) || !seek(0, stream_seek::END)) { - return -1; - } + seek(0, stream_seek::END); 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) { - return false; - } + virtual void seek(offset_type, stream_seek = stream_seek::SET) {} 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 size_t write_bytes(void const *, size_t) { return 0; } + virtual void read_bytes(void *, size_t) {} + virtual void write_bytes(void const *, size_t) {} virtual int getchar() { 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); - return write_bytes(&wc, 1) == 1; + write_bytes(&wc, 1); } template @@ -83,19 +84,14 @@ struct stream { template void writeln(T const &v) { write(v); - if (!putchar('\n')) { - /* consistency with format module */ - throw format_error{"stream EOF"}; - } + putchar('\n'); } template void writeln(T const &v, A const &...args) { write(v); write(args...); - if (!putchar('\n')) { - throw format_error{"stream EOF"}; - } + putchar('\n'); } template @@ -104,44 +100,40 @@ struct stream { template void writefln(string_range fmt, A const &...args) { writef(fmt, args...); - if (!putchar('\n')) { - throw format_error{"stream EOF"}; - } + putchar('\n'); } template stream_range iter(); template - size_t put(T const *v, size_t count) { - return write_bytes(v, count * sizeof(T)) / sizeof(T); + void put(T const *v, size_t count) { + write_bytes(v, count * sizeof(T)); } template - bool put(T v) { - return write_bytes(&v, sizeof(T)) == sizeof(T); + void put(T v) { + write_bytes(&v, sizeof(T)); } template - size_t get(T *v, size_t count) { - return read_bytes(v, count * sizeof(T)) / sizeof(T); + void get(T *v, size_t count) { + read_bytes(v, count * sizeof(T)); } template - bool get(T &v) { - return read_bytes(&v, sizeof(T)) == sizeof(T); + void get(T &v) { + read_bytes(&v, sizeof(T)); } template T get() { T r; - return get(r) ? r : T(); + get(r); + return r; } }; -template -size_t range_put_n(stream_range &range, T const *p, size_t n); - template struct stream_range: input_range> { using range_category = input_range_tag; @@ -150,28 +142,28 @@ struct stream_range: input_range> { using size_type = size_t; using difference_type = stream_off_t; - template - friend size_t range_put_n(stream_range &range, TT const *p, size_t n); - stream_range() = delete; 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) {} 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() { - if (empty()) { - return false; - } + void pop_front() { T val; - return !!p_stream->read_bytes(&val, sizeof(T)); + p_stream->read_bytes(&val, sizeof(T)); } T front() const { 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; } @@ -179,17 +171,9 @@ struct stream_range: input_range> { return p_stream->tell() == s.p_stream->tell(); } - bool put(T val) { - size_t v = p_stream->write_bytes(&val, sizeof(T)); - p_size += v; - return (v == sizeof(T)); - } - - size_t copy(std::remove_cv_t *p, size_t n = -1) { - if (n == size_t(-1)) { - n = p_stream->size() / sizeof(T); - } - return p_stream->get(p, n); + void put(T val) { + p_stream->write_bytes(&val, sizeof(T)); + p_size += sizeof(T); } private: @@ -197,11 +181,6 @@ private: stream_off_t p_size; }; -template -inline size_t range_put_n(stream_range &range, T const *p, size_t n) { - return range.p_stream->put(p, n); -} - template inline stream_range stream::iter() { return stream_range(*this); @@ -215,26 +194,22 @@ namespace detail { using size_type = size_t; using difference_type = ptrdiff_t; - fmt_stream_range(stream &s): p_s(s) {} - bool put(char c) { - return p_s.write_bytes(&c, 1) == 1; + fmt_stream_range(stream *s): p_s(s) {} + void put(char c) { + 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 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 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...); } } diff --git a/ostd/string.hh b/ostd/string.hh index 5307698..8901cf9 100644 --- a/ostd/string.hh +++ b/ostd/string.hh @@ -77,26 +77,26 @@ public: bool empty() const { return p_beg == p_end; } - bool pop_front() { - if (p_beg == p_end) { - return false; - } + void pop_front() { ++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) { - size_t olen = p_end - p_beg; + void pop_front_n(size_t n) { p_beg += n; if (p_beg > p_end) { - p_beg = p_end; - return olen; + throw std::out_of_range{"pop_front_n of too many elements"}; } - 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; } @@ -108,26 +108,26 @@ public: return range.p_beg - p_beg; } - bool pop_back() { + void pop_back() { if (p_end == p_beg) { - return false; + return; } --p_end; - return true; } - bool push_back() { ++p_end; return true; } + void push_back() { + ++p_end; + } - size_t pop_back_n(size_t n) { - size_t olen = p_end - p_beg; + void pop_back_n(size_t n) { p_end -= n; if (p_end < p_beg) { - p_end = p_beg; - return olen; + throw std::out_of_range{"pop_back_n of too many elements"}; } - 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); } @@ -147,12 +147,8 @@ public: T &operator[](size_t i) const { return p_beg[i]; } - bool put(T v) { - if (empty()) { - return false; - } + void put(T v) { *(p_beg++) = v; - return true; } T *data() { return p_beg; } @@ -183,17 +179,6 @@ diffsize: return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0); } - template - std::enable_if_t, 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 *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 */ operator std::basic_string_view>() const { return std::basic_string_view>{data(), size()}; @@ -203,14 +188,6 @@ private: T *p_beg, *p_end; }; -template -inline size_t range_put_n(basic_char_range &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; using string_range = basic_char_range; @@ -461,68 +438,64 @@ namespace detail { template struct ConcatPut { template - static bool put(R &sink, string_range v) { - return v.size() && (range_put_n(sink, &v[0], v.size()) == v.size()); + static void put(R &sink, string_range v) { + sink = ostd::copy(v, sink); } }; template struct ConcatPut { template - static bool put(R &sink, char v) { - return sink.put(v); + static void put(R &sink, char v) { + sink.put(v); } }; } template -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); if (range.empty()) { - return true; + return std::forward(sink); } for (;;) { - if (!detail::ConcatPut< + detail::ConcatPut< decltype(func(range.front())) - >::put(sink, func(range.front()))) { - return false; - } + >::put(sink, func(range.front())); range.pop_front(); if (range.empty()) { break; } - range_put_n(sink, &sep[0], sep.size()); + sink = ostd::copy(sep, sink); } - return true; + return std::forward(sink); } template -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); if (range.empty()) { - return true; + return std::forward(sink); } for (;;) { string_range ret = range.front(); - if (!ret.size() || (range_put_n(sink, &ret[0], ret.size()) != ret.size())) { - return false; - } + sink = ostd::copy(ret, sink); range.pop_front(); if (range.empty()) { break; } - range_put_n(sink, &sep[0], sep.size()); + sink = ostd::copy(sep, sink); } - return true; + return std::forward(sink); } template -bool concat(R &&sink, std::initializer_list v, string_range sep, F func) { +R &&concat(R &&sink, std::initializer_list v, string_range sep, F func) { return concat(sink, ostd::iter(v), sep, func); } template -bool concat(R &&sink, std::initializer_list v, string_range sep = " ") { +R &&concat(R &&sink, std::initializer_list v, string_range sep = " ") { return concat(sink, ostd::iter(v), sep); } @@ -534,34 +507,18 @@ namespace detail { using size_type = size_t; using difference_type = ptrdiff_t; - template - friend size_t range_put_n(tostr_range &range, char const *p, size_t n); - tostr_range() = delete; - tostr_range(R &out): p_out(out), p_written(0) {} - bool put(char v) { - bool ret = p_out.put(v); - p_written += ret; - return ret; + tostr_range(R &out): p_out(out) {} + void put(char v) { + p_out.put(v); } - size_t put_string(string_range r) { - size_t ret = range_put_n(p_out, r.data(), r.size()); - p_written += ret; - return ret; + void put_string(string_range r) { + p_out = ostd::copy(r, p_out); } - size_t get_written() const { return p_written; } private: R &p_out; - size_t p_written; }; - template - inline size_t range_put_n(tostr_range &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 static std::true_type test_stringify( decltype(std::declval().to_string(std::declval())) * @@ -590,13 +547,12 @@ struct to_string>> { std::string operator()(T const &v) const { std::string ret("{"); auto x = appender_range{}; - if (concat(x, ostd::iter(v), ", ", to_string< + concat(x, ostd::iter(v), ", ", to_string< std::remove_const_t >> - >())) { - ret += x.get(); - } + >()); + ret += x.get(); ret += "}"; return ret; } @@ -778,7 +734,8 @@ public: } else { 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() { if (p_allocated) {