Loading [MathJax]/jax/input/TeX/config.js
Gamedev Framework (gf)  0.19.0
A C++17 framework for 2D games
Array2D.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016-2021 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 "CoreApi.h"
31 #include "Math.h"
32 #include "Range.h"
33 #include "SerializationFwd.h"
34 #include "Vector.h"
35 
36 namespace gf {
37 #ifndef DOXYGEN_SHOULD_SKIP_THIS
38 inline namespace v1 {
39 #endif
40 
49  template<typename I>
50  class Index2D {
51  public:
58  : m_size(0, 0)
59  {
60  }
61 
68  : m_size(size)
69  {
70  }
71 
75  Index2D(const Index2D&) = default;
76 
80  Index2D& operator=(const Index2D&) = default;
81 
85  Index2D(Index2D&&) = default;
86 
90  Index2D& operator=(Index2D&&) = default;
91 
97  void swap(Index2D& other) {
98  std::swap(m_size, other.m_size);
99  }
100 
111  constexpr Vector<I, 2> getSize() const noexcept {
112  return m_size;
113  }
114 
120  constexpr I getCols() const noexcept {
121  return m_size.col;
122  }
123 
129  constexpr I getRows() const noexcept {
130  return m_size.row;
131  }
132 
140  constexpr bool isValid(Vector<I, 2> pos) const noexcept {
141  return pos.col < m_size.col && pos.row < m_size.row && (std::is_unsigned<I>::value || (0 <= pos.col && 0 <= pos.row));
142  }
143 
150  constexpr Vector<I, 2> toPosition(std::size_t index) const noexcept {
151  return { static_cast<I>(index % m_size.col), static_cast<I>(index / m_size.col) };
152  }
153 
160  constexpr std::size_t toIndex(Vector<I, 2> pos) const noexcept {
161  return pos.row * m_size.col + pos.col;
162  }
163 
176  constexpr RangeZ getIndexRange() const noexcept {
177  return { 0, static_cast<std::size_t>(m_size.col) * static_cast<std::size_t>(m_size.row) };
178  }
179 
185  constexpr Range<I> getRowRange() const noexcept {
186  return { 0, m_size.row };
187  }
188 
194  constexpr Range<I> getColRange() const noexcept {
195  return { 0, m_size.col };
196  }
197 
203  constexpr PositionRange<I> getPositionRange() const noexcept {
204  return { getColRange(), getRowRange() };
205  }
206 
214  return getNeighborSquareRange(pos, 1);
215  }
216 
224  return getNeighborSquareRange(pos, 2);
225  }
226 
234  return getNeighborDiamondRange(pos, 1);
235  }
236 
244  return getNeighborDiamondRange(pos, 2);
245  }
246 
249  private:
250  NeighborSquareRange<I> getNeighborSquareRange(Vector<I, 2> pos, I n) const noexcept {
251  assert(isValid(pos));
252 
253  auto colMin = pos.col - std::min(pos.col, n);
254  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
255  auto rowMin = pos.row - std::min(pos.row, n);
256  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
257 
258  return NeighborSquareRange<I>{ Range<I>{ colMin, colMax + 1 }, Range<I>{ rowMin, rowMax + 1 }, pos };
259  }
260 
261  NeighborDiamondRange<I> getNeighborDiamondRange(Vector<I, 2> pos, I n) const noexcept {
262  assert(isValid(pos));
263 
264  auto colMin = pos.col - std::min(pos.col, n);
265  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
266  auto rowMin = pos.row - std::min(pos.row, n);
267  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
268 
269  return NeighborDiamondRange<I>{ Range<I>{ colMin, colMax + 1 }, Range<I>{ rowMin, rowMax + 1 }, pos, n };
270  }
271 
272  private:
273  Vector<I, 2> m_size;
274  };
275 
276 // MSVC does not like extern template
277 #ifndef _MSC_VER
278  extern template class GF_CORE_API Index2D<unsigned>;
279  extern template class GF_CORE_API Index2D<int>;
280 #endif
281 
303  template<typename T, typename I = unsigned>
304  class Array2D : public Index2D<I> {
305  public:
312  : Index2D<I>()
313  {
314  }
315 
322  : Index2D<I>(size)
323  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height))
324  {
325  }
326 
333  Array2D(Vector<I, 2> size, const T& value)
334  : Index2D<I>(size)
335  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height), value)
336  {
337  }
338 
342  Array2D(const Array2D&) = default;
343 
347  Array2D& operator=(const Array2D&) = default;
348 
352  Array2D(Array2D&&) = default;
353 
357  Array2D& operator=(Array2D&&) = default;
358 
364  void swap(Array2D& other) {
365  Index2D<I>::swap(other);
366  std::swap(m_data, other.m_data);
367  }
368 
369  using Index2D<I>::getSize;
370  using Index2D<I>::getCols;
371  using Index2D<I>::getRows;
372  using Index2D<I>::isValid;
374  using Index2D<I>::toIndex;
381 
395  const T *getDataPtr() const noexcept {
396  return m_data.data();
397  }
398 
404  std::size_t getDataSize() const noexcept {
405  return m_data.size();
406  }
407 
416  constexpr bool isEmpty() const noexcept {
417  return m_data.empty();
418  }
419 
433  return get(pos);
434  }
435 
442  T& operator()(std::size_t index) {
443  return m_data[index];
444  }
445 
451  const T& operator()(Vector<I, 2> pos) const {
452  return get(pos);
453  }
454 
461  const T& operator()(std::size_t index) const {
462  return m_data[index];
463  }
464 
479  const T *begin() const noexcept {
480  return m_data.data();
481  }
482 
489  const T *end() const noexcept {
490  return m_data.data() + m_data.size();
491  }
492 
499  T *begin() noexcept {
500  return m_data.data();
501  }
502 
509  T *end() noexcept {
510  return m_data.data() + m_data.size();
511  }
512 
515  private:
516  T& get(Vector<I, 2> pos) {
517  return m_data[toIndex(pos)];
518  }
519 
520  const T& get(Vector<I, 2> pos) const {
521  return m_data[toIndex(pos)];
522  }
523 
524  private:
525  std::vector<T> m_data;
526  };
527 
532  template<typename T, typename I>
533  bool operator==(const Array2D<T,I>& lhs, const Array2D<T,I>& rhs) {
534  auto lhsSize = lhs.getSize();
535  auto rhsSize = rhs.getSize();
536 
537  if (lhsSize.width != rhsSize.width || lhsSize.height != rhsSize.height) {
538  return false;
539  }
540 
541  return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
542  }
543 
548  template<typename T, typename I>
550  auto size = array.getSize();
551  ar | size.width | size.height;
552 
553  for (auto& item : array) {
554  ar | const_cast<T&>(item);
555  }
556 
557  return ar;
558  }
559 
564  template<typename T, typename I>
566  Vector<I, 2> size;
567  ar | size.width | size.height;
568 
569  Array2D<T,I> tmp(size);
570 
571  for (auto& item : tmp) {
572  ar | item;
573  }
574 
575  array = std::move(tmp);
576  return ar;
577  }
578 
579 
580 #ifndef DOXYGEN_SHOULD_SKIP_THIS
581 }
582 #endif
583 }
584 
585 #endif // ARRAY2D_H
A deserializer from a binary file.
Definition: Serialization.h:151
constexpr bool isValid(Vector< I, 2 > pos) const noexcept
Check if a position is valid.
Definition: Array2D.h:140
constexpr Vector< I, 2 > toPosition(std::size_t index) const noexcept
Transform a 1D position into a 2D position.
Definition: Array2D.h:150
A two-dimensional array.
Definition: Array2D.h:304
constexpr Range< I > getRowRange() const noexcept
Get the row range.
Definition: Array2D.h:185
A half-open range of values.
Definition: Range.h:44
T * end() noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:509
Index2D()
Default constructor.
Definition: Array2D.h:57
A two-dimensional array with no data.
Definition: Array2D.h:50
NeighborDiamondRange< I > get4NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 4 neighbors (at most)
Definition: Array2D.h:233
const T * begin() const noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:479
STL namespace.
const T * getDataPtr() const noexcept
Get the pointer to raw data.
Definition: Array2D.h:395
constexpr Range< I > getColRange() const noexcept
Get the column range.
Definition: Array2D.h:194
std::size_t getDataSize() const noexcept
Get the raw data size.
Definition: Array2D.h:404
A 2D range.
Definition: Range.h:426
void swap(Array2D &other)
Swap with another array.
Definition: Array2D.h:364
constexpr Vector< I, 2 > getSize() const noexcept
Get the size of the array.
Definition: Array2D.h:111
NeighborSquareRange< I > get24NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 24 neighbors (at most)
Definition: Array2D.h:223
constexpr RangeZ getIndexRange() const noexcept
Get the 1D index range of the array.
Definition: Array2D.h:176
Deserializer & operator|(Deserializer &ar, Array2D< T, I > &array)
Deserialize a 2D array.
Definition: Array2D.h:565
Serializer & operator|(Serializer &ar, const Array2D< T, I > &array)
Serialize a 2D array.
Definition: Array2D.h:549
A serializer to a binary file.
Definition: Serialization.h:43
The namespace for gf classes.
Definition: Action.h:35
Array2D()
Default constructor.
Definition: Array2D.h:311
Array2D(Vector< I, 2 > size)
Constructor with a size.
Definition: Array2D.h:321
T & operator()(Vector< I, 2 > pos)
Get the element at a given 2D position.
Definition: Array2D.h:432
const T & operator()(std::size_t index) const
Get the element at a given 1D index.
Definition: Array2D.h:461
A 2D range.
Definition: Range.h:595
constexpr bool isEmpty() const noexcept
Check if the array is empty.
Definition: Array2D.h:416
NeighborSquareRange< I > get8NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 8 neighbors (at most)
Definition: Array2D.h:213
constexpr std::size_t toIndex(Vector< I, 2 > pos) const noexcept
Transform a 2D position into a 1D position.
Definition: Array2D.h:160
A 2D range.
Definition: Range.h:278
T * begin() noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:499
Array2D(Vector< I, 2 > size, const T &value)
Constructor with a size and a value.
Definition: Array2D.h:333
NeighborDiamondRange< I > get12NeighborsRange(Vector< I, 2 > pos) const noexcept
Get a range for 12 neighbors (at most)
Definition: Array2D.h:243
constexpr PositionRange< I > getPositionRange() const noexcept
Get the position range.
Definition: Array2D.h:203
bool operator==(const Array2D< T, I > &lhs, const Array2D< T, I > &rhs)
Equality operator for 2D array.
Definition: Array2D.h:533
constexpr I getRows() const noexcept
Get the number of rows.
Definition: Array2D.h:129
T & operator()(std::size_t index)
Get the element at a given 1D index.
Definition: Array2D.h:442
const T & operator()(Vector< I, 2 > pos) const
Get the element at a given 2D position.
Definition: Array2D.h:451
Index2D(Vector< I, 2 > size)
Constructor with a size.
Definition: Array2D.h:67
void swap(Index2D &other)
Swap with another array.
Definition: Array2D.h:97
constexpr I getCols() const noexcept
Get the number of columns.
Definition: Array2D.h:120
const T * end() const noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:489