forked from OctaForge/libostd
revamped output ranges and input range pop funcs
This commit is contained in:
parent
2661ba91ae
commit
e4dc237f4d
|
@ -778,24 +778,24 @@ public:
|
||||||
return p_range.distance_back(r.p_range);
|
return p_range.distance_back(r.p_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() { return p_range.pop_front(); }
|
void pop_front() { p_range.pop_front(); }
|
||||||
bool pop_back() { return p_range.pop_back(); }
|
void pop_back() { p_range.pop_back(); }
|
||||||
|
|
||||||
bool push_front() { return p_range.pop_front(); }
|
void push_front() { p_range.pop_front(); }
|
||||||
bool push_back() { return p_range.push_back(); }
|
void push_back() { p_range.push_back(); }
|
||||||
|
|
||||||
range_size_t<T> pop_front_n(range_size_t<T> n) {
|
void pop_front_n(range_size_t<T> n) {
|
||||||
p_range.pop_front_n(n);
|
p_range.pop_front_n(n);
|
||||||
}
|
}
|
||||||
range_size_t<T> pop_back_n(range_size_t<T> n) {
|
void pop_back_n(range_size_t<T> n) {
|
||||||
p_range.pop_back_n(n);
|
p_range.pop_back_n(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
range_size_t<T> push_front_n(range_size_t<T> n) {
|
void push_front_n(range_size_t<T> n) {
|
||||||
return p_range.push_front_n(n);
|
p_range.push_front_n(n);
|
||||||
}
|
}
|
||||||
range_size_t<T> push_back_n(range_size_t<T> n) {
|
void push_back_n(range_size_t<T> n) {
|
||||||
return p_range.push_back_n(n);
|
p_range.push_back_n(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
R front() const { return p_func(p_range.front()); }
|
R front() const { return p_func(p_range.front()); }
|
||||||
|
@ -887,10 +887,9 @@ public:
|
||||||
return p_range.equals_front(r.p_range);
|
return p_range.equals_front(r.p_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
bool ret = p_range.pop_front();
|
p_range.pop_front();
|
||||||
advance_valid();
|
advance_valid();
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
range_reference_t<T> front() const { return p_range.front(); }
|
range_reference_t<T> front() const { return p_range.front(); }
|
||||||
|
|
|
@ -549,8 +549,8 @@ struct directory_range: input_range<directory_range> {
|
||||||
return p_stream->empty();
|
return p_stream->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
return p_stream->pop_front();
|
p_stream->pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
file_info front() const {
|
file_info front() const {
|
||||||
|
|
202
ostd/format.hh
202
ostd/format.hh
|
@ -147,11 +147,7 @@ struct format_spec {
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
bool read_until_spec(R &writer, size_t *wret) {
|
bool read_until_spec(R &writer) {
|
||||||
size_t written = 0;
|
|
||||||
if (wret) {
|
|
||||||
*wret = 0;
|
|
||||||
}
|
|
||||||
if (p_fmt.empty()) {
|
if (p_fmt.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -161,34 +157,21 @@ struct format_spec {
|
||||||
if (p_fmt.front() == '%') {
|
if (p_fmt.front() == '%') {
|
||||||
goto plain;
|
goto plain;
|
||||||
}
|
}
|
||||||
bool r = read_spec();
|
return read_spec();
|
||||||
if (wret) {
|
|
||||||
*wret = written;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
plain:
|
plain:
|
||||||
++written;
|
|
||||||
writer.put(p_fmt.front());
|
writer.put(p_fmt.front());
|
||||||
p_fmt.pop_front();
|
p_fmt.pop_front();
|
||||||
}
|
}
|
||||||
if (wret) {
|
|
||||||
*wret = written;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
size_t write_spaces(R &writer, size_t n, bool left, char c = ' ') const {
|
void write_spaces(R &writer, size_t n, bool left, char c = ' ') const {
|
||||||
if (left == bool(p_flags & FMT_FLAG_DASH)) {
|
if (left == bool(p_flags & FMT_FLAG_DASH)) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
int r = p_width - int(n);
|
|
||||||
for (int w = p_width - int(n); --w >= 0; writer.put(c));
|
for (int w = p_width - int(n); --w >= 0; writer.put(c));
|
||||||
if (r < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string_range rest() const {
|
string_range rest() const {
|
||||||
|
@ -196,26 +179,26 @@ struct format_spec {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
size_t build_spec(R &&out, string_range spec) const {
|
R &&build_spec(R &&out, string_range spec) const {
|
||||||
size_t ret = out.put('%');
|
out.put('%');
|
||||||
if (p_flags & FMT_FLAG_DASH ) {
|
if (p_flags & FMT_FLAG_DASH ) {
|
||||||
ret += out.put('-');
|
out.put('-');
|
||||||
}
|
}
|
||||||
if (p_flags & FMT_FLAG_ZERO ) {
|
if (p_flags & FMT_FLAG_ZERO ) {
|
||||||
ret += out.put('0');
|
out.put('0');
|
||||||
}
|
}
|
||||||
if (p_flags & FMT_FLAG_SPACE) {
|
if (p_flags & FMT_FLAG_SPACE) {
|
||||||
ret += out.put(' ');
|
out.put(' ');
|
||||||
}
|
}
|
||||||
if (p_flags & FMT_FLAG_PLUS ) {
|
if (p_flags & FMT_FLAG_PLUS ) {
|
||||||
ret += out.put('+');
|
out.put('+');
|
||||||
}
|
}
|
||||||
if (p_flags & FMT_FLAG_HASH ) {
|
if (p_flags & FMT_FLAG_HASH ) {
|
||||||
ret += out.put('#');
|
out.put('#');
|
||||||
}
|
}
|
||||||
ret += range_put_n(out, "*.*", 3);
|
out = ostd::copy(string_range{"*.*"}, out);
|
||||||
ret += range_put_n(out, &spec[0], spec.size());
|
out = ostd::copy(spec, out);
|
||||||
return ret;
|
return std::forward<R>(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
int width() const { return p_width; }
|
int width() const { return p_width; }
|
||||||
|
@ -446,9 +429,9 @@ inline void to_format(T const &v, R &writer, format_spec const &fs) {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
inline size_t write_u(R &writer, format_spec const *fl, bool neg, T val) {
|
inline void write_u(R &writer, format_spec const *fl, bool neg, T val) {
|
||||||
char buf[20];
|
char buf[20];
|
||||||
size_t r = 0, n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
char spec = fl->spec();
|
char spec = fl->spec();
|
||||||
if (spec == 's') spec = 'd';
|
if (spec == 's') spec = 'd';
|
||||||
|
@ -464,54 +447,50 @@ namespace detail {
|
||||||
for (; val; val /= base) {
|
for (; val; val /= base) {
|
||||||
buf[n++] = detail::fmt_digits[spec >= 'a'][val % base];
|
buf[n++] = detail::fmt_digits[spec >= 'a'][val % base];
|
||||||
}
|
}
|
||||||
r = n;
|
|
||||||
|
|
||||||
int flags = fl->flags();
|
int flags = fl->flags();
|
||||||
bool lsgn = flags & FMT_FLAG_PLUS;
|
bool lsgn = flags & FMT_FLAG_PLUS;
|
||||||
bool lsp = flags & FMT_FLAG_SPACE;
|
bool lsp = flags & FMT_FLAG_SPACE;
|
||||||
bool zero = flags & FMT_FLAG_ZERO;
|
bool zero = flags & FMT_FLAG_ZERO;
|
||||||
bool sign = neg + lsgn + lsp;
|
bool sign = neg + lsgn + lsp;
|
||||||
r += sign;
|
|
||||||
|
|
||||||
char const *pfx = nullptr;
|
char const *pfx = nullptr;
|
||||||
size_t pfxlen = 0;
|
size_t pfxlen = 0;
|
||||||
if (flags & FMT_FLAG_HASH && spec != 'd') {
|
if (flags & FMT_FLAG_HASH && spec != 'd') {
|
||||||
pfx = detail::fmt_intpfx[spec >= 'a'][specn - 3];
|
pfx = detail::fmt_intpfx[spec >= 'a'][specn - 3];
|
||||||
pfxlen = !!pfx[1] + 1;
|
pfxlen = !!pfx[1] + 1;
|
||||||
r += pfxlen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!zero) {
|
if (!zero) {
|
||||||
r += fl->write_spaces(writer, n + pfxlen + sign, true, ' ');
|
fl->write_spaces(writer, n + pfxlen + sign, true, ' ');
|
||||||
}
|
}
|
||||||
if (sign) {
|
if (sign) {
|
||||||
writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
|
writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
|
||||||
}
|
}
|
||||||
range_put_n(writer, pfx, pfxlen);
|
writer = ostd::copy(string_range{pfx, pfx + pfxlen}, writer);
|
||||||
if (zero) {
|
if (zero) {
|
||||||
r += fl->write_spaces(writer, n + pfxlen + sign, true, '0');
|
fl->write_spaces(writer, n + pfxlen + sign, true, '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = int(n - 1); i >= 0; --i) {
|
for (int i = int(n - 1); i >= 0; --i) {
|
||||||
writer.put(buf[i]);
|
writer.put(buf[i]);
|
||||||
}
|
}
|
||||||
r += fl->write_spaces(writer, n + sign + pfxlen, false);
|
fl->write_spaces(writer, n + sign + pfxlen, false);
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename ...A>
|
template<typename R, typename ...A>
|
||||||
static size_t format_impl(
|
static void format_impl(
|
||||||
R &writer, bool escape, string_range fmt, A const &...args
|
R &writer, bool escape, string_range fmt, A const &...args
|
||||||
);
|
);
|
||||||
|
|
||||||
template<size_t I>
|
template<size_t I>
|
||||||
struct FmtTupleUnpacker {
|
struct FmtTupleUnpacker {
|
||||||
template<typename R, typename T, typename ...A>
|
template<typename R, typename T, typename ...A>
|
||||||
static inline size_t unpack(
|
static inline void unpack(
|
||||||
R &writer, bool esc, string_range fmt,
|
R &writer, bool esc, string_range fmt,
|
||||||
T const &item, A const &...args
|
T const &item, A const &...args
|
||||||
) {
|
) {
|
||||||
return FmtTupleUnpacker<I - 1>::unpack(
|
FmtTupleUnpacker<I - 1>::unpack(
|
||||||
writer, esc, fmt, item, std::get<I - 1>(item), args...
|
writer, esc, fmt, item, std::get<I - 1>(item), args...
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -520,11 +499,11 @@ namespace detail {
|
||||||
template<>
|
template<>
|
||||||
struct FmtTupleUnpacker<0> {
|
struct FmtTupleUnpacker<0> {
|
||||||
template<typename R, typename T, typename ...A>
|
template<typename R, typename T, typename ...A>
|
||||||
static inline size_t unpack(
|
static inline void unpack(
|
||||||
R &writer, bool esc, string_range fmt,
|
R &writer, bool esc, string_range fmt,
|
||||||
T const &, A const &...args
|
T const &, A const &...args
|
||||||
) {
|
) {
|
||||||
return format_impl(writer, esc, fmt, args...);
|
format_impl(writer, esc, fmt, args...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -541,55 +520,51 @@ namespace detail {
|
||||||
constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value;
|
constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value;
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
inline size_t format_ritem(
|
inline void format_ritem(
|
||||||
R &writer, bool esc, bool, string_range fmt,
|
R &writer, bool esc, bool, string_range fmt,
|
||||||
T const &item, std::enable_if_t<!is_tuple_like<T>, bool> = true
|
T const &item, std::enable_if_t<!is_tuple_like<T>, bool> = true
|
||||||
) {
|
) {
|
||||||
return format_impl(writer, esc, fmt, item);
|
format_impl(writer, esc, fmt, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
inline size_t format_ritem(
|
inline void format_ritem(
|
||||||
R &writer, bool esc, bool expandval, string_range fmt,
|
R &writer, bool esc, bool expandval, string_range fmt,
|
||||||
T const &item, std::enable_if_t<is_tuple_like<T>, bool> = true
|
T const &item, std::enable_if_t<is_tuple_like<T>, bool> = true
|
||||||
) {
|
) {
|
||||||
if (expandval) {
|
if (expandval) {
|
||||||
return FmtTupleUnpacker<std::tuple_size<T>::value>::unpack(
|
FmtTupleUnpacker<std::tuple_size<T>::value>::unpack(
|
||||||
writer, esc, fmt, item
|
writer, esc, fmt, item
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
format_impl(writer, esc, fmt, item);
|
||||||
}
|
}
|
||||||
return format_impl(writer, esc, fmt, item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
inline size_t write_range(
|
inline void write_range(
|
||||||
R &writer, format_spec const *fl, bool escape, bool expandval,
|
R &writer, format_spec const *fl, bool escape, bool expandval,
|
||||||
string_range sep, T const &val,
|
string_range sep, T const &val,
|
||||||
std::enable_if_t<detail::iterable_test<T>, bool> = true
|
std::enable_if_t<detail::iterable_test<T>, bool> = true
|
||||||
) {
|
) {
|
||||||
/* XXX: maybe handle error cases? */
|
|
||||||
auto range = ostd::iter(val);
|
auto range = ostd::iter(val);
|
||||||
if (range.empty()) {
|
if (range.empty()) {
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
size_t ret = 0;
|
|
||||||
/* test first item */
|
/* test first item */
|
||||||
ret += format_ritem(
|
format_ritem(writer, escape, expandval, fl->rest(), range.front());
|
||||||
writer, escape, expandval, fl->rest(), range.front()
|
|
||||||
);
|
|
||||||
range.pop_front();
|
range.pop_front();
|
||||||
/* write the rest (if any) */
|
/* write the rest (if any) */
|
||||||
for (; !range.empty(); range.pop_front()) {
|
for (; !range.empty(); range.pop_front()) {
|
||||||
ret += range_put_n(writer, &sep[0], sep.size());
|
writer = ostd::copy(sep, writer);
|
||||||
ret += format_ritem(
|
format_ritem(
|
||||||
writer, escape, expandval, fl->rest(), range.front()
|
writer, escape, expandval, fl->rest(), range.front()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
inline size_t write_range(
|
inline void write_range(
|
||||||
R &, format_spec const *, bool, bool, string_range,
|
R &, format_spec const *, bool, bool, string_range,
|
||||||
T const &, std::enable_if_t<!detail::iterable_test<T>, bool> = true
|
T const &, std::enable_if_t<!detail::iterable_test<T>, bool> = true
|
||||||
) {
|
) {
|
||||||
|
@ -661,24 +636,23 @@ namespace detail {
|
||||||
|
|
||||||
/* string base writer */
|
/* string base writer */
|
||||||
template<typename R>
|
template<typename R>
|
||||||
size_t write_str(R &writer, bool escape, string_range val) const {
|
void write_str(R &writer, bool escape, string_range val) const {
|
||||||
if (escape) {
|
if (escape) {
|
||||||
return write_str(writer, false, escape_fmt_str(val));
|
write_str(writer, false, escape_fmt_str(val));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
size_t n = val.size();
|
size_t n = val.size();
|
||||||
if (this->precision()) {
|
if (this->precision()) {
|
||||||
n = this->precision();
|
n = this->precision();
|
||||||
}
|
}
|
||||||
size_t r = n;
|
this->write_spaces(writer, n, true);
|
||||||
r += this->write_spaces(writer, n, true);
|
writer = ostd::copy(val.slice(0, n), writer);
|
||||||
range_put_n(writer, &val[0], n);
|
this->write_spaces(writer, n, false);
|
||||||
r += this->write_spaces(writer, n, false);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* char values */
|
/* char values */
|
||||||
template<typename R>
|
template<typename R>
|
||||||
size_t write_char(R &writer, bool escape, char val) const {
|
void write_char(R &writer, bool escape, char val) const {
|
||||||
if (escape) {
|
if (escape) {
|
||||||
char const *esc = escape_fmt_char(val, '\'');
|
char const *esc = escape_fmt_char(val, '\'');
|
||||||
if (esc) {
|
if (esc) {
|
||||||
|
@ -687,13 +661,13 @@ namespace detail {
|
||||||
size_t elen = strlen(esc);
|
size_t elen = strlen(esc);
|
||||||
memcpy(buf + 1, esc, elen);
|
memcpy(buf + 1, esc, elen);
|
||||||
buf[elen + 1] = '\'';
|
buf[elen + 1] = '\'';
|
||||||
return write_val(writer, false, ostd::string_range{
|
write_val(writer, false, ostd::string_range{
|
||||||
buf, buf + elen + 2
|
buf, buf + elen + 2
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t r = 1 + escape * 2;
|
this->write_spaces(writer, 1 + escape * 2, true);
|
||||||
r += this->write_spaces(writer, 1 + escape * 2, true);
|
|
||||||
if (escape) {
|
if (escape) {
|
||||||
writer.put('\'');
|
writer.put('\'');
|
||||||
writer.put(val);
|
writer.put(val);
|
||||||
|
@ -701,13 +675,12 @@ namespace detail {
|
||||||
} else {
|
} else {
|
||||||
writer.put(val);
|
writer.put(val);
|
||||||
}
|
}
|
||||||
r += this->write_spaces(writer, 1 + escape * 2, false);
|
this->write_spaces(writer, 1 + escape * 2, false);
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* floating point */
|
/* floating point */
|
||||||
template<typename R, typename T, bool Long = std::is_same_v<T, ldouble>>
|
template<typename R, typename T, bool Long = std::is_same_v<T, ldouble>>
|
||||||
size_t write_float(R &writer, bool, T val) const {
|
void write_float(R &writer, bool, T val) const {
|
||||||
char buf[16], rbuf[128];
|
char buf[16], rbuf[128];
|
||||||
char fmtspec[Long + 1];
|
char fmtspec[Long + 1];
|
||||||
|
|
||||||
|
@ -723,7 +696,7 @@ namespace detail {
|
||||||
fmtspec[0] = 'L';
|
fmtspec[0] = 'L';
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[this->build_spec(iter(buf), fmtspec)] = '\0';
|
this->build_spec(iter(buf), fmtspec).put('\0');
|
||||||
int ret = snprintf(
|
int ret = snprintf(
|
||||||
rbuf, sizeof(rbuf), buf, this->width(),
|
rbuf, sizeof(rbuf), buf, this->width(),
|
||||||
this->has_precision() ? this->precision() : 6, val
|
this->has_precision() ? this->precision() : 6, val
|
||||||
|
@ -745,43 +718,45 @@ namespace detail {
|
||||||
/* see above */
|
/* see above */
|
||||||
throw format_error{"invalid float format"};
|
throw format_error{"invalid float format"};
|
||||||
}
|
}
|
||||||
range_put_n(writer, dbuf, ret);
|
writer = ostd::copy(string_range{dbuf, dbuf + ret}, writer);
|
||||||
delete[] dbuf;
|
delete[] dbuf;
|
||||||
} else {
|
} else {
|
||||||
range_put_n(writer, rbuf, ret);
|
writer = ostd::copy(string_range{rbuf, rbuf + ret}, writer);
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
size_t write_val(R &writer, bool escape, T const &val) const {
|
void write_val(R &writer, bool escape, T const &val) const {
|
||||||
/* stuff fhat can be custom-formatted goes first */
|
/* stuff fhat can be custom-formatted goes first */
|
||||||
if constexpr(fmt_tofmt_test<T, tostr_range<R>>) {
|
if constexpr(fmt_tofmt_test<T, tostr_range<R>>) {
|
||||||
tostr_range<R> sink(writer);
|
tostr_range<R> sink(writer);
|
||||||
to_format(val, sink, *this);
|
to_format(val, sink, *this);
|
||||||
return sink.get_written();
|
return;
|
||||||
}
|
}
|
||||||
/* second best, we can convert to string slice */
|
/* second best, we can convert to string slice */
|
||||||
if constexpr(std::is_constructible_v<string_range, T const &>) {
|
if constexpr(std::is_constructible_v<string_range, T const &>) {
|
||||||
if (this->spec() != 's') {
|
if (this->spec() != 's') {
|
||||||
throw format_error{"strings need the '%s' spec"};
|
throw format_error{"strings need the '%s' spec"};
|
||||||
}
|
}
|
||||||
return write_str(writer, escape, val);
|
write_str(writer, escape, val);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* bools, check if printing as string, otherwise convert to int */
|
/* bools, check if printing as string, otherwise convert to int */
|
||||||
if constexpr(std::is_same_v<T, bool>) {
|
if constexpr(std::is_same_v<T, bool>) {
|
||||||
if (this->spec() == 's') {
|
if (this->spec() == 's') {
|
||||||
return write_val(writer, ("false\0true") + (6 * val));
|
write_val(writer, ("false\0true") + (6 * val));
|
||||||
} else {
|
} else {
|
||||||
return write_val(writer, int(val));
|
write_val(writer, int(val));
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* character values */
|
/* character values */
|
||||||
if constexpr(std::is_same_v<T, char>) {
|
if constexpr(std::is_same_v<T, char>) {
|
||||||
if (this->spec() != 's' && this->spec() != 'c') {
|
if (this->spec() != 's' && this->spec() != 'c') {
|
||||||
throw format_error{"cannot format chars with the given spec"};
|
throw format_error{"cannot format chars with the given spec"};
|
||||||
}
|
}
|
||||||
return write_char(writer, escape, val);
|
write_char(writer, escape, val);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* pointers, write as pointer with %s and otherwise as unsigned...
|
/* pointers, write as pointer with %s and otherwise as unsigned...
|
||||||
* char pointers are handled by the string case above
|
* char pointers are handled by the string case above
|
||||||
|
@ -793,32 +768,36 @@ namespace detail {
|
||||||
has_precision() ? precision() : -1,
|
has_precision() ? precision() : -1,
|
||||||
(spec() == 's') ? (flags() | FMT_FLAG_HASH) : flags()
|
(spec() == 's') ? (flags() | FMT_FLAG_HASH) : flags()
|
||||||
};
|
};
|
||||||
return detail::write_u(writer, &sp, false, size_t(val));
|
detail::write_u(writer, &sp, false, size_t(val));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* integers */
|
/* integers */
|
||||||
if constexpr(std::is_integral_v<T>) {
|
if constexpr(std::is_integral_v<T>) {
|
||||||
if constexpr(std::is_signed_v<T>) {
|
if constexpr(std::is_signed_v<T>) {
|
||||||
/* signed integers */
|
/* signed integers */
|
||||||
using UT = std::make_unsigned_t<T>;
|
using UT = std::make_unsigned_t<T>;
|
||||||
return detail::write_u(
|
detail::write_u(
|
||||||
writer, this, val < 0,
|
writer, this, val < 0,
|
||||||
(val < 0) ? static_cast<UT>(-val) : static_cast<UT>(val)
|
(val < 0) ? static_cast<UT>(-val) : static_cast<UT>(val)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
/* unsigned integers */
|
/* unsigned integers */
|
||||||
return detail::write_u(writer, this, false, val);
|
detail::write_u(writer, this, false, val);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* floats */
|
/* floats */
|
||||||
if constexpr(std::is_floating_point_v<T>) {
|
if constexpr(std::is_floating_point_v<T>) {
|
||||||
return write_float(writer, escape, val);
|
write_float(writer, escape, val);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* stuff that can be to_string'd, worst reliable case, allocates */
|
/* stuff that can be to_string'd, worst reliable case, allocates */
|
||||||
if constexpr(fmt_tostr_test<T>) {
|
if constexpr(fmt_tostr_test<T>) {
|
||||||
if (this->spec() != 's') {
|
if (this->spec() != 's') {
|
||||||
throw format_error{"custom objects need the '%s' spec"};
|
throw format_error{"custom objects need the '%s' spec"};
|
||||||
}
|
}
|
||||||
return write_val(writer, false, ostd::to_string<T>{}(val));
|
write_val(writer, false, ostd::to_string<T>{}(val));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* we ran out of options, failure */
|
/* we ran out of options, failure */
|
||||||
throw format_error{"the value cannot be formatted"};
|
throw format_error{"the value cannot be formatted"};
|
||||||
|
@ -826,23 +805,23 @@ namespace detail {
|
||||||
|
|
||||||
/* actual writer */
|
/* actual writer */
|
||||||
template<typename R, typename T, typename ...A>
|
template<typename R, typename T, typename ...A>
|
||||||
size_t write_arg(
|
void write_arg(
|
||||||
R &writer, size_t idx, T const &val, A const &...args
|
R &writer, size_t idx, T const &val, A const &...args
|
||||||
) const {
|
) const {
|
||||||
if (idx) {
|
if (idx) {
|
||||||
if constexpr(!sizeof...(A)) {
|
if constexpr(!sizeof...(A)) {
|
||||||
throw format_error{"not enough format arguments"};
|
throw format_error{"not enough format arguments"};
|
||||||
} else {
|
} else {
|
||||||
return write_arg(writer, idx - 1, args...);
|
write_arg(writer, idx - 1, args...);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return write_val(writer, this->p_nested_escape, val);
|
write_val(writer, this->p_nested_escape, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* range writer */
|
/* range writer */
|
||||||
template<typename R, typename T, typename ...A>
|
template<typename R, typename T, typename ...A>
|
||||||
size_t write_range(
|
void write_range(
|
||||||
R &writer, size_t idx, bool expandval, string_range sep,
|
R &writer, size_t idx, bool expandval, string_range sep,
|
||||||
T const &val, A const &...args
|
T const &val, A const &...args
|
||||||
) const {
|
) const {
|
||||||
|
@ -850,10 +829,10 @@ namespace detail {
|
||||||
if constexpr(!sizeof...(A)) {
|
if constexpr(!sizeof...(A)) {
|
||||||
throw format_error{"not enough format arguments"};
|
throw format_error{"not enough format arguments"};
|
||||||
} else {
|
} else {
|
||||||
return write_range(writer, idx - 1, expandval, sep, args...);
|
write_range(writer, idx - 1, expandval, sep, args...);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return detail::write_range(
|
detail::write_range(
|
||||||
writer, this, this->p_nested_escape, expandval, sep, val
|
writer, this, this->p_nested_escape, expandval, sep, val
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -861,13 +840,12 @@ namespace detail {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R, typename ...A>
|
template<typename R, typename ...A>
|
||||||
inline size_t format_impl(
|
inline void format_impl(
|
||||||
R &writer, bool escape, string_range fmt, A const &...args
|
R &writer, bool escape, string_range fmt, A const &...args
|
||||||
) {
|
) {
|
||||||
size_t argidx = 1, twr = 0, written = 0;
|
size_t argidx = 1;
|
||||||
detail::write_spec spec(fmt, escape);
|
detail::write_spec spec(fmt, escape);
|
||||||
while (spec.read_until_spec(writer, &twr)) {
|
while (spec.read_until_spec(writer)) {
|
||||||
written += twr;
|
|
||||||
size_t argpos = spec.index();
|
size_t argpos = spec.index();
|
||||||
if (spec.is_nested()) {
|
if (spec.is_nested()) {
|
||||||
if (!argpos) {
|
if (!argpos) {
|
||||||
|
@ -875,7 +853,7 @@ namespace detail {
|
||||||
}
|
}
|
||||||
/* FIXME: figure out a better way */
|
/* FIXME: figure out a better way */
|
||||||
detail::write_spec nspec(spec.nested(), spec.nested_escape());
|
detail::write_spec nspec(spec.nested(), spec.nested_escape());
|
||||||
written += nspec.write_range(
|
nspec.write_range(
|
||||||
writer, argpos - 1, (spec.flags() & FMT_FLAG_HASH),
|
writer, argpos - 1, (spec.flags() & FMT_FLAG_HASH),
|
||||||
spec.nested_sep(), args...
|
spec.nested_sep(), args...
|
||||||
);
|
);
|
||||||
|
@ -906,33 +884,31 @@ namespace detail {
|
||||||
spec.set_width(argpos - 2 - argprec, args...);
|
spec.set_width(argpos - 2 - argprec, args...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
written += spec.write_arg(writer, argpos - 1, args...);
|
spec.write_arg(writer, argpos - 1, args...);
|
||||||
}
|
}
|
||||||
written += twr;
|
|
||||||
return written;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
inline ptrdiff_t format_impl(R &writer, bool, string_range fmt) {
|
inline void format_impl(R &writer, bool, string_range fmt) {
|
||||||
size_t written = 0;
|
|
||||||
detail::write_spec spec(fmt, false);
|
detail::write_spec spec(fmt, false);
|
||||||
if (spec.read_until_spec(writer, &written)) {
|
if (spec.read_until_spec(writer)) {
|
||||||
throw format_error{"format spec without format arguments"};
|
throw format_error{"format spec without format arguments"};
|
||||||
}
|
}
|
||||||
return written;
|
|
||||||
}
|
}
|
||||||
} /* namespace detail */
|
} /* namespace detail */
|
||||||
|
|
||||||
template<typename R, typename ...A>
|
template<typename R, typename ...A>
|
||||||
inline size_t format(R &&writer, string_range fmt, A const &...args) {
|
inline R &&format(R &&writer, string_range fmt, A const &...args) {
|
||||||
return detail::format_impl(writer, false, fmt, args...);
|
detail::format_impl(writer, false, fmt, args...);
|
||||||
|
return std::forward<R>(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
inline size_t format(R &&writer, format_spec const &fmt, T const &val) {
|
inline R &&format(R &&writer, format_spec const &fmt, T const &val) {
|
||||||
/* we can do this as there are no members added... but ugly, FIXME later */
|
/* we can do this as there are no members added... but ugly, FIXME later */
|
||||||
detail::write_spec const &wsp = static_cast<detail::write_spec const &>(fmt);
|
detail::write_spec const &wsp = static_cast<detail::write_spec const &>(fmt);
|
||||||
return wsp.write_arg(writer, 0, val);
|
wsp.write_arg(writer, 0, val);
|
||||||
|
return std::forward<R>(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace ostd */
|
} /* namespace ostd */
|
||||||
|
|
73
ostd/io.hh
73
ostd/io.hh
|
@ -9,6 +9,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
#include "ostd/platform.hh"
|
#include "ostd/platform.hh"
|
||||||
#include "ostd/string.hh"
|
#include "ostd/string.hh"
|
||||||
|
@ -27,6 +29,11 @@ namespace detail {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: inherit from system_error and come up with the proper infra for it */
|
||||||
|
struct io_error: std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
struct file_stream: stream {
|
struct file_stream: stream {
|
||||||
file_stream(): p_f(), p_owned(false) {}
|
file_stream(): p_f(), p_owned(false) {}
|
||||||
file_stream(file_stream const &) = delete;
|
file_stream(file_stream const &) = delete;
|
||||||
|
@ -93,38 +100,59 @@ struct file_stream: stream {
|
||||||
return feof(p_f) != 0;
|
return feof(p_f) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool seek(stream_off_t pos, stream_seek whence = stream_seek::SET) {
|
void seek(stream_off_t pos, stream_seek whence = stream_seek::SET) {
|
||||||
#ifndef OSTD_PLATFORM_WIN32
|
#ifndef OSTD_PLATFORM_WIN32
|
||||||
return fseeko(p_f, pos, int(whence)) >= 0;
|
if (fseeko(p_f, pos, int(whence)))
|
||||||
#else
|
#else
|
||||||
return _fseeki64(p_f, pos, int(whence)) >= 0;
|
if (_fseeki64(p_f, pos, int(whence)))
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
throw io_error{"file_stream seek error"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_off_t tell() const {
|
stream_off_t tell() const {
|
||||||
#ifndef OSTD_PLATFORM_WIN32
|
#ifndef OSTD_PLATFORM_WIN32
|
||||||
return ftello(p_f);
|
auto ret = ftello(p_f);
|
||||||
#else
|
#else
|
||||||
return _ftelli64(p_f);
|
auto ret = _ftelli64(p_f);
|
||||||
#endif
|
#endif
|
||||||
|
if (ret < 0) {
|
||||||
|
throw io_error{"file_stream tell error"};
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool flush() { return !fflush(p_f); }
|
void flush() {
|
||||||
|
if (fflush(p_f)) {
|
||||||
size_t read_bytes(void *buf, size_t count) {
|
throw io_error{"file_stream flush error"};
|
||||||
return fread(buf, 1, count, p_f);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write_bytes(void const *buf, size_t count) {
|
void read_bytes(void *buf, size_t count) {
|
||||||
return fwrite(buf, 1, count, p_f);
|
if (fread(buf, 1, count, p_f) != count) {
|
||||||
|
throw io_error{"file_stream read error"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_bytes(void const *buf, size_t count) {
|
||||||
|
if (fwrite(buf, 1, count, p_f) != count) {
|
||||||
|
throw io_error{"file_stream write error"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getchar() {
|
int getchar() {
|
||||||
return fgetc(p_f);
|
int ret = fgetc(p_f);
|
||||||
|
if (ret == EOF) {
|
||||||
|
throw io_error{"file_stream EOF"};
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool putchar(int c) {
|
void putchar(int c) {
|
||||||
return fputc(c, p_f) != EOF;
|
if (fputc(c, p_f) == EOF) {
|
||||||
|
throw io_error{"file_stream EOF"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(file_stream &s) {
|
void swap(file_stream &s) {
|
||||||
|
@ -159,14 +187,12 @@ namespace detail {
|
||||||
using difference_type = ptrdiff_t;
|
using difference_type = ptrdiff_t;
|
||||||
|
|
||||||
stdout_range() {}
|
stdout_range() {}
|
||||||
bool put(char c) {
|
void put(char c) {
|
||||||
return putchar(c) != EOF;
|
if (putchar(c) == EOF) {
|
||||||
|
throw io_error{"stdout EOF"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t range_put_n(stdout_range &, char const *p, size_t n) {
|
|
||||||
return fwrite(p, 1, n, stdout);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -184,8 +210,7 @@ template<typename T>
|
||||||
inline void writeln(T const &v) {
|
inline void writeln(T const &v) {
|
||||||
write(v);
|
write(v);
|
||||||
if (putchar('\n') == EOF) {
|
if (putchar('\n') == EOF) {
|
||||||
/* consistency with format module */
|
throw io_error{"stdout EOF"};
|
||||||
throw format_error{"stream EOF"};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +219,7 @@ inline void writeln(T const &v, A const &...args) {
|
||||||
write(v);
|
write(v);
|
||||||
write(args...);
|
write(args...);
|
||||||
if (putchar('\n') == EOF) {
|
if (putchar('\n') == EOF) {
|
||||||
throw format_error{"stream EOF"};
|
throw io_error{"stdout EOF"};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +232,7 @@ template<typename ...A>
|
||||||
inline void writefln(string_range fmt, A const &...args) {
|
inline void writefln(string_range fmt, A const &...args) {
|
||||||
writef(fmt, args...);
|
writef(fmt, args...);
|
||||||
if (putchar('\n') == EOF) {
|
if (putchar('\n') == EOF) {
|
||||||
throw format_error{"stream EOF"};
|
throw io_error{"stdout EOF"};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
402
ostd/range.hh
402
ostd/range.hh
|
@ -15,6 +15,7 @@
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "ostd/types.hh"
|
#include "ostd/types.hh"
|
||||||
|
|
||||||
|
@ -198,7 +199,7 @@ template<typename T> constexpr bool is_contiguous_range =
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
static std::true_type test_outrange(typename std::is_same<
|
static std::true_type test_outrange(typename std::is_same<
|
||||||
decltype(std::declval<R &>().put(std::declval<T>())), bool
|
decltype(std::declval<R &>().put(std::declval<T>())), void
|
||||||
>::type *);
|
>::type *);
|
||||||
|
|
||||||
template<typename, typename>
|
template<typename, typename>
|
||||||
|
@ -392,14 +393,14 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool next() { return p_range.pop_front(); }
|
void next() { p_range.pop_front(); }
|
||||||
bool prev() { return p_range.push_front(); }
|
void prev() { p_range.push_front(); }
|
||||||
|
|
||||||
range_size_t<T> next_n(range_size_t<T> n) {
|
void next_n(range_size_t<T> n) {
|
||||||
return p_range.pop_front_n(n);
|
p_range.pop_front_n(n);
|
||||||
}
|
}
|
||||||
range_size_t<T> prev_n(range_size_t<T> n) {
|
void prev_n(range_size_t<T> n) {
|
||||||
return p_range.push_front_n(n);
|
p_range.push_front_n(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
range_difference_t<T> add_n(range_difference_t<T> n) {
|
range_difference_t<T> add_n(range_difference_t<T> n) {
|
||||||
|
@ -497,44 +498,32 @@ inline range_difference_t<R> operator-(
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename R>
|
template<typename R>
|
||||||
range_size_t<R> pop_front_n(R &range, range_size_t<R> n) {
|
void pop_front_n(R &range, range_size_t<R> n) {
|
||||||
for (range_size_t<R> i = 0; i < n; ++i) {
|
for (range_size_t<R> i = 0; i < n; ++i) {
|
||||||
if (!range.pop_front()) {
|
range.pop_front();
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
range_size_t<R> pop_back_n(R &range, range_size_t<R> n) {
|
void pop_back_n(R &range, range_size_t<R> n) {
|
||||||
for (range_size_t<R> i = 0; i < n; ++i) {
|
for (range_size_t<R> i = 0; i < n; ++i) {
|
||||||
if (!range.pop_back()) {
|
range.pop_back();
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
range_size_t<R> push_front_n(R &range, range_size_t<R> n) {
|
void push_front_n(R &range, range_size_t<R> n) {
|
||||||
for (range_size_t<R> i = 0; i < n; ++i) {
|
for (range_size_t<R> i = 0; i < n; ++i) {
|
||||||
if (!range.push_front()) {
|
range.push_front();
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
range_size_t<R> push_back_n(R &range, range_size_t<R> n) {
|
void push_back_n(R &range, range_size_t<R> n) {
|
||||||
for (range_size_t<R> i = 0; i < n; ++i) {
|
for (range_size_t<R> i = 0; i < n; ++i) {
|
||||||
if (!range.push_back()) {
|
range.push_back();
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename>
|
template<typename>
|
||||||
|
@ -562,23 +551,23 @@ struct input_range {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Size>
|
template<typename Size>
|
||||||
Size pop_front_n(Size n) {
|
void pop_front_n(Size n) {
|
||||||
return detail::pop_front_n<B>(*static_cast<B *>(this), n);
|
detail::pop_front_n<B>(*static_cast<B *>(this), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Size>
|
template<typename Size>
|
||||||
Size pop_back_n(Size n) {
|
void pop_back_n(Size n) {
|
||||||
return detail::pop_back_n<B>(*static_cast<B *>(this), n);
|
detail::pop_back_n<B>(*static_cast<B *>(this), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Size>
|
template<typename Size>
|
||||||
Size push_front_n(Size n) {
|
void push_front_n(Size n) {
|
||||||
return detail::push_front_n<B>(*static_cast<B *>(this), n);
|
detail::push_front_n<B>(*static_cast<B *>(this), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Size>
|
template<typename Size>
|
||||||
Size push_back_n(Size n) {
|
void push_back_n(Size n) {
|
||||||
return detail::push_back_n<B>(*static_cast<B *>(this), n);
|
detail::push_back_n<B>(*static_cast<B *>(this), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
B iter() const {
|
B iter() const {
|
||||||
|
@ -621,30 +610,6 @@ struct input_range {
|
||||||
return range_half<B>(iter());
|
return range_half<B>(iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename OR, typename Size>
|
|
||||||
std::enable_if_t<is_output_range<OR>, Size> copy(OR &&orange, Size n = -1) {
|
|
||||||
B r(*static_cast<B const *>(this));
|
|
||||||
Size on = n;
|
|
||||||
for (; n && !r.empty(); --n) {
|
|
||||||
if (!orange.put(r.front())) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
return (on - n);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Value, typename Size>
|
|
||||||
Size copy(Value *p, Size n = -1) {
|
|
||||||
B r(*static_cast<B const *>(this));
|
|
||||||
Size on = n;
|
|
||||||
for (; n && !r.empty(); --n) {
|
|
||||||
*p++ = r.front();
|
|
||||||
r.pop_front();
|
|
||||||
}
|
|
||||||
return (on - n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* iterator like interface operating on the front part of the range
|
/* iterator like interface operating on the front part of the range
|
||||||
* this is sometimes convenient as it can be used within expressions */
|
* this is sometimes convenient as it can be used within expressions */
|
||||||
|
|
||||||
|
@ -729,15 +694,6 @@ struct output_range {
|
||||||
using range_category = output_range_tag;
|
using range_category = output_range_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
inline range_size_t<R> range_put_n(
|
|
||||||
R &range, range_value_t<R> const *p, range_size_t<R> n
|
|
||||||
) {
|
|
||||||
range_size_t<R> on = n;
|
|
||||||
for (; n && range.put(*p++); --n);
|
|
||||||
return (on - n);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct noop_output_range: output_range<noop_output_range<T>> {
|
struct noop_output_range: output_range<noop_output_range<T>> {
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
@ -745,7 +701,7 @@ struct noop_output_range: output_range<noop_output_range<T>> {
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using difference_type = ptrdiff_t;
|
using difference_type = ptrdiff_t;
|
||||||
|
|
||||||
bool put(T const &) { return true; }
|
void put(T const &) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
|
@ -755,13 +711,6 @@ struct counting_output_range: output_range<counting_output_range<R>> {
|
||||||
using size_type = range_size_t<R>;
|
using size_type = range_size_t<R>;
|
||||||
using difference_type = range_difference_t<R>;
|
using difference_type = range_difference_t<R>;
|
||||||
|
|
||||||
template<typename RR>
|
|
||||||
friend range_size_t<counting_output_range<RR>> range_put_n(
|
|
||||||
counting_output_range<RR> &range,
|
|
||||||
range_value_t<counting_output_range<RR>> *p,
|
|
||||||
range_size_t<counting_output_range<RR>> n
|
|
||||||
);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
R p_range;
|
R p_range;
|
||||||
size_type p_written = 0;
|
size_type p_written = 0;
|
||||||
|
@ -770,15 +719,13 @@ public:
|
||||||
counting_output_range() = delete;
|
counting_output_range() = delete;
|
||||||
counting_output_range(R const &range): p_range(range) {}
|
counting_output_range(R const &range): p_range(range) {}
|
||||||
|
|
||||||
bool put(value_type const &v) {
|
void put(value_type const &v) {
|
||||||
bool ret = p_range.put(v);
|
p_range.put(v);
|
||||||
p_written += ret;
|
++p_written;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
bool put(value_type &&v) {
|
void put(value_type &&v) {
|
||||||
bool ret = p_range.put(std::move(v));
|
p_range.put(std::move(v));
|
||||||
p_written += ret;
|
++p_written;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type get_written() const {
|
size_type get_written() const {
|
||||||
|
@ -786,17 +733,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
inline range_size_t<counting_output_range<R>> range_put_n(
|
|
||||||
counting_output_range<R> &range,
|
|
||||||
range_value_t<counting_output_range<R>> *p,
|
|
||||||
range_size_t<counting_output_range<R>> n
|
|
||||||
) {
|
|
||||||
auto ret = range_put_n(range.p_range, p, n);
|
|
||||||
range.p_written += ret;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
template<typename R>
|
||||||
inline counting_output_range<R> range_counter(R const &range) {
|
inline counting_output_range<R> range_counter(R const &range) {
|
||||||
return counting_output_range<R>{range};
|
return counting_output_range<R>{range};
|
||||||
|
@ -967,23 +903,17 @@ public:
|
||||||
|
|
||||||
bool empty() const { return p_beg == p_end; }
|
bool empty() const { return p_beg == p_end; }
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
if (empty()) {
|
p_beg.next();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return p_beg.next();
|
void push_front() {
|
||||||
|
p_beg.prev();
|
||||||
}
|
}
|
||||||
bool push_front() {
|
void pop_back() {
|
||||||
return p_beg.prev();
|
p_end.prev();
|
||||||
}
|
}
|
||||||
bool pop_back() {
|
void push_back() {
|
||||||
if (empty()) {
|
p_end.next();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return p_end.prev();
|
|
||||||
}
|
|
||||||
bool push_back() {
|
|
||||||
return p_end.next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() const { return *p_beg; }
|
reference front() const { return *p_beg; }
|
||||||
|
@ -1013,11 +943,11 @@ public:
|
||||||
return p_beg[idx];
|
return p_beg[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool put(value_type const &v) {
|
void put(value_type const &v) {
|
||||||
return p_beg.range().put(v);
|
p_beg.range().put(v);
|
||||||
}
|
}
|
||||||
bool put(value_type &&v) {
|
void put(value_type &&v) {
|
||||||
return p_beg.range().put(std::move(v));
|
p_beg.range().put(std::move(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type *data() { return p_beg.data(); }
|
value_type *data() { return p_beg.data(); }
|
||||||
|
@ -1077,17 +1007,17 @@ public:
|
||||||
return -p_range.distance_front(r.p_range);
|
return -p_range.distance_front(r.p_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() { return p_range.pop_back(); }
|
void pop_front() { p_range.pop_back(); }
|
||||||
bool pop_back() { return p_range.pop_front(); }
|
void pop_back() { p_range.pop_front(); }
|
||||||
|
|
||||||
bool push_front() { return p_range.push_back(); }
|
void push_front() { p_range.push_back(); }
|
||||||
bool push_back() { return p_range.push_front(); }
|
void push_back() { p_range.push_front(); }
|
||||||
|
|
||||||
size_type pop_front_n(size_type n) { return p_range.pop_front_n(n); }
|
void pop_front_n(size_type n) { p_range.pop_front_n(n); }
|
||||||
size_type pop_back_n(size_type n) { return p_range.pop_back_n(n); }
|
void pop_back_n(size_type n) { p_range.pop_back_n(n); }
|
||||||
|
|
||||||
size_type push_front_n(size_type n) { return p_range.push_front_n(n); }
|
void push_front_n(size_type n) { p_range.push_front_n(n); }
|
||||||
size_type push_back_n(size_type n) { return p_range.push_back_n(n); }
|
void push_back_n(size_type n) { p_range.push_back_n(n); }
|
||||||
|
|
||||||
reference front() const { return p_range.back(); }
|
reference front() const { return p_range.back(); }
|
||||||
reference back() const { return p_range.front(); }
|
reference back() const { return p_range.front(); }
|
||||||
|
@ -1153,17 +1083,17 @@ public:
|
||||||
return p_range.distance_back(r.p_range);
|
return p_range.distance_back(r.p_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() { return p_range.pop_front(); }
|
void pop_front() { p_range.pop_front(); }
|
||||||
bool pop_back() { return p_range.pop_back(); }
|
void pop_back() { p_range.pop_back(); }
|
||||||
|
|
||||||
bool push_front() { return p_range.push_front(); }
|
void push_front() { p_range.push_front(); }
|
||||||
bool push_back() { return p_range.push_back(); }
|
void push_back() { p_range.push_back(); }
|
||||||
|
|
||||||
size_type pop_front_n(size_type n) { return p_range.pop_front_n(n); }
|
void pop_front_n(size_type n) { p_range.pop_front_n(n); }
|
||||||
size_type pop_back_n(size_type n) { return p_range.pop_back_n(n); }
|
void pop_back_n(size_type n) { p_range.pop_back_n(n); }
|
||||||
|
|
||||||
size_type push_front_n(size_type n) { return p_range.push_front_n(n); }
|
void push_front_n(size_type n) { p_range.push_front_n(n); }
|
||||||
size_type push_back_n(size_type n) { return p_range.push_back_n(n); }
|
void push_back_n(size_type n) { p_range.push_back_n(n); }
|
||||||
|
|
||||||
reference front() const { return std::move(p_range.front()); }
|
reference front() const { return std::move(p_range.front()); }
|
||||||
reference back() const { return std::move(p_range.back()); }
|
reference back() const { return std::move(p_range.back()); }
|
||||||
|
@ -1174,8 +1104,8 @@ public:
|
||||||
return move_range{p_range.slice(start, end)};
|
return move_range{p_range.slice(start, end)};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool put(value_type const &v) { return p_range.put(v); }
|
void put(value_type const &v) { p_range.put(v); }
|
||||||
bool put(value_type &&v) { return p_range.put(std::move(v)); }
|
void put(value_type &&v) { p_range.put(std::move(v)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -1198,7 +1128,7 @@ struct number_range: input_range<number_range<T>> {
|
||||||
return p_a == range.p_a;
|
return p_a == range.p_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() { p_a += p_step; return true; }
|
void pop_front() { p_a += p_step; }
|
||||||
T front() const { return p_a; }
|
T front() const { return p_a; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1277,18 +1207,14 @@ public:
|
||||||
return p_range.equals_front(r.p_range);
|
return p_range.equals_front(r.p_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
if (p_range.pop_front()) {
|
p_range.pop_front();
|
||||||
++p_index;
|
++p_index;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type pop_front_n(size_type n) {
|
void pop_front_n(size_type n) {
|
||||||
size_type ret = p_range.pop_front_n(n);
|
p_range.pop_front_n(n);
|
||||||
p_index += ret;
|
p_index += n;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() const {
|
reference front() const {
|
||||||
|
@ -1333,18 +1259,16 @@ public:
|
||||||
|
|
||||||
bool empty() const { return (p_remaining <= 0) || p_range.empty(); }
|
bool empty() const { return (p_remaining <= 0) || p_range.empty(); }
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
if (p_range.pop_front()) {
|
p_range.pop_front();
|
||||||
|
if (p_remaining >= 1) {
|
||||||
--p_remaining;
|
--p_remaining;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type pop_front_n(size_type n) {
|
void pop_front_n(size_type n) {
|
||||||
size_type ret = p_range.pop_front_n(n);
|
p_range.pop_front_n(n);
|
||||||
p_remaining -= ret;
|
p_remaining -= std::min(n, p_remaining);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() const { return p_range.front(); }
|
reference front() const { return p_range.front(); }
|
||||||
|
@ -1395,9 +1319,9 @@ public:
|
||||||
return p_range.equals_front(r.p_range);
|
return p_range.equals_front(r.p_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() { return p_range.pop_front_n(p_chunksize) > 0; }
|
void pop_front() { p_range.pop_front_n(p_chunksize); }
|
||||||
size_type pop_front_n(size_type n) {
|
void pop_front_n(size_type n) {
|
||||||
return p_range.pop_front_n(p_chunksize * n) / p_chunksize;
|
p_range.pop_front_n(p_chunksize * n);
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() const { return p_range.take(p_chunksize); }
|
reference front() const { return p_range.take(p_chunksize); }
|
||||||
|
@ -1405,14 +1329,14 @@ public:
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<size_t I, size_t N, typename T>
|
template<size_t I, size_t N, typename T>
|
||||||
inline bool join_range_pop(T &tup) {
|
inline void join_range_pop(T &tup) {
|
||||||
if constexpr(I != N) {
|
if constexpr(I != N) {
|
||||||
if (!std::get<I>(tup).empty()) {
|
if (!std::get<I>(tup).empty()) {
|
||||||
return std::get<I>(tup).pop_front();
|
std::get<I>(tup).pop_front();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return join_range_pop<I + 1, N>(tup);
|
join_range_pop<I + 1, N>(tup);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t I, size_t N, typename T>
|
template<size_t I, size_t N, typename T>
|
||||||
|
@ -1423,6 +1347,7 @@ namespace detail {
|
||||||
}
|
}
|
||||||
return join_range_front<I + 1, N>(tup);
|
return join_range_front<I + 1, N>(tup);
|
||||||
}
|
}
|
||||||
|
/* fallback, will probably throw */
|
||||||
return std::get<0>(tup).front();
|
return std::get<0>(tup).front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1471,8 +1396,8 @@ public:
|
||||||
}, p_ranges);
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
return detail::join_range_pop<0, sizeof...(R)>(p_ranges);
|
detail::join_range_pop<0, sizeof...(R)>(p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() const {
|
reference front() const {
|
||||||
|
@ -1539,9 +1464,9 @@ public:
|
||||||
}, p_ranges);
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
return std::apply([](auto &...args) {
|
std::apply([](auto &...args) {
|
||||||
return (... && args.pop_front());
|
(args.pop_front(), ...);
|
||||||
}, p_ranges);
|
}, p_ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1593,14 +1518,12 @@ struct appender_range: output_range<appender_range<T>> {
|
||||||
size_type size() const { return p_data.size(); }
|
size_type size() const { return p_data.size(); }
|
||||||
size_type capacity() const { return p_data.capacity(); }
|
size_type capacity() const { return p_data.capacity(); }
|
||||||
|
|
||||||
bool put(typename T::const_reference v) {
|
void put(typename T::const_reference v) {
|
||||||
p_data.push_back(v);
|
p_data.push_back(v);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool put(typename T::value_type &&v) {
|
void put(typename T::value_type &&v) {
|
||||||
p_data.push_back(std::move(v));
|
p_data.push_back(std::move(v));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
T &get() { return p_data; }
|
T &get() { return p_data; }
|
||||||
|
@ -1691,39 +1614,40 @@ struct iterator_range: input_range<iterator_range<T>> {
|
||||||
/* satisfy input_range / forward_range */
|
/* satisfy input_range / forward_range */
|
||||||
bool empty() const { return p_beg == p_end; }
|
bool empty() const { return p_beg == p_end; }
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
if (p_beg == p_end) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++p_beg;
|
++p_beg;
|
||||||
return true;
|
/* rely on iterators to do their own checks */
|
||||||
|
if constexpr(std::is_pointer_v<T>) {
|
||||||
|
if (p_beg > p_end) {
|
||||||
|
throw std::out_of_range{"pop_front on empty range"};
|
||||||
}
|
}
|
||||||
bool push_front() {
|
}
|
||||||
--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;
|
using IC = typename std::iterator_traits<T>::iterator_category;
|
||||||
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
||||||
size_type olen = size_type(p_end - p_beg);
|
|
||||||
p_beg += n;
|
p_beg += n;
|
||||||
|
/* rely on iterators to do their own checks */
|
||||||
|
if constexpr(std::is_pointer_v<T>) {
|
||||||
if (p_beg > p_end) {
|
if (p_beg > p_end) {
|
||||||
p_beg = p_end;
|
throw std::out_of_range{"pop_front_n of too many elements"};
|
||||||
return olen;
|
}
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
} else {
|
} else {
|
||||||
return detail::pop_front_n(*this, n);
|
detail::pop_front_n(*this, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type push_front_n(size_type n) {
|
void push_front_n(size_type n) {
|
||||||
using IC = typename std::iterator_traits<T>::iterator_category;
|
using IC = typename std::iterator_traits<T>::iterator_category;
|
||||||
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
||||||
p_beg -= n;
|
p_beg -= n;
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
return detail::push_front_n(*this, n);
|
detail::push_front_n(*this, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1738,39 +1662,40 @@ struct iterator_range: input_range<iterator_range<T>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* satisfy bidirectional_range */
|
/* satisfy bidirectional_range */
|
||||||
bool pop_back() {
|
void pop_back() {
|
||||||
|
/* rely on iterators to do their own checks */
|
||||||
|
if constexpr(std::is_pointer_v<T>) {
|
||||||
if (p_end == p_beg) {
|
if (p_end == p_beg) {
|
||||||
return false;
|
throw std::out_of_range{"pop_back on empty range"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
--p_end;
|
--p_end;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
bool push_back() {
|
void push_back() {
|
||||||
++p_end; return true;
|
++p_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type pop_back_n(size_type n) {
|
void pop_back_n(size_type n) {
|
||||||
using IC = typename std::iterator_traits<T>::iterator_category;
|
using IC = typename std::iterator_traits<T>::iterator_category;
|
||||||
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
||||||
size_type olen = size_type(p_end - p_beg);
|
|
||||||
p_end -= n;
|
p_end -= n;
|
||||||
|
/* rely on iterators to do their own checks */
|
||||||
|
if constexpr(std::is_pointer_v<T>) {
|
||||||
if (p_end < p_beg) {
|
if (p_end < p_beg) {
|
||||||
p_end = p_beg;
|
throw std::out_of_range{"pop_back_n of too many elements"};
|
||||||
return olen;
|
}
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
} else {
|
} else {
|
||||||
return detail::pop_back_n(*this, n);
|
detail::pop_back_n(*this, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type push_back_n(size_type n) {
|
void push_back_n(size_type n) {
|
||||||
using IC = typename std::iterator_traits<T>::iterator_category;
|
using IC = typename std::iterator_traits<T>::iterator_category;
|
||||||
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
||||||
p_end += n;
|
p_end += n;
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
return detail::push_back_n(*this, n);
|
detail::push_back_n(*this, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1798,100 +1723,17 @@ struct iterator_range: input_range<iterator_range<T>> {
|
||||||
value_type const *data() const { return p_beg; }
|
value_type const *data() const { return p_beg; }
|
||||||
|
|
||||||
/* satisfy output_range */
|
/* satisfy output_range */
|
||||||
bool put(value_type const &v) {
|
void put(value_type const &v) {
|
||||||
if (empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*(p_beg++) = v;
|
*(p_beg++) = v;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool put(value_type &&v) {
|
|
||||||
if (empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
void put(value_type &&v) {
|
||||||
*(p_beg++) = std::move(v);
|
*(p_beg++) = std::move(v);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
std::enable_if_t<is_output_range<R>, size_type> copy(
|
|
||||||
R &&orange, size_type n = -1
|
|
||||||
) {
|
|
||||||
if constexpr(std::is_pointer_v<T>) {
|
|
||||||
size_type c = size();
|
|
||||||
if (n < c) {
|
|
||||||
c = n;
|
|
||||||
}
|
|
||||||
return range_put_n(orange, p_beg, c);
|
|
||||||
} else {
|
|
||||||
size_type on = n;
|
|
||||||
for (; n && !empty(); --n) {
|
|
||||||
if (!orange.put(front())) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pop_front();
|
|
||||||
}
|
|
||||||
return (on - n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type copy(std::remove_cv_t<value_type> *p, size_type n = -1) {
|
|
||||||
using IC = typename std::iterator_traits<T>::iterator_category;
|
|
||||||
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
|
||||||
size_type c = size();
|
|
||||||
if (n < c) {
|
|
||||||
c = n;
|
|
||||||
}
|
|
||||||
if constexpr(std::is_pointer_v<T> && std::is_pod_v<value_type>) {
|
|
||||||
memcpy(p, p_beg, c * sizeof(value_type));
|
|
||||||
return c;
|
|
||||||
} else {
|
|
||||||
return copy(iterator_range<
|
|
||||||
std::remove_cv_t<value_type> *
|
|
||||||
>(p, p + c), c);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
size_type on = n;
|
|
||||||
for (; n && !empty(); --n) {
|
|
||||||
*p++ = front();
|
|
||||||
pop_front();
|
|
||||||
}
|
|
||||||
return (on - n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
T p_beg, p_end;
|
T p_beg, p_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline auto range_put_n(
|
|
||||||
iterator_range<T> &range, range_value_t<iterator_range<T>> const *p,
|
|
||||||
range_size_t<iterator_range<T>> n
|
|
||||||
) {
|
|
||||||
using IC = typename std::iterator_traits<T>::iterator_category;
|
|
||||||
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
|
|
||||||
using value_type = range_value_t<iterator_range<T>>;
|
|
||||||
auto ret = range.size();
|
|
||||||
if (n < ret) {
|
|
||||||
ret = n;
|
|
||||||
}
|
|
||||||
if constexpr(std::is_pointer_v<T> && std::is_pod_v<value_type>) {
|
|
||||||
memcpy(&range.front(), p, ret * sizeof(value_type));
|
|
||||||
range.pop_front_n(ret);
|
|
||||||
} else {
|
|
||||||
for (auto i = ret; i; --i) {
|
|
||||||
range.front() = *p++;
|
|
||||||
range.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
auto on = n;
|
|
||||||
for (; n && range.put(*p++); --n);
|
|
||||||
return (on - n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
iterator_range<T> make_range(T beg, T end) {
|
iterator_range<T> make_range(T beg, T end) {
|
||||||
return iterator_range<T>{beg, end};
|
return iterator_range<T>{beg, end};
|
||||||
|
|
117
ostd/stream.hh
117
ostd/stream.hh
|
@ -43,32 +43,33 @@ struct stream {
|
||||||
|
|
||||||
virtual offset_type size() {
|
virtual offset_type size() {
|
||||||
offset_type p = tell();
|
offset_type p = tell();
|
||||||
if ((p < 0) || !seek(0, stream_seek::END)) {
|
seek(0, stream_seek::END);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
offset_type e = tell();
|
offset_type e = tell();
|
||||||
return ((p == e) || seek(p, stream_seek::SET)) ? e : -1;
|
if (p == e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
seek(p, stream_seek::SET);
|
||||||
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool seek(offset_type, stream_seek = stream_seek::SET) {
|
virtual void seek(offset_type, stream_seek = stream_seek::SET) {}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual offset_type tell() const { return -1; }
|
virtual offset_type tell() const { return -1; }
|
||||||
|
|
||||||
virtual bool flush() { return true; }
|
virtual void flush() {}
|
||||||
|
|
||||||
virtual size_t read_bytes(void *, size_t) { return 0; }
|
virtual void read_bytes(void *, size_t) {}
|
||||||
virtual size_t write_bytes(void const *, size_t) { return 0; }
|
virtual void write_bytes(void const *, size_t) {}
|
||||||
|
|
||||||
virtual int getchar() {
|
virtual int getchar() {
|
||||||
byte c;
|
byte c;
|
||||||
return (read_bytes(&c, 1) == 1) ? c : -1;
|
read_bytes(&c, 1);
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool putchar(int c) {
|
virtual void putchar(int c) {
|
||||||
byte wc = byte(c);
|
byte wc = byte(c);
|
||||||
return write_bytes(&wc, 1) == 1;
|
write_bytes(&wc, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -83,19 +84,14 @@ struct stream {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void writeln(T const &v) {
|
void writeln(T const &v) {
|
||||||
write(v);
|
write(v);
|
||||||
if (!putchar('\n')) {
|
putchar('\n');
|
||||||
/* consistency with format module */
|
|
||||||
throw format_error{"stream EOF"};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename ...A>
|
template<typename T, typename ...A>
|
||||||
void writeln(T const &v, A const &...args) {
|
void writeln(T const &v, A const &...args) {
|
||||||
write(v);
|
write(v);
|
||||||
write(args...);
|
write(args...);
|
||||||
if (!putchar('\n')) {
|
putchar('\n');
|
||||||
throw format_error{"stream EOF"};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...A>
|
template<typename ...A>
|
||||||
|
@ -104,44 +100,40 @@ struct stream {
|
||||||
template<typename ...A>
|
template<typename ...A>
|
||||||
void writefln(string_range fmt, A const &...args) {
|
void writefln(string_range fmt, A const &...args) {
|
||||||
writef(fmt, args...);
|
writef(fmt, args...);
|
||||||
if (!putchar('\n')) {
|
putchar('\n');
|
||||||
throw format_error{"stream EOF"};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T = char>
|
template<typename T = char>
|
||||||
stream_range<T> iter();
|
stream_range<T> iter();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
size_t put(T const *v, size_t count) {
|
void put(T const *v, size_t count) {
|
||||||
return write_bytes(v, count * sizeof(T)) / sizeof(T);
|
write_bytes(v, count * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool put(T v) {
|
void put(T v) {
|
||||||
return write_bytes(&v, sizeof(T)) == sizeof(T);
|
write_bytes(&v, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
size_t get(T *v, size_t count) {
|
void get(T *v, size_t count) {
|
||||||
return read_bytes(v, count * sizeof(T)) / sizeof(T);
|
read_bytes(v, count * sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool get(T &v) {
|
void get(T &v) {
|
||||||
return read_bytes(&v, sizeof(T)) == sizeof(T);
|
read_bytes(&v, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T get() {
|
T get() {
|
||||||
T r;
|
T r;
|
||||||
return get(r) ? r : T();
|
get(r);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
size_t range_put_n(stream_range<T> &range, T const *p, size_t n);
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct stream_range<T, true>: input_range<stream_range<T>> {
|
struct stream_range<T, true>: input_range<stream_range<T>> {
|
||||||
using range_category = input_range_tag;
|
using range_category = input_range_tag;
|
||||||
|
@ -150,28 +142,28 @@ struct stream_range<T, true>: input_range<stream_range<T>> {
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using difference_type = stream_off_t;
|
using difference_type = stream_off_t;
|
||||||
|
|
||||||
template<typename TT>
|
|
||||||
friend size_t range_put_n(stream_range<TT> &range, TT const *p, size_t n);
|
|
||||||
|
|
||||||
stream_range() = delete;
|
stream_range() = delete;
|
||||||
stream_range(stream &s): p_stream(&s), p_size(s.size()) {}
|
stream_range(stream &s): p_stream(&s), p_size(s.size()) {}
|
||||||
stream_range(stream_range const &r): p_stream(r.p_stream), p_size(r.p_size) {}
|
stream_range(stream_range const &r): p_stream(r.p_stream), p_size(r.p_size) {}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return (p_size - p_stream->tell()) < stream_off_t(sizeof(T));
|
try {
|
||||||
|
auto pos = p_stream->tell();
|
||||||
|
return (p_size - pos) < stream_off_t(sizeof(T));
|
||||||
|
} catch (...) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
if (empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
T val;
|
T val;
|
||||||
return !!p_stream->read_bytes(&val, sizeof(T));
|
p_stream->read_bytes(&val, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
T front() const {
|
T front() const {
|
||||||
T val;
|
T val;
|
||||||
p_stream->seek(-p_stream->read_bytes(&val, sizeof(T)), stream_seek::CUR);
|
p_stream->read_bytes(&val, sizeof(T));
|
||||||
|
p_stream->seek(-sizeof(T), stream_seek::CUR);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,17 +171,9 @@ struct stream_range<T, true>: input_range<stream_range<T>> {
|
||||||
return p_stream->tell() == s.p_stream->tell();
|
return p_stream->tell() == s.p_stream->tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool put(T val) {
|
void put(T val) {
|
||||||
size_t v = p_stream->write_bytes(&val, sizeof(T));
|
p_stream->write_bytes(&val, sizeof(T));
|
||||||
p_size += v;
|
p_size += sizeof(T);
|
||||||
return (v == sizeof(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
|
|
||||||
if (n == size_t(-1)) {
|
|
||||||
n = p_stream->size() / sizeof(T);
|
|
||||||
}
|
|
||||||
return p_stream->get(p, n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -197,11 +181,6 @@ private:
|
||||||
stream_off_t p_size;
|
stream_off_t p_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline size_t range_put_n(stream_range<T> &range, T const *p, size_t n) {
|
|
||||||
return range.p_stream->put(p, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline stream_range<T> stream::iter() {
|
inline stream_range<T> stream::iter() {
|
||||||
return stream_range<T>(*this);
|
return stream_range<T>(*this);
|
||||||
|
@ -215,26 +194,22 @@ namespace detail {
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using difference_type = ptrdiff_t;
|
using difference_type = ptrdiff_t;
|
||||||
|
|
||||||
fmt_stream_range(stream &s): p_s(s) {}
|
fmt_stream_range(stream *s): p_s(s) {}
|
||||||
bool put(char c) {
|
void put(char c) {
|
||||||
return p_s.write_bytes(&c, 1) == 1;
|
p_s->write_bytes(&c, 1);
|
||||||
}
|
}
|
||||||
stream &p_s;
|
stream *p_s;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline size_t range_put_n(fmt_stream_range &range, char const *p, size_t n) {
|
|
||||||
return range.p_s.write_bytes(p, n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void stream::write(T const &v) {
|
inline void stream::write(T const &v) {
|
||||||
format(detail::fmt_stream_range{*this}, format_spec{'s'}, v);
|
format(detail::fmt_stream_range{this}, format_spec{'s'}, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...A>
|
template<typename ...A>
|
||||||
inline void stream::writef(string_range fmt, A const &...args) {
|
inline void stream::writef(string_range fmt, A const &...args) {
|
||||||
format(detail::fmt_stream_range{*this}, fmt, args...);
|
format(detail::fmt_stream_range{this}, fmt, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
141
ostd/string.hh
141
ostd/string.hh
|
@ -77,26 +77,26 @@ public:
|
||||||
|
|
||||||
bool empty() const { return p_beg == p_end; }
|
bool empty() const { return p_beg == p_end; }
|
||||||
|
|
||||||
bool pop_front() {
|
void pop_front() {
|
||||||
if (p_beg == p_end) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++p_beg;
|
++p_beg;
|
||||||
return true;
|
if (p_beg > p_end) {
|
||||||
|
throw std::out_of_range{"pop_front on empty range"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void push_front() {
|
||||||
|
--p_beg;
|
||||||
}
|
}
|
||||||
bool push_front() { --p_beg; return true; }
|
|
||||||
|
|
||||||
size_t pop_front_n(size_t n) {
|
void pop_front_n(size_t n) {
|
||||||
size_t olen = p_end - p_beg;
|
|
||||||
p_beg += n;
|
p_beg += n;
|
||||||
if (p_beg > p_end) {
|
if (p_beg > p_end) {
|
||||||
p_beg = p_end;
|
throw std::out_of_range{"pop_front_n of too many elements"};
|
||||||
return olen;
|
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t push_front_n(size_t n) { p_beg -= n; return true; }
|
void push_front_n(size_t n) {
|
||||||
|
p_beg -= n;
|
||||||
|
}
|
||||||
|
|
||||||
T &front() const { return *p_beg; }
|
T &front() const { return *p_beg; }
|
||||||
|
|
||||||
|
@ -108,26 +108,26 @@ public:
|
||||||
return range.p_beg - p_beg;
|
return range.p_beg - p_beg;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pop_back() {
|
void pop_back() {
|
||||||
if (p_end == p_beg) {
|
if (p_end == p_beg) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
--p_end;
|
--p_end;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
bool push_back() { ++p_end; return true; }
|
void push_back() {
|
||||||
|
++p_end;
|
||||||
|
}
|
||||||
|
|
||||||
size_t pop_back_n(size_t n) {
|
void pop_back_n(size_t n) {
|
||||||
size_t olen = p_end - p_beg;
|
|
||||||
p_end -= n;
|
p_end -= n;
|
||||||
if (p_end < p_beg) {
|
if (p_end < p_beg) {
|
||||||
p_end = p_beg;
|
throw std::out_of_range{"pop_back_n of too many elements"};
|
||||||
return olen;
|
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t push_back_n(size_t n) { p_end += n; return true; }
|
void push_back_n(size_t n) {
|
||||||
|
p_end += n;
|
||||||
|
}
|
||||||
|
|
||||||
T &back() const { return *(p_end - 1); }
|
T &back() const { return *(p_end - 1); }
|
||||||
|
|
||||||
|
@ -147,12 +147,8 @@ public:
|
||||||
|
|
||||||
T &operator[](size_t i) const { return p_beg[i]; }
|
T &operator[](size_t i) const { return p_beg[i]; }
|
||||||
|
|
||||||
bool put(T v) {
|
void put(T v) {
|
||||||
if (empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*(p_beg++) = v;
|
*(p_beg++) = v;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
T *data() { return p_beg; }
|
T *data() { return p_beg; }
|
||||||
|
@ -183,17 +179,6 @@ diffsize:
|
||||||
return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0);
|
return (s1 < s2) ? -1 : ((s1 > s2) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
std::enable_if_t<is_output_range<R>, size_t> copy(R &&orange, size_t n = -1) {
|
|
||||||
return range_put_n(orange, data(), std::min(n, size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
|
|
||||||
size_t c = std::min(n, size());
|
|
||||||
TR::copy(p, data(), c);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* that way we can assign, append etc to std::string */
|
/* that way we can assign, append etc to std::string */
|
||||||
operator std::basic_string_view<std::remove_cv_t<T>>() const {
|
operator std::basic_string_view<std::remove_cv_t<T>>() const {
|
||||||
return std::basic_string_view<std::remove_cv_t<T>>{data(), size()};
|
return std::basic_string_view<std::remove_cv_t<T>>{data(), size()};
|
||||||
|
@ -203,14 +188,6 @@ private:
|
||||||
T *p_beg, *p_end;
|
T *p_beg, *p_end;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename TR>
|
|
||||||
inline size_t range_put_n(basic_char_range<T, TR> &range, T const *p, size_t n) {
|
|
||||||
size_t an = std::min(n, range.size());
|
|
||||||
TR::copy(range.data(), p, an);
|
|
||||||
range.pop_front_n(an);
|
|
||||||
return an;
|
|
||||||
}
|
|
||||||
|
|
||||||
using char_range = basic_char_range<char>;
|
using char_range = basic_char_range<char>;
|
||||||
using string_range = basic_char_range<char const>;
|
using string_range = basic_char_range<char const>;
|
||||||
|
|
||||||
|
@ -461,68 +438,64 @@ namespace detail {
|
||||||
template<typename T, bool B>
|
template<typename T, bool B>
|
||||||
struct ConcatPut<T, true, B> {
|
struct ConcatPut<T, true, B> {
|
||||||
template<typename R>
|
template<typename R>
|
||||||
static bool put(R &sink, string_range v) {
|
static void put(R &sink, string_range v) {
|
||||||
return v.size() && (range_put_n(sink, &v[0], v.size()) == v.size());
|
sink = ostd::copy(v, sink);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct ConcatPut<T, false, true> {
|
struct ConcatPut<T, false, true> {
|
||||||
template<typename R>
|
template<typename R>
|
||||||
static bool put(R &sink, char v) {
|
static void put(R &sink, char v) {
|
||||||
return sink.put(v);
|
sink.put(v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T, typename F>
|
template<typename R, typename T, typename F>
|
||||||
bool concat(R &&sink, T const &v, string_range sep, F func) {
|
R &&concat(R &&sink, T const &v, string_range sep, F func) {
|
||||||
auto range = ostd::iter(v);
|
auto range = ostd::iter(v);
|
||||||
if (range.empty()) {
|
if (range.empty()) {
|
||||||
return true;
|
return std::forward<R>(sink);
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!detail::ConcatPut<
|
detail::ConcatPut<
|
||||||
decltype(func(range.front()))
|
decltype(func(range.front()))
|
||||||
>::put(sink, func(range.front()))) {
|
>::put(sink, func(range.front()));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
range.pop_front();
|
range.pop_front();
|
||||||
if (range.empty()) {
|
if (range.empty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
range_put_n(sink, &sep[0], sep.size());
|
sink = ostd::copy(sep, sink);
|
||||||
}
|
}
|
||||||
return true;
|
return std::forward<R>(sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
bool concat(R &&sink, T const &v, string_range sep = " ") {
|
R &&concat(R &&sink, T const &v, string_range sep = " ") {
|
||||||
auto range = ostd::iter(v);
|
auto range = ostd::iter(v);
|
||||||
if (range.empty()) {
|
if (range.empty()) {
|
||||||
return true;
|
return std::forward<R>(sink);
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
string_range ret = range.front();
|
string_range ret = range.front();
|
||||||
if (!ret.size() || (range_put_n(sink, &ret[0], ret.size()) != ret.size())) {
|
sink = ostd::copy(ret, sink);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
range.pop_front();
|
range.pop_front();
|
||||||
if (range.empty()) {
|
if (range.empty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
range_put_n(sink, &sep[0], sep.size());
|
sink = ostd::copy(sep, sink);
|
||||||
}
|
}
|
||||||
return true;
|
return std::forward<R>(sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T, typename F>
|
template<typename R, typename T, typename F>
|
||||||
bool concat(R &&sink, std::initializer_list<T> v, string_range sep, F func) {
|
R &&concat(R &&sink, std::initializer_list<T> v, string_range sep, F func) {
|
||||||
return concat(sink, ostd::iter(v), sep, func);
|
return concat(sink, ostd::iter(v), sep, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
bool concat(R &&sink, std::initializer_list<T> v, string_range sep = " ") {
|
R &&concat(R &&sink, std::initializer_list<T> v, string_range sep = " ") {
|
||||||
return concat(sink, ostd::iter(v), sep);
|
return concat(sink, ostd::iter(v), sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,34 +507,18 @@ namespace detail {
|
||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using difference_type = ptrdiff_t;
|
using difference_type = ptrdiff_t;
|
||||||
|
|
||||||
template<typename RR>
|
|
||||||
friend size_t range_put_n(tostr_range<RR> &range, char const *p, size_t n);
|
|
||||||
|
|
||||||
tostr_range() = delete;
|
tostr_range() = delete;
|
||||||
tostr_range(R &out): p_out(out), p_written(0) {}
|
tostr_range(R &out): p_out(out) {}
|
||||||
bool put(char v) {
|
void put(char v) {
|
||||||
bool ret = p_out.put(v);
|
p_out.put(v);
|
||||||
p_written += ret;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
size_t put_string(string_range r) {
|
void put_string(string_range r) {
|
||||||
size_t ret = range_put_n(p_out, r.data(), r.size());
|
p_out = ostd::copy(r, p_out);
|
||||||
p_written += ret;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
size_t get_written() const { return p_written; }
|
|
||||||
private:
|
private:
|
||||||
R &p_out;
|
R &p_out;
|
||||||
size_t p_written;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
inline size_t range_put_n(tostr_range<R> &range, char const *p, size_t n) {
|
|
||||||
size_t ret = range_put_n(range.p_out, p, n);
|
|
||||||
range.p_written += ret;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename R>
|
template<typename T, typename R>
|
||||||
static std::true_type test_stringify(
|
static std::true_type test_stringify(
|
||||||
decltype(std::declval<T const &>().to_string(std::declval<R &>())) *
|
decltype(std::declval<T const &>().to_string(std::declval<R &>())) *
|
||||||
|
@ -590,13 +547,12 @@ struct to_string<T, std::enable_if_t<detail::iterable_test<T>>> {
|
||||||
std::string operator()(T const &v) const {
|
std::string operator()(T const &v) const {
|
||||||
std::string ret("{");
|
std::string ret("{");
|
||||||
auto x = appender_range<std::string>{};
|
auto x = appender_range<std::string>{};
|
||||||
if (concat(x, ostd::iter(v), ", ", to_string<
|
concat(x, ostd::iter(v), ", ", to_string<
|
||||||
std::remove_const_t<std::remove_reference_t<
|
std::remove_const_t<std::remove_reference_t<
|
||||||
range_reference_t<decltype(ostd::iter(v))>
|
range_reference_t<decltype(ostd::iter(v))>
|
||||||
>>
|
>>
|
||||||
>())) {
|
>());
|
||||||
ret += x.get();
|
ret += x.get();
|
||||||
}
|
|
||||||
ret += "}";
|
ret += "}";
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -778,7 +734,8 @@ public:
|
||||||
} else {
|
} else {
|
||||||
p_buf = sbuf;
|
p_buf = sbuf;
|
||||||
}
|
}
|
||||||
p_buf[input.copy(p_buf)] = '\0';
|
char_range bufr{p_buf, p_buf + input.size()};
|
||||||
|
ostd::copy(input, bufr).put('\0');
|
||||||
}
|
}
|
||||||
~temp_c_string() {
|
~temp_c_string() {
|
||||||
if (p_allocated) {
|
if (p_allocated) {
|
||||||
|
|
Loading…
Reference in a new issue