-
Notifications
You must be signed in to change notification settings - Fork 10
/
adjacent.hpp
86 lines (72 loc) · 3.1 KB
/
adjacent.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#ifndef ADJACENT_HPP
#define ADJACENT_HPP
/* range view adaptor to represent pairs of consecutive elements:
Applying it on range containing:
{a, b, c, d, e, f}
produces a view seeing:
{
std::pair(a,b),
std::pair(b,c),
std::pair(c,d),
std::pair(d,e),
std::pair(e,f)
}
*/
#include "iterator_range.hpp"
#include "named_type.hpp"
#include <iterator>
#include <utility>
namespace ranges
{
template<typename Iterator>
using BeginIterator = NamedType<Iterator, struct begin_context>;
template<typename Iterator>
using EndIterator = NamedType<Iterator, struct end_context>;
template<typename UnderlyingIterator>
class adjacent_iterator
: public std::iterator<
typename std::iterator_traits<UnderlyingIterator>::iterator_category,
std::pair<typename std::iterator_traits<UnderlyingIterator>::value_type, typename std::iterator_traits<UnderlyingIterator>::value_type>,
typename std::iterator_traits<UnderlyingIterator>::difference_type,
const std::pair<typename std::iterator_traits<UnderlyingIterator>::value_type, typename std::iterator_traits<UnderlyingIterator>::value_type>*,
const std::pair<typename std::iterator_traits<UnderlyingIterator>::value_type, typename std::iterator_traits<UnderlyingIterator>::value_type>&
>
{
public:
explicit adjacent_iterator(BeginIterator<UnderlyingIterator> begin, EndIterator<UnderlyingIterator> end) : iterator_(begin.get()), next_(begin.get() != end.get() ? std::next(begin.get()) : begin.get()), isEnd_(false) {}
explicit adjacent_iterator(EndIterator<UnderlyingIterator> end) : iterator_(end.get()), next_(end.get()), isEnd_(true) {}
adjacent_iterator operator++() {++iterator_; ++next_; return *this;}
auto operator*() { return std::make_pair(*iterator_, *next_);}
bool operator==(const adjacent_iterator& other)
{
if (isEnd_ == other.isEnd_) return iterator_ == other.iterator_;
if (other.isEnd_) return next_ == other.iterator_;
if (isEnd_) return iterator_ == other.next_;
}
bool operator!=(const adjacent_iterator& other){ return !(*this == other); }
auto operator-(const adjacent_iterator& other) { return next_ - other.next_;}
private:
UnderlyingIterator iterator_;
UnderlyingIterator next_;
bool isEnd_;
};
namespace view
{
template<typename Range>
auto consecutive(Range& range) -> iterator_range<adjacent_iterator<decltype(range.begin())>>
{
using UnderlyingIterator = decltype(range.begin());
return iterator_range<adjacent_iterator<UnderlyingIterator>>(
adjacent_iterator<UnderlyingIterator>(BeginIterator<UnderlyingIterator>(range.begin()), EndIterator<UnderlyingIterator>(range.end())),
adjacent_iterator<UnderlyingIterator>(EndIterator<UnderlyingIterator>(range.end())));
}
class adjacent_adaptor {};
adjacent_adaptor adjacent;
template<typename Range>
auto operator|(Range& range, adjacent_adaptor) -> iterator_range<adjacent_iterator<decltype(range.begin())>>
{
return consecutive(range);
}
} // namespace view
} // namespace ranges
#endif