revamped output ranges and input range pop funcs

master
Daniel Kolesa 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);
}
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<T> pop_front_n(range_size_t<T> n) {
void pop_front_n(range_size_t<T> 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);
}
range_size_t<T> push_front_n(range_size_t<T> n) {
return p_range.push_front_n(n);
void push_front_n(range_size_t<T> n) {
p_range.push_front_n(n);
}
range_size_t<T> push_back_n(range_size_t<T> n) {
return p_range.push_back_n(n);
void push_back_n(range_size_t<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<T> front() const { return p_range.front(); }

View File

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

View File

@ -147,11 +147,7 @@ struct format_spec {
{}
template<typename R>
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<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)) {
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<typename R>
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<R>(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<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];
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<typename R, typename ...A>
static size_t format_impl(
static void format_impl(
R &writer, bool escape, string_range fmt, A const &...args
);
template<size_t I>
struct FmtTupleUnpacker {
template<typename R, typename T, typename ...A>
static inline size_t unpack(
static inline void unpack(
R &writer, bool esc, string_range fmt,
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...
);
}
@ -520,11 +499,11 @@ namespace detail {
template<>
struct FmtTupleUnpacker<0> {
template<typename R, typename T, typename ...A>
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<T>(0))::value;
template<typename R, typename T>
inline size_t format_ritem(
inline void format_ritem(
R &writer, bool esc, bool, string_range fmt,
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>
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<is_tuple_like<T>, bool> = true
) {
if (expandval) {
return FmtTupleUnpacker<std::tuple_size<T>::value>::unpack(
FmtTupleUnpacker<std::tuple_size<T>::value>::unpack(
writer, esc, fmt, item
);
} else {
format_impl(writer, esc, fmt, item);
}
return format_impl(writer, esc, fmt, item);
}
template<typename R, typename T>
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<detail::iterable_test<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<typename R, typename T>
inline size_t write_range(
inline void write_range(
R &, format_spec const *, bool, bool, string_range,
T const &, std::enable_if_t<!detail::iterable_test<T>, bool> = true
) {
@ -661,24 +636,23 @@ namespace detail {
/* string base writer */
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) {
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<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) {
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<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 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<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 */
if constexpr(fmt_tofmt_test<T, tostr_range<R>>) {
tostr_range<R> 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<string_range, T const &>) {
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<T, bool>) {
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<T, char>) {
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<T>) {
if constexpr(std::is_signed_v<T>) {
/* signed integers */
using UT = std::make_unsigned_t<T>;
return detail::write_u(
detail::write_u(
writer, this, val < 0,
(val < 0) ? static_cast<UT>(-val) : static_cast<UT>(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<T>) {
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<T>) {
if (this->spec() != 's') {
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 */
throw format_error{"the value cannot be formatted"};
@ -826,23 +805,23 @@ namespace detail {
/* actual writer */
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
) 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<typename R, typename T, typename ...A>
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<typename R, typename ...A>
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<typename R>
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<typename R, typename ...A>
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<R>(writer);
}
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 */
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 */

View File

@ -9,6 +9,8 @@
#include <stdio.h>
#include <vector>
#include <stdexcept>
#include <system_error>
#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<typename T>
@ -184,8 +210,7 @@ template<typename T>
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<typename ...A>
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"};
}
}

View File

@ -15,6 +15,7 @@
#include <iterator>
#include <type_traits>
#include <initializer_list>
#include <algorithm>
#include "ostd/types.hh"
@ -198,7 +199,7 @@ template<typename T> constexpr bool is_contiguous_range =
namespace detail {
template<typename R, typename T>
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 *);
template<typename, typename>
@ -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<T> next_n(range_size_t<T> n) {
return p_range.pop_front_n(n);
void next_n(range_size_t<T> n) {
p_range.pop_front_n(n);
}
range_size_t<T> prev_n(range_size_t<T> n) {
return p_range.push_front_n(n);
void prev_n(range_size_t<T> n) {
p_range.push_front_n(n);
}
range_difference_t<T> add_n(range_difference_t<T> n) {
@ -497,43 +498,31 @@ inline range_difference_t<R> operator-(
namespace detail {
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) {
if (!range.pop_front()) {
return i;
}
range.pop_front();
}
return n;
}
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) {
if (!range.pop_back()) {
return i;
}
range.pop_back();
}
return n;
}
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) {
if (!range.push_front()) {
return i;
}
range.push_front();
}
return n;
}
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) {
if (!range.push_back()) {
return i;
}
range.push_back();
}
return n;
}
}
@ -562,23 +551,23 @@ struct input_range {
}
template<typename Size>
Size pop_front_n(Size n) {
return detail::pop_front_n<B>(*static_cast<B *>(this), n);
void pop_front_n(Size n) {
detail::pop_front_n<B>(*static_cast<B *>(this), n);
}
template<typename Size>
Size pop_back_n(Size n) {
return detail::pop_back_n<B>(*static_cast<B *>(this), n);
void pop_back_n(Size n) {
detail::pop_back_n<B>(*static_cast<B *>(this), n);
}
template<typename Size>
Size push_front_n(Size n) {
return detail::push_front_n<B>(*static_cast<B *>(this), n);
void push_front_n(Size n) {
detail::push_front_n<B>(*static_cast<B *>(this), n);
}
template<typename Size>
Size push_back_n(Size n) {
return detail::push_back_n<B>(*static_cast<B *>(this), n);
void push_back_n(Size n) {
detail::push_back_n<B>(*static_cast<B *>(this), n);
}
B iter() const {
@ -621,30 +610,6 @@ struct input_range {
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
* 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<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>
struct noop_output_range: output_range<noop_output_range<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 difference_type = ptrdiff_t;
bool put(T const &) { return true; }
void put(T const &) {}
};
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 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:
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<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>
inline counting_output_range<R> range_counter(R const &range) {
return counting_output_range<R>{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<typename T>
@ -1198,7 +1128,7 @@ struct number_range: input_range<number_range<T>> {
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<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 (!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>
@ -1423,6 +1347,7 @@ namespace detail {
}
return join_range_front<I + 1, N>(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<appender_range<T>> {
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<iterator_range<T>> {
/* 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<T>) {
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<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
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<T>) {
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<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
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<iterator_range<T>> {
}
/* 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<T>) {
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<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
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<T>) {
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<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
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<iterator_range<T>> {
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<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:
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>
iterator_range<T> make_range(T beg, T end) {
return iterator_range<T>{beg, end};

View File

@ -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<typename T>
@ -83,19 +84,14 @@ struct stream {
template<typename T>
void writeln(T const &v) {
write(v);
if (!putchar('\n')) {
/* consistency with format module */
throw format_error{"stream EOF"};
}
putchar('\n');
}
template<typename T, typename ...A>
void writeln(T const &v, A const &...args) {
write(v);
write(args...);
if (!putchar('\n')) {
throw format_error{"stream EOF"};
}
putchar('\n');
}
template<typename ...A>
@ -104,44 +100,40 @@ struct stream {
template<typename ...A>
void writefln(string_range fmt, A const &...args) {
writef(fmt, args...);
if (!putchar('\n')) {
throw format_error{"stream EOF"};
}
putchar('\n');
}
template<typename T = char>
stream_range<T> iter();
template<typename T>
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<typename T>
bool put(T v) {
return write_bytes(&v, sizeof(T)) == sizeof(T);
void put(T v) {
write_bytes(&v, sizeof(T));
}
template<typename T>
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<typename T>
bool get(T &v) {
return read_bytes(&v, sizeof(T)) == sizeof(T);
void get(T &v) {
read_bytes(&v, sizeof(T));
}
template<typename T>
T get() {
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>
struct stream_range<T, true>: input_range<stream_range<T>> {
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 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(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<T, true>: input_range<stream_range<T>> {
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<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<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>
inline stream_range<T> stream::iter() {
return stream_range<T>(*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<typename T>
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>
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 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<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 */
operator std::basic_string_view<std::remove_cv_t<T>>() const {
return std::basic_string_view<std::remove_cv_t<T>>{data(), size()};
@ -203,14 +188,6 @@ private:
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 string_range = basic_char_range<char const>;
@ -461,68 +438,64 @@ namespace detail {
template<typename T, bool B>
struct ConcatPut<T, true, B> {
template<typename R>
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<typename T>
struct ConcatPut<T, false, true> {
template<typename R>
static bool put(R &sink, char v) {
return sink.put(v);
static void put(R &sink, char v) {
sink.put(v);
}
};
}
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);
if (range.empty()) {
return true;
return std::forward<R>(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<R>(sink);
}
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);
if (range.empty()) {
return true;
return std::forward<R>(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<R>(sink);
}
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);
}
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);
}
@ -534,34 +507,18 @@ namespace detail {
using size_type = size_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(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<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>
static std::true_type test_stringify(
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 ret("{");
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<
range_reference_t<decltype(ostd::iter(v))>
>>
>())) {
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) {