Generating dictionary for struct with member array whose counter is a size_t

Hello all,

I am trying to create dictionaries for a class whose members include pointers to structs of the form

struct epm_gsl_block {
  size_t size;
  double *data; //[size]
 struct epm_gsl_vector {
   size_t size;
   size_t stride;
   double *data; //[size]
   epm_gsl_block *block;
   int owner;

These are bit-compatible with equivalent structs in the GSL library (gsl_block and gsl_vector). Originally the class member was a gsl_vector* pointer; but since I could not get genreflex to build dictionaries for these foreign structs (and since I later recognized I would have to add the annotations //[size]) I created these bit-compatible structs, which can be converted back and forth via reinterpret_cast-ing. However, there are remaining problems with persistency — I get the following errors:

Error in TStreamerInfo::Build: epm_gsl_block, discarding: double* data, illegal [size] (must be Int_t)
Error in TStreamerInfo::Build: epm_gsl_vector, discarding: double* data, illegal [size] (must be Int_t)

The underlying type of size_t is typically an unsigned long, rather than an unsigned int. The relevant code that restricts of the counter to be integer is found in TStreamerInfo.cxx (from, starting at line 447):

TDataType* dtCounter = dmCounter->GetDataType();
Bool_t isInteger = dtCounter && ((dtCounter->GetType() == 3) || (dtCounter->GetType() == 13));
if (!dtCounter || !isInteger) {
   Error("Build", "%s, discarding: %s %s, illegal [%s] (must be Int_t)\n", GetName(), dmFull, dmName, counterName);

Types 3 and 13 are Int_t and UInt_t, while 4 and 14 are Long_t and ULong_t. I cannot think of a reason why it shouldn’t be possible to to allow the dtCounter to be a long type integer (especially since size_t is the canonical type for the size of an array in modern C/C++). Is there are workaround for this issue, or would it be possible to extend TStreamerInfo to allow long types for the counter?

AFAK … due to ROOT limitations, the variable “size” of the “data” array must (read my lips: MUST) be “a 32 bit signed integer (Int_t)”.

Could you elaborate? For one, I see that the code in TStreamerInfo.cxx accepts a signed int or an unsigned int, thus ((dtCounter->GetType() == 3) || (dtCounter->GetType() == 13), so is it it really true that the size variable must be signed? And second, the fact that only types 3 and 13, and not 4 and 14, are accepted in TStreamerInfo is clearly a ROOT limitation. Is this all you mean, or do you mean that if accepting types 4 and 14 were added here, code would break somewhere else?

Yes, other place in the code currently assume that the index is 32bits and thus adding support for 64bits is possible but not trivial (one part is hunting all the places that make this assumptions.


OK, thank you both for the clarification. In that case, could a possible workaround be based on a structure like

struct container_gsl_block {
   int array_size;
   struct {
      size_t size;
      double* data; //[array_size]
	} clone_gsl_block;

gsl_block* get_gsl_block(container_gsl_block* b) {
	return reinterpret_cast<gsl_block*>(&(b->clone_gsl_block));

More work would be required for me to flesh this out, of course, but my idea is that the values of array_size and size will always be forced to be equal – in practice the size never gets greater than O(10) so there will be no overflow problems. Will Reflex be able to parse this structure, with array_size, a member of the outer struct, representing the size of data in the inner struct?

Also, might I suggest that support for 64 bit indices be considered in the future? The pay-off for my single use-case is probably not worth the large amount of work you indicate would be necessary, but perhaps others might find benefit – especially since std::size_t is nowadays promoted as the canonical index type for people learning C++?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.