-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFlattenAdapter.h
118 lines (103 loc) · 4.2 KB
/
FlattenAdapter.h
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "adl.h"
#include <cstddef>
#include <type_traits>
#include <iterator>
template<typename Container>
class FlattenAdapter
{
using OuterIt = decltype(adl_end(std::declval<Container&>()));
using InnerIt = decltype(adl_end(*adl_end(std::declval<Container&>())));
template<bool Const>
class Iterator
{
public:
using difference_type = std::ptrdiff_t;
using value_type = typename std::iterator_traits<InnerIt>::value_type;
using pointer = typename std::conditional<Const,
const typename std::iterator_traits<InnerIt>::pointer,
typename std::iterator_traits<InnerIt>::pointer>::type;
using reference = typename std::conditional<Const,
const typename std::iterator_traits<InnerIt>::reference,
typename std::iterator_traits<InnerIt>::reference>::type;
using iterator_category = typename std::common_type<
typename std::iterator_traits<OuterIt>::iterator_category,
typename std::iterator_traits<InnerIt>::iterator_category,
std::bidirectional_iterator_tag>::type;
Iterator(Container& c, OuterIt outer, InnerIt inner)
: c(c), outer(outer), inner(inner)
{
go_to_next();
}
operator Iterator<true>() const { return {c, outer, inner}; }
reference operator*() const { return *inner; }
pointer operator->() const { return &*inner; }
Iterator& operator++() { ++inner; go_to_next(); return *this; }
Iterator operator++(int) { auto ret = *this; ++*this; return ret; }
Iterator& operator--()
{
if (outer == adl_end(c)) inner = adl_end(*--outer);
while (inner == adl_begin(*outer)) inner = adl_end(*--outer);
--inner;
return *this;
}
Iterator operator--(int) { auto ret = *this; --*this; return ret; }
bool operator==(const Iterator& other) const
{ return outer == other.outer && inner == other.inner; }
bool operator!=(const Iterator& other) const
{ return !(*this == other); }
private:
void go_to_next()
{
while (outer != adl_end(c) && inner == adl_end(*outer)) {
++outer;
if (outer == adl_end(c)) inner = InnerIt();
else inner = adl_begin(*outer);
}
}
Container& c;
OuterIt outer;
InnerIt inner;
};
public:
using iterator = Iterator<std::is_const<Container>::value>;
using const_iterator = Iterator<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using value_type = typename iterator::value_type;
using size_type = std::size_t;
using difference_type = typename iterator::difference_type;
using reference = typename iterator::reference;
using const_reference = typename const_iterator::reference;
using pointer = typename iterator::pointer;
using const_pointer = typename const_iterator::pointer;
FlattenAdapter(Container& c) : c(c) {}
iterator begin()
{
return {c, adl_begin(c), adl_begin(c) == adl_end(c)
? InnerIt() : adl_begin(*adl_begin(c))};
}
const_iterator begin() const
{
return {c, adl_begin(c), adl_begin(c) == adl_end(c)
? InnerIt() : adl_begin(*adl_begin(c))};
}
const_iterator cbegin() const { return begin(); }
iterator end() { return {c, adl_end(c), InnerIt()}; }
const_iterator end() const { return {c, adl_end(c), InnerIt()}; }
const_iterator cend() const { return end(); }
reverse_iterator rbegin() { return reverse_iterator{end()}; }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator{end()}; }
const_reverse_iterator crbegin() const { return rbegin(); }
reverse_iterator rend() { return reverse_iterator{begin()}; }
const_reverse_iterator rend() const
{ return const_reverse_iterator{begin()}; }
const_reverse_iterator crend() const { return rend(); }
private:
Container& c;
};
template<typename Container>
FlattenAdapter<Container> flatten(Container& c)
{
return {c};
}