C++ Simple matrix for the rest of us

Intro

The Introduction

“…There are issues such as dynamic memory allocation in C/C++, which is forbidden, under the DO-178B standard, in safety-critical embedded avionics code…”
The source

Before knowing the above, the other day I have developed a handy little template to hold and provide, a plain 2d array, completely on the stack (aka the “matrix”).

It is also fully “compile-time capable” with the full static internal presentation.

It is very handy to gently enforce company-wide C++ policies and to give some useful functionality in return. I am calling this approach “almost a pod”.

Before we proceed:  I do know about Expression Templates and few other optimization techniques. Alas. I do consider them an overkill in this context.

All of the dbj::stack_matrix is in this one header file.

Tests are in this another, single header file.

Probably the main reason for having matrices in some app is matrix multiplication. With this API it is rather silly simple, one could say:

/* 
taken from
https://github.com/dbj-systems/dbjplusplus/blob/master/test/dbj_static_matrix_test.h
*/

/* make 3 matrices */
using A = stack_matrix<int, 3, 3, DBJ_UID >;
using B = stack_matrix<int, A::cols(),3,DBJ_UID >;
using R = stack_matrix<int, A::rows(),   B::cols(), DBJ_UID >;

/* fill them with a callback */
A::for_each(filler);
B::for_each(filler);

/* multiply them*/
stack_matrix_multiply<A, B, R>();
/* 
R contains the result 
*/

After multiplication, A,B and R relationship is: A[n][m] x B[m][p] = R[n][p] . Columns of A must be the same as rows of B, and R matrix size must be A rows x B cols.

Nice, simple, functional and easy. Since this is all stack solution, the maximum matrix size matter here a lot and is approx 64KB.

This API is more than enough for the 99% of real-life use cases.  No huge and complex matrix libraries required.

In case you need matrix addition, difference and such I am sure you will find it very easy to add them by observing how is multiplication implemented, in there.

This is, after all, an open-source. Just please respect the copyright.

In case you just want to use ‘dbj::static_matrix’ as matrix storage, you are most welcome.  You will be also more than capable to do so. By looking into the two headers, whose GitHub links are provided.

Example. I personally use its storage in a C++ standard way

// unique int[5][7] on the stack
using A = stack_matrix<int, 5, 7, DBJ_UID >;
//
// make the standard C++ reference wrapper
std::reference_wrapper<int[A::rows()][A::cols()]> 
   ref_a = std::ref(A::data());
//
// or make a native reference to the matrix inside
// int(&)[5][7]
A::matrix_ref_type mr_a = ref_a;

That way I can reach the storage inside and use it elsewhere, to change it or to read it.

If I am using some external API written in a proper standard C++

//
// external API
//
template<
   typename T, size_t N, size_t M, size_t P
  >
 void multiply(
     T(&a)[N][M], 
     T(&b)[M][P], 
     T(&c)[N][P]
);

I can use this in a “super silly” way:

// use the 3rd party API and dbj static_matrix storage
multiply(A::data(), B::data(), R::data());

Really, a celebration of modern C++. But.