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 !