-
Notifications
You must be signed in to change notification settings - Fork 91
/
Copy pathrange.hpp
98 lines (76 loc) · 4.53 KB
/
range.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
87
88
89
90
91
92
93
94
95
96
97
98
#ifndef _RANGE_HPP_
#define _RANGE_HPP_
/* This is a C++ clone of http://www.digitalmars.com/d/2.0/phobos/std_range.html
* I had assumed such a thing would be in Boost, but I can't find it
* There is a range library in Boost which seems relevant, it might be working syncing with that a bit more.
*
* This great presentation is what originally taught be the idea of ranges. http://lambda-the-ultimate.org/node/3520
* In particular, I want zip() and chain()
*/
template<class Iterator>
class IteratorRange {
private:
Iterator current;
const Iterator end;
static Iterator dummy[0];
typedef decltype(*dummy[0]) Iterated; // I don't like this dummy thing, but it lets me get the right decltype
public:
IteratorRange(const Iterator &_begin, const Iterator &_end) : current(_begin), end(_end) {}
IteratorRange(std::pair<Iterator, Iterator> be) : current(be.first), end(be.second) {}
bool empty() const { return current == end; }
Iterated &front() const { return *current; }
Iterator frontIterator() const { return current; }
void popFront() { ++current; }
};
template<class Container>
class ContainerProperties {
static Container c;
public:
typedef decltype(c.begin()) BeginType;
typedef decltype(c.rbegin()) RBeginType; // I wonder what'll happen for types without an rbegin()? Hopefully won't be a compile-fail, unless we actually use this type. Might need some template magic
};
template<class Container>
class ContainerRange : public IteratorRange<typename ContainerProperties<Container>::BeginType> {
public:
ContainerRange(Container &c) : IteratorRange<typename ContainerProperties<Container>::BeginType>(c.begin(),
c.end()) {}
};
template<class Container>
class ContainerRangeReverse : public IteratorRange<typename ContainerProperties<Container>::RBeginType> {
public:
ContainerRangeReverse(Container &c) : IteratorRange<typename ContainerProperties<Container>::RBeginType>(c.rbegin(),
c.rend()) {}
};
template<class Range>
class RangeTypes {
static Range r;
public:
typedef decltype(r.front()) ElementType;
};
template<class Range>
class ChainedRange { // Chain Two together
Range first;
Range second;
public:
ChainedRange(const Range &_first, const Range &_second) : first(_first), second(_second) {}
bool empty() const { return first.empty() && second.empty(); }
bool firstEmpty() const { return first.empty(); }
typename RangeTypes<Range>::ElementType front() const { return first.empty() ? second.front() : first.front(); }
void popFront() { if (first.empty()) second.popFront(); else first.popFront(); }
};
#define macro_cat(a, b) a ## b
#define macro_xcat(x, y) macro_cat(x,y)
#define crazy234identifier macro_xcat(arbitrary_Foreach_lsdfjk,__LINE__)
#define Foreach(DECL, RANGE_TO_FOREACH) \
for(bool crazy234identifier = false; !crazy234identifier && !(RANGE_TO_FOREACH).empty() ; ({ if(!crazy234identifier) (RANGE_TO_FOREACH).popFront() ; }) ) /* break (and continue) work as expected */ \
if((crazy234identifier = true)) \
for(DECL = (RANGE_TO_FOREACH).front() ; crazy234identifier ; crazy234identifier=false)
#define ForeachContainer(DECL, CONTAINER_TO_FOREACH) /* break (and continue) work as expected */ \
for(pair<bool, ContainerRange< decltype(CONTAINER_TO_FOREACH) > > crazy234identifier(false, CONTAINER_TO_FOREACH); !crazy234identifier.first && !(crazy234identifier.second).empty() ; ({ if(!crazy234identifier.first) (crazy234identifier.second).popFront() ; }) ) \
if((crazy234identifier.first = true)) \
for(DECL = (crazy234identifier.second).front() ; crazy234identifier.first ; crazy234identifier.first=false)
#define ForeachContainerReverse(DECL, CONTAINER_TO_FOREACH) /* break (and continue) work as expected */ \
for(pair<bool, ContainerRangeReverse< decltype(CONTAINER_TO_FOREACH) > > crazy234identifier(false, CONTAINER_TO_FOREACH); !crazy234identifier.first && !(crazy234identifier.second).empty() ; ({ if(!crazy234identifier.first) (crazy234identifier.second).popFront() ; }) ) \
if((crazy234identifier.first = true)) \
for(DECL = (crazy234identifier.second).front() ; crazy234identifier.first ; crazy234identifier.first=false)
#endif