AoC code coverage
Current view: top level - aoclib - Grid2d.h (source / functions) Coverage Total Hit
Test: master Lines: 96.6 % 205 198
Test Date: 2025-07-28 10:53:57 Functions: 99.5 % 200 199

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include "Vector.h"
       4              : 
       5              : #include <absl/container/flat_hash_map.h>
       6              : #include <absl/hash/hash.h>
       7              : #include <experimental/mdspan>
       8              : #include <fmt/ostream.h>
       9              : #include <libassert/assert.hpp>
      10              : 
      11              : #include <array>
      12              : #include <iosfwd>
      13              : #include <limits>
      14              : #include <vector>
      15              : 
      16              : namespace stdex = std::experimental;
      17              : 
      18              : template <typename T> class Grid2d;
      19              : 
      20              : template <typename T> class Grid2dSpan {
      21              : public:
      22              :   static constexpr size_t numDimensions = 2u;
      23              :   using Span = stdex::mdspan<T, stdex::dextents<int, numDimensions>, stdex::layout_stride>;
      24              :   using ElementType = Span::element_type;
      25              :   using ExtentsType = Span::extents_type;
      26              :   using IndexType = Span::index_type;
      27              :   using Coord = Vec2<IndexType>;
      28              :   using SizeType = Span::size_type;
      29              :   using MappingType = Span::mapping_type;
      30              : 
      31          219 :   Grid2dSpan() = default;
      32              :   Grid2dSpan(ElementType *p, auto const xSize, auto const ySize)
      33          258 :       : _span(p,
      34          258 :               MappingType{ExtentsType{integerCast<IndexType>(xSize), integerCast<IndexType>(ySize)},
      35          258 :                           std::array<IndexType, 2u>{1, integerCast<IndexType>(xSize)}}) {}
      36              : 
      37              :   Grid2dSpan(ElementType *p, auto const xSize, auto const ySize, auto const xStride,
      38              :              auto const yStride)
      39         7078 :       : _span(p,
      40         7078 :               MappingType{ExtentsType{integerCast<IndexType>(xSize), integerCast<IndexType>(ySize)},
      41         7078 :                           std::array<IndexType, 2u>{integerCast<IndexType>(xStride),
      42         7078 :                                                     integerCast<IndexType>(yStride)}}) {}
      43              : 
      44              :   Grid2dSpan(ElementType *p, auto const xSize, auto const ySize, auto const yStride)
      45         1060 :       : _span(p,
      46         1060 :               MappingType{ExtentsType{integerCast<IndexType>(xSize), integerCast<IndexType>(ySize)},
      47         1060 :                           std::array<IndexType, 2u>{1, integerCast<IndexType>(yStride)}}) {}
      48              : 
      49         4870 :   Grid2dSpan(ElementType *p, MappingType const &mapping) : _span(p, mapping) {}
      50              : 
      51          604 :   template <typename U> Grid2dSpan(Grid2dSpan<U> const &other) : _span(other.span()) {}
      52              : 
      53              :   [[nodiscard]] ElementType &operator[](std::integral auto const x,
      54     49467839 :                                         std::integral auto const y) const {
      55     49467839 :     return _span[x, y];
      56     49467839 :   }
      57     20368338 :   template <std::integral U> [[nodiscard]] ElementType &operator[](Vec2<U> const &x) const {
      58     20368338 :     return _span[x.x(), x.y()];
      59     20368338 :   }
      60              : 
      61     62368255 :   [[nodiscard]] IndexType xSize() const { return _span.extent(0); }
      62      2782211 :   [[nodiscard]] IndexType ySize() const { return _span.extent(1); }
      63            2 :   [[nodiscard]] Vec2<IndexType> size() const { return {_span.extent(0), _span.extent(1)}; }
      64              : 
      65         3434 :   [[nodiscard]] Grid2dSpan column(IndexType const x) const {
      66         3434 :     return {&_span[x, 0], 1, ySize(), _span.mapping().strides()[0], _span.mapping().strides()[1]};
      67         3434 :   }
      68         3142 :   [[nodiscard]] Grid2dSpan line(IndexType const y) const {
      69         3142 :     return {&_span[0, y], xSize(), 1, 1, _span.mapping().strides()[1]};
      70         3142 :   }
      71              : 
      72         1085 :   template <class F> void forEach(F f) const {
      73       214423 :     for (int y = 0; y < ySize(); ++y)
      74     48758416 :       for (int x = 0; x < xSize(); ++x)
      75     48545078 :         f(_span[x, y]);
      76         1085 :   }
      77              : 
      78              :   void fill(ElementType const &e) const;
      79              : 
      80              :   [[nodiscard]] Coord find(ElementType const &e) const;
      81              :   [[nodiscard]] std::vector<Coord> findAll(ElementType const &e) const;
      82              : 
      83              :   [[nodiscard]] auto map(auto &&mapFunc) const -> Grid2d<decltype(mapFunc(' '))>;
      84              :   [[nodiscard]] size_t count(ElementType const &e) const;
      85              :   [[nodiscard]] size_t count_if(auto predicate) const;
      86              : 
      87              :   [[nodiscard]] ElementType max() const;
      88              :   [[nodiscard]] ElementType sum() const;
      89              : 
      90        10344 :   [[nodiscard]] Span const &span() const { return _span; }
      91          600 :   [[nodiscard]] Grid2dSpan subgrid(Coord const &begin, Coord const &end) const {
      92          600 :     return {&((*this)[begin]), end.x() - begin.x(), end.y() - begin.y(), _span.stride(1u)};
      93          600 :   }
      94              : 
      95              :   [[nodiscard]] Grid2dSpan flipX() const {
      96              :     return {&(*this)[xSize() - 1, 0], xSize(), ySize(), -_span.stride(0), _span.stride(1)};
      97              :   }
      98              : 
      99            2 :   [[nodiscard]] Grid2dSpan flipY() const {
     100            2 :     return {&(*this)[0, ySize() - 1], xSize(), ySize(), _span.stride(0), -_span.stride(1)};
     101            2 :   }
     102              : 
     103              : private:
     104              :   Span _span;
     105              : };
     106              : 
     107              : template <typename T> class Grid2d {
     108              : public:
     109              :   using SpanType = Grid2dSpan<T>;
     110              :   using ElementType = SpanType::ElementType;
     111              :   using IndexType = SpanType::IndexType;
     112              :   using Coord = SpanType::Coord;
     113              :   using SizeType = SpanType::SizeType;
     114              : 
     115            8 :   Grid2d() = default;
     116              : 
     117              :   Grid2d(std::integral auto const xSize, std::integral auto const ySize)
     118          223 :       : _data(xSize * ySize), _span(_data.data(), xSize, ySize) {}
     119              : 
     120              :   Grid2d(std::integral auto const xSize, std::integral auto const ySize, ElementType const &init)
     121           35 :       : _data(integerCast<size_t>(xSize * ySize), init), _span(_data.data(), xSize, ySize) {}
     122              : 
     123              :   Grid2d(std::integral auto const xSize, std::integral auto const ySize, ElementType const &init,
     124              :          std::integral auto const numGhostLayers)
     125          460 :       : _data(integerCast<size_t>((xSize + 2 * numGhostLayers) * (ySize + 2 * numGhostLayers)),
     126          460 :               init),
     127          460 :         _span(&_data[numGhostLayers * (xSize + 2 * numGhostLayers) + numGhostLayers], xSize, ySize,
     128          460 :               xSize + 2 * numGhostLayers) {}
     129              : 
     130              :   template <std::integral U> Grid2d(Vec2<U> const &size) : Grid2d(size.x(), size.y()) {}
     131              : 
     132              :   template <std::integral U>
     133              :   Grid2d(Vec2<U> const &size, ElementType const &init) : Grid2d(size.x(), size.y(), init) {}
     134              : 
     135              :   template <std::integral U>
     136              :   Grid2d(Vec2<U> const &size, ElementType const &init, auto const numGhostLayers)
     137            2 :       : Grid2d(size.x(), size.y(), init, numGhostLayers) {}
     138              : 
     139              :   Grid2d(Grid2d const &other)
     140         4870 :       : _data(other._data),
     141         4870 :         _span(_data.data() + other.pointerOffset(), other.span().span().mapping()) {} // NOLINT
     142              : 
     143           74 :   Grid2d(Grid2d &&other) noexcept : _data(std::move(other._data)), _span(std::move(other._span)) {
     144           74 :     other._span = SpanType{};
     145           74 :   }
     146              : 
     147              :   Grid2d &operator=(Grid2d const &other) {
     148              :     _data = other._data;
     149              :     _span = SpanType(_data.data() + other.pointerOffset(), other.span().span().mapping());
     150              :     return *this;
     151              :   }
     152              : 
     153          137 :   Grid2d &operator=(Grid2d &&other) noexcept {
     154          137 :     _data = std::move(other._data);
     155          137 :     _span = std::move(other._span);
     156          137 :     other._span = SpanType{};
     157          137 :     return *this;
     158          137 :   }
     159              : 
     160         5670 :   ~Grid2d() = default;
     161              : 
     162          604 :   operator Grid2dSpan<T const>() const { return _span; }
     163          580 :   operator Grid2dSpan<T>() { return _span; }
     164              : 
     165      6080706 :   [[nodiscard]] ElementType &operator[](std::integral auto const x, std::integral auto const y) {
     166      6080706 :     return _span[x, y];
     167      6080706 :   }
     168              :   [[nodiscard]] ElementType const &operator[](std::integral auto const x,
     169       609047 :                                               std::integral auto const y) const {
     170       609047 :     return _span[x, y];
     171       609047 :   }
     172              : 
     173     20200347 :   template <std::integral U> [[nodiscard]] ElementType &operator[](Vec2<U> const &x) {
     174     20200347 :     return _span[x.x(), x.y()];
     175     20200347 :   }
     176      6278047 :   template <std::integral U> [[nodiscard]] ElementType const &operator[](Vec2<U> const &x) const {
     177      6278047 :     return _span[x.x(), x.y()];
     178      6278047 :   }
     179              : 
     180      6874413 :   [[nodiscard]] IndexType xSize() const { return _span.xSize(); }
     181        97983 :   [[nodiscard]] IndexType ySize() const { return _span.ySize(); }
     182            2 :   [[nodiscard]] Vec2<IndexType> size() const { return _span.size(); }
     183              : 
     184         2913 :   [[nodiscard]] bool inBounds(Coord const &x) const {
     185         2913 :     return x.x() >= 0 && x.y() >= 0 && x.x() < xSize() && x.y() < ySize();
     186         2913 :   }
     187              : 
     188              :   [[nodiscard]] SpanType column(IndexType const x) const { return _span.column(x); }
     189              :   [[nodiscard]] SpanType line(IndexType const y) const { return _span.line(y); }
     190              : 
     191           35 :   void fill(ElementType const &e) { return _span.fill(e); }
     192              : 
     193           12 :   [[nodiscard]] Coord find(ElementType const &e) const { return _span.find(e); }
     194            4 :   [[nodiscard]] std::vector<Coord> findAll(ElementType const &e) const { return _span.findAll(e); }
     195              : 
     196         9894 :   [[nodiscard]] SpanType const &span() const { return _span; }
     197              : 
     198            4 :   [[nodiscard]] auto map(auto &&mapFunc) const -> Grid2d<decltype(mapFunc(' '))> {
     199            4 :     return _span.map(std::forward<decltype(mapFunc)>(mapFunc));
     200            4 :   }
     201            7 :   [[nodiscard]] size_t count(ElementType const &e) const { return _span.count(e); }
     202          441 :   [[nodiscard]] size_t count_if(auto predicate) const { return _span.count_if(predicate); }
     203            1 :   [[nodiscard]] ElementType max() const { return _span.max(); }
     204            1 :   [[nodiscard]] ElementType sum() const { return _span.sum(); }
     205              : 
     206          600 :   [[nodiscard]] Grid2dSpan<T> subgrid(Coord const &begin, Coord const &end) const {
     207          600 :     return _span.subgrid(begin, end);
     208          600 :   }
     209              : 
     210            2 :   [[nodiscard]] Grid2dSpan<T> flipY() const { return _span.flipY(); }
     211              :   [[nodiscard]] Grid2dSpan<T> flipX() const { return _span.flipX(); }
     212              : 
     213              : private:
     214         4870 :   [[nodiscard]] size_t pointerOffset() const { return _span.span().data_handle() - _data.data(); }
     215              :   std::vector<T> _data;
     216              :   SpanType _span;
     217              : };
     218              : 
     219          788 : template <typename T> bool operator==(Grid2dSpan<T> const &lhs, Grid2dSpan<T> const &rhs) {
     220          788 :   if (lhs.xSize() != rhs.xSize() || lhs.ySize() != rhs.ySize())
     221            0 :     return false;
     222              : 
     223          788 :   using IndexType = Grid2dSpan<T>::IndexType;
     224         6720 :   for (IndexType y = 0; y < lhs.ySize(); ++y)
     225        15430 :     for (IndexType x = 0; x < lhs.xSize(); ++x)
     226         9498 :       if (lhs[x, y] != rhs[x, y])
     227            0 :         return false;
     228              : 
     229          788 :   return true;
     230          788 : }
     231              : 
     232              : template <typename T> bool operator==(Grid2d<T> const &lhs, Grid2d<T> const &rhs) {
     233              :   return lhs.span() == rhs.span();
     234              : }
     235              : 
     236         2512 : template <typename T> bool operator<(Grid2dSpan<T> const &lhs, Grid2dSpan<T> const &rhs) {
     237         2512 :   if (lhs.xSize() != rhs.xSize() || lhs.ySize() != rhs.ySize())
     238            0 :     return false;
     239              : 
     240         2512 :   using IndexType = Grid2dSpan<T>::IndexType;
     241        41764 :   for (IndexType y = 0; y < lhs.ySize(); ++y)
     242      4102422 :     for (IndexType x = 0; x < lhs.xSize(); ++x) {
     243      4063170 :       if (lhs[x, y] < rhs[x, y])
     244         1170 :         return true;
     245      4062000 :       if (lhs[x, y] > rhs[x, y])
     246         1340 :         return false;
     247      4062000 :     }
     248            2 :   return false;
     249         2512 : }
     250              : 
     251         2512 : template <typename T> bool operator<(Grid2d<T> const &lhs, Grid2d<T> const &rhs) {
     252         2512 :   return lhs.span() < rhs.span();
     253         2512 : }
     254              : 
     255         5000 : template <typename H, typename T> H AbslHashValue(H h, Grid2dSpan<T> const &s) {
     256         5000 :   H state = H::combine(std::move(h), s.xSize(), s.ySize());
     257         5000 :   using IndexType = Grid2dSpan<T>::IndexType;
     258        38732 :   for (IndexType y = 0; y < s.ySize(); ++y)
     259        96196 :     for (IndexType x = 0; x < s.xSize(); ++x)
     260        62464 :       state = H::combine(std::move(state), s[x, y]);
     261         5000 :   return state;
     262         5000 : }
     263              : 
     264              : template <typename H, typename T> H AbslHashValue(H h, Grid2d<T> const &s) {
     265              :   return AbslHashValue(std::move(h), s.span());
     266              : }
     267              : 
     268           35 : template <typename T> void Grid2dSpan<T>::fill(ElementType const &e) const {
     269       176435 :   forEach([&e](ElementType &ee) { ee = e; });
     270           35 : }
     271              : 
     272           12 : template <typename T> auto Grid2dSpan<T>::find(ElementType const &e) const -> Coord {
     273          774 :   for (Coord c{0, 0}; c[1] < ySize(); ++c[1])
     274       103670 :     for (c[0] = 0; c[0] < xSize(); ++c[0])
     275       102908 :       if ((*this)[c] == e)
     276           12 :         return c;
     277              : 
     278            0 :   return {xSize(), ySize()};
     279           12 : }
     280              : 
     281              : template <typename T>
     282            8 : auto Grid2dSpan<T>::findAll(ElementType const &e) const -> std::vector<Coord> {
     283            8 :   std::vector<Coord> result;
     284          688 :   for (Coord c{0, 0}; c[1] < ySize(); ++c[1])
     285        72380 :     for (c[0] = 0; c[0] < xSize(); ++c[0])
     286        71700 :       if ((*this)[c] == e)
     287         6432 :         result.push_back(c);
     288              : 
     289            8 :   return result;
     290            8 : }
     291              : 
     292              : template <typename T>
     293            4 : auto Grid2dSpan<T>::map(auto &&mapFunc) const -> Grid2d<decltype(mapFunc(' '))> {
     294            4 :   Grid2d<decltype(mapFunc(' '))> result(xSize(), ySize());
     295          484 :   for (int y = 0; y < ySize(); ++y)
     296        59844 :     for (int x = 0; x < xSize(); ++x)
     297        59364 :       result[x, y] = mapFunc(_span[x, y]);
     298            4 :   return result;
     299            4 : }
     300              : 
     301          448 : template <typename T> size_t Grid2dSpan<T>::count_if(auto predicate) const {
     302          448 :   size_t ctr = 0;
     303      6363635 :   forEach([&](ElementType const &e) {
     304      6363635 :     if (predicate(e))
     305      2398237 :       ++ctr;
     306      6363635 :   });
     307          448 :   return ctr;
     308          448 : }
     309              : 
     310            7 : template <typename T> size_t Grid2dSpan<T>::count(ElementType const &e) const {
     311      1049660 :   return count_if([&e](ElementType const &ee) { return ee == e; });
     312            7 : }
     313              : 
     314            1 : template <typename T> auto Grid2dSpan<T>::max() const -> ElementType {
     315            1 :   ElementType max = _span[0, 0];
     316         9801 :   forEach([&max](ElementType const &e) {
     317         9801 :     if (e > max)
     318            9 :       max = e;
     319         9801 :   });
     320              : 
     321            1 :   return max;
     322            1 : }
     323              : 
     324            1 : template <typename T> auto Grid2dSpan<T>::sum() const -> ElementType {
     325            1 :   ElementType sum = ElementType();
     326      1000000 :   forEach([&sum](ElementType const &e) { sum += e; });
     327              : 
     328            1 :   return sum;
     329            1 : }
     330              : 
     331              : std::ostream &operator<<(std::ostream &oss, Grid2dSpan<char> const &span);
     332            0 : inline std::ostream &operator<<(std::ostream &oss, Grid2d<char> const &grid) {
     333            0 :   return oss << grid.span();
     334            0 : }
     335              : 
     336              : template <> struct fmt::formatter<Grid2dSpan<char>> : ostream_formatter {};
     337              : template <> struct fmt::formatter<Grid2d<char>> : ostream_formatter {};
     338              : 
     339              : template <typename T> class SparseGrid2d {
     340              : public:
     341              :   using ElementType = T;
     342              :   using IndexType = int;
     343              :   using Coord = Vec2<IndexType>;
     344              :   using SizeType = size_t;
     345              : 
     346            2 :   SparseGrid2d(ElementType const &defaultValue) : _defaultValue(defaultValue) {}
     347              : 
     348              :   [[nodiscard]] ElementType operator[](auto const x, auto const y) const { (*this)[{x, y}]; }
     349        11596 :   [[nodiscard]] ElementType operator[](Coord const &x) const {
     350        11596 :     auto it = _map.find(x);
     351        11596 :     return it == _map.end() ? _defaultValue : it->second;
     352        11596 :   }
     353              : 
     354         3316 :   void set(Coord const &x, ElementType const &value) { _map[x] = value; }
     355              :   void set(int const x, int const y, ElementType const &value) { _map[{x, y}] = value; }
     356              : 
     357            2 :   [[nodiscard]] std::pair<Coord, Coord> nonDefaultCoordsInterval() const {
     358            2 :     Coord min(std::numeric_limits<IndexType>::max());
     359            2 :     Coord max(std::numeric_limits<IndexType>::min());
     360         3316 :     for (auto const &[coord, val] : _map) {
     361         3316 :       min = elementwiseMin(min, coord);
     362         3316 :       max = elementwiseMax(max, coord);
     363         3316 :     }
     364              : 
     365            2 :     return {min, max};
     366            2 :   }
     367              : 
     368            2 :   [[nodiscard]] std::tuple<Grid2d<T>, Coord> toGrid2d() const {
     369            2 :     auto const [min, max] = nonDefaultCoordsInterval();
     370            2 :     Coord const size = max - min + 1;
     371              : 
     372            2 :     Grid2d<T> grid(size.x(), size.y(), _defaultValue);
     373            2 :     for (auto const &[coord, val] : _map)
     374         3316 :       grid[coord - min] = val;
     375            2 :     return {std::move(grid), min};
     376            2 :   }
     377              : 
     378              : private:
     379              :   ElementType _defaultValue;
     380              :   absl::flat_hash_map<Coord, ElementType> _map;
     381              : };
     382              : 
     383              : std::ostream &operator<<(std::ostream &oss, SparseGrid2d<char> const &span);
     384              : 
     385              : template <> struct fmt::formatter<SparseGrid2d<char>> : ostream_formatter {};
        

Generated by: LCOV version 2.0-1