Gamedev Framework (gf)  0.2.0
A C++11 framework for 2D games
Array2D.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016 Julien Bernard
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 #ifndef ARRAY2D_H
22 #define ARRAY2D_H
23 
24 #include <cassert>
25 #include <vector>
26 
27 #include "Portability.h"
28 #include "Range.h"
29 #include "Vector.h"
30 
31 namespace gf {
32 #ifndef DOXYGEN_SHOULD_SKIP_THIS
33 inline namespace v1 {
34 #endif
35 
36  /**
37  * @ingroup core
38  * @brief A two-dimensional array
39  *
40  * gf::Array represents a two-dimensional array, organized in row-major order.
41  *
42  * Contrary to the usual way of accessing 2D arrays, the first coordinate is
43  * the column and the second coordinate is the row. So that, if `size` is the
44  * size of the array and `pos` if the position in the array:
45  *
46  * - @f$ 0 \leq \mathtt{pos.x} = \mathtt{pos.col} < \mathtt{size.width} = \mathtt{size.col} @f$
47  * - @f$ 0 \leq \mathtt{pos.y} = \mathtt{pos.row} < \mathtt{size.height} = \mathtt{size.row} @f$
48  *
49  * Some convinient visitors are provided to visit the four neighbours (up,
50  * down, left and right), or the eight neighbours.
51  *
52  * @sa gf::Matrix
53  */
54  template<class T>
55  class Array2D {
56  public:
57  /**
58  * @brief Default constructor
59  *
60  * Creates an empty array.
61  */
63  : m_size(0, 0)
64  {
65 
66  }
67 
68  /**
69  * @brief Constructor with a size
70  *
71  * @param size The size of the array
72  */
73  Array2D(Vector2u size)
74  : m_size(size)
75  , m_data(size.width * size.height)
76  {
77 
78  }
79 
80  /**
81  * @brief Constructor with a size and a value
82  *
83  * @param size The size of the array
84  * @param value The initial value in the array
85  */
86  Array2D(Vector2u size, const T& value)
87  : m_size(size)
88  , m_data(size.width * size.height, value)
89  {
90 
91  }
92 
93  /**
94  * @brief Default copy constructor
95  */
96  Array2D(const Array2D&) = default;
97 
98  /**
99  * @brief Default copy assignment
100  */
101  Array2D& operator=(const Array2D&) = default;
102 
103  /**
104  * @brief Default move constructor
105  */
106  Array2D(Array2D&&) = default;
107 
108  /**
109  * @brief Default move assignement
110  */
111  Array2D& operator=(Array2D&&) = default;
112 
113  /**
114  * @name Raw data access
115  * @{
116  */
117 
118  /**
119  * @brief Get the pointer to raw data
120  *
121  * The returned pointer is `const` so you can not modify the array with
122  * this function.
123  *
124  * @return The pointer to raw data
125  */
126  const T *getDataPtr() const noexcept {
127  return m_data.data();
128  }
129 
130  /**
131  * @brief Get the raw data size
132  *
133  * @return The total number of elements in the array
134  */
135  std::size_t getDataSize() const noexcept {
136  return m_data.size();
137  }
138 
139  /**
140  * @brief Get the size of the array
141  *
142  * @return The size of the array
143  */
144  constexpr Vector2u getSize() const noexcept {
145  return m_size;
146  }
147 
148  /**
149  * @brief Get the number of columns
150  *
151  * @return The number of columns
152  */
153  constexpr unsigned getCols() const noexcept {
154  return m_size.col;
155  }
156 
157  /**
158  * @brief Get the number of rows
159  *
160  * @return The number of rows
161  */
162  constexpr unsigned getRows() const noexcept {
163  return m_size.row;
164  }
165 
166  /**
167  * @brief Check if the array is empty
168  *
169  * An empty array is an array with @f$ 0 @f$ elements, i.e. either the
170  * number of columns is @f$ 0 @f$ or the number of rows is @f$ 0 @f$.
171  *
172  * @return True if the array is empty
173  */
174  constexpr bool isEmpty() const noexcept {
175  return m_data.empty();
176  }
177 
178  /** @} */
179 
180  /**
181  * @name Elements access
182  * @{
183  */
184 
185  /**
186  * @brief Get the element at a given 2D position
187  *
188  * @param pos The 2D position of the element
189  */
190  T& operator()(Vector2u pos) {
191  return get(pos);
192  }
193 
194  /**
195  * @brief Get the element at a given 1D position
196  *
197  * @param pos The 1D position of the element
198  * @sa getPositionRange()
199  */
200  T& operator()(std::size_t pos) {
201  return m_data[pos];
202  }
203 
204  /**
205  * @brief Get the element at a given 2D position
206  *
207  * @param pos The 2D position of the element
208  */
209  const T& operator()(Vector2u pos) const {
210  return get(pos);
211  }
212 
213  /**
214  * @brief Get the element at a given 1D position
215  *
216  * @param pos The 1D position of the element
217  * @sa getPositionRange()
218  */
219  const T& operator()(std::size_t pos) const {
220  return m_data[pos];
221  }
222 
223  /**
224  * @brief Transform a 1D position into a 2D position
225  *
226  * @param pos A 1D position
227  * @return The corresponding 2D position
228  */
229  constexpr Vector2u toPosition(std::size_t pos) const noexcept {
230  return { pos % m_size.col, pos / m_size.col };
231  }
232 
233  /** @} */
234 
235  /**
236  * @name Visitors
237  * @{
238  */
239 
240  /**
241  * @brief Visit the 4 neighbours of a given position
242  *
243  * This function calls a callback function for every neighbour in the
244  * vertical and horizontal direction. The function checks if the neighbour
245  * actually exists.
246  *
247  * The callback function has the following prototype:
248  *
249  * ~~~{.cc}
250  * void callback(Vector2u pos, T value);
251  * // pos is the position of the neighbour
252  * // value is the value of the neighbour
253  * ~~~
254  *
255  * The callback function can be a simple function but also a
256  * [lambda expression](http://en.cppreference.com/w/cpp/language/lambda).
257  *
258  * @param pos The position
259  * @param func A callback function
260  */
261  template<typename Func>
262  void visit4Neighbours(Vector2u pos, Func func) {
263  if (pos.row > 0) {
264  Vector2u neighbour{ pos.col, pos.row - 1 };
265  func(neighbour, get(neighbour));
266  }
267 
268  if (pos.row < m_size.row - 1) {
269  Vector2u neighbour{ pos.col, pos.row + 1 };
270  func(neighbour, get(neighbour));
271  }
272 
273  if (pos.col > 0) {
274  Vector2u neighbour{ pos.col - 1, pos.row };
275  func(neighbour, get(neighbour));
276  }
277 
278  if (pos.col < m_size.col - 1) {
279  Vector2u neighbour{ pos.col + 1, pos.row };
280  func(neighbour, get(neighbour));
281  }
282  }
283 
284  /**
285  * @brief Visit the 4 neighbours of a given position
286  *
287  * This function calls a callback function for every neighbour in the
288  * vertical and horizontal direction. The function checks if the neighbour
289  * actually exists.
290  *
291  * The callback function has the following prototype:
292  *
293  * ~~~{.cc}
294  * void callback(Vector2u pos, T value);
295  * // pos is the position of the neighbour
296  * // value is the value of the neighbour
297  * ~~~
298  *
299  * The callback function can be a simple function but also a
300  * [lambda expression](http://en.cppreference.com/w/cpp/language/lambda).
301  *
302  * @param pos The position
303  * @param func A callback function
304  */
305  template<typename Func>
306  void visit4Neighbours(Vector2u pos, Func func) const {
307  if (pos.row > 0) {
308  Vector2u neighbour{ pos.col, pos.row - 1 };
309  func(neighbour, get(neighbour));
310  }
311 
312  if (pos.row < m_size.row - 1) {
313  Vector2u neighbour{ pos.col, pos.row + 1 };
314  func(neighbour, get(neighbour));
315  }
316 
317  if (pos.col > 0) {
318  Vector2u neighbour{ pos.col - 1, pos.row };
319  func(neighbour, get(neighbour));
320  }
321 
322  if (pos.col < m_size.col - 1) {
323  Vector2u neighbour{ pos.col + 1, pos.row };
324  func(neighbour, get(neighbour));
325  }
326  }
327 
328  /**
329  * @brief Visit the 8 neighbours of a given position
330  *
331  * This function calls a callback function for every neighbour in the
332  * vertical, horizontal and diagonal direction. The function checks if the
333  * neighbour actually exists.
334  *
335  * The callback function has the following prototype:
336  *
337  * ~~~{.cc}
338  * void callback(Vector2u pos, T value);
339  * // pos is the position of the neighbour
340  * // value is the value of the neighbour
341  * ~~~
342  *
343  * The callback function can be a simple function but also a
344  * [lambda expression](http://en.cppreference.com/w/cpp/language/lambda).
345  *
346  * @param pos The position
347  * @param func A callback function
348  */
349  template<typename Func>
350  void visit8Neighbours(const Vector2u& pos, Func func) {
351  for (int i = -1; i <= 1; ++i) {
352  if (pos.row == 0 && i == -1) {
353  continue;
354  }
355 
356  if (pos.row + 1 == m_size.row && i == 1) {
357  continue;
358  }
359 
360  for (int j = -1; j <= 1; ++j) {
361  if (pos.col == 0 && j == -1) {
362  continue;
363  }
364 
365  if (pos.col + 1 == m_size.col && j == 1) {
366  continue;
367  }
368 
369  if (i != 0 || j != 0) {
370  Vector2u neighbour{ pos.col + i, pos.row + j };
371  func(neighbour, get(neighbour));
372  }
373  }
374  }
375  }
376 
377  /**
378  * @brief Visit the 8 neighbours of a given position
379  *
380  * This function calls a callback function for every neighbour in the
381  * vertical, horizontal and diagonal direction. The function checks if the
382  * neighbour actually exists.
383  *
384  * The callback function has the following prototype:
385  *
386  * ~~~{.cc}
387  * void callback(Vector2u pos, T value);
388  * // pos is the position of the neighbour
389  * // value is the value of the neighbour
390  * ~~~
391  *
392  * The callback function can be a simple function but also a
393  * [lambda expression](http://en.cppreference.com/w/cpp/language/lambda).
394  *
395  * @param pos The position
396  * @param func A callback function
397  */
398  template<typename Func>
399  void visit8Neighbours(Vector2u pos, Func func) const {
400  for (int i = -1; i <= 1; ++i) {
401  if (pos.row == 0 && i == -1) {
402  continue;
403  }
404 
405  if (pos.row + 1 == m_size.row && i == 1) {
406  continue;
407  }
408 
409  for (int j = -1; j <= 1; ++j) {
410  if (pos.col == 0 && j == -1) {
411  continue;
412  }
413 
414  if (pos.col + 1 == m_size.col && j == 1) {
415  continue;
416  }
417 
418  if (i != 0 || j != 0) {
419  Vector2u neighbour{ pos.col + i, pos.row + j };
420  func(neighbour, get(neighbour));
421  }
422  }
423  }
424  }
425 
426  /** @} */
427 
428  /**
429  * @name Iterators and ranges
430  * @{
431  */
432 
433  /**
434  * @brief Get an iterator to the first element of the array
435  *
436  * @return A `begin` iterator to the array
437  * @sa end()
438  */
439  const T *begin() const noexcept {
440  return m_data.data();
441  }
442 
443  /**
444  * @brief Get an iterator to the element following the last element of the array
445  *
446  * @return An `end` iterator to the array
447  * @sa begin()
448  */
449  const T *end() const noexcept {
450  return m_data.data() + m_data.size();
451  }
452 
453  /**
454  * @brief Get an iterator to the first element of the array
455  *
456  * @return A `begin` iterator to the array
457  * @sa end()
458  */
459  T *begin() noexcept {
460  return m_data.data();
461  }
462 
463  /**
464  * @brief Get an iterator to the element following the last element of the array
465  *
466  * @return An `end` iterator to the array
467  * @sa begin()
468  */
469  T *end() noexcept {
470  return m_data.data() + m_data.size();
471  }
472 
473  /**
474  * @brief Get the 1D position range of the array
475  *
476  * @return A range with all the 1D positions in the array
477  */
478  constexpr RangeZ getPositionRange() const noexcept {
479  return { 0, m_size.col * m_size.row };
480  }
481 
482  /**
483  * @brief Get the row range
484  *
485  * @return A range with all the rows
486  */
487  constexpr RangeU getRowRange() const noexcept {
488  return { 0, m_size.row };
489  }
490 
491  /**
492  * @brief Get the column range
493  *
494  * @return A range with all the columns
495  */
496  constexpr RangeU getColRange() const noexcept {
497  return { 0, m_size.col };
498  }
499 
500  /** @} */
501 
502  private:
503  T& get(Vector2u pos) {
504  return m_data[pos.row * m_size.col + pos.col];
505  }
506 
507  const T& get(Vector2u pos) const {
508  return m_data[pos.row * m_size.col + pos.col];
509  }
510 
511  private:
512  Vector2u m_size;
513  std::vector<T> m_data;
514  };
515 
516 #ifndef DOXYGEN_SHOULD_SKIP_THIS
517 }
518 #endif
519 }
520 
521 #endif // ARRAY2D_H
A two-dimensional array.
Definition: Array2D.h:55
constexpr unsigned getCols() const noexcept
Get the number of columns.
Definition: Array2D.h:153
Array2D(Vector2u size)
Constructor with a size.
Definition: Array2D.h:73
constexpr RangeU getRowRange() const noexcept
Get the row range.
Definition: Array2D.h:487
Array2D & operator=(const Array2D &)=default
Default copy assignment.
const T * begin() const noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:439
constexpr Vector(T x, T y)
Constructor that takes 2 components.
Definition: Vector.h:355
const T & operator()(Vector2u pos) const
Get the element at a given 2D position.
Definition: Array2D.h:209
void visit4Neighbours(Vector2u pos, Func func)
Visit the 4 neighbours of a given position.
Definition: Array2D.h:262
T & operator()(std::size_t pos)
Get the element at a given 1D position.
Definition: Array2D.h:200
T * begin() noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:459
std::size_t getDataSize() const noexcept
Get the raw data size.
Definition: Array2D.h:135
constexpr Vector2u getSize() const noexcept
Get the size of the array.
Definition: Array2D.h:144
void visit8Neighbours(const Vector2u &pos, Func func)
Visit the 8 neighbours of a given position.
Definition: Array2D.h:350
const T * end() const noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:449
void visit8Neighbours(Vector2u pos, Func func) const
Visit the 8 neighbours of a given position.
Definition: Array2D.h:399
Definition: Action.h:34
const T * getDataPtr() const noexcept
Get the pointer to raw data.
Definition: Array2D.h:126
T & operator()(Vector2u pos)
Get the element at a given 2D position.
Definition: Array2D.h:190
const T & operator()(std::size_t pos) const
Get the element at a given 1D position.
Definition: Array2D.h:219
Array2D()
Default constructor.
Definition: Array2D.h:62
Vector(const Vector &other)=default
Default copy constructor.
Array2D(Vector2u size, const T &value)
Constructor with a size and a value.
Definition: Array2D.h:86
constexpr RangeU getColRange() const noexcept
Get the column range.
Definition: Array2D.h:496
constexpr RangeZ getPositionRange() const noexcept
Get the 1D position range of the array.
Definition: Array2D.h:478
Array2D(Array2D &&)=default
Default move constructor.
constexpr Vector2u toPosition(std::size_t pos) const noexcept
Transform a 1D position into a 2D position.
Definition: Array2D.h:229
constexpr unsigned getRows() const noexcept
Get the number of rows.
Definition: Array2D.h:162
Array2D & operator=(Array2D &&)=default
Default move assignement.
void visit4Neighbours(Vector2u pos, Func func) const
Visit the 4 neighbours of a given position.
Definition: Array2D.h:306
constexpr bool isEmpty() const noexcept
Check if the array is empty.
Definition: Array2D.h:174
T * end() noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:469
Array2D(const Array2D &)=default
Default copy constructor.