Home > Back-end >  Can I use a constexpr function to run an algorithm on an array at compile time?
Can I use a constexpr function to run an algorithm on an array at compile time?

Time:12-28

I have an array like this one below:

std::array<char, 10> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

I have to add 2 more bytes that would represent the checksum of the array.
The checksum is calculated like this:

char x = 0;
char y = 0;

for (int i = 0; i < size; i  )
{
    x = x   array[i];
    y = x   y;
}

Finally, the values x and y should be added at the end array.

I want the array to be static inside a method of a class. I don't know if that matters.

class Foo
{
 public:
  char * getData(void)
  {
    static std::array<char, 10> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    // checksum must be calculated here.
    return &numbers[0];
  }
}

If I leave two extra bytes space in the array and pass it by reference in a constexpr function. Would that work?

constexpr void checksum_calc(std::array<char, 12>& arr)
{
  char x = 0;
  char y = 0;
  
  for (int i = 0; i < 12 - 2; i  )
  {
      x = x   array[i];
      y = x   y;
  }
  arr[10] = x;
  arr[11] = y;
}

Also, if I want the array to work on different sizes, can I make it a template?
Like this?

template <size_t sz>
constexpr void checksum_calc(std::array<char, sz>& arr)
{
  char x = 0;
  char y = 0;
  
  for (int i = 0; i < sz - 2; i  )
  {
      x = x   array[i];
      y = x   y;
  }
  arr[sz - 2] = x;
  arr[sz - 1] = y;
}

Example:

char * getData()
{
  // two extra bytes for the checksum
  static std::array<char, 12> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  checksum_calc<12>(numbers);
  return &numbers[0];
}

The reason I chose a template is because I want arrays of different sizes like:

Example 2:

char * foo_getData()
{
  // two extra bytes for the checksum
  static std::array<char, 7> numbers = {1, 2, 3, 4, 5};
  checksum_calc<7>(numbers);
  return &numbers[0];
}

char * bar_getData()
{
  // two extra bytes for the checksum
  static std::array<char, 9> numbers = {1, 2, 3, 4, 5, 6, 7};
  checksum_calc<9>(numbers);
  return &numbers[0];
}

The purpose is to have a constant array followed by 2 bytes checksum that must be calculated.
I don't want to calculate it by hand and add it.

Is what I'm trying to do a good practice?

CodePudding user response:

Also, if you want to create constexpr arrays and have C 17 you can do following:

template <size_t sz>
constexpr std::array<char, sz 2> checksum_calc(const std::array<char, sz>& arr)
{
  std::array<char, sz 2> res = {};
  char x = 0;
  char y = 0;
  
  for (int i = 0; i < sz; i  )
  {
      res[i] = arr[i];
      x = x   arr[i];
      y = x   y;
  }
  res[sz] = x;
  res[sz 1] = y;
  return res;
}

And then use it like this:

constexpr array<char, 1> a1 = {1};
constexpr auto a2 = checksum_calc(a1);

//or

constexpr auto a3 = checksum_calc<1>({2});

CodePudding user response:

Do you need checksum_calc to be separated? Otherwise, you can play more with C 17 capabilities and group your array and checksum compute together: https://godbolt.org/z/TW8EEG7Ej

template<typename _Ty, std::size_t _N>class checksumed_array {
  std::array<_Ty, _N   2> _data;

  constexpr void compute_checksum() noexcept {
    char x = 0;
    char y = 0;

    for (int i = 0; i < _N; i  ) {
      x = x   _data[i];
      y = x   y;
    }
    _data[_N] = x;
    _data[_N 1] = y;
  }
public:
  template<typename... _TyInt>
  constexpr checksumed_array(_TyInt... vals) noexcept : _data{ ((_Ty)vals)... } {
    compute_checksum();
  }

  constexpr const _Ty& operator[](std::size_t i) const noexcept {
    return _data[i];
  }

  constexpr operator const std::array<_Ty, _N   2>& () const noexcept {
    return _data;
  }
};

Thanks to this, everything is static and can probably be better optimized away. Warning: operator[] and cast should be done without const context for this class to operate at runtime.

Use example :

constexpr checksumed_array<int, 3> ca = { 1, 2, 3 };
std::cout << ca[2] << " " << ca[3] << " " << ca[4] << "\n";

[Edit 1] Fixed missing const attributes for operator[] and cast... Thanks @doug from comments !

  • Related