-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgrid.cc
More file actions
171 lines (137 loc) · 4.79 KB
/
grid.cc
File metadata and controls
171 lines (137 loc) · 4.79 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <array>
#include <iostream>
#include <numeric>
#include <vector>
template <typename T, std::size_t Dim>
class GridView;
template <typename T, std::size_t Dim>
class GridIter;
namespace std {
template <typename T, std::size_t Dim>
struct iterator_traits<GridIter<T, Dim>> {
using value_type = GridView<T, Dim>;
using difference_type = std::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
using iterator_category = std::random_access_iterator_tag;
};
} // namespace std
template <typename T, std::size_t Dim>
struct GridTrait {
using iterator = GridIter<T, Dim - 1>;
static iterator iter(T *data, std::size_t *offsets) {
return {data, offsets};
}
};
template <typename T>
struct GridTrait<T, 1> {
using iterator = T *;
static iterator iter(T *data, std::size_t *offsets) {
(void)offsets;
return data;
}
};
template <typename T, std::size_t Dim>
class GridView {
public:
using size_type = std::array<std::size_t, Dim>;
using trait = GridTrait<T, Dim>;
GridView(T *data, std::size_t *offsets)
: m_data{data}, m_offsets{offsets} {}
decltype(auto) operator[](std::size_t index) { return *(begin() + index); }
T &operator[](size_type index) {
std::size_t idx = index[Dim - 1];
for (std::ptrdiff_t i = Dim - 2; i >= 0; --i)
idx += m_offsets[i + 1] * index[i];
return m_data[idx];
}
decltype(auto) at(std::size_t index) {
auto it = begin() + index;
if (it >= end())
throw std::out_of_range{"index out of range"};
return *it;
}
T &at(size_type index) {
auto it = &(*this)[index];
if (it >= _end())
throw std::out_of_range{"index out of range"};
return *it;
}
decltype(auto) begin() { return trait::iter(m_data, &m_offsets[1]); }
decltype(auto) end() { return trait::iter(_end(), &m_offsets[1]); }
private:
T *m_data;
std::size_t *m_offsets;
T *_end() { return m_data + m_offsets[0]; }
};
template <typename T, std::size_t Dim>
class GridIter {
static_assert(Dim > 0, "dimension must be positive");
public:
using trait = std::iterator_traits<GridIter>;
using value_type = typename trait::value_type;
using difference_type = typename trait::difference_type;
GridIter(T *data, std::size_t *offsets)
: m_data{data}, m_offsets{offsets} {}
value_type operator*() { return {m_data, m_offsets}; }
bool operator!=(const GridIter &other) { return m_data != other.m_data; }
bool operator<(const GridIter &other) { return m_data < other.m_data; }
GridIter operator+(difference_type diff) {
return {m_data + diff * m_offsets[0], m_offsets};
}
bool operator>(const GridIter &other) { return other < *this; }
bool operator<=(const GridIter &other) { return !(*this > other); }
bool operator>=(const GridIter &other) { return !(*this < other); }
GridIter operator-(difference_type diff) { return *this + (-diff); }
GridIter &operator+=(difference_type diff) { return *this = *this + diff; }
GridIter &operator-=(difference_type diff) { return *this = *this - diff; }
GridIter &operator++() { return *this += 1; }
GridIter &operator--() { return *this -= 1; }
private:
T *m_data;
std::size_t *m_offsets;
};
template <typename T, std::size_t Dim>
class Grid {
static_assert(Dim > 0, "dimension must be positive");
public:
using view_type = GridView<T, Dim>;
using size_type = typename view_type::size_type;
explicit Grid(size_type sizes)
: m_data(std::accumulate(sizes.begin(), sizes.end(), 1,
std::multiplies<>())) {
std::size_t offset = 1;
for (std::ptrdiff_t i = Dim - 1; i >= 0; --i) {
offset *= sizes[i];
m_offsets[i] = offset;
}
}
decltype(auto) operator[](std::size_t index) { return view()[index]; }
decltype(auto) operator[](size_type index) { return view()[index]; }
decltype(auto) at(std::size_t index) { return view().at(index); }
decltype(auto) at(size_type index) { return view().at(index); }
decltype(auto) begin() { return view().begin(); }
decltype(auto) end() { return view().end(); }
view_type view() { return {m_data.data(), m_offsets.data()}; }
private:
std::vector<T> m_data;
size_type m_offsets;
};
int main() {
Grid<int, 2> grid{{{2, 3}}};
grid[{{0, 2}}] = 2;
grid[1][1] = 1;
std::cout << grid.at(0).at(2) << '\n';
std::cout << grid.at({{1, 1}}) << '\n';
try {
// FIXME: this should throw
grid.at({{0, 3}});
} catch (const std::out_of_range &) {
std::cout << "caught out of range\n";
}
for (auto r : grid) {
for (auto i : r)
std::cout << i << ' ';
std::cout << '\n';
}
}