ROOT Version: 5.34.38
Platform: linux
Compiler: gcc/clang
I a data analysis and simulation framework for Gamma-Ray Astronomy,
we have a class that inherits from TClonesArray just adding a new method.
However, this class is not nicely serializable to root files (e.g. the TBrowser does not show member fields of the objects in the array as opposed to when using the TClonesArray directly).
What is needed to implement I/O same as for the TClonesArray?
MClonesArray.h:
#ifndef MARS_MCLONESARRAY_H
#define MARS_MCLONESARRAY_H
#include "TClonesArray.h"
class MClonesArray : public TClonesArray
{
public:
enum EStatusBits {
kForgetBits = BIT(0), // Do not create branches for fBits, fUniqueID
kNoSplit = BIT(1), // No splitting in TBranch
kBypassStreamer = BIT(12), // Class Streamer not called (default)
};
using TClonesArray::TClonesArray;
TObject **FirstRef();
void FastShrink(Int_t n);
void FastRemove(Int_t idx1, Int_t idx2);
void UncheckedSort();
virtual ~MClonesArray() {}
ClassDef(MClonesArray, 2) // A TClonesArray with optimized sorting and shrinking
};
#endif //MARS_MCLONESARRAY_H
MClonesArray.cpp
#include "TObject.h"
#include "TClonesArray.h"
#include "MClonesArray.h"
#include "TClass.h"
ClassImp(MClonesArray)
TObject** MClonesArray::FirstRef() { return fCont; }
// --------------------------------------------------------------------------
//
// This is an extremely optimized version of ExpandCreateFast. It only resets
// the marker for the last element (fLast) to n-1 and doesn't change anything
// else. This implicitly assumes that the stored objects don't allocate
// memory. It does not necessarily mean that the slots after fLast
// are empty (set to 0). This is what is assumed in the TClonesArray.
// We also don't call Changed() because it would reset Sorted. If the
// array was sorted before it is also sorted now. You MUST make sure
// that you only set n in a range for which valid entries have been
// created before (e.g. by ExpandCreateFast).
//
void MClonesArray::FastShrink(Int_t n)
{
fLast = n - 1;
}
// --------------------------------------------------------------------------
//
// This is a optimized (faster) version of Delete which deletes consequtive
// entries from index idx1 to idx2 (both included) and calls their
// destructor. Note that there is no range checking done!
//
void MClonesArray::FastRemove(Int_t idx1, Int_t idx2)
{
// Remove object at index idx.
//if (!BoundsOk("RemoveAt", idx1)) return 0;
//if (!BoundsOk("RemoveAt", idx2)) return 0;
Long_t dtoronly = TObject::GetDtorOnly();
idx1 -= fLowerBound;
idx2 -= fLowerBound;
for (TObject **obj=fCont+idx1; obj<=fCont+idx2; obj++)
{
if (!*obj)
continue;
if ((*obj)->TestBit(kNotDeleted)) {
// Tell custom operator delete() not to delete space when
// object fCont[i] is deleted. Only destructors are called
// for this object.
TObject::SetDtorOnly(*obj);
delete *obj;
}
*obj = 0;
// recalculate array size
}
TObject::SetDtorOnly((void*)dtoronly);
if (idx1<=fLast && fLast<=idx2)
{
do {
fLast--;
} while (fLast >= 0 && fCont[fLast] == 0);
}
Changed();
}
// --------------------------------------------------------------------------
//
// This is an optimized version of Sort which doesn't check the
// IsSortable flag before. It only sorts the entries from 0
// to GetEntriesFast().
//
void MClonesArray::UncheckedSort()
{
if (fSorted)
return;
const Int_t nentries = GetEntriesFast();
if (nentries <= 0)
return;
QSort(GetObjectRef(First()), fKeep->GetObjectRef(fKeep->First()),
0, TMath::Min(nentries, kMaxInt-fLowerBound));
fSorted = kTRUE;
}
// This seems not to be enough to make this serialize nicely into
// root files. I'm out of ideas.
void MClonesArray::Streamer(TBuffer &b)
{
TClonesArray::Streamer(b);
}
And this entry in our linkdef to create the dictionary:
#pragma link C++ class MClonesArray-;
Though uproot I found out, that the MClonesArray writes an empty string fClonesName
to the file.
Any help would be greatly appreciated!