Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transpose template parameter pack

I want to pass a row-major argument list to a constexpr constructor and store the data in a column-major array. I have to transpose the template parameter pack from row-major to column-major and the only way I came up with was by using a temporary array like this:

template <typename T, std::size_t rows, std::size_t cols = rows>
class Matrix final
{
public:
  std::array<T, cols * rows> m; // column-major matrix

  template <typename ...A>
  constexpr Matrix(const A... args) noexcept:
    m{transpose(std::array<T, rows * cols>{args...}, std::make_index_sequence<rows * cols>{})}
  {}

  template <std::size_t ...i>
  constexpr auto transpose(const std::array<T, cols * rows> a,
                           const std::index_sequence<i...>) noexcept
  {
    return std::array<T, cols * rows>{a[((i % rows) * cols + i / rows)]...};
  }
};

I guess there is no other way to access the elements in a parameter-pack out of order, but maybe there is a way to do it without an intermediate array.

like image 721
Elviss Strazdins Avatar asked May 16 '26 10:05

Elviss Strazdins


1 Answers

To significantly improve the performance of debug builds without removing features, you'll need to replace std::array with a more basic functionless version:

https://quick-bench.com/q/FS2cphByJEWMFMsquI_Yor8ZnyI

The resulting version (ChangedArrayBasic) is ~2.8x faster than the original on Clang 12.0, -O0, libstdc++.

The index operator must not be used since it appears to be largely unoptimizable in practice, instead the internal array needs to be accessed manually.

template <class T, size_t N>
struct BasicCustomArray
{
  T d[N];
};

template <typename T, std::size_t rows, std::size_t cols = rows>
class NewMatrixBasic final
{
public:
  using Arr = BasicCustomArray<T, cols * rows>; // <-----------------------------
  Arr m; // column-major matrix

  template <typename ...A>
  constexpr NewMatrixBasic(const A... args) noexcept:
    m{transpose(Arr{args...}, std::make_index_sequence<rows * cols>{})}
  {}

  template <std::size_t ...i>
  constexpr auto transpose(const Arr a,
                           const std::index_sequence<i...>) noexcept
  {
    return Arr{a.d[((i % rows) * cols + i / rows)]...}; // <---------------------
  }
};
like image 191
archo Avatar answered May 17 '26 23:05

archo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!