AoC code coverage
Current view: top level - aoclib - Vector.h (source / functions) Coverage Total Hit
Test: master Lines: 100.0 % 103 103
Test Date: 2025-07-28 10:53:57 Functions: 94.7 % 113 107

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include "IntegerCast.h"
       4              : 
       5              : #include <absl/hash/hash.h>
       6              : 
       7              : #include <algorithm>
       8              : #include <array>
       9              : #include <functional>
      10              : #include <ranges>
      11              : 
      12              : template <size_t N, typename T> class Vector {
      13              : public:
      14              :   using ElementType = T;
      15              :   using IndexType = int;
      16              : 
      17         7658 :   constexpr Vector() : _data{} {};
      18              : 
      19              :   explicit constexpr Vector(ElementType const &init)
      20              :     requires(N > 1u)
      21            4 :   {
      22            4 :     std::fill(_data.begin(), _data.end(), init);
      23            4 :   }
      24              : 
      25              :   template <typename... Ts>
      26              :   constexpr Vector(Ts &&...vals)
      27              :     requires(sizeof...(Ts) == N)
      28        37756 :       : _data{std::forward<Ts>(vals)...} {}
      29              : 
      30              :   template <typename U>
      31              :   explicit constexpr Vector(Vector<N, U> const &other)
      32              :     requires(!std::is_same_v<T, U>)
      33         1920 :   {
      34         1920 :     std::ranges::copy(other, begin());
      35         1920 :   }
      36              : 
      37              :   template <typename U>
      38              :   explicit constexpr Vector(Vector<N, U> &&other)
      39              :     requires(!std::is_same_v<T, U>)
      40              :   {
      41              :     std::ranges::move(std::move(other), begin());
      42              :   }
      43              : 
      44     25655872 :   [[nodiscard]] constexpr ElementType &operator[](auto const i) {
      45     25655872 :     ASSUME(integerCast<IndexType>(i) < size());
      46     25655872 :     return _data[integerCast<size_t>(i)];
      47     25655872 :   }
      48              : 
      49    102962494 :   [[nodiscard]] constexpr ElementType const &operator[](auto const i) const {
      50    102962494 :     ASSUME(integerCast<IndexType>(i) < size());
      51    102962494 :     return _data[integerCast<size_t>(i)];
      52    102962494 :   }
      53              : 
      54     13927726 :   [[nodiscard]] constexpr ElementType &x() { return (*this)[0]; }
      55     47045507 :   [[nodiscard]] constexpr ElementType const &x() const { return (*this)[0]; }
      56              :   [[nodiscard]] constexpr ElementType &y()
      57              :     requires(N >= 2)
      58     11304098 :   {
      59     11304098 :     return (*this)[1];
      60     11304098 :   }
      61              : 
      62              :   [[nodiscard]] constexpr ElementType const &y() const
      63              :     requires(N >= 2)
      64     46978844 :   {
      65     46978844 :     return (*this)[1];
      66     46978844 :   }
      67              : 
      68              :   [[nodiscard]] constexpr ElementType &z()
      69              :     requires(N >= 3)
      70        32010 :   {
      71        32010 :     return (*this)[2];
      72        32010 :   }
      73              : 
      74              :   [[nodiscard]] constexpr ElementType const &z() const
      75              :     requires(N >= 3)
      76      8549160 :   {
      77      8549160 :     return (*this)[2];
      78      8549160 :   }
      79              : 
      80              :   [[nodiscard]] constexpr T *data() { return _data.data(); }
      81              :   [[nodiscard]] constexpr T const *data() const { return _data.data(); }
      82    190166609 :   [[nodiscard]] constexpr size_t size() const { return N; }
      83              : 
      84      9864334 :   [[nodiscard]] constexpr auto begin() { return _data.begin(); }
      85      4945274 :   [[nodiscard]] constexpr auto end() { return _data.end(); }
      86     70904194 :   [[nodiscard]] constexpr auto begin() const { return _data.begin(); }
      87      9409750 :   [[nodiscard]] constexpr auto end() const { return _data.end(); }
      88              :   [[nodiscard]] constexpr auto cbegin() const { return _data.cbegin(); }
      89              :   [[nodiscard]] constexpr auto cend() const { return _data.cend(); }
      90              :   [[nodiscard]] constexpr auto rbegin() { return _data.rbegin(); }
      91              :   [[nodiscard]] constexpr auto rend() { return _data.rend(); }
      92              :   [[nodiscard]] constexpr auto rbegin() const { return _data.rbegin(); }
      93              :   [[nodiscard]] constexpr auto rend() const { return _data.rend(); }
      94              :   [[nodiscard]] constexpr auto crbegin() const { return _data.crbegin(); }
      95              :   [[nodiscard]] constexpr auto crend() const { return _data.crend(); }
      96              : 
      97     10934467 :   [[nodiscard]] friend constexpr Vector operator+(Vector const &lhs, Vector const &rhs) {
      98     10934467 :     return {std::views::zip_transform(std::plus{}, lhs, rhs)};
      99     10934467 :   }
     100              : 
     101      4413411 :   [[nodiscard]] friend constexpr Vector operator-(Vector const &lhs, Vector const &rhs) {
     102      4413411 :     return {std::views::zip_transform(std::minus{}, lhs, rhs)};
     103      4413411 :   }
     104              : 
     105              :   [[nodiscard]] friend constexpr Vector operator*(Vector const &lhs, Vector const &rhs) {
     106              :     return {std::views::zip_transform(std::multiplies{}, lhs, rhs)};
     107              :   }
     108              : 
     109        18830 :   [[nodiscard]] friend constexpr Vector operator/(Vector const &lhs, Vector const &rhs) {
     110        18830 :     return {std::views::zip_transform(std::divides{}, lhs, rhs)};
     111        18830 :   }
     112              : 
     113         1000 :   [[nodiscard]] friend constexpr Vector operator%(Vector const &lhs, Vector const &rhs) {
     114         1000 :     return {std::views::zip_transform(std::modulus{}, lhs, rhs)};
     115         1000 :   }
     116              : 
     117            2 :   [[nodiscard]] friend constexpr Vector operator-(Vector const &v) {
     118            2 :     return {std::views::transform(v, std::negate{})};
     119            2 :   }
     120              : 
     121      4894452 :   constexpr Vector &operator+=(Vector const &other) {
     122      4894452 :     std::ranges::transform(*this, other, this->begin(), std::plus{});
     123      4894452 :     return *this;
     124      4894452 :   }
     125              : 
     126        47311 :   constexpr Vector &operator-=(Vector const &other) {
     127        47311 :     std::ranges::transform(*this, other, this->begin(), std::minus{});
     128        47311 :     return *this;
     129        47311 :   }
     130              : 
     131              :   constexpr Vector &operator*=(Vector const &other) {
     132              :     std::ranges::transform(*this, other, this->begin(), std::multiplies{});
     133              :     return *this;
     134              :   }
     135              : 
     136              :   constexpr Vector &operator/=(Vector const &other) {
     137              :     std::ranges::transform(*this, other, this->begin(), std::divides{});
     138              :     return *this;
     139              :   }
     140              : 
     141              :   constexpr Vector &operator%=(Vector const &other) {
     142              :     std::ranges::transform(*this, other, this->begin(), std::modulus{});
     143              :     return *this;
     144              :   }
     145              : 
     146            2 :   [[nodiscard]] constexpr friend Vector operator+(Vector const &lhs, ElementType const &rhs) {
     147            4 :     return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e + rhs; })};
     148            2 :   }
     149              : 
     150            4 :   [[nodiscard]] constexpr friend Vector operator-(Vector const &lhs, ElementType const &rhs) {
     151            8 :     return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e - rhs; })};
     152            4 :   }
     153              : 
     154        24547 :   [[nodiscard]] constexpr friend Vector operator*(Vector const &lhs, ElementType const &rhs) {
     155        49094 :     return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e * rhs; })};
     156        24547 :   }
     157              : 
     158          640 :   [[nodiscard]] constexpr friend Vector operator/(Vector const &lhs, ElementType const &rhs) {
     159         1280 :     return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e / rhs; })};
     160          640 :   }
     161              : 
     162              :   [[nodiscard]] constexpr friend Vector operator%(Vector const &lhs, ElementType const &rhs) {
     163              :     return {std::ranges::transform_view(lhs, [&rhs](ElementType const &e) { return e % rhs; })};
     164              :   }
     165              : 
     166            2 :   [[nodiscard]] constexpr friend Vector operator+(ElementType const &lhs, Vector const &rhs) {
     167            4 :     return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs + e; })};
     168            2 :   }
     169              : 
     170              :   [[nodiscard]] constexpr friend Vector operator-(ElementType const &lhs, Vector const &rhs) {
     171              :     return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs - e; })};
     172              :   }
     173              : 
     174        50295 :   [[nodiscard]] constexpr friend Vector operator*(ElementType const &lhs, Vector const &rhs) {
     175       100590 :     return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs * e; })};
     176        50295 :   }
     177              : 
     178              :   [[nodiscard]] constexpr friend Vector operator/(ElementType const &lhs, Vector const &rhs) {
     179              :     return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs / e; })};
     180              :   }
     181              : 
     182              :   [[nodiscard]] constexpr friend Vector operator%(ElementType const &lhs, Vector const &rhs) {
     183              :     return {std::ranges::transform_view(rhs, [&lhs](ElementType const &e) { return lhs % e; })};
     184              :   }
     185              : 
     186       153746 :   constexpr auto operator<=>(Vector const &other) const = default;
     187              : 
     188        69398 :   template <typename H> [[nodiscard]] friend constexpr H AbslHashValue(H h, Vector const &v) {
     189        69398 :     return H::combine(std::move(h), v._data);
     190        69398 :   }
     191              : 
     192         3316 :   [[nodiscard]] constexpr friend Vector elementwiseMin(Vector const &lhs, Vector const &rhs) {
     193         3316 :     return {std::views::zip_transform(
     194         6632 :         [](ElementType const &l, ElementType const &r) { return std::min(l, r); }, lhs, rhs)};
     195         3316 :   }
     196              : 
     197         3316 :   [[nodiscard]] constexpr friend Vector elementwiseMax(Vector const &lhs, Vector const &rhs) {
     198         3316 :     return {std::views::zip_transform(
     199         6632 :         [](ElementType const &l, ElementType const &r) { return std::max(l, r); }, lhs, rhs)};
     200         3316 :   }
     201              : 
     202      4362915 :   [[nodiscard]] constexpr ElementType l1norm() const {
     203      4362915 :     return std::ranges::fold_left(
     204      8725830 :         *this | std::views::transform([](auto const &x) { return std::abs(x); }), ElementType{0},
     205      4362915 :         std::plus{});
     206      4362915 :   }
     207              : 
     208              : private:
     209              :   template <std::ranges::sized_range R>
     210              :   constexpr Vector(R const &r)
     211              :     requires(!std::is_same_v<std::remove_cvref_t<R>, Vector<N, T>>)
     212              :   {
     213              :     DEBUG_ASSERT(std::ranges::size(r) == N);
     214              :     std::ranges::copy(r, _data.begin());
     215              :   };
     216              : 
     217              :   template <std::ranges::sized_range R>
     218              :   constexpr Vector(R &&r)
     219              :     requires(!std::is_same_v<std::remove_cvref_t<R>, Vector<N, T>>)
     220     15449836 :   {
     221     15449836 :     DEBUG_ASSERT(std::ranges::size(r) == N);
     222     15449836 :     std::ranges::move(std::forward<R>(r), _data.begin());
     223     15449836 :   };
     224              : 
     225              :   std::array<ElementType, N> _data;
     226              : };
     227              : 
     228              : // Custom specialization of std::hash can be injected in namespace std.
     229              : template <size_t N, typename T> struct std::hash<Vector<N, T>> : public absl::Hash<Vector<N, T>> {};
     230              : 
     231              : // Making Vector "tuple-like" to enable structured bindings
     232              : template <size_t N, typename T>
     233              : struct std::tuple_size<Vector<N, T>> : public integral_constant<std::size_t, N> {};
     234              : 
     235              : template <std::size_t I, size_t N, typename T>
     236              :   requires(I < N)
     237              : struct std::tuple_element<I, Vector<N, T>> {
     238              :   using type = T;
     239              : };
     240              : 
     241              : template <std::size_t I, size_t N, typename T>
     242              :   requires(I < N)
     243            8 : constexpr T &get(Vector<N, T> &v) {
     244            8 :   return v[I];
     245            8 : }
     246              : 
     247              : template <std::size_t I, size_t N, typename T>
     248              :   requires(I < N)
     249              : constexpr T const &get(Vector<N, T> const &v) {
     250              :   return v[I];
     251              : }
     252              : 
     253              : template <std::size_t I, size_t N, typename T>
     254              :   requires(I < N)
     255            8 : constexpr T &&get(Vector<N, T> &&v) {
     256            8 :   return std::move(get<I>(v));
     257            8 : }
     258              : 
     259              : template <std::size_t I, size_t N, typename T>
     260              :   requires(I < N)
     261              : constexpr T const &&get(Vector<N, T> const &&v) {
     262              :   return std::move(get<I>(v));
     263              : }
     264              : 
     265              : template <typename T> using Vec2 = Vector<2u, T>;
     266              : template <typename T> using Vec3 = Vector<3u, T>;
        

Generated by: LCOV version 2.0-1