From ef147c538c4d946f295468b1a66e2837c00a10d3 Mon Sep 17 00:00:00 2001 From: q66 Date: Sat, 22 Apr 2017 17:12:20 +0200 Subject: [PATCH] add complete input iterator type for any range --- examples/range.cc | 9 ++++++ ostd/range.hh | 72 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/examples/range.cc b/examples/range.cc index 8bca8d2..b79ee20 100644 --- a/examples/range.cc +++ b/examples/range.cc @@ -1,6 +1,7 @@ #include #include #include +#include using namespace ostd; @@ -66,4 +67,12 @@ int main() { for (auto v: iter({ 5, 10, 15, 20 }).zip(iter({ 6, 11, 16, 21 }))) { writeln(v.first, ", ", v.second); } + + /* insertion into containers with full_iterator */ + writeln("vector range insert"); + std::vector foo = { 5, 10, 35, 40 }; + writeln("before insert: ", foo); + auto r = range(15, 35, 5); + foo.insert(foo.cbegin() + 2, r.iter_begin(), r.iter_end()); + writeln("after insert: ", foo); } diff --git a/ostd/range.hh b/ostd/range.hh index 414365b..e8fc731 100644 --- a/ostd/range.hh +++ b/ostd/range.hh @@ -45,6 +45,7 @@ #include #include #include +#include namespace ostd { @@ -619,7 +620,49 @@ namespace detail { return !p_range.empty(); } private: - std::decay_t p_range; + T p_range; + }; + + // complete range iterator + template + struct full_range_iterator { + using iterator_category = std::input_iterator_tag; + using value_type = range_value_t; + using reference = range_reference_t; + using pointer = value_type *; + using difference_type = std::make_signed_t>; + + full_range_iterator(): p_range(std::nullopt) {} + full_range_iterator(T const &range): p_range(range) {} + + bool operator==(full_range_iterator const &v) const { + if (!p_range) { + if (v.p_range) { + return (*v.p_range).empty(); + } + return true; + } + return (*p_range).empty(); + } + bool operator!=(full_range_iterator const &v) const { + return !((*this) == v); + } + + reference operator*() const { + return (*p_range).front(); + } + + full_range_iterator &operator++() { + p_range.value().pop_front(); + return *this; + } + full_range_iterator operator++(int) { + full_range_iterator ret{p_range.value()}; + (*p_range).pop_front(); + return ret; + } + private: + std::optional p_range; }; } @@ -724,6 +767,23 @@ inline range_size_t range_pop_back_n(IR &range, range_size_t n) { */ template struct input_range { + /** @brief A complete input iterator type for the range. + * + * This is a complete iterator type that you can create with + * iter_begin(). This iterator can only be used to represent + * the full range sequence - i.e. from the beginning to the + * end of the range, with the end always being iter_end(). + * + * Using an incremented version of iter_begin() as an ending is + * undefined as the ending iterator is not used by itself, this + * is why it's an input iterator type (if the function this is + * used with tried to use a temporary copy of the iterator as + * an end, it'd result in incorrect behavior). Thus, this is + * mostly meant to insert ranges into data structures that + * take input iterators in their insertion methods. + */ + using full_iterator = detail::full_range_iterator; + /** @brief Creates a very simple iterator for range-based for loop. * * Thanks to this, you can use the range-based for loop with ranges @@ -740,6 +800,16 @@ struct input_range { return nullptr; } + /** @brief Constructs a full_iterator for the range. */ + full_iterator iter_begin() const { + return full_iterator{*static_cast(this)}; + } + + /** @brief Constructs a full_iterator end. */ + full_iterator iter_end() const { + return full_iterator{}; + } + /** @brief Creates a copy of the range. * * This is just like copy-constructing the range.