Gamedev Framework (gf)  0.12.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  }
64 
71  : m_size(size)
72  {
73 
74  }
75 
79  Index2D(const Index2D&) = default;
80 
84  Index2D& operator=(const Index2D&) = default;
85 
89  Index2D(Index2D&&) = default;
90 
94  Index2D& operator=(Index2D&&) = default;
95 
101  void swap(Index2D& other) {
102  std::swap(m_size, other.m_size);
103  }
104 
115  constexpr Vector<I, 2> getSize() const noexcept {
116  return m_size;
117  }
118 
124  constexpr I getCols() const noexcept {
125  return m_size.col;
126  }
127 
133  constexpr I getRows() const noexcept {
134  return m_size.row;
135  }
136 
144  constexpr bool isValid(Vector<I, 2> pos) const noexcept {
145  return pos.col < m_size.col && pos.row < m_size.row && (std::is_unsigned<I>::value || (0 <= pos.col && 0 <= pos.row));
146  }
147 
154  constexpr Vector<I, 2> toPosition(std::size_t index) const noexcept {
155  return { static_cast<I>(index % m_size.col), static_cast<I>(index / m_size.col) };
156  }
157 
164  constexpr std::size_t toIndex(Vector<I, 2> pos) const noexcept {
165  return pos.row * m_size.col + pos.col;
166  }
167 
180  constexpr RangeZ getIndexRange() const noexcept {
181  return { 0, static_cast<std::size_t>(m_size.col) * static_cast<std::size_t>(m_size.row) };
182  }
183 
189  constexpr Range<I> getRowRange() const noexcept {
190  return { 0, m_size.row };
191  }
192 
198  constexpr Range<I> getColRange() const noexcept {
199  return { 0, m_size.col };
200  }
201 
207  constexpr PositionRange<I> getPositionRange() const noexcept {
208  return { getColRange(), getRowRange() };
209  }
210 
218  return getNeighborSquareRange(pos, 1);
219  }
220 
228  return getNeighborSquareRange(pos, 2);
229  }
230 
238  return getNeighborDiamondRange(pos, 1);
239  }
240 
248  return getNeighborDiamondRange(pos, 2);
249  }
250 
253  private:
254  NeighborSquareRange<I> getNeighborSquareRange(Vector<I, 2> pos, I n) const noexcept {
255  assert(isValid(pos));
256 
257  auto colMin = pos.col - std::min(pos.col, n);
258  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
259  auto rowMin = pos.row - std::min(pos.row, n);
260  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
261 
262  return NeighborSquareRange<I>{ Range<I>{ colMin, colMax + 1 }, Range<I>{ rowMin, rowMax + 1 }, pos };
263  }
264 
265  NeighborDiamondRange<I> getNeighborDiamondRange(Vector<I, 2> pos, I n) const noexcept {
266  assert(isValid(pos));
267 
268  auto colMin = pos.col - std::min(pos.col, n);
269  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
270  auto rowMin = pos.row - std::min(pos.row, n);
271  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
272 
273  return NeighborDiamondRange<I>{ Range<I>{ colMin, colMax + 1 }, Range<I>{ rowMin, rowMax + 1 }, pos, n };
274  }
275 
276  private:
277  Vector<I, 2> m_size;
278  };
279 
280 // MSVC does not like extern template
281 #ifndef _MSC_VER
282  extern template class GF_API Index2D<unsigned>;
283  extern template class GF_API Index2D<int>;
284 #endif
285 
307  template<typename T, typename I = unsigned>
308  class Array2D : public Index2D<I> {
309  public:
316  : Index2D<I>()
317  {
318 
319  }
320 
327  : Index2D<I>(size)
328  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height))
329  {
330 
331  }
332 
339  Array2D(Vector<I, 2> size, const T& value)
340  : Index2D<I>(size)
341  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height), value)
342  {
343 
344  }
345 
349  Array2D(const Array2D&) = default;
350 
354  Array2D& operator=(const Array2D&) = default;
355 
359  Array2D(Array2D&&) = default;
360 
364  Array2D& operator=(Array2D&&) = default;
365 
371  void swap(Array2D& other) {
372  Index2D<I>::swap(other);
373  std::swap(m_data, other.m_data);
374  }
375 
376  using Index2D<I>::getSize;
377  using Index2D<I>::getCols;
378  using Index2D<I>::getRows;
379  using Index2D<I>::isValid;
381  using Index2D<I>::toIndex;
388 
402  const T *getDataPtr() const noexcept {
403  return m_data.data();
404  }
405 
411  std::size_t getDataSize() const noexcept {
412  return m_data.size();
413  }
414 
423  constexpr bool isEmpty() const noexcept {
424  return m_data.empty();
425  }
426 
440  return get(pos);
441  }
442 
449  T& operator()(std::size_t index) {
450  return m_data[index];
451  }
452 
458  const T& operator()(Vector<I, 2> pos) const {
459  return get(pos);
460  }
461 
468  const T& operator()(std::size_t index) const {
469  return m_data[index];
470  }
471 
486  const T *begin() const noexcept {
487  return m_data.data();
488  }
489 
496  const T *end() const noexcept {
497  return m_data.data() + m_data.size();
498  }
499 
506  T *begin() noexcept {
507  return m_data.data();
508  }
509 
516  T *end() noexcept {
517  return m_data.data() + m_data.size();
518  }
519 
522  private:
523  T& get(Vector<I, 2> pos) {
524  return m_data[toIndex(pos)];
525  }
526 
527  const T& get(Vector<I, 2> pos) const {
528  return m_data[toIndex(pos)];
529  }
530 
531  private:
532  std::vector<T> m_data;
533  };
534 
539  template<typename T, typename I>
540  bool operator==(const Array2D<T,I>& lhs, const Array2D<T,I>& rhs) {
541  auto lhsSize = lhs.getSize();
542  auto rhsSize = rhs.getSize();
543 
544  if (lhsSize.width != rhsSize.width || lhsSize.height != rhsSize.height) {
545  return false;
546  }
547 
548  return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
549  }
550 
555  template<typename T, typename I>
557  auto size = array.getSize();
558  ar | size.width | size.height;
559 
560  for (auto& item : array) {
561  ar | item;
562  }
563 
564  return ar;
565  }
566 
571  template<typename T, typename I>
573  Vector<I, 2> size;
574  ar | size.width | size.height;
575 
576  Array2D<T,I> tmp(size);
577 
578  for (auto& item : tmp) {
579  ar | item;
580  }
581 
582  array = std::move(tmp);
583  return ar;
584  }
585 
586 
587 #ifndef DOXYGEN_SHOULD_SKIP_THIS
588 }
589 #endif
590 }
591 
592 #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:144
constexpr Vector< I, 2 > toPosition(std::size_t index) const noexcept
Transform a 1D position into a 2D position.
Definition: Array2D.h:154
A two-dimensional array.
Definition: Array2D.h:308
Serializer & operator|(Serializer &ar, const Array2D< T, I > &array)
Serialize a 2D array.
Definition: Array2D.h:556
constexpr Range< I > getRowRange() const noexcept
Get the row range.
Definition: Array2D.h:189
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:516
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:572
NeighborDiamondRange< I > get4NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 4 neighbors (at most)
Definition: Array2D.h:237
const T * begin() const noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:486
STL namespace.
const T * getDataPtr() const noexcept
Get the pointer to raw data.
Definition: Array2D.h:402
constexpr Range< I > getColRange() const noexcept
Get the column range.
Definition: Array2D.h:198
std::size_t getDataSize() const noexcept
Get the raw data size.
Definition: Array2D.h:411
A 2D range.
Definition: Range.h:429
void swap(Array2D &other)
Swap with another array.
Definition: Array2D.h:371
constexpr Vector< I, 2 > getSize() const noexcept
Get the size of the array.
Definition: Array2D.h:115
NeighborSquareRange< I > get24NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 24 neighbors (at most)
Definition: Array2D.h:227
constexpr RangeZ getIndexRange() const noexcept
Get the 1D index range of the array.
Definition: Array2D.h:180
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:315
Array2D(Vector< I, 2 > size)
Constructor with a size.
Definition: Array2D.h:326
T & operator()(Vector< I, 2 > pos)
Get the element at a given 2D position.
Definition: Array2D.h:439
const T & operator()(std::size_t index) const
Get the element at a given 1D index.
Definition: Array2D.h:468
A 2D range.
Definition: Range.h:599
constexpr bool isEmpty() const noexcept
Check if the array is empty.
Definition: Array2D.h:423
NeighborSquareRange< I > get8NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 8 neighbors (at most)
Definition: Array2D.h:217
constexpr std::size_t toIndex(Vector< I, 2 > pos) const noexcept
Transform a 2D position into a 1D position.
Definition: Array2D.h:164
A 2D range.
Definition: Range.h:280
T * begin() noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:506
Array2D(Vector< I, 2 > size, const T &value)
Constructor with a size and a value.
Definition: Array2D.h:339
NeighborDiamondRange< I > get12NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 12 neighbors (at most)
Definition: Array2D.h:247
constexpr PositionRange< I > getPositionRange() const noexcept
Get the position range.
Definition: Array2D.h:207
bool operator==(const Array2D< T, I > &lhs, const Array2D< T, I > &rhs)
Equality operator for 2D array.
Definition: Array2D.h:540
constexpr I getRows() const noexcept
Get the number of rows.
Definition: Array2D.h:133
T & operator()(std::size_t index)
Get the element at a given 1D index.
Definition: Array2D.h:449
const T & operator()(Vector< I, 2 > pos) const
Get the element at a given 2D position.
Definition: Array2D.h:458
Index2D(Vector< I, 2 > size)
Constructor with a size.
Definition: Array2D.h:70
void swap(Index2D &other)
Swap with another array.
Definition: Array2D.h:101
constexpr I getCols() const noexcept
Get the number of columns.
Definition: Array2D.h:124
const T * end() const noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:496