SGL
gridlocation.h
1 /*
2  * File: gridlocation.h
3  * --------------------
4  * This file exports the <code>GridLocation</code> structure, which is a small
5  * structure representing a row and column.
6  * The row/column values are allowed to be negative or out of bounds; if an
7  * out-of-bounds location is passed to a grid, the grid will throw an error.
8  *
9  * Several members of the <code>Grid</code> and <code>SparseGrid</code> classes
10  * have been retrofitted to accept <code>GridLocation</code>s in place of integers
11  * for row/column indexes.
12  *
13  * This file also declares the <code>GridLocationRange</code> class,
14  * which represents a 2D range of grid locations that can be looped over.
15  *
16  * See gridlocation.cpp for the implementation of each member.
17  *
18  * @version 2021/04/03
19  * - removed dependencies
20  * - removed hashCode
21  * - added to_string
22  * @version 2018/03/12
23  * - initial version
24  */
25 
26 
27 #ifndef _gridlocation_h
28 #define _gridlocation_h
29 
30 #include <exception>
31 #include <iostream>
32 #include <iterator>
33 #include <stdexcept>
34 #include <string>
35 
36 class GridLocationRange; // forward declaration
37 
38 struct GridLocation {
39 public:
40 
41  /*
42  * Constructs a location representing the given row and column.
43  * Any indexes are allowed, including negatives and out-of-bounds indexes.
44  */
45  GridLocation(int row, int col);
46 
47  /*
48  * Constructs a default location 0, 0.
49  */
50  GridLocation();
51 
52  /*
53  * Returns a string representation of this location, such as "r2c17".
54  */
55  string toString() const;
56 
57  /* row and column data - may be directly accessed or modified */
58  int row;
59  int col;
60 };
61 
62 /*
63  * Returns a string representation of this location, such as "r2c17".
64  */
65 string to_string(const GridLocation& value);
66 
67 /*
68  * Relational operators for comparing grid locations.
69  */
70 bool operator <(const GridLocation& loc1, const GridLocation& loc2);
71 bool operator <=(const GridLocation& loc1, const GridLocation& loc2);
72 bool operator ==(const GridLocation& loc1, const GridLocation& loc2);
73 bool operator !=(const GridLocation& loc1, const GridLocation& loc2);
74 bool operator >(const GridLocation& loc1, const GridLocation& loc2);
75 bool operator >=(const GridLocation& loc1, const GridLocation& loc2);
76 
77 /*
78  * I/O stream operators for reading or writing locations in their toString format.
79  */
80 std::ostream& operator <<(std::ostream& out, const GridLocation& loc);
81 std::istream& operator >>(std::istream& input, GridLocation& loc);
82 
83 
84 /*
85  * Represents a range of grid locations.
86  * The actual individual grid locations are not all created and stored in
87  * this object; that would require a lot of memory usage.
88  * Instead, we primarily use this class for for-each looping over a given range
89  * of locations using its internal iterator.
90  *
91  * Common usage pattern:
92  * GridLocationRange range(0, 0, 10, 5);
93  * for (GridLocation loc : range) { ... }
94  *
95  * or, if you have a Grid collection, its locations() method returns a GridLocationRange
96  * object that you can loop over directly.
97  *
98  * for (GridLocation loc : grid.locations()) { ... }
99  */
100 class GridLocationRange {
101 private:
102  /*
103  * Internal iterator over range of indexes.
104  */
105  class GridLocationRangeIterator : public std::iterator<std::input_iterator_tag, GridLocation> {
106  private:
107  const GridLocationRange* glr;
108  GridLocation loc;
109 
110  public:
111  GridLocationRangeIterator(const GridLocationRange* glr, bool end)
112  : glr(glr) {
113  if (end) {
114  loc.row = glr->endRow() + 1;
115  loc.col = glr->endCol() + 1;
116  } else {
117  loc = glr->startLocation();
118  }
119  }
120 
121  GridLocationRangeIterator(const GridLocationRangeIterator& itr)
122  : glr(itr.glr),
123  loc(itr.loc) {
124  // empty
125  }
126 
127  GridLocationRangeIterator& operator ++() {
128  if (glr->isRowMajor()) {
129  loc.col++;
130  if (loc.col > glr->endCol()) {
131  loc.col = glr->startCol();
132  loc.row++;
133  }
134  } else {
135  loc.row++;
136  if (loc.row > glr->endRow()) {
137  loc.row = glr->startRow();
138  loc.col++;
139  }
140  }
141  if (!glr->contains(loc)) {
142  loc.row = glr->endRow() + 1;
143  loc.col = glr->endCol() + 1;
144  }
145  return *this;
146  }
147 
148  GridLocationRangeIterator operator ++(int) {
149  GridLocationRangeIterator copy(*this);
150  operator++();
151  return copy;
152  }
153 
154  GridLocationRangeIterator& operator --() {
155  if (glr->isRowMajor()) {
156  loc.col--;
157  if (loc.col < glr->startCol()) {
158  loc.col = glr->endCol();
159  loc.row--;
160  }
161  } else {
162  loc.row--;
163  if (loc.row < glr->startRow()) {
164  loc.row = glr->endRow();
165  loc.col--;
166  }
167  }
168  return *this;
169  }
170 
171  GridLocationRangeIterator operator --(int) {
172  GridLocationRangeIterator copy(*this);
173  operator--();
174  return copy;
175  }
176 
177  bool operator ==(const GridLocationRangeIterator& rhs) const {
178  return loc == rhs.loc;
179  }
180 
181  bool operator !=(const GridLocationRangeIterator& rhs) const {
182  return !(*this == rhs);
183  }
184 
185  bool operator <(const GridLocationRangeIterator& rhs) const {
186  if (glr != rhs.glr) {
187  throw std::runtime_error("GridLocationRange Iterator::operator <: Iterators are in different ranges");
188  }
189  return loc < rhs.loc;
190  }
191 
192  bool operator <=(const GridLocationRangeIterator& rhs) const {
193  if (glr != rhs.glr) {
194  throw std::runtime_error("GridLocationRange Iterator::operator <=: Iterators are in different ranges");
195  }
196  return loc <= rhs.loc;
197  }
198 
199  bool operator >(const GridLocationRangeIterator& rhs) const {
200  if (glr != rhs.glr) {
201  throw std::runtime_error("GridLocationRange Iterator::operator >: Iterators are in different ranges");
202  }
203  return loc > rhs.loc;
204  }
205 
206  bool operator >=(const GridLocationRangeIterator& rhs) const {
207  if (glr != rhs.glr) {
208  throw std::runtime_error("GridLocationRange Iterator::operator >=: Iterators are in different ranges");
209  }
210  return loc >= rhs.loc;
211  }
212 
213  const GridLocation& operator *() const {
214  return loc;
215  }
216 
217  const GridLocation* operator ->() const {
218  return &loc;
219  }
220  };
221 
222  GridLocation _start;
223  GridLocation _end;
224  bool _isRowMajor;
225 
226 public:
227  /*
228  * Constructs a range over the given start/end locations, inclusive.
229  * The isRowMajor flag indicates whether we will loop over the range in
230  * row-major order (true, default) or column-major order (false).
231  */
232  GridLocationRange(int startRow = 0, int startCol = 0, int endRow = 0, int endCol = 0, bool isRowMajor = true);
233 
234  /*
235  * Constructs a range over the given start/end locations, inclusive.
236  * The isRowMajor flag indicates whether we will loop over the range in
237  * row-major order (true, default) or column-major order (false).
238  */
239  GridLocationRange(const GridLocation& startLoc, const GridLocation& endLoc, bool isRowMajor = true);
240 
241  /*
242  * Returns an iterator over the range.
243  */
244  GridLocationRangeIterator begin() const;
245 
246  /*
247  * Returns true if this range entirely contains the given other range.
248  */
249  bool contains(const GridLocation& loc) const;
250 
251  /*
252  * Returns an iterator at the end of the range.
253  */
254  GridLocationRangeIterator end() const;
255 
256  /*
257  * Returns the last column in this range, inclusive.
258  */
259  int endCol() const;
260 
261  /*
262  * Returns the last row/column location in this range, inclusive.
263  */
264  const GridLocation& endLocation() const;
265 
266  /*
267  * Returns the last row in this range, inclusive.
268  */
269  int endRow() const;
270 
271  /*
272  * Returns true if this range contains no rows or columns.
273  */
274  bool isEmpty() const;
275 
276  /*
277  * Returns true if this range should be traversed in row-major order,
278  * as specified at time of construction (default true).
279  */
280  bool isRowMajor() const;
281 
282  /*
283  * Returns the first column in this range.
284  */
285  int startCol() const;
286 
287  /*
288  * Returns the first row/column location in this range.
289  */
290  const GridLocation& startLocation() const;
291 
292  /*
293  * Returns the first row in this range.
294  */
295  int startRow() const;
296 
297  /*
298  * Returns a string representation of this range,
299  * such as "[r1c3 .. r4c7]".
300  */
301  string toString() const;
302 };
303 
304 /*
305  * I/O stream operators for writing location ranges in their toString format.
306  */
307 std::ostream& operator <<(std::ostream& out, const GridLocationRange& range);
308 
309 #endif // _gridlocation_h