Gamedev Framework (gf)  0.11.0
A C++14 framework for 2D games
Array2D.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016-2018 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 
64  template<typename T, typename I = unsigned>
65  class Array2D {
66  public:
73  : m_size(0, 0)
74  {
75 
76  }
77 
84  : m_size(size)
85  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height))
86  {
87 
88  }
89 
96  Array2D(Vector<I, 2> size, const T& value)
97  : m_size(size)
98  , m_data(static_cast<std::size_t>(size.width) * static_cast<std::size_t>(size.height), value)
99  {
100 
101  }
102 
106  Array2D(const Array2D&) = default;
107 
111  Array2D& operator=(const Array2D&) = default;
112 
116  Array2D(Array2D&&) = default;
117 
121  Array2D& operator=(Array2D&&) = default;
122 
128  void swap(Array2D& other) {
129  std::swap(m_data, other.m_data);
130  std::swap(m_size, other.m_size);
131  }
132 
146  const T *getDataPtr() const noexcept {
147  return m_data.data();
148  }
149 
155  std::size_t getDataSize() const noexcept {
156  return m_data.size();
157  }
158 
164  constexpr Vector<I, 2> getSize() const noexcept {
165  return m_size;
166  }
167 
173  constexpr I getCols() const noexcept {
174  return m_size.col;
175  }
176 
182  constexpr I getRows() const noexcept {
183  return m_size.row;
184  }
185 
194  constexpr bool isEmpty() const noexcept {
195  return m_data.empty();
196  }
197 
205  constexpr bool isValid(Vector<I, 2> pos) const noexcept {
206  return pos.col < m_size.col && pos.row < m_size.row && (std::is_unsigned<I>::value || (0 <= pos.col && 0 <= pos.row));
207  }
208 
222  return get(pos);
223  }
224 
231  T& operator()(std::size_t index) {
232  return m_data[index];
233  }
234 
240  const T& operator()(Vector<I, 2> pos) const {
241  return get(pos);
242  }
243 
250  const T& operator()(std::size_t index) const {
251  return m_data[index];
252  }
253 
260  constexpr Vector<I, 2> toPosition(std::size_t pos) const noexcept {
261  return { pos % m_size.col, pos / m_size.col };
262  }
263 
292  template<typename Func>
293  void visit4Neighbors(Vector<I, 2> pos, Func func) {
294  visitNeighborsDiamond(pos, func, 1);
295  }
296 
318  template<typename Func>
319  void visit4Neighbors(Vector<I, 2> pos, Func func) const {
320  visitNeighborsDiamond(pos, func, 1);
321  }
322 
344  template<typename Func>
345  void visit12Neighbors(Vector<I, 2> pos, Func func) {
346  visitNeighborsDiamond(pos, func, 2);
347  }
348 
370  template<typename Func>
371  void visit12Neighbors(Vector<I, 2> pos, Func func) const {
372  visitNeighborsDiamond(pos, func, 2);
373  }
374 
396  template<typename Func>
397  void visit8Neighbors(Vector<I, 2> pos, Func func) {
398  visitNeighborsSquare(pos, func, 1);
399  }
400 
424  template<typename Func>
425  void visit8Neighbors(Vector<I, 2> pos, Func func) const {
426  visitNeighborsSquare(pos, func, 1);
427  }
428 
450  template<typename Func>
451  void visit24Neighbors(Vector<I, 2> pos, Func func) {
452  visitNeighborsSquare(pos, func, 2);
453  }
454 
476  template<typename Func>
477  void visit24Neighbors(Vector<I, 2> pos, Func func) const {
478  visitNeighborsSquare(pos, func, 2);
479  }
480 
494  const T *begin() const noexcept {
495  return m_data.data();
496  }
497 
504  const T *end() const noexcept {
505  return m_data.data() + m_data.size();
506  }
507 
514  T *begin() noexcept {
515  return m_data.data();
516  }
517 
524  T *end() noexcept {
525  return m_data.data() + m_data.size();
526  }
527 
533  constexpr RangeZ getIndexRange() const noexcept {
534  return { 0, m_size.col * m_size.row };
535  }
536 
542  constexpr Range<I> getRowRange() const noexcept {
543  return { 0, m_size.row };
544  }
545 
551  constexpr Range<I> getColRange() const noexcept {
552  return { 0, m_size.col };
553  }
554 
560  constexpr PositionRange<I> getPositionRange() const noexcept {
561  return { getColRange(), getRowRange() };
562  }
563 
566  private:
567  T& get(Vector<I, 2> pos) {
568  return m_data[pos.row * m_size.col + pos.col];
569  }
570 
571  const T& get(Vector<I, 2> pos) const {
572  return m_data[pos.row * m_size.col + pos.col];
573  }
574 
575  template<typename Func>
576  void visitNeighborsSquare(Vector<I, 2> pos, Func func, I n) const {
577  assert(isValid(pos));
578 
579  auto colMin = pos.col - std::min(pos.col, n);
580  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
581  auto rowMin = pos.row - std::min(pos.row, n);
582  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
583 
584  for (auto row = rowMin; row <= rowMax; ++row) {
585  for (auto col = colMin; col <= colMax; ++col) {
586  if (col == pos.col && row == pos.row) { // avoid to include VectorOps.h
587  continue;
588  }
589 
590  func({ col, row }, get({ col, row }));
591  }
592  }
593  }
594 
595  template<typename Func>
596  void visitNeighborsSquare(Vector<I, 2> pos, Func func, I n) {
597  assert(isValid(pos));
598 
599  auto colMin = pos.col - std::min(pos.col, n);
600  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
601  auto rowMin = pos.row - std::min(pos.row, n);
602  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
603 
604  for (auto row = rowMin; row <= rowMax; ++row) {
605  for (auto col = colMin; col <= colMax; ++col) {
606  if (col == pos.col && row == pos.row) { // avoid to include VectorOps.h
607  continue;
608  }
609 
610  func({ col, row }, get({ col, row }));
611  }
612  }
613  }
614 
615 
616  template<typename Func>
617  void visitNeighborsDiamond(Vector<I, 2> pos, Func func, I n) const {
618  assert(isValid(pos));
619 
620  auto colMin = pos.col - std::min(pos.col, n);
621  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
622  auto rowMin = pos.row - std::min(pos.row, n);
623  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
624 
625  for (auto row = rowMin; row <= rowMax; ++row) {
626  for (auto col = colMin; col <= colMax; ++col) {
627  if (col == pos.col && row == pos.row) { // avoid to include VectorOps.h
628  continue;
629  }
630 
631  if (gf::absdiff(col, pos.col) + gf::absdiff(row, pos.row) > n) {
632  continue;
633  }
634 
635  func({ col, row }, get({ col, row }));
636  }
637  }
638  }
639 
640  template<typename Func>
641  void visitNeighborsDiamond(Vector<I, 2> pos, Func func, I n) {
642  assert(isValid(pos));
643 
644  auto colMin = pos.col - std::min(pos.col, n);
645  auto colMax = pos.col + std::min(m_size.col - pos.col - 1, n);
646  auto rowMin = pos.row - std::min(pos.row, n);
647  auto rowMax = pos.row + std::min(m_size.row - pos.row - 1, n);
648 
649  for (auto row = rowMin; row <= rowMax; ++row) {
650  for (auto col = colMin; col <= colMax; ++col) {
651  if (col == pos.col && row == pos.row) { // avoid to include VectorOps.h
652  continue;
653  }
654 
655  if (gf::absdiff(col, pos.col) + gf::absdiff(row, pos.row) > n) {
656  continue;
657  }
658 
659  func({ col, row }, get({ col, row }));
660  }
661  }
662  }
663 
664  private:
665  Vector<I, 2> m_size;
666  std::vector<T> m_data;
667  };
668 
673  template<typename T, typename I>
674  bool operator==(const Array2D<T,I>& lhs, const Array2D<T,I>& rhs) {
675  auto lhsSize = lhs.getSize();
676  auto rhsSize = rhs.getSize();
677 
678  if (lhsSize.width != rhsSize.width || lhsSize.height != rhsSize.height) {
679  return false;
680  }
681 
682  return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
683  }
684 
689  template<typename T, typename I>
691  auto size = array.getSize();
692  ar | size.width | size.height;
693 
694  for (auto& item : array) {
695  ar | item;
696  }
697 
698  return ar;
699  }
700 
705  template<typename T, typename I>
707  Vector<I, 2> size;
708  ar | size.width | size.height;
709 
710  Array2D<T,I> tmp(size);
711 
712  for (auto& item : tmp) {
713  ar | item;
714  }
715 
716  array = std::move(tmp);
717  return ar;
718  }
719 
720 
721 #ifndef DOXYGEN_SHOULD_SKIP_THIS
722 }
723 #endif
724 }
725 
726 #endif // ARRAY2D_H
A deserializer from a binary file.
Definition: Serialization.h:153
A two-dimensional array.
Definition: Array2D.h:65
Serializer & operator|(Serializer &ar, const Array2D< T, I > &array)
Serialize a 2D array.
Definition: Array2D.h:690
A half-open range of values.
Definition: Range.h:42
T * end() noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:524
Deserializer & operator|(Deserializer &ar, Array2D< T, I > &array)
Deserialize a 2D array.
Definition: Array2D.h:706
const T * begin() const noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:494
STL namespace.
const T * getDataPtr() const noexcept
Get the pointer to raw data.
Definition: Array2D.h:146
std::size_t getDataSize() const noexcept
Get the raw data size.
Definition: Array2D.h:155
void swap(Array2D &other)
Swap with another array.
Definition: Array2D.h:128
constexpr T absdiff(T lhs, T rhs)
Absolute difference of two values.
Definition: Math.h:313
void visit4Neighbors(Vector< I, 2 > pos, Func func) const
Visit the 4 neighbors of a given position.
Definition: Array2D.h:319
constexpr Range< I > getRowRange() const noexcept
Get the row range.
Definition: Array2D.h:542
constexpr PositionRange< I > getPositionRange() const noexcept
Get the position range.
Definition: Array2D.h:560
void visit12Neighbors(Vector< I, 2 > pos, Func func) const
Visit the 12 neighbors of a given position.
Definition: Array2D.h:371
constexpr I getCols() const noexcept
Get the number of columns.
Definition: Array2D.h:173
constexpr Vector< I, 2 > toPosition(std::size_t pos) const noexcept
Transform a 1D position into a 2D position.
Definition: Array2D.h:260
void visit24Neighbors(Vector< I, 2 > pos, Func func) const
Visit the 24 neighbors of a given position.
Definition: Array2D.h:477
void visit8Neighbors(Vector< I, 2 > pos, Func func) const
Visit the 8 neighbors of a given position.
Definition: Array2D.h:425
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:72
Array2D(Vector< I, 2 > size)
Constructor with a size.
Definition: Array2D.h:83
constexpr bool isValid(Vector< I, 2 > pos) const noexcept
Check if a position is valid.
Definition: Array2D.h:205
void visit24Neighbors(Vector< I, 2 > pos, Func func)
Visit the 24 neighbors of a given position.
Definition: Array2D.h:451
T & operator()(Vector< I, 2 > pos)
Get the element at a given 2D position.
Definition: Array2D.h:221
const T & operator()(std::size_t index) const
Get the element at a given 1D index.
Definition: Array2D.h:250
constexpr bool isEmpty() const noexcept
Check if the array is empty.
Definition: Array2D.h:194
constexpr I getRows() const noexcept
Get the number of rows.
Definition: Array2D.h:182
constexpr Vector< I, 2 > getSize() const noexcept
Get the size of the array.
Definition: Array2D.h:164
A 2D range.
Definition: Range.h:225
constexpr Range< I > getColRange() const noexcept
Get the column range.
Definition: Array2D.h:551
T * begin() noexcept
Get an iterator to the first element of the array.
Definition: Array2D.h:514
Array2D(Vector< I, 2 > size, const T &value)
Constructor with a size and a value.
Definition: Array2D.h:96
constexpr RangeZ getIndexRange() const noexcept
Get the 1D index range of the array.
Definition: Array2D.h:533
bool operator==(const Array2D< T, I > &lhs, const Array2D< T, I > &rhs)
Equality operator for 2D array.
Definition: Array2D.h:674
T & operator()(std::size_t index)
Get the element at a given 1D index.
Definition: Array2D.h:231
const T & operator()(Vector< I, 2 > pos) const
Get the element at a given 2D position.
Definition: Array2D.h:240
void visit12Neighbors(Vector< I, 2 > pos, Func func)
Visit the 12 neighbors of a given position.
Definition: Array2D.h:345
void visit8Neighbors(Vector< I, 2 > pos, Func func)
Visit the 8 neighbors of a given position.
Definition: Array2D.h:397
void visit4Neighbors(Vector< I, 2 > pos, Func func)
Visit the 4 neighbors of a given position.
Definition: Array2D.h:293
const T * end() const noexcept
Get an iterator to the element following the last element of the array.
Definition: Array2D.h:504