From f6519405708ae283e566d8bb71e72603bbb9f260 Mon Sep 17 00:00:00 2001 From: q66 Date: Sun, 27 Mar 2016 21:06:00 +0100 Subject: [PATCH] add initial implementation of range joiner (join any type-compatible ranges into one) --- examples/range.cc | 25 +++++++-- ostd/range.hh | 125 ++++++++++++++++++++++++++++++++++++++++++++ ostd/type_traits.hh | 4 +- 3 files changed, 148 insertions(+), 6 deletions(-) diff --git a/examples/range.cc b/examples/range.cc index f61e284..2b8c296 100644 --- a/examples/range.cc +++ b/examples/range.cc @@ -5,23 +5,40 @@ using namespace ostd; int main() { - /* range iter */ + /* range iter - prints 0 to 9 each on new line */ writeln("range iter test"); for (int i: range(10)) writeln(i); - /* algorithm: map */ + /* algorithm: map - prints 0.5 to 9.5 each on new line */ writeln("range map test"); for (float f: map(range(10), [](int v) { return v + 0.5f; })) writeln(f); - /* alrogithm: filter */ + /* algorithm: filter - prints 10, 15, 8 each on new line */ writeln("range filter test"); auto il = { 5, 5, 5, 5, 5, 10, 15, 4, 8, 2 }; for (int i: filter(iter(il), [](int v) { return v > 5; })) writeln(i); - /* generate string ABCDEF */ + /* prints ABCDEF (ASCII 65, 66, 67, 68, 69, 70) */ String s(map(range(6), [](int v) -> char { return v + 65; })); writeln(s); + + /* join a few ranges together - prints 11, 22, 33 ... 99 each on new line */ + auto x = { 11, 22, 33 }; + auto y = { 44, 55, 66 }; + auto z = { 77, 88, 99 }; + for (auto i: join(iter(x), iter(y), iter(z))) { + writeln(i); + } + + /* chunk a range into subranges - prints + * {11, 22, 33} + * {44, 55, 66} + * {77, 88, 99} + */ + auto cr = { 11, 22, 33, 44, 55, 66, 77, 88, 99 }; + for (auto r: chunks(iter(cr), 3)) + writeln(r); } diff --git a/ostd/range.hh b/ostd/range.hh index 7a5c555..8eeeb54 100644 --- a/ostd/range.hh +++ b/ostd/range.hh @@ -13,6 +13,7 @@ #include "ostd/types.hh" #include "ostd/utility.hh" #include "ostd/type_traits.hh" +#include "ostd/tuple.hh" namespace ostd { @@ -1215,6 +1216,130 @@ ChunksRange chunks(const T &it, RangeSize chs) { return ChunksRange(it, chs); } +namespace detail { + template + struct TupleEmptyRanges { + template + static bool empty(const T &tup) { + if (!ostd::get(tup).empty()) + return false; + return TupleEmptyRanges::empty(tup); + } + }; + + template + struct TupleEmptyRanges { + template + static bool empty(const T &) { + return true; + } + }; + + template + struct TupleEqualRanges { + template + static bool equal(const T &tup1, const T &tup2) { + if (!ostd::get(tup1).equals_front(ostd::get(tup2))) + return false; + return TupleEqualRanges::empty(tup1, tup2); + } + }; + + template + struct TupleEqualRanges { + template + static bool equal(const T &, const T &) { + return true; + } + }; + + template + struct TuplePopRanges { + template + static bool pop(T &tup) { + if (!ostd::get(tup).empty()) { + return ostd::get(tup).pop_front(); + } + return TuplePopRanges::pop(tup); + } + }; + + template + struct TuplePopRanges { + template + static bool pop(T &) { + return false; + } + }; + + template + struct TupleRangeFront { + template + static T front(const U &tup) { + if (!ostd::get(tup).empty()) { + return ostd::get(tup).front(); + } + return TupleRangeFront::front(tup); + } + }; + + template + struct TupleRangeFront { + template + static T front(const U &tup) { + return ostd::get<0>(tup).front(); + } + }; +} + +template +struct JoinRange: InputRange, + CommonType...>, + CommonType...>, CommonType...>, + CommonType...>, CommonType...>> { +private: + Tuple p_ranges; +public: + JoinRange() = delete; + JoinRange(const R &...ranges): p_ranges(ranges...) {} + JoinRange(R &&...ranges): p_ranges(forward(ranges)...) {} + JoinRange(const JoinRange &v): p_ranges(v.p_ranges) {} + JoinRange(JoinRange &&v): p_ranges(move(v.p_ranges)) {} + + JoinRange &operator=(const JoinRange &v) { + p_ranges = v.p_ranges; + return *this; + } + + JoinRange &operator=(JoinRange &&v) { + p_ranges = move(v.p_ranges); + return *this; + } + + bool empty() const { + return detail::TupleEmptyRanges<0, sizeof...(R)>::empty(p_ranges); + } + + bool equals_front(const JoinRange &r) const { + return detail::TupleEqualRanges<0, sizeof...(R)>::equal(p_ranges, + r.p_ranges); + } + + bool pop_front() { + return detail::TuplePopRanges<0, sizeof...(R)>::pop(p_ranges); + } + + CommonType...> front() const { + return detail::TupleRangeFront<0, sizeof...(R), + CommonType...>>::front(p_ranges); + } +}; + +template +JoinRange join(R1 r1, R2 r2, R ...rr) { + return JoinRange(move(r1), move(r2), move(rr)...); +} + template struct AppenderRange: OutputRange, typename T::Value, typename T::Reference, typename T::Size, typename T::Difference> { diff --git a/ostd/type_traits.hh b/ostd/type_traits.hh index 4fcd4e7..49aaecb 100644 --- a/ostd/type_traits.hh +++ b/ostd/type_traits.hh @@ -1095,8 +1095,8 @@ namespace detail { }; } -template -using CommonType = typename detail::CommonTypeBase::Type; +template +using CommonType = typename detail::CommonTypeBase::Type; /* aligned storage */