Genreflex generated streamer vs rootcint generated streamer

Dear Experts,

I wanted to write my own streamer for a class which has pointer to array. Nothing is derived from TObject. I also wanted to use genreflex.

Here is my simple class A:

class A {
public:
int m_n;
A():m_n(7){}
virtual ~A();
ClassDef(A,1);
};

genreflex (gendict.py from 5.23, others from 5.22a. This is to avoid a problem with vector. ) produces the streamer like this.

void ::a::Streamer(TBuffer &b) {
if (b.IsReading()) {
b.ReadClassBuffer(::a::Class(),this);
} else {
b.WriteClassBuffer(::a::Class(),this);
}
}

and rootcint produces:

void A::Streamer(TBuffer &R__b)
{
// Stream an object of class A.

UInt_t R__s, R__c;
if (R__b.IsReading()) {
Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
R__b >> m_n;
R__b.CheckByteCount(R__s, R__c, A::IsA());
} else {
R__c = R__b.WriteVersion(A::IsA(), kTRUE);
R__b << m_n;
R__b.SetByteCount(R__c, kTRUE);
}
}

I copied rootcint version and pasted into A_rflx.cxx which is produced with genreflex. When I write and read the tfile, I get the following error.

Error in TBufferFile::CheckByteCount: object of class A read too few bytes: 6 instead of 10

once per event. If I use genreflex generated streamer, I don’t get such error.

How can I use (something like) rootcint generated Streamer with genreflex? This is because I would like to read/write class members by myself.

I can also remove the error if I remove calls to ReadVersion, CheckByteCount, WriteVersion and SetByteCount functions in rootcint generated streamer.

I use 5.22a version of root except for gendict.py which is from 5.23
It happens even if I use 5.22a version of gendict.py

Thanks!

Nobu

Hi Nobu,

you are comparing two different (and incompatible) versions of Streamer incarnations. The reflex one corresponds to CINT’s #pragma link C++ class A+; (note the “+” at the end). I never planned to make CINT-without-plus and Reflex dictionaries compatible.

If that doesn’t answer your question I will need to understand what exactly you are trying to do.

Cheers, Axel.

Hi Alex,

Thanks for a reply. I get the same Streamer as genreflex when I add “+” in LinkDef.h.

How can I write the streamer contents instead of

if (R__b.IsReading()) {
R__b.ReadClassBuffer(A::Class(),this);
} else {
R__b.WriteClassBuffer(A::Class(),this);
}

Can I just write like
if(R__b.IsReading()) {
R__b >> m_i;
m_m = new double[m_i*(m_i+1)/2];
R__b.ReadFastArray(m_m, m_i*(m_i+1)/2);
} …

and don’t worry about versions or byte counts?

[quote]How can I write the streamer contents instead of [/quote]In rootcint, by using ‘-’ instead of ‘+’.

[quote]and don’t worry about versions or byte counts?[/quote]You could, but why would you? Removing the version number means that you will never be able to evolve/change your class and still be able to read old files. Removing the byte count removes one ‘protection’ against problems (including typo in your streamer and file corruptions). Without the byte-count one problem night render the entire file unreadable.

Cheers,
Philippe.

Hi Philippe,

Could you tell me how the Streamer (new format) looks like for the following class?

class A {
int m_i;
double *m_m;
A(int i);
A();
};

A::A():m_i(0), m_m(NULL) {}

A::A(int i): m_i(i) {
int size = (m_i*(m_i+1))/2;
m_m = size>0?new double [size]:NULL;
}

Thanks,

Nobu

Hi Nobu,

if (R__b.IsReading()) { R__b.ReadClassBuffer(A::Class(),this); } else { R__b.WriteClassBuffer(A::Class(),this); }
However you will need to modify your class slightly:

[code]class A {
int m_i;
int m_size;
double *m_m; //[m_size]
A(int i);
A();
};

A::A():m_i(0), m_m(NULL) {}

A::A(int i): m_i(i) {
m_size = (m_i*(m_i+1))/2;
m_m = size>0?new double [size]:NULL;
}[/code]The [m_size] is necessary for the I/O to know the size of the array. Alternatively, you can also use:[code]
class A {
int m_i;
vector m_m;
A(int i);
A();
};

A::A():m_i(0), m_m(NULL) {}

A::A(int i): m_i(i) {
int size = (m_i*(m_i+1))/2;
m_m.resize(size);
} [/code]

Cheers,
Philippe.

Hi Alex and Philippe,

OK. I solved my problem. Upon inspecting the ROOT code, I found I needed the third argument to ReadVersion, thisClass::IsA(). It was not in rootcint generated code (without “+”). The following does it.

I have then a question. How can I embed this kind of code in selection.xml and or A.h (with version) as I don’t want to hand write my streamer?

As you can see I need to do a special memory management for m.

UInt_t R__s, R__c;
if (R__b.IsReading()) {
Version_t R__v = R__b.ReadVersion(&R__s, &R__c, thisClass::IsA());
int nrow_tmp;
R__b >> nrow_tmp;
if(nrow_tmp!=nrow) {
if(m!=NULL) delete_m(size,m);
nrow = nrow_tmp;
size = (nrow * (nrow + 1)) / 2;
if(nrow>0) {
m = new_m(size);
} else {
m = NULL;
}
}
if(size>0) R__b.ReadFastArray(m,size);
R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
} else {
R__c = R__b.WriteVersion(thisClass::IsA(), kTRUE);
R__b << nrow;
if(size>0) R__b.WriteFastArray(m,size);
R__b.SetByteCount(R__c, kTRUE);
}

Hi,

The easiest is to slightly modify your class (see my previous post).

Cheers,
Philippe.

Hi Philippe,

Thanks.

I understand that with rootcint, I can add //[size]. With “+” it even took [(m_i*(m_i+1))/2] although I did not try to run with it.

Is there documentation on how I embed the code (example shown on P. 17 of your presentation at CHEP? especially for selection.xml case?

I want to use my own memory management to allocate the array, rather than new.

Best,

Nobu