start cleaning up the range system for nicer syntax

master
Daniel Kolesa 2017-02-13 23:04:02 +01:00
parent 21da5ec3d1
commit 08e980cd0a
7 changed files with 333 additions and 255 deletions

View File

@ -776,9 +776,13 @@ inline auto foldr_f(T &&init, F &&func) {
}
template<typename T, typename F, typename R>
struct MapRange: InputRange<
MapRange<T, F, R>, RangeCategory<T>, R, R, RangeSize<T>
> {
struct MapRange: InputRange<MapRange<T, F, R>> {
using Category = RangeCategory<T>;
using Value = R;
using Reference = R;
using Size = RangeSize<T>;
using Difference = RangeDifference<T>;
private:
T p_range;
std::decay_t<F> p_func;
@ -873,10 +877,13 @@ inline auto map(F &&func) {
}
template<typename T, typename F>
struct FilterRange: InputRange<
FilterRange<T, F>, std::common_type_t<RangeCategory<T>, ForwardRangeTag>,
RangeValue<T>, RangeReference<T>, RangeSize<T>
> {
struct FilterRange: InputRange<FilterRange<T, F>> {
using Category = std::common_type_t<RangeCategory<T>, ForwardRangeTag>;
using Value = RangeValue<T>;
using Reference = RangeReference<T>;
using Size = RangeSize<T>;
using Difference = RangeDifference<T>;
private:
T p_range;
std::decay_t<F> p_pred;

View File

@ -530,9 +530,13 @@ inline void swap(DirectoryStream &a, DirectoryStream &b) {
a.swap(b);
}
struct DirectoryRange: InputRange<
DirectoryRange, InputRangeTag, FileInfo, FileInfo, size_t, long
> {
struct DirectoryRange: InputRange<DirectoryRange> {
using Category = InputRangeTag;
using Value = FileInfo;
using Reference = FileInfo;
using Size = size_t;
using Difference = long;
DirectoryRange() = delete;
DirectoryRange(DirectoryStream &s): p_stream(&s) {}
DirectoryRange(DirectoryRange const &r): p_stream(r.p_stream) {}

View File

@ -214,8 +214,8 @@ struct FormatSpec {
if (p_flags & FMT_FLAG_HASH ) {
ret += out.put('#');
}
ret += out.put_n("*.*", 3);
ret += out.put_n(&spec[0], spec.size());
ret += range_put_n(out, "*.*", 3);
ret += range_put_n(out, &spec[0], spec.size());
return ret;
}
@ -488,7 +488,7 @@ namespace detail {
if (sign) {
writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
}
writer.put_n(pfx, pfxlen);
range_put_n(writer, pfx, pfxlen);
if (zero) {
r += fl->write_spaces(writer, n + pfxlen + sign, true, '0');
}
@ -581,7 +581,7 @@ namespace detail {
range.pop_front();
/* write the rest (if any) */
for (; !range.empty(); range.pop_front()) {
ret += writer.put_n(&sep[0], sep.size());
ret += range_put_n(writer, &sep[0], sep.size());
ret += format_ritem(
writer, escape, expandval, fl->rest(), range.front()
);
@ -672,7 +672,7 @@ namespace detail {
}
size_t r = n;
r += this->write_spaces(writer, n, true);
writer.put_n(&val[0], n);
range_put_n(writer, &val[0], n);
r += this->write_spaces(writer, n, false);
return r;
}
@ -746,10 +746,10 @@ namespace detail {
/* see above */
throw format_error{"invalid float format"};
}
writer.put_n(dbuf, ret);
range_put_n(writer, dbuf, ret);
delete[] dbuf;
} else {
writer.put_n(rbuf, ret);
range_put_n(writer, rbuf, ret);
}
return ret;
}

View File

@ -152,15 +152,21 @@ static FileStream err(stderr);
namespace detail {
/* lightweight output range for direct stdout */
struct StdoutRange: OutputRange<StdoutRange, char> {
struct StdoutRange: OutputRange<StdoutRange> {
using Value = char;
using Reference = char &;
using Size = size_t;
using Difference = ptrdiff_t;
StdoutRange() {}
bool put(char c) {
return putchar(c) != EOF;
}
size_t put_n(char const *p, size_t n) {
return fwrite(p, 1, n, stdout);
}
};
inline size_t range_put_n(StdoutRange &, char const *p, size_t n) {
return fwrite(p, 1, n, stdout);
}
}
template<typename T>

View File

@ -542,17 +542,8 @@ struct JoinRange;
template<typename ...>
struct ZipRange;
template<
typename B, typename C, typename V, typename R = V &,
typename S = size_t, typename D = ptrdiff_t
>
template<typename B>
struct InputRange {
using Category = C;
using Size = S;
using Difference = D;
using Value = V;
using Reference = R;
detail::RangeIterator<B> begin() const {
return detail::RangeIterator<B>(*static_cast<B const *>(this));
}
@ -560,18 +551,22 @@ struct InputRange {
return detail::RangeIterator<B>();
}
template<typename Size>
Size pop_front_n(Size n) {
return 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);
}
template<typename Size>
Size push_front_n(Size n) {
return 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);
}
@ -592,10 +587,12 @@ struct InputRange {
return EnumeratedRange<B>(iter());
}
template<typename Size>
TakeRange<B> take(Size n) const {
return TakeRange<B>(iter(), n);
}
template<typename Size>
ChunksRange<B> chunks(Size n) const {
return ChunksRange<B>(iter(), n);
}
@ -614,14 +611,7 @@ struct InputRange {
return RangeHalf<B>(iter());
}
Size put_n(Value const *p, Size n) {
B &r = *static_cast<B *>(this);
Size on = n;
for (; n && r.put(*p++); --n);
return (on - n);
}
template<typename OR>
template<typename OR, typename Size>
std::enable_if_t<IsOutputRange<OR>, Size> copy(OR &&orange, Size n = -1) {
B r(*static_cast<B const *>(this));
Size on = n;
@ -634,7 +624,8 @@ struct InputRange {
return (on - n);
}
Size copy(std::remove_cv_t<Value> *p, Size n = -1) {
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) {
@ -647,8 +638,10 @@ struct InputRange {
/* iterator like interface operating on the front part of the range
* this is sometimes convenient as it can be used within expressions */
Reference operator*() const {
return std::forward<Reference>(static_cast<B const *>(this)->front());
auto operator*() const {
return std::forward<decltype(static_cast<B const *>(this)->front())>(
static_cast<B const *>(this)->front()
);
}
B &operator++() {
@ -671,21 +664,25 @@ struct InputRange {
return tmp;
}
template<typename Difference>
B operator+(Difference n) const {
B tmp(*static_cast<B const *>(this));
tmp.pop_front_n(n);
return tmp;
}
template<typename Difference>
B operator-(Difference n) const {
B tmp(*static_cast<B const *>(this));
tmp.push_front_n(n);
return tmp;
}
template<typename Difference>
B &operator+=(Difference n) {
static_cast<B *>(this)->pop_front_n(n);
return *static_cast<B *>(this);
}
template<typename Difference>
B &operator-=(Difference n) {
static_cast<B *>(this)->push_front_n(n);
return *static_cast<B *>(this);
@ -717,6 +714,20 @@ struct InputRange {
}
};
template<typename B>
struct OutputRange {
using Category = OutputRangeTag;
};
template<typename R>
inline RangeSize<R> range_put_n(
R &range, RangeValue<R> const *p, RangeSize<R> n
) {
RangeSize<R> on = n;
for (; n && range.put(*p++); --n);
return (on - n);
}
inline auto reverse() {
return [](auto &&obj) { return obj.reverse(); };
}
@ -839,37 +850,19 @@ inline auto citer(T const &r) -> decltype(ranged_traits<T const>::iter(r)) {
return ranged_traits<T const>::iter(r);
}
template<
typename B, typename V, typename R = V &,
typename S = size_t, typename D = ptrdiff_t
>
struct OutputRange {
using Category = OutputRangeTag;
using Size = S;
using Difference = D;
using Value = V;
using Reference = R;
Size put_n(Value const *p, Size n) {
B &r = *static_cast<B *>(this);
Size on = n;
for (; n && r.put(*p++); --n);
return (on - n);
}
};
template<typename T>
struct HalfRange: InputRange<HalfRange<T>,
RangeCategory<typename T::Range>,
RangeValue<typename T::Range>,
RangeReference<typename T::Range>,
RangeSize<typename T::Range>,
RangeDifference<typename T::Range>
> {
struct HalfRange: InputRange<HalfRange<T>> {
using Category = RangeCategory <typename T::Range>;
using Value = RangeValue <typename T::Range>;
using Reference = RangeReference <typename T::Range>;
using Size = RangeSize <typename T::Range>;
using Difference = RangeDifference<typename T::Range>;
private:
using Rtype = typename T::Range;
T p_beg;
T p_end;
public:
HalfRange() = delete;
HalfRange(HalfRange const &range):
@ -957,14 +950,16 @@ public:
};
template<typename T>
struct ReverseRange: InputRange<ReverseRange<T>,
std::common_type_t<RangeCategory<T>, FiniteRandomAccessRangeTag>,
RangeValue<T>, RangeReference<T>, RangeSize<T>, RangeDifference<T>
> {
private:
using Rref = RangeReference<T>;
using Rsize = RangeSize<T>;
struct ReverseRange: InputRange<ReverseRange<T>> {
using Category = std::common_type_t<
RangeCategory<T>, FiniteRandomAccessRangeTag
>;
using Value = RangeValue <T>;
using Reference = RangeReference <T>;
using Size = RangeSize <T>;
using Difference = RangeDifference<T>;
private:
T p_range;
public:
@ -991,7 +986,7 @@ public:
}
bool empty() const { return p_range.empty(); }
Rsize size() const { return p_range.size(); }
Size size() const { return p_range.size(); }
bool equals_front(ReverseRange const &r) const {
return p_range.equals_back(r.p_range);
@ -1013,33 +1008,34 @@ public:
bool push_front() { return p_range.push_back(); }
bool push_back() { return p_range.push_front(); }
Rsize pop_front_n(Rsize n) { return p_range.pop_front_n(n); }
Rsize pop_back_n(Rsize n) { return p_range.pop_back_n(n); }
Size pop_front_n(Size n) { return p_range.pop_front_n(n); }
Size pop_back_n(Size n) { return p_range.pop_back_n(n); }
Rsize push_front_n(Rsize n) { return p_range.push_front_n(n); }
Rsize push_back_n(Rsize n) { return p_range.push_back_n(n); }
Size push_front_n(Size n) { return p_range.push_front_n(n); }
Size push_back_n(Size n) { return p_range.push_back_n(n); }
Rref front() const { return p_range.back(); }
Rref back() const { return p_range.front(); }
Reference front() const { return p_range.back(); }
Reference back() const { return p_range.front(); }
Rref operator[](Rsize i) const { return p_range[size() - i - 1]; }
Reference operator[](Size i) const { return p_range[size() - i - 1]; }
ReverseRange<T> slice(Rsize start, Rsize end) const {
Rsize len = p_range.size();
ReverseRange<T> slice(Size start, Size end) const {
Size len = p_range.size();
return ReverseRange<T>(p_range.slice(len - end, len - start));
}
};
template<typename T>
struct MoveRange: InputRange<MoveRange<T>,
std::common_type_t<RangeCategory<T>, FiniteRandomAccessRangeTag>,
RangeValue<T>, RangeValue<T> &&, RangeSize<T>, RangeDifference<T>
> {
private:
using Rval = RangeValue<T>;
using Rref = RangeValue<T> &&;
using Rsize = RangeSize<T>;
struct MoveRange: InputRange<MoveRange<T>> {
using Category = std::common_type_t<
RangeCategory<T>, FiniteRandomAccessRangeTag
>;
using Value = RangeValue <T>;
using Reference = RangeValue <T> &&;
using Size = RangeSize <T>;
using Difference = RangeDifference<T>;
private:
T p_range;
public:
@ -1066,7 +1062,7 @@ public:
}
bool empty() const { return p_range.empty(); }
Rsize size() const { return p_range.size(); }
Size size() const { return p_range.size(); }
bool equals_front(MoveRange const &r) const {
return p_range.equals_front(r.p_range);
@ -1088,27 +1084,33 @@ public:
bool push_front() { return p_range.push_front(); }
bool push_back() { return p_range.push_back(); }
Rsize pop_front_n(Rsize n) { return p_range.pop_front_n(n); }
Rsize pop_back_n(Rsize n) { return p_range.pop_back_n(n); }
Size pop_front_n(Size n) { return p_range.pop_front_n(n); }
Size pop_back_n(Size n) { return p_range.pop_back_n(n); }
Rsize push_front_n(Rsize n) { return p_range.push_front_n(n); }
Rsize push_back_n(Rsize n) { return p_range.push_back_n(n); }
Size push_front_n(Size n) { return p_range.push_front_n(n); }
Size push_back_n(Size n) { return p_range.push_back_n(n); }
Rref front() const { return std::move(p_range.front()); }
Rref back() const { return std::move(p_range.back()); }
Reference front() const { return std::move(p_range.front()); }
Reference back() const { return std::move(p_range.back()); }
Rref operator[](Rsize i) const { return std::move(p_range[i]); }
Reference operator[](Size i) const { return std::move(p_range[i]); }
MoveRange<T> slice(Rsize start, Rsize end) const {
MoveRange<T> slice(Size start, Size end) const {
return MoveRange<T>(p_range.slice(start, end));
}
bool put(Rval const &v) { return p_range.put(v); }
bool put(Rval &&v) { return p_range.put(std::move(v)); }
bool put(Value const &v) { return p_range.put(v); }
bool put(Value &&v) { return p_range.put(std::move(v)); }
};
template<typename T>
struct NumberRange: InputRange<NumberRange<T>, ForwardRangeTag, T, T> {
struct NumberRange: InputRange<NumberRange<T>> {
using Category = ForwardRangeTag;
using Value = T;
using Reference = T;
using Size = size_t;
using Difference = ptrdiff_t;
NumberRange() = delete;
NumberRange(T a, T b, T step = T(1)):
p_a(a), p_b(b), p_step(step)
@ -1139,7 +1141,13 @@ inline NumberRange<T> range(T v) {
}
template<typename T>
struct PointerRange: InputRange<PointerRange<T>, ContiguousRangeTag, T> {
struct PointerRange: InputRange<PointerRange<T>> {
using Category = ContiguousRangeTag;
using Value = T;
using Reference = T &;
using Size = size_t;
using Difference = ptrdiff_t;
private:
struct Nat {};
@ -1257,29 +1265,13 @@ public:
return true;
}
size_t put_n(T const *p, size_t n) {
size_t ret = size();
if (n < ret) {
ret = n;
}
if constexpr(std::is_pod_v<T>) {
memcpy(p_beg, p, ret * sizeof(T));
p_beg += ret;
return ret;
}
for (size_t i = ret; i; --i) {
*p_beg++ = *p++;
}
return ret;
}
template<typename R>
std::enable_if_t<IsOutputRange<R>, size_t> copy(R &&orange, size_t n = -1) {
size_t c = size();
if (n < c) {
c = n;
}
return orange.put_n(p_beg, c);
return range_put_n(orange, p_beg, c);
}
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
@ -1301,6 +1293,24 @@ private:
T *p_beg, *p_end;
};
template<typename T>
inline size_t range_put_n(PointerRange<T> &range, T const *p, size_t n) {
size_t ret = range.size();
if (n < ret) {
ret = n;
}
if constexpr(std::is_pod_v<T>) {
memcpy(&range.front(), p, ret * sizeof(T));
range.pop_front_n(ret);
return ret;
}
for (size_t i = ret; i; --i) {
range.front() = *p++;
range.pop_front();
}
return ret;
}
template<typename T, size_t N>
struct ranged_traits<T[N]> {
static PointerRange<T> iter(T (&array)[N]) {
@ -1332,17 +1342,16 @@ struct EnumeratedValue {
};
template<typename T>
struct EnumeratedRange: InputRange<EnumeratedRange<T>,
std::common_type_t<RangeCategory<T>, ForwardRangeTag>, RangeValue<T>,
EnumeratedValue<RangeReference<T>, RangeSize<T>>,
RangeSize<T>
> {
private:
using Rref = RangeReference<T>;
using Rsize = RangeSize<T>;
struct EnumeratedRange: InputRange<EnumeratedRange<T>> {
using Category = std::common_type_t<RangeCategory<T>, ForwardRangeTag>;
using Value = RangeValue<T>;
using Reference = EnumeratedValue<RangeReference<T>, RangeSize<T>>;
using Size = RangeSize<T>;
using Difference = RangeDifference<T>;
private:
T p_range;
Rsize p_index;
Size p_index;
public:
EnumeratedRange() = delete;
@ -1392,25 +1401,29 @@ public:
return false;
}
Rsize pop_front_n(Rsize n) {
Rsize ret = p_range.pop_front_n(n);
Size pop_front_n(Size n) {
Size ret = p_range.pop_front_n(n);
p_index += ret;
return ret;
}
EnumeratedValue<Rref, Rsize> front() const {
return EnumeratedValue<Rref, Rsize> { p_index, p_range.front() };
Reference front() const {
return Reference{p_index, p_range.front()};
}
};
template<typename T>
struct TakeRange: InputRange<TakeRange<T>,
std::common_type_t<RangeCategory<T>, ForwardRangeTag>,
RangeValue<T>, RangeReference<T>, RangeSize<T>
> {
struct TakeRange: InputRange<TakeRange<T>> {
using Category = std::common_type_t<RangeCategory<T>, ForwardRangeTag>;
using Value = RangeValue <T>;
using Reference = RangeReference <T>;
using Size = RangeSize <T>;
using Difference = RangeDifference<T>;
private:
T p_range;
RangeSize<T> p_remaining;
Size p_remaining;
public:
TakeRange() = delete;
TakeRange(T const &range, RangeSize<T> rem):
@ -1442,13 +1455,13 @@ public:
return false;
}
RangeSize<T> pop_front_n(RangeSize<T> n) {
RangeSize<T> ret = p_range.pop_front_n(n);
Size pop_front_n(Size n) {
Size ret = p_range.pop_front_n(n);
p_remaining -= ret;
return ret;
}
RangeReference<T> front() const { return p_range.front(); }
Reference front() const { return p_range.front(); }
bool equals_front(TakeRange const &r) const {
return p_range.equals_front(r.p_range);
@ -1456,13 +1469,17 @@ public:
};
template<typename T>
struct ChunksRange: InputRange<ChunksRange<T>,
std::common_type_t<RangeCategory<T>, ForwardRangeTag>,
TakeRange<T>, TakeRange<T>, RangeSize<T>
> {
struct ChunksRange: InputRange<ChunksRange<T>> {
using Category = std::common_type_t<RangeCategory<T>, ForwardRangeTag>;
using Value = TakeRange <T>;
using Reference = TakeRange <T>;
using Size = RangeSize <T>;
using Difference = RangeDifference<T>;
private:
T p_range;
RangeSize<T> p_chunksize;
Size p_chunksize;
public:
ChunksRange() = delete;
ChunksRange(T const &range, RangeSize<T> chs):
@ -1491,11 +1508,11 @@ public:
}
bool pop_front() { return p_range.pop_front_n(p_chunksize) > 0; }
RangeSize<T> pop_front_n(RangeSize<T> n) {
Size pop_front_n(Size n) {
return p_range.pop_front_n(p_chunksize * n) / p_chunksize;
}
TakeRange<T> front() const { return p_range.take(p_chunksize); }
Reference front() const { return p_range.take(p_chunksize); }
};
namespace detail {
@ -1523,12 +1540,16 @@ namespace detail {
}
template<typename ...R>
struct JoinRange: InputRange<JoinRange<R...>,
std::common_type_t<ForwardRangeTag, RangeCategory<R>...>,
std::common_type_t<RangeValue<R>...>, std::common_type_t<RangeReference<R>...>,
std::common_type_t<RangeSize<R>...>, std::common_type_t<RangeDifference<R>...>> {
struct JoinRange: InputRange<JoinRange<R...>> {
using Category = std::common_type_t<ForwardRangeTag, RangeCategory<R>...>;
using Value = std::common_type_t<RangeValue<R>...>;
using Reference = std::common_type_t<RangeReference<R>...>;
using Size = std::common_type_t<RangeSize<R>...>;
using Difference = std::common_type_t<RangeDifference<R>...>;
private:
std::tuple<R...> p_ranges;
public:
JoinRange() = delete;
JoinRange(R const &...ranges): p_ranges(ranges...) {}
@ -1585,14 +1606,16 @@ namespace detail {
}
template<typename ...R>
struct ZipRange: InputRange<ZipRange<R...>,
std::common_type_t<ForwardRangeTag, RangeCategory<R>...>,
detail::ZipValue<RangeValue<R>...>,
detail::ZipValue<RangeReference<R>...>,
std::common_type_t<RangeSize<R>...>,
std::common_type_t<RangeDifference<R>...>> {
struct ZipRange: InputRange<ZipRange<R...>> {
using Category = std::common_type_t<ForwardRangeTag, RangeCategory<R>...>;
using Value = detail::ZipValue<RangeValue<R>...>;
using Reference = detail::ZipValue<RangeReference<R>...>;
using Size = std::common_type_t<RangeSize<R>...>;
using Difference = std::common_type_t<RangeDifference<R>...>;
private:
std::tuple<R...> p_ranges;
public:
ZipRange() = delete;
ZipRange(R const &...ranges): p_ranges(ranges...) {}
@ -1638,8 +1661,12 @@ public:
};
template<typename T>
struct AppenderRange: OutputRange<AppenderRange<T>, typename T::value_type,
typename T::reference, typename T::size_type, typename T::difference_type> {
struct AppenderRange: OutputRange<AppenderRange<T>> {
using Value = typename T::value_type;
using Reference = typename T::reference;
using Size = typename T::size_type;
using Difference = typename T::difference_type;
AppenderRange(): p_data() {}
AppenderRange(T const &v): p_data(v) {}
AppenderRange(T &&v): p_data(std::move(v)) {}
@ -1731,25 +1758,19 @@ template<typename T>
using IteratorRangeTag = typename detail::IteratorRangeTagBase<T>::Type;
template<typename T>
struct IteratorRange: InputRange<
IteratorRange<T>,
std::conditional_t<
struct IteratorRange: InputRange<IteratorRange<T>> {
using Category = std::conditional_t<
std::is_pointer_v<T>,
ContiguousRangeTag,
IteratorRangeTag<typename std::iterator_traits<T>::iterator_category>
>,
typename std::iterator_traits<T>::value_type,
typename std::iterator_traits<T>::reference,
std::make_unsigned_t<typename std::iterator_traits<T>::difference_type>,
typename std::iterator_traits<T>::difference_type
> {
private:
using ValT = typename std::iterator_traits<T>::value_type;
using RefT = typename std::iterator_traits<T>::reference;
using DiffT = typename std::iterator_traits<T>::difference_type;
using SizeT = std::make_unsigned_t<typename std::iterator_traits<T>::difference_type>;
>;
using Value = typename std::iterator_traits<T>::value_type;
using Reference = typename std::iterator_traits<T>::reference;
using Size = std::make_unsigned_t<
typename std::iterator_traits<T>::difference_type
>;
using Difference = typename std::iterator_traits<T>::difference_type;
public:
IteratorRange(T beg = T{}, T end = T{}): p_beg(beg), p_end(end) {}
template<typename U, typename = std::enable_if_t<
@ -1789,10 +1810,10 @@ public:
--p_beg; return true;
}
SizeT pop_front_n(SizeT n) {
Size pop_front_n(Size n) {
using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
SizeT olen = SizeT(p_end - p_beg);
Size olen = Size(p_end - p_beg);
p_beg += n;
if (p_beg > p_end) {
p_beg = p_end;
@ -1804,7 +1825,7 @@ public:
}
}
SizeT push_front_n(SizeT n) {
Size push_front_n(Size 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;
@ -1814,13 +1835,13 @@ public:
}
}
RefT front() const { return *p_beg; }
Reference front() const { return *p_beg; }
bool equals_front(IteratorRange const &range) const {
return p_beg == range.p_beg;
}
DiffT distance_front(IteratorRange const &range) const {
Difference distance_front(IteratorRange const &range) const {
return range.p_beg - p_beg;
}
@ -1836,10 +1857,10 @@ public:
++p_end; return true;
}
SizeT pop_back_n(SizeT n) {
Size pop_back_n(Size n) {
using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
SizeT olen = SizeT(p_end - p_beg);
Size olen = Size(p_end - p_beg);
p_end -= n;
if (p_end < p_beg) {
p_end = p_beg;
@ -1851,7 +1872,7 @@ public:
}
}
SizeT push_back_n(SizeT n) {
Size push_back_n(Size 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;
@ -1861,7 +1882,7 @@ public:
}
}
RefT back() const { return *(p_end - 1); }
Reference back() const { return *(p_end - 1); }
bool equals_back(IteratorRange const &range) const {
return p_end == range.p_end;
@ -1872,13 +1893,13 @@ public:
}
/* satisfy FiniteRandomAccessRange */
SizeT size() const { return SizeT(p_end - p_beg); }
Size size() const { return Size(p_end - p_beg); }
IteratorRange slice(SizeT start, SizeT end) const {
IteratorRange slice(Size start, Size end) const {
return IteratorRange(p_beg + start, p_beg + end);
}
RefT operator[](SizeT i) const { return p_beg[i]; }
Reference operator[](Size i) const { return p_beg[i]; }
/* satisfy OutputRange */
bool put(T const &v) {
@ -1896,39 +1917,16 @@ public:
return true;
}
SizeT put_n(ValT const *p, SizeT n) {
using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
SizeT ret = size();
if (n < ret) {
ret = n;
}
if constexpr(std::is_pointer_v<T> && std::is_pod_v<ValT>) {
memcpy(p_beg, p, ret * sizeof(ValT));
p_beg += ret;
} else {
for (SizeT i = ret; i; --i) {
*p_beg++ = *p++;
}
}
return ret;
} else {
SizeT on = n;
for (; n && put(*p++); --n);
return (on - n);
}
}
template<typename R>
std::enable_if_t<IsOutputRange<R>, SizeT> copy(R &&orange, SizeT n = -1) {
std::enable_if_t<IsOutputRange<R>, Size> copy(R &&orange, Size n = -1) {
if constexpr(std::is_pointer_v<T>) {
SizeT c = size();
Size c = size();
if (n < c) {
c = n;
}
return orange.put_n(p_beg, c);
return range_put_n(orange, p_beg, c);
} else {
SizeT on = n;
Size on = n;
for (; n && !empty(); --n) {
if (!orange.put(front())) {
break;
@ -1939,21 +1937,21 @@ public:
}
}
SizeT copy(std::remove_cv_t<ValT> *p, SizeT n = -1) {
Size copy(std::remove_cv_t<Value> *p, Size n = -1) {
using IC = typename std::iterator_traits<T>::iterator_category;
if constexpr(std::is_convertible_v<IC, std::random_access_iterator_tag>) {
SizeT c = size();
Size c = size();
if (n < c) {
c = n;
}
if constexpr(std::is_pointer_v<T> && std::is_pod_v<ValT>) {
memcpy(p, p_beg, c * sizeof(ValT));
if constexpr(std::is_pointer_v<T> && std::is_pod_v<Value>) {
memcpy(p, p_beg, c * sizeof(Value));
return c;
} else {
return copy(IteratorRange<std::remove_cv_t<ValT> *>(p, p + c), c);
return copy(IteratorRange<std::remove_cv_t<Value> *>(p, p + c), c);
}
} else {
SizeT on = n;
Size on = n;
for (; n && !empty(); --n) {
*p++ = front();
pop_front();
@ -1965,6 +1963,35 @@ private:
T p_beg, p_end;
};
template<typename T>
inline RangeSize<IteratorRange<T>> range_put_n(
IteratorRange<T> &range, RangeValue<IteratorRange<T>> const *p,
RangeSize<IteratorRange<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 = RangeValue<IteratorRange<T>>;
auto ret = range.size();
if (n < ret) {
ret = n;
}
if constexpr(std::is_pointer_v<T> && std::is_pod_v<Value>) {
memcpy(&range.front(), p, ret * sizeof(Value));
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>
IteratorRange<T> make_range(T beg, T end) {
return IteratorRange<T>{beg, end};

View File

@ -141,9 +141,19 @@ struct Stream {
};
template<typename T>
struct StreamRange<T, true>: InputRange<
StreamRange<T>, InputRangeTag, T, T, size_t, StreamOffset
> {
size_t range_put_n(StreamRange<T> &range, T const *p, size_t n);
template<typename T>
struct StreamRange<T, true>: InputRange<StreamRange<T>> {
using Category = InputRangeTag;
using Value = T;
using Reference = T;
using Size = size_t;
using Difference = StreamOffset;
template<typename TT>
friend size_t range_put_n(StreamRange<TT> &range, TT const *p, size_t n);
StreamRange() = delete;
StreamRange(Stream &s): p_stream(&s), p_size(s.size()) {}
StreamRange(StreamRange const &r): p_stream(r.p_stream), p_size(r.p_size) {}
@ -176,10 +186,6 @@ struct StreamRange<T, true>: InputRange<
return (v == sizeof(T));
}
size_t put_n(T const *p, size_t n) {
return p_stream->put(p, n);
}
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
if (n == size_t(-1)) {
n = p_stream->size() / sizeof(T);
@ -192,6 +198,11 @@ private:
StreamOffset p_size;
};
template<typename T>
inline size_t range_put_n(StreamRange<T> &range, T const *p, size_t n) {
return range.p_stream->put(p, n);
}
template<typename T>
inline StreamRange<T> Stream::iter() {
return StreamRange<T>(*this);
@ -199,16 +210,22 @@ inline StreamRange<T> Stream::iter() {
namespace detail {
/* lightweight output range for write/writef on streams */
struct FmtStreamRange: OutputRange<FmtStreamRange, char> {
struct FmtStreamRange: OutputRange<FmtStreamRange> {
using Value = char;
using Reference = char &;
using Size = size_t;
using Difference = ptrdiff_t;
FmtStreamRange(Stream &s): p_s(s) {}
bool put(char c) {
return p_s.write_bytes(&c, 1) == 1;
}
size_t put_n(char const *p, size_t n) {
return p_s.write_bytes(p, n);
}
Stream &p_s;
};
inline size_t range_put_n(FmtStreamRange &range, char const *p, size_t n) {
return range.p_s.write_bytes(p, n);
}
}
template<typename T>

View File

@ -23,9 +23,13 @@
namespace ostd {
template<typename T, typename TR = std::char_traits<std::remove_const_t<T>>>
struct CharRangeBase: InputRange<
CharRangeBase<T>, ContiguousRangeTag, T
> {
struct CharRangeBase: InputRange<CharRangeBase<T>> {
using Category = ContiguousRangeTag;
using Value = T;
using Reference = T &;
using Size = size_t;
using Difference = ptrdiff_t;
private:
struct Nat {};
@ -154,13 +158,6 @@ public:
return true;
}
size_t put_n(T const *p, size_t n) {
size_t an = ostd::min(n, size());
TR::copy(p_beg, p, an);
p_beg += an;
return an;
}
T *data() { return p_beg; }
T const *data() const { return p_beg; }
@ -191,7 +188,7 @@ diffsize:
template<typename R>
std::enable_if_t<IsOutputRange<R>, size_t> copy(R &&orange, size_t n = -1) {
return orange.put_n(data(), ostd::min(n, size()));
return range_put_n(orange, data(), ostd::min(n, size()));
}
size_t copy(std::remove_cv_t<T> *p, size_t n = -1) {
@ -209,6 +206,14 @@ private:
T *p_beg, *p_end;
};
template<typename T, typename TR>
inline size_t range_put_n(CharRangeBase<T, TR> &range, T const *p, size_t n) {
size_t an = ostd::min(n, range.size());
TR::copy(range.data(), p, an);
range.pop_front_n(an);
return an;
}
using CharRange = CharRangeBase<char>;
using ConstCharRange = CharRangeBase<char const>;
@ -311,7 +316,7 @@ namespace detail {
struct ConcatPut<T, true, B> {
template<typename R>
static bool put(R &sink, ConstCharRange v) {
return v.size() && (sink.put_n(&v[0], v.size()) == v.size());
return v.size() && (range_put_n(sink, &v[0], v.size()) == v.size());
}
};
@ -340,7 +345,7 @@ bool concat(R &&sink, T const &v, ConstCharRange sep, F func) {
if (range.empty()) {
break;
}
sink.put_n(&sep[0], sep.size());
range_put_n(sink, &sep[0], sep.size());
}
return true;
}
@ -353,14 +358,14 @@ bool concat(R &&sink, T const &v, ConstCharRange sep = " ") {
}
for (;;) {
ConstCharRange ret = range.front();
if (!ret.size() || (sink.put_n(&ret[0], ret.size()) != ret.size())) {
if (!ret.size() || (range_put_n(sink, &ret[0], ret.size()) != ret.size())) {
return false;
}
range.pop_front();
if (range.empty()) {
break;
}
sink.put_n(&sep[0], sep.size());
range_put_n(sink, &sep[0], sep.size());
}
return true;
}
@ -377,7 +382,15 @@ bool concat(R &&sink, std::initializer_list<T> v, ConstCharRange sep = " ") {
namespace detail {
template<typename R>
struct TostrRange: OutputRange<TostrRange<R>, char> {
struct TostrRange: OutputRange<TostrRange<R>> {
using Value = char;
using Reference = char &;
using Size = size_t;
using Difference = ptrdiff_t;
template<typename RR>
friend size_t range_put_n(TostrRange<RR> &range, char const *p, size_t n);
TostrRange() = delete;
TostrRange(R &out): p_out(out), p_written(0) {}
bool put(char v) {
@ -385,20 +398,24 @@ namespace detail {
p_written += ret;
return ret;
}
size_t put_n(char const *v, size_t n) {
size_t ret = p_out.put_n(v, n);
size_t put_string(ConstCharRange r) {
size_t ret = range_put_n(p_out, r.data(), r.size());
p_written += ret;
return ret;
}
size_t put_string(ConstCharRange r) {
return put_n(&r[0], r.size());
}
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(TostrRange<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 auto test_stringify(int) -> std::integral_constant<
bool, std::is_same_v<decltype(std::declval<T>().stringify()), std::string>