As noted in the comments in TStreamerInfo, the length of an array to be reflected should be annotated thusly:
//
// look for a pointer data member with a counter
// in the comment string, like so:
//
// int n;
// double* MyArray; //[n]
//
Is the reverse order allowed, e.g.
//
// look for a pointer data member with a counter
// in the comment string, like so:
//
// double* MyArray; //[n]
// int n;
//
For reasons that have to do with the order of bits in memory, I must do the latter, but Iām not sure if this is responsible for some of the errors I get, which look like
Error in <TStreamerInfo::Build>: epm_gsl_block, discarding: double* data, illegal [reflex_size]
where epm_gsl_block is the struct containing these entries, data corresponds to MyArray, and reflex_size corresponds to n.
Not at the moment. This is a side effect of storing the data members in the strict order they are listed (and of course myArray can not be read until n has been read).
This is indeed a limitation that we could lift by updating TStreamerInfo::Build to detect this case and to update the order in which the data member are stored on the file (to have n comes before MyArray). This is doable but would require external help to have the resource to implement and test this.
OK, thank you for the clarification. Sadly, this does make things a bit more difficult for me, but should be circumventable with a small penalty overhead. Due to the limitation you explained to me in another thread, where the index variable must be 32 bit, I have worked on creating structs of the form
With this structure, a pointer of type epm_gsl_vector* v can be converted to a gsl_vector pointer via reinterpret_cast<gsl_block*>(v). Importantly, this correctly handles the epm_gsl_block* member.
However, things will be more difficult once I move my reflex_size members to the front of the structs. Such as epm_gsl_vector* v can be cast via reinterpret_cast<gsl_vector*>(&(v->size)), but the block member of the reinterpreted pointer will point to a section of memory beginning with the uint32_t reflex_size member rather than the std::size_t size member, as is required for bit-compatibility.
Iāll have to circumvent this by temporarily adjusting the block pointer and then adjusting it back. So, unlike my previous attempted solution, there will be run-time costs involved instead of just compile-time reinterpreting (but it should have the advantage of workingā¦).
which this the part known by the compiler as āepm_gsl_blockā ina epm_gsl_block_real object would start at the ārightā address (and the members would be in the right order for ROOT).
On second thought, you couldnāt have meant this, because then //[reflex_size] would mean nothing without the inheritance - but then an epm_gsl_block pointer is a pointer to an empty struct. Should that then be reinterpreted?
[quote=ājwimberl, post:6, topic:24347ā]
On second thought, you couldnāt have meant this, because then //[reflex_size] would mean nothing without the inheritance [/quote]Exactly.
but then an epm_gsl_block pointer is a pointer to an empty struct. Should that then be reinterpreted?
Yes, in your code, you would only use epm_gsl_block_real but then the other code (to which you are trying to be binary compatible) will have a different definition of epm_gsl_block but that lines up nicely (member-wise in memory) with yours.
The reason to have the āemptyā struct is to get the compiler to do (automatically) the offset shuffling you were mentioning.
I believe this is a faithful but simplified implementation of your suggestion. However, the printout of stest->size is 10376293541461622785 rather than 1. (Actually, itās unpredictable, and does give 1 sometimes).
Your solution has a wonderful extra feature that you might not have realized - it permits (with caution) casting backwards! Adding the following in main
Iām not quite sure why the difference between e and f is only 2. However, this code successfully takes a pointer to a block_original and casts it to a block_real pointer, which starts some point earlier in memory. The size and val elements of the casted block_real pointer refer to the same memory as for the block_original pointer; the reflex_size element refers to whatever part of memory precedes the block_original, of course, and its behavior is undefined and should not be used. With caution, though, this should allow me to take GSL pointers created/allocated by GSL functions and treat them as though they are my type for the purposes of using C++ operator overloads.