-
Notifications
You must be signed in to change notification settings - Fork 38
/
test.cpp
120 lines (98 loc) · 3.33 KB
/
test.cpp
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
119
120
#include "range.hpp"
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
template <typename R>
void print_range(R const& range);
template <typename R>
void test_range_size(R const& range);
int main() {
using std::cout;
using util::lang::range;
using util::lang::indices;
cout << "Basic usage: iterating over a range of numbers.\n";
for (auto i : range(1, 5)) {
cout << i << " ";
}
cout << "\n";
cout << "Ranges can be “infinite”.\n";
for (auto u : range(0u)) {
if (u == 3u) {
cout << "\n";
break;
}
cout << u << " ";
}
cout << "Ranges can be non-numeric, as long as the type is incrementable and equality comparable.\n";
print_range(range('a', 'd'));
cout << "Ranges can be non-contiguous.\n";
print_range(range(20u, 29u).step(2u));
cout << "… and we can even step backwards.\n";
for (auto i : range(100).step(-3)) {
if (i < 90) {
cout << "\n";
break;
}
cout << i << " ";
}
cout << "\n";
cout << "Container indices are a special case of ranges.\n";
std::vector<int> x{1, 2, 3};
print_range(indices(x));
print_range(indices({"foo", "bar"}));
cout << "Strings are containers, too.\n";
print_range(indices("foobar").step(2));
cout << "\n";
// TODO: Test cases; do something smarter with them.
print_range(range(6, 10));
print_range(range(1, 8).step(2));
print_range(range(8, 1).step(-2));
print_range(range(8.0, 1.0).step(-2.0));
cout << "\n";
cout << "Mixed type inference:\n";
print_range(range(0, sizeof "Hello"));
cout << "Inferred as mangled type name "
<< typeid(typename std::iterator_traits<decltype(range(0, sizeof "Hello").begin())>::value_type).name()
<< " (expected: " << typeid(decltype(sizeof "Hello")).name() << ")\n";
cout << "\n";
test_range_size(range(1, 8).step(2));
test_range_size(range(8.0, 1.0).step(-2.0));
test_range_size(range(8, 1).step(-2));
test_range_size(range(0.1, 0.11).step(2));
test_range_size(range(-7, 1).step(7));
}
namespace util { namespace lang {
template <typename T>
std::ostream& operator <<(std::ostream& out, step_range_proxy<T> const& r) {
return out << "range(" << *r.begin() << ", " << *r.end() << ")"
<< ".step(" << r.begin().step_ << ")";
}
template <typename T>
std::ostream& operator <<(std::ostream& out, range_proxy<T> const& r) {
return out << "range(" << *r.begin() << ", " << *r.end() << ")";
}
}}
template <typename R>
void print_range(R const& range) {
using T = typename std::iterator_traits<decltype(range.begin())>::value_type;
std::cout << range << " = ";
std::copy(range.begin(), range.end(), std::ostream_iterator<T>(std::cout, " "));
std::cout << "\n";
}
template <typename R>
std::size_t manual_range_size(R const& range) {
std::size_t size = 0;
for (auto const& _ : range) ++size, (void) _;
return size;
}
template <typename R>
void test_range_size(R const& range) {
auto const real_size = manual_range_size(R{range});
if (real_size == range.size()) {
std::cout << range << ".size() = " << real_size << "\n";
} else {
std::cout << "ERROR: " << range << ".size() ≠ " << real_size
<< " (was " << range.size() << ")!\n";
}
}