Embedded C++ static initialization of struct arrays - c++

While migrating to C++ I require a certain function that seems to have been deprecated.
sorry, unimplemented: non-trivial designated initializers not supported
What is the correct way to implement the following data storage system in C++ for memory constraint systems?
typedef union union_t {
float f;
int i;
} arg;
typedef struct type_t {
int a;
arg b;
int d;
} element;
const element list[] = {
{
.a = 1,
.b = { .f = 3.141519f },
.d = 6
},
{
.a = 3,
.b = { .i = 1 },
}
};
Often the use of std:map or std:vector is suggested. Which is suitable, however list is immutable and must be able to compile and link to a specific block of flash. Both seem unfit for that purpose.
The highest I can go is ARM Compiler 6, which is C++14.

The way you shown is almost correct compliant with the incoming C++20 standard. Only that .d also have to be initialized. Is it what I suggest to use.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf
To handle this in C++14 you have to initilize it explicilty:
typedef union union_t {
float f;
int i;
} arg;
typedef struct type_t {
int a;
arg b;
int d;
} element;
const element list[] = {
{
/*.a = */ 1,
/*.b = */ { /*.f = */ 3.141519f },
/*.d = */ 6
},
{
/* .a = */ 3,
/* .b = */ { /* .i = */ 1 },
0
}
};

Related

Initializing an array of pointers to structs in C++

Initializing an array of pointers to structs in C can be done using compound literals.
typedef struct {
int a;
int b;
} s;
In C:
s *ptrArray[] = {
&(s){
.a = 1,
.b = 2
},
&(s){
.a = 4,
.b = 5
}
};
How can this be done in C++?
I have also seen the difference in initializing structs in C++ not using compound statements:
s s1 = { a: 7, b: 8 };
First - initializing anything to the address of a temporary value seems extremely fishy, in C as well. Are you sure that's valid? Hmmm. Anyway, a C++ compiler will really not let you do that.
As for the your designated (named-field) initialization C++ line - it's actually non-standard, it's a GNU C++ extension, and you can't rely on it.
You could do this:
struct s { int a, b; };
int main() {
s data[] = { { 1, 2 }, { 4, 5 } };
// instead of ptrArray[i], use &(data[i])
}
This compiles just fine. But - a more C++'ish version of this code would be:
#include <array>
struct s { int a, b; };
int main() {
std::array<s, 2> data { s{ 1, 2 }, s{ 4, 5 } };
// instead of ptrArray[i], use &(data[i]),
// or use iterators, or ranged for loops
}
Why would you want to use std::array? Here's one explanation of the benefits. Actually, you could do slightly better and repeat yourself less with:
int main() {
auto data = make_array(s{ 1, 2 }, s{ 4, 5 });
// instead of ptrArray[i], use &(data[i]),
// or use iterators, or ranged for loops
}
The make_array function is taken from here; you also have std::experimental::make_array(), but that's not standardized yet.
If you want to add or remove elements from data at run-time, you might switch to using std::vector:
#include <vector>
struct s { int a, b; };
int main() {
std::vector<s> data { s{ 1, 2 }, s{ 4, 5 } };
// instead of ptrArray[i], use &(data[i]),
// or use iterators, or ranged for loops
}
The reason your initialize was failing is you were attempting to initialize the array of pointers to struct to the address of numeric literal constants. The same as:
#define A 5
int b = &A; /* NOT HAPPENING */
(you can't take the address of 5)
You can solve your problem by simply initializing an array of s instead of an array of pointers to s, e.g.:
s ptrarr[] = { {1, 2}, {4, 5} };
With that change, your array will initialize fine, e.g.
#include <iostream>
typedef struct {
int a;
int b;
} s;
int main (void) {
s ptrarr[] = { {1, 2}, {4, 5} };
int cnt = 0;
for (auto& i : ptrarr)
std::cout << "ptrarr[" << cnt++ << "] : " << i.a << ", " << i.b << "\n";
}
Example Use/Output
$ ./bin/ptrarrystruct
ptrarr[0] : 1, 2
ptrarr[1] : 4, 5

Checking function pointers type

Let define a structure parser :
struct parser {
int (*buffer_push_strategy)();
int (*escape_buffer_push_strategy)();
int (*do_callback_strategy)();
};
I have an initialization function :
int parser_init() {
if (some_condition) {
parser->buffer_push_strategy = buffer_push_strategy1;
parser->escape_buffer_push_strategy = escape_buffer_push_strategy1;
parser->do_callback_strategy = do_callback_strategy1;
}
else {
parser->buffer_push_strategy = buffer_push_strategy2;
parser->escape_buffer_push_strategy = escape_buffer_push_strategy2;
parser->do_callback_strategy = do_callback_strategy2;
}
return 0;
}
where the strategy functions are defined somewhere.
Ok, so my interest is to determine which strategy has been used when I write the unit tests. Any idea how to accomplish that?
I saw something on internet about is_pointer function from C++ 11, but I don`t think this would help me.
parser is a variable:
struct parserT {
int (*buffer_push_strategy)();
int (*escape_buffer_push_strategy)();
int (*do_callback_strategy)();
} parser;
If you want to know which the strategy is, you could use:
int strategy= (parser->buffer_push_strategy == buffer_push_strategy1) ? 1 : 2;
Perhaps, you prefer to store the strategy number:
int parser_init() {
if (some_condition) {
parser->buffer_push_strategy = buffer_push_strategy1;
parser->escape_buffer_push_strategy = escape_buffer_push_strategy1;
parser->do_callback_strategy = do_callback_strategy1;
return 1;
}
else {
parser->buffer_push_strategy = buffer_push_strategy2;
parser->escape_buffer_push_strategy = escape_buffer_push_strategy2;
parser->do_callback_strategy = do_callback_strategy2;
return 2;
}
}
Then, you could init the parser as:
const int STRATEGY= parser_init();
You can compare function pointers
if(p.buffer_push_strategy == buffer_push_strategy1)
See https://ideone.com/QQzL1c

Is it possible to cast Foo to ubyte[size] at compile time?

Is it possible to cast Foo to ubyte[size] at compile time?
Here is a bit more context:
struct Algebraic(Types...)
if(Types.length < char.max - 1){
import std.traits: Largest;
import std.meta: IndexOf;
static immutable maxSize = Largest!(Types).sizeof;
this(T)(in T t)
if(IndexOf!(T, Types) !is -1){
type = IndexOf!(T, Types);
data = *cast(ubyte[maxSize]*)&t;
}
void opAssign(T)(in T t)
if(IndexOf!(T, Types) !is -1){
type = IndexOf!(T, Types);
data = *cast(ubyte[maxSize]*)&t;
}
inout(T*) peek(T)() inout{
if(type is IndexOf!(T, Types)){
return cast(inout(T*))&data;
}
return null;
}
private:
ubyte[maxSize] data;
char type = char.max;
}
struct Branch{
int index;
int left;
int right;
}
struct Leaf{
int index;
}
struct Foo{
alias Node = Algebraic!(Branch, Leaf);
Node n = Branch(1,2,3);
//Error: cannot convert &const(Branch) to ubyte[12]* at compile time
}
The problem is that I can not cast Branch to ubyte[maxSize] at compile time.
I am not aware of any "clean" approach (one that would make use of compiler knowledge of ABI) because CTFE is very conservative in preventing reinterpretation. However, if this is a blocker, it is possible to build up byte array manually making use of the fact struct ABI is very simple:
import std.traits;
ubyte[T.sizeof] reinterpret (T) ( T x )
if (!hasIndirections!T)
{
typeof(return) result;
static if (is(T == struct))
{
size_t offset = 0;
foreach (ref field; x.tupleof)
{
result[offset .. offset + field.sizeof] = reinterpret(field);
offset += field.sizeof;
}
}
else static if (is(T : ulong))
{
for (auto i = 0; i < x.sizeof; ++i)
result[i] = cast(ubyte) (x >> 8*i);
}
else
{
// handle floating types, arrays etc.
}
return result;
}
struct S
{
int x, y;
}
static immutable bytes = reinterpret(S(42, 42));
pragma(msg, bytes);
There is one huge limitation with this approach: you are required to adjust to proper ABI manually. Stuff like endianess is trivial, but handling field alignment properly is likely to be a pain (I am not even trying to do so in this snippet).

c++ int array with values of 2 dimension int array (3d array)

I'm trying to make an array which contain int[][] items
i.e
int version0Indexes[][4] = { {1,2,3,4}, {5,6,7,8} };
int version1Indexes[][4] = { ...... };
int version15Indexes[][4] = { ... };
(total of 16)
int indexes[][][] = { version0Indexes,version1Indexes, .. };
anyone can suggest how to do so ?
Thanks
You can use an array of pointers to array:
int (*indexes[])[4] = { version0Indexes, version1Indexes, .. };
Either you inline your arrays inside indexes:
int indexes[][2][4] = {
{ { 1, 2, 3, 4}, {5, 6, 7, 8} },
{ {....}, {....} }
....
}
Or you make indexes an array of pointers:
int (*indexes[])[4] = { version0Indexes, version1Indexes, .... };
What you wrote in your question is not directly possible because, when used, an array variable is actually a pointer (that's why indices has to be an array of pointers).

What is a "yield return" equivalent in the D programming language?

Here is a simple generator in C#.
IEnumerable<int> Foo()
{
int a = 1, b = 1;
while(true)
{
yield return b;
int temp = a + b;
a = b;
b = temp;
}
}
How do I write a similar generator in Digital Mars D?
(The question is about the yield return statement)
Thanks!
Update.
That's interesting. Since I'm just generating a mathematical sequence, using recurrence may be a good option.
auto fib = recurrence!("a[n-1] + a[n-2]")(1, 1);
foreach (e; take(fib, 10)) // <- prints first ten numbers from the sequence
{
writeln(e);
}
There's no exact equivalent in D. Here are some rough equivalents:
Using opApply-style internal iteration. This doesn't allow iterating over two iterators in lockstep, though:
struct Foo {
int opApply(int delegate(ref int) dg) {
int a = 1, b = 1;
int result;
while(true) {
result = dg(b);
if(result) break;
int temp = a + b;
a = b;
b = temp;
}
return result;
}
}
void main() {
// Show usage:
Foo foo;
foreach(elem; foo) {
// Do stuff.
}
}
Use ranges. These are slightly harder to write in some cases, but are very efficient and allow lockstep iteration. This can also be iterated over with a foreach loop, exactly like the opApply version:
struct Foo {
int a = 1, b = 1;
int front() #property {
return b;
}
void popFront() {
int temp = a + b;
a = b;
b = temp;
}
// This range is infinite, i.e. never empty.
enum bool empty = false;
typeof(this) save() #property { return this; }
}
If you really need coroutine-style stuff you can combine ranges and opApply together using core.thread.Fiber, but you'll probably find that either ranges or opApply does what you need almost all the time.
See here; example excerpt below:
module main;
import std.stdio;
import generators;
void genSquares(out int result, int from, int to)
{
foreach (x; from .. to + 1)
yield!result(x * x);
}
void main(string[] argv)
{
foreach (sqr; generator(&genSquares, 10, 20))
writeln(sqr);
}
The std.concurrency module now has a Generator class which makes this even easier (and you don't need a third-party library).
The class is an input range, so it can be used with for loops and all the standard std.range/std.algorithm functions.
import std.stdio;
import std.range;
import std.algorithm;
import std.concurrency : Generator, yield;
void main(string[] args) {
auto gen = new Generator!int({
foreach(i; 1..10)
yield(i);
});
gen
.map!(x => x*2)
.each!writeln
;
}