From 6ec72a6ecd86a9f6e718854b05f34a783d1acb0c Mon Sep 17 00:00:00 2001 From: q66 Date: Mon, 30 Jan 2017 22:07:12 +0100 Subject: [PATCH] add IteratorRange to make a range out of any two iterators --- ostd/range.hh | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/ostd/range.hh b/ostd/range.hh index 0675d6e..bc0dfa0 100644 --- a/ostd/range.hh +++ b/ostd/range.hh @@ -12,6 +12,7 @@ #include #include #include +#include #include "ostd/types.hh" #include "ostd/utility.hh" @@ -1754,6 +1755,158 @@ inline AppenderRange appender(T &&v) { return AppenderRange(std::forward(v)); } +namespace detail { + template + struct IteratorRangeTagBase { + /* fallback, the most basic range */ + using Type = InputRangeTag; + }; + + template<> + struct IteratorRangeTagBase { + using Type = OutputRangeTag; + }; + + template<> + struct IteratorRangeTagBase { + using Type = ForwardRangeTag; + }; + + template<> + struct IteratorRangeTagBase { + using Type = BidirectionalRangeTag; + }; + + template<> + struct IteratorRangeTagBase { + using Type = FiniteRandomAccessRangeTag; + }; +} + +template +using IteratorRangeTag = typename detail::IteratorRangeTagBase::Type; + +template +struct IteratorRange: InputRange< + IteratorRange, + IteratorRangeTag::iterator_category>, + typename std::iterator_traits::value_type, + typename std::iterator_traits::reference, + size_t, + typename std::iterator_traits::difference_type +> { +private: + struct Nat {}; + + using RefT = typename std::iterator_traits::reference; + using DiffT = typename std::iterator_traits::difference_type; + +public: + IteratorRange(T beg = T{}, T end = T{}): p_beg(beg), p_end(end) {} + IteratorRange(T beg, size_t n): p_beg(beg), p_end(beg + n) {} + + IteratorRange(IteratorRange const &v): p_beg(v.p_beg), p_end(v.p_end) {} + IteratorRange(IteratorRange &&v): + p_beg(std::move(v.p_beg)), p_end(std::move(v.p_end)) + {} + + IteratorRange &operator=(IteratorRange const &v) { + p_beg = v.p_beg; + p_end = v.p_end; + return *this; + } + + IteratorRange &operator=(IteratorRange &&v) { + p_beg = std::move(v.p_beg); + p_end = std::move(v.p_end); + return *this; + } + + /* satisfy InputRange / ForwardRange */ + bool empty() const { return p_beg == p_end; } + + bool pop_front() { + if (p_beg == p_end) { + return false; + } + ++p_beg; + return true; + } + bool push_front() { + --p_beg; return true; + } + + RefT 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 { + return range.p_beg - p_beg; + } + + /* satisfy BidirectionalRange */ + bool pop_back() { + if (p_end == p_beg) { + return false; + } + --p_end; + return true; + } + bool push_back() { + ++p_end; return true; + } + + RefT back() const { return *(p_end - 1); } + + bool equals_back(IteratorRange const &range) const { + return p_end == range.p_end; + } + + ptrdiff_t distance_back(IteratorRange const &range) const { + return range.p_end - p_end; + } + + /* satisfy FiniteRandomAccessRange */ + size_t size() const { return p_end - p_beg; } + + IteratorRange slice(size_t start, size_t end) const { + return IteratorRange(p_beg + start, p_beg + end); + } + + RefT operator[](size_t i) const { return p_beg[i]; } + + /* satisfy OutputRange */ + bool put(T const &v) { + if (empty()) { + return false; + } + *(p_beg++) = v; + return true; + } + bool put(T &&v) { + if (empty()) { + return false; + } + *(p_beg++) = std::move(v); + return true; + } + +private: + T p_beg, p_end; +}; + +template +IteratorRange make_range(T beg, T end) { + return IteratorRange{beg, end}; +} + +template +IteratorRange make_range(T beg, size_t n) { + return IteratorRange{beg, beg + n}; +} + } /* namespace ostd */ #endif