Gamedev Framework (gf)  0.17.0
A C++14 framework for 2D games
Array2D.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016-2019 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 <algorithm>
26 #include <type_traits>
27 #include <utility>
28 #include <vector>
29 
30 #include "Log.h"
31 
32 #include "Math.h"
33 #include "Portability.h"
34 #include "Range.h"
35 #include "SerializationFwd.h"
36 #include "Vector.h"
37 
38 namespace gf {
39 #ifndef DOXYGEN_SHOULD_SKIP_THIS
40 inline namespace v1 {
41 #endif
42 
51  template<typename I>
52  class Index2D {
53  public:
60  : m_size(0, 0)
61  {
62  }
63 
70  : m_size(size)
71  {
72  }
73 
77  Index2D(const Index2D&) = default;
78 
82  Index2D& operator=(const Index2D&) = default;
83 
87  Index2D(Index2D&&) = default;
88 
92  Index2D& operator=(Index2D&&) = default;
93 
99  void swap(Index2D& other) {
100  std::swap(m_size, other.m_size);
101  }
102 
113  constexpr Vector<I, 2> getSize() const noexcept {
114  return m_size;
115  }
116 
122  constexpr I getCols() const noexcept {
123  return m_size.col;
124  }
125 
131  constexpr I getRows() const noexcept {
132  return m_size.row;
133  }
134 
142  constexpr bool isValid(Vector<I, 2> pos) const noexcept {
143  return pos.col < m_size.col && pos.row < m_size.row && (std::is_unsigned<I>::value || (0 <= pos.col && 0 <= pos.row));
144  }
145 
152  constexpr Vector<I, 2> toPosition(std::size_t index) const noexcept {
153  return { static_cast<I>(index % m_size.col), static_cast<I>(index / m_size.col) };
154  }
155 
162  constexpr std::size_t toIndex(Vector<I, 2> pos) const noexcept {
163  return pos.row * m_size.col + pos.col;
164  }
165 
178  constexpr RangeZ getIndexRange() const noexcept {
179  return { 0, static_cast<std::size_t>(m_size.col) * static_cast<std::size_t>(m_size.row) };
180  }
181 
187  constexpr Range<I> getRowRange() const noexcept {
188  return { 0, m_size.row };
189  }
190 
196  constexpr Range<I> getColRange() const noexcept {
197  return { 0, m_size.col };
198  }
199 
205  constexpr PositionRange<I> getPositionRange() const noexcept {
206  return { getColRange(), getRowRange() };
207  }
208 
216  return getNeighborSquareRange(pos, 1);
217  }
218 
226  return getNeighborSquareRange(pos, 2);
227  }
228 
236  return getNeighborDiamondRange(pos, 1);
237  }
238 
246  return getNeighborDiamondRange(pos, 2);
247  }
248 
251  private:
252  NeighborSquareRange<I> getNeighborSquareRange(Vector<I, 2> pos, I n) const noexcept {
253  assert(isValid(pos));
254 
255  auto colMin = pos.col - std::min(pos.col, n);
256  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
257  auto rowMin = pos.row - std::min(pos.row, n);
258  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
259 
260  return NeighborSquareRange<I>{ Range<I>{ colMin, colMax + 1 }, Range<I>{ rowMin, rowMax + 1 }, pos };
261  }
262 
263  NeighborDiamondRange<I> getNeighborDiamondRange(Vector<I, 2> pos, I n) const noexcept {
264  assert(isValid(pos));
265 
266  auto colMin = pos.col - std::min(pos.col, n);
267  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
268  auto rowMin = pos.row - std::min(pos.row, n);
269  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
270 
271  return NeighborDiamondRange<I>{ Range<I>{ colMin, colMax + 1 }, Range<I>{ rowMin, rowMax + 1 }, pos, n };
272  }
273 
274  private:
275  Vector<I, 2> m_size;
276  };
277 
278 // MSVC does not like extern template
279 #ifndef _MSC_VER
280  extern template class GF_API Index2D<unsigned>;
281  extern template class GF_API Index2D<int>;
282 #endif
283 
305  template<typename T, typename I = unsigned>
306  class Array2D : public Index2D<I> {
307  public:
314  : Index2D<I>()
315  {
316  }
317 
324  : Index2D<I>(size)
325  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height))
326  {
327  }
328 
335  Array2D(Vector<I, 2> size, const T& value)
336  : Index2D<I>(size)
337  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height), value)
338  {
339  }
340 
344  Array2D(const Array2D&) = default;
345 
349  Array2D& operator=(const Array2D&) = default;
350 
354  Array2D(Array2D&&) = default;
355 
359  Array2D& operator=(Array2D&&) = default;
360 
366  void swap(Array2D& other) {
367  Index2D<I>::swap(other);
368  std::swap(m_data, other.m_data);
369  }
370 
371  using Index2D<I>::getSize;
372  using Index2D<I>::getCols;
373  using Index2D<I>::getRows;
374  using Index2D<I>::isValid;
376  using Index2D<I>::toIndex;
383 
397  const T *getDataPtr() const noexcept {
398  return m_data.data();
399  }
400 
406  std::size_t getDataSize() const noexcept {
407  return m_data.size();
408  }
409 
418  constexpr bool isEmpty() const noexcept {
419  return m_data.empty();
420  }
421 
435  return get(pos);
436  }
437 
444  T& operator()(std::size_t index) {
445  return m_data[index];
446  }
447 
453  const T& operator()(Vector<I, 2> pos) const {
454  return get(pos);
455  }
456 
463  const T& operator()(std::size_t index) const {
464  return m_data[index];
465  }
466 
481  const T *begin() const noexcept {
482  return m_data.data();
483  }
484 
491  const T *end() const noexcept {
492  return m_data.data() + m_data.size();
493  }
494 
501  T *begin() noexcept {
502  return m_data.data();
503  }
504 
511  T *end() noexcept {
512  return m_data.data() + m_data.size();
513  }
514 
517  private:
518  T& get(Vector<I, 2> pos) {
519  return m_data[toIndex(pos)];
520  }
521 
522  const T& get(Vector<I, 2> pos) const {
523  return m_data[toIndex(pos)];
524  }
525 
526  private:
527  std::vector<T> m_data;
528  };
529 
534  template<typename T, typename I>
535  bool operator==(const Array2D<T,I>& lhs, const Array2D<T,I>& rhs) {
536  auto lhsSize = lhs.getSize();
537  auto rhsSize = rhs.getSize();
538 
539  if (lhsSize.width != rhsSize.width || lhsSize.height != rhsSize.height) {
540  return false;
541  }
542 
543  return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
544  }
545 
550  template<typename T, typename I>
552  auto size = array.getSize();
553  ar | size.width | size.height;
554 
555  for (auto& item : array) {
556  ar | item;
557  }
558 
559  return ar;
560  }
561 
566  template<typename T, typename I>
568  Vector<I, 2> size;
569  ar | size.width | size.height;
570 
571  Array2D<T,I> tmp(size);
572 
573  for (auto& item : tmp) {
574  ar | item;
575  }
576 
577  array = std::move(tmp);
578  return ar;
579  }
580 
581 
582 #ifndef DOXYGEN_SHOULD_SKIP_THIS
583 }
584 #endif
585 }
586 
587 #endif // ARRAY2D_H
A deserializer from a binary file.
Definition: Serialization.h:153
constexpr bool isValid(Vector< I, 2 > pos) const noexcept
Check if a position is valid.
Definition: Array2D.h:142
constexpr Vector< I, 2 > toPosition(std::size_t index) const noexcept
Transform a 1D position into a 2D position.
Definition: Array2D.h:152
A two-dimensional array.
Definition: Array2D.h:306
Serializer & operator|(Serializer &ar, const Array2D< T, I > &array)
Serialize a 2D array.
Definition: Array2D.h:551
constexpr Range< I > getRowRange() const noexcept
Get the row range.
Definition: Array2D.h:187
A half-open range of values.
Definition: Range.h:43
T * end() noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:511
Index2D()
Default constructor.
Definition: Array2D.h:59
A two-dimensional array with no data.
Definition: Array2D.h:52
Deserializer & operator|(Deserializer &ar, Array2D< T, I > &array)
Deserialize a 2D array.
Definition: Array2D.h:567
NeighborDiamondRange< I > get4NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 4 neighbors (at most)
Definition: Array2D.h:235
const T * begin() const noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:481
STL namespace.
const T * getDataPtr() const noexcept
Get the pointer to raw data.
Definition: Array2D.h:397
constexpr Range< I > getColRange() const noexcept
Get the column range.
Definition: Array2D.h:196
std::size_t getDataSize() const noexcept
Get the raw data size.
Definition: Array2D.h:406
A 2D range.
Definition: Range.h:424
void swap(Array2D &other)
Swap with another array.
Definition: Array2D.h:366
constexpr Vector< I, 2 > getSize() const noexcept
Get the size of the array.
Definition: Array2D.h:113
NeighborSquareRange< I > get24NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 24 neighbors (at most)
Definition: Array2D.h:225
constexpr RangeZ getIndexRange() const noexcept
Get the 1D index range of the array.
Definition: Array2D.h:178
A serializer to a binary file.
Definition: Serialization.h:45
The namespace for gf classes.
Definition: Action.h:35
Array2D()
Default constructor.
Definition: Array2D.h:313
Array2D(Vector< I, 2 > size)
Constructor with a size.
Definition: Array2D.h:323
T & operator()(Vector< I, 2 > pos)
Get the element at a given 2D position.
Definition: Array2D.h:434
const T & operator()(std::size_t index) const
Get the element at a given 1D index.
Definition: Array2D.h:463
A 2D range.
Definition: Range.h:592
constexpr bool isEmpty() const noexcept
Check if the array is empty.
Definition: Array2D.h:418
NeighborSquareRange< I > get8NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 8 neighbors (at most)
Definition: Array2D.h:215
constexpr std::size_t toIndex(Vector< I, 2 > pos) const noexcept
Transform a 2D position into a 1D position.
Definition: Array2D.h:162
constexpr ArrayRef< T > array(const T *data, std::size_t size)
Create a constant reference to an array.
Definition: ArrayRef.h:204
A 2D range.
Definition: Range.h:277
T * begin() noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:501
Array2D(Vector< I, 2 > size, const T &value)
Constructor with a size and a value.
Definition: Array2D.h:335
NeighborDiamondRange< I > get12NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 12 neighbors (at most)
Definition: Array2D.h:245
constexpr PositionRange< I > getPositionRange() const noexcept
Get the position range.
Definition: Array2D.h:205
bool operator==(const Array2D< T, I > &lhs, const Array2D< T, I > &rhs)
Equality operator for 2D array.
Definition: Array2D.h:535
constexpr I getRows() const noexcept
Get the number of rows.
Definition: Array2D.h:131
T & operator()(std::size_t index)
Get the element at a given 1D index.
Definition: Array2D.h:444
const T & operator()(Vector< I, 2 > pos) const
Get the element at a given 2D position.
Definition: Array2D.h:453
Index2D(Vector< I, 2 > size)
Constructor with a size.
Definition: Array2D.h:69
void swap(Index2D &other)
Swap with another array.
Definition: Array2D.h:99
constexpr I getCols() const noexcept
Get the number of columns.
Definition: Array2D.h:122
const T * end() const noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:491