diff --git a/io/io/inc/TBufferJSON.h b/io/io/inc/TBufferJSON.h index 11d8a8b61866a..492f3fd9471a0 100644 --- a/io/io/inc/TBufferJSON.h +++ b/io/io/inc/TBufferJSON.h @@ -361,7 +361,7 @@ class TBufferJSON : public TBuffer { } virtual UShort_t WriteProcessID(TProcessID * /*pid*/) { - Error("WriteProcessID", "useless"); + // Error("WriteProcessID", "useless"); return 0; } @@ -421,15 +421,14 @@ class TBufferJSON : public TBuffer { TJSONStackObj *Stack(Int_t depth = 0); void WorkWithClass(TStreamerInfo *info, const TClass *cl = 0); - void WorkWithElement(TStreamerElement *elem, Int_t comp_type); - + void WorkWithElement(TStreamerElement *elem, Int_t); void JsonDisablePostprocessing(); Int_t JsonSpecialClass(const TClass *cl) const; void JsonStartElement(const TStreamerElement *elem, const TClass *base_class = 0); - void PerformPostProcessing(TJSONStackObj *stack, const TStreamerElement *elem = 0); + void PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl = 0); void JsonWriteBasic(Char_t value); void JsonWriteBasic(Short_t value); @@ -459,7 +458,6 @@ class TBufferJSON : public TBuffer { std::map fJsonrMap; //! map of recorded objects, used in JsonR to restore references unsigned fJsonrCnt; //! counter for all objects and arrays TObjArray fStack; //! stack of streamer infos - Bool_t fExpectedChain; //! flag to resolve situation when several elements of same basic type stored as FastArray Int_t fCompact; //! 0 - no any compression, 1 - no spaces in the begin, 2 - no new lines, 3 - no spaces at all TString fSemicolon; //! depending from compression level, " : " or ":" TString fArraySepar; //! depending from compression level, ", " or "," diff --git a/io/io/inc/TStreamerInfo.h b/io/io/inc/TStreamerInfo.h index 34adeb95e0fcb..14b144fdc7520 100644 --- a/io/io/inc/TStreamerInfo.h +++ b/io/io/inc/TStreamerInfo.h @@ -112,6 +112,7 @@ class TStreamerInfo : public TVirtualStreamerInfo { TStreamerInfoActions::TActionSequence *fWriteObjectWise; /// fgCount; ///GetEntries(); } Int_t GetNumber() const {return fNumber;} diff --git a/io/io/src/TBufferJSON.cxx b/io/io/src/TBufferJSON.cxx index 7f80e580fb27e..6b29f3ac69682 100644 --- a/io/io/src/TBufferJSON.cxx +++ b/io/io/src/TBufferJSON.cxx @@ -94,6 +94,7 @@ class TArrayIndexProducer { TArrayI fIndicies; TArrayI fMaxIndex; TString fRes; + Bool_t fIsArray; public: TArrayIndexProducer(TStreamerElement* elem, Int_t arraylen, const char* separ) : @@ -102,13 +103,15 @@ class TArrayIndexProducer { fSepar(separ), fIndicies(), fMaxIndex(), - fRes() + fRes(), + fIsArray(kFALSE) { Bool_t usearrayindx = elem && (elem->GetArrayDim() > 0); + Bool_t usearraylen = (arraylen > 1); if (usearrayindx && (arraylen > 0)) { if ((elem->GetType() == TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop) || - (elem->GetType() == TStreamerInfo::kStreamLoop)) usearrayindx = kFALSE; + (elem->GetType() == TStreamerInfo::kStreamLoop)) { usearrayindx = kFALSE; usearraylen = kTRUE; } else if (arraylen != elem->GetArrayLength()) { printf("Problem with JSON coding of element %s type %d \n", elem->GetName(), elem->GetType()); @@ -120,11 +123,13 @@ class TArrayIndexProducer { fMaxIndex.Set(elem->GetArrayDim()); for(int dim=0;dimGetArrayDim();dim++) fMaxIndex[dim] = elem->GetMaxIndex(dim); + fIsArray = fTotalLen>1; } else - if (arraylen > 1) { + if (usearraylen) { fTotalLen = arraylen; fMaxIndex.Set(1); fMaxIndex[0] = arraylen; + fIsArray = kTRUE; } if (fMaxIndex.GetSize() > 0) { @@ -139,7 +144,8 @@ class TArrayIndexProducer { fSepar(separ), fIndicies(), fMaxIndex(), - fRes() + fRes(), + fIsArray(kFALSE) { Int_t ndim = member->GetArrayDim(); if (extradim > 0) ndim++; @@ -159,6 +165,7 @@ class TArrayIndexProducer { fTotalLen *= extradim; } } + fIsArray = fTotalLen>1; } Int_t ReduceDimension() @@ -171,13 +178,14 @@ class TArrayIndexProducer { fMaxIndex.Set(ndim); fIndicies.Set(ndim); fTotalLen = fTotalLen/len; + fIsArray = fTotalLen>1; return len; } Bool_t IsArray() const { - return (fTotalLen>1); + return fIsArray; } Bool_t IsDone() const @@ -238,7 +246,6 @@ class TJSONStackObj : public TObject { public: TStreamerInfo *fInfo; //! TStreamerElement *fElem; //! element in streamer info - Int_t fElemNumber; //! number of streamer element in streamer info Bool_t fIsStreamerInfo; //! Bool_t fIsElemOwner; //! Bool_t fIsPostProcessed;//! indicate that value is written @@ -252,7 +259,6 @@ class TJSONStackObj : public TObject { TObject(), fInfo(0), fElem(0), - fElemNumber(0), fIsStreamerInfo(kFALSE), fIsElemOwner(kFALSE), fIsPostProcessed(kFALSE), @@ -299,7 +305,6 @@ TBufferJSON::TBufferJSON() : fJsonrMap(), fJsonrCnt(0), fStack(), - fExpectedChain(kFALSE), fCompact(0), fSemicolon(" : "), fArraySepar(", "), @@ -1130,6 +1135,9 @@ void TBufferJSON::JsonWriteObject(const void *obj, const TClass *cl, Bool_t chec } } + // reuse post-processing code for TObject or TRef + PerformPostProcessing(stack, cl); + if ((special_kind == 0) && ((stack->fValues.GetLast() >= 0) || (fValue.Length() > 0))) { if (gDebug > 0) @@ -1262,8 +1270,6 @@ void TBufferJSON::IncrementLevel(TVirtualStreamerInfo *info) void TBufferJSON::WorkWithClass(TStreamerInfo *sinfo, const TClass *cl) { - fExpectedChain = kFALSE; - if (sinfo != 0) cl = sinfo->GetClass(); if (cl == 0) return; @@ -1273,8 +1279,8 @@ void TBufferJSON::WorkWithClass(TStreamerInfo *sinfo, const TClass *cl) TJSONStackObj *stack = Stack(); if ((stack != 0) && stack->IsStreamerElement() && !stack->fIsObjStarted && - ((stack->fElem->GetType() == TStreamerInfo::kObject) || - (stack->fElem->GetType() == TStreamerInfo::kAny))) { + ((stack->fElem->GetType() == TStreamerInfo::kObject) || + (stack->fElem->GetType() == TStreamerInfo::kAny))) { stack->fIsObjStarted = kTRUE; @@ -1300,8 +1306,6 @@ void TBufferJSON::WorkWithClass(TStreamerInfo *sinfo, const TClass *cl) void TBufferJSON::DecrementLevel(TVirtualStreamerInfo *info) { - fExpectedChain = kFALSE; - if (gDebug > 2) Info("DecrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom")); @@ -1346,10 +1350,8 @@ void TBufferJSON::SetStreamerElementNumber(TStreamerElement *elem, Int_t comp_ty /// that class member will be streamed /// Name of element used in JSON -void TBufferJSON::WorkWithElement(TStreamerElement *elem, Int_t comp_type) +void TBufferJSON::WorkWithElement(TStreamerElement *elem, Int_t) { - fExpectedChain = kFALSE; - TJSONStackObj *stack = Stack(); if (stack == 0) { Error("WorkWithElement", "stack is empty"); @@ -1392,19 +1394,10 @@ void TBufferJSON::WorkWithElement(TStreamerElement *elem, Int_t comp_type) return; } - Bool_t isBasicType = (elem->GetType() > 0) && (elem->GetType() < 20); - - fExpectedChain = isBasicType && (comp_type - elem->GetType() == TStreamerInfo::kOffsetL); - - if (fExpectedChain && (gDebug > 3)) - Info("WorkWithElement", " Expects chain for elem %s number %d", - elem->GetName(), number); - TClass *base_class = elem->IsBase() ? elem->GetClassPointer() : 0; stack = PushStack(0); stack->fElem = (TStreamerElement *) elem; - stack->fElemNumber = number; stack->fIsElemOwner = (number < 0); JsonStartElement(elem, base_class); @@ -1564,16 +1557,13 @@ void TBufferJSON::ClassMember(const char *name, const char *typeName, //////////////////////////////////////////////////////////////////////////////// /// Function is converts TObject and TString structures to more compact representation -void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, - const TStreamerElement *elem) +void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl) { - if ((elem == 0) && stack->fIsPostProcessed) return; - if (elem == 0) elem = stack->fElem; - if (elem == 0) return; + if (stack->fIsPostProcessed) return; - if (gDebug > 3) - Info("PerformPostProcessing", "Element %s type %s", - elem->GetName(), elem->GetTypeName()); + const TStreamerElement *elem = stack->fElem; + + if (!elem && !obj_cl) return; stack->fIsPostProcessed = kTRUE; @@ -1583,13 +1573,20 @@ void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, return; } - const char *typname = elem->IsBase() ? elem->GetName() : elem->GetTypeName(); - Bool_t isTObject = (elem->GetType() == TStreamerInfo::kTObject) || (strcmp("TObject", typname) == 0); - Bool_t isTString = elem->GetType() == TStreamerInfo::kTString; - Bool_t isSTLstring = elem->GetType() == TStreamerInfo::kSTLstring; - Bool_t isOffsetPArray = (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20); + Bool_t isTObject(kFALSE), isTRef(kFALSE), isTString(kFALSE), isSTLstring(kFALSE), isOffsetPArray(kFALSE), isTArray(kFALSE); - Bool_t isTArray = (strncmp("TArray", typname, 6) == 0); + if (obj_cl) { + if (obj_cl == TObject::Class()) isTObject = kTRUE; + else if (obj_cl == TRef::Class()) isTRef = kTRUE; + else return; + } else { + const char *typname = elem->IsBase() ? elem->GetName() : elem->GetTypeName(); + isTObject = (elem->GetType() == TStreamerInfo::kTObject) || (strcmp("TObject", typname) == 0); + isTString = elem->GetType() == TStreamerInfo::kTString; + isSTLstring = elem->GetType() == TStreamerInfo::kSTLstring; + isOffsetPArray = (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20); + isTArray = (strncmp("TArray", typname, 6) == 0); + } if (isTString || isSTLstring) { // just remove all kind of string length information @@ -1607,15 +1604,22 @@ void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, (strcmp(stack->fValues.Last()->GetName(), "1") == 0)) { stack->fValues.Delete(); } else { - Error("PerformPostProcessing", "Wrong values for kOffsetP type %s name %s", - typname, (elem ? elem->GetName() : "---")); + Error("PerformPostProcessing", "Wrong values for kOffsetP element %s", + (elem ? elem->GetName() : "---")); stack->fValues.Delete(); fValue = "[]"; } - } else if (isTObject) { - if (stack->fValues.GetLast() != 0) { + } else if (isTObject || isTRef) { + // complex workaround for TObject/TRef streamer + // would be nice if other solution can be found + // Here is not supported TRef on TRef (double reference) + + Int_t cnt = stack->fValues.GetLast()+1; + if (fValue.Length() > 0) cnt++; + + if (cnt<2 || cnt>3) { if (gDebug > 0) - Error("PerformPostProcessing", "When storing TObject, number of items %d not equal to 2", stack->fValues.GetLast()); + Error("PerformPostProcessing", "When storing TObject/TRef, strange number of items %d", cnt); AppendOutput(",", "\"dummy\""); AppendOutput(fSemicolon.Data()); } else { @@ -1624,15 +1628,24 @@ void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, AppendOutput(stack->fValues.At(0)->GetName()); AppendOutput(",", "\"fBits\""); AppendOutput(fSemicolon.Data()); + AppendOutput((stack->fValues.GetLast()>0) ? stack->fValues.At(1)->GetName() : fValue.Data()); + if (cnt==3) { + AppendOutput(",", "\"fPID\""); + AppendOutput(fSemicolon.Data()); + AppendOutput((stack->fValues.GetLast()>1) ? stack->fValues.At(2)->GetName() : fValue.Data()); + } + + stack->fValues.Delete(); + fValue.Clear(); + return; } - stack->fValues.Delete(); } else if (isTArray) { // for TArray one deletes complete stack stack->fValues.Delete(); } - if (elem->IsBase() && (fValue.Length() == 0)) { + if (elem && elem->IsBase() && (fValue.Length() == 0)) { // here base class data already completely stored return; } @@ -2484,48 +2497,27 @@ void TBufferJSON::WriteArrayDouble32(const Double_t *d, Int_t n, TJSONPushValue(); \ if (n <= 0) { /*fJsonrCnt++;*/ fValue.Append("[]"); return; } \ TStreamerElement* elem = Stack(0)->fElem; \ - if ((elem != 0) && (elem->GetType()>TStreamerInfo::kOffsetL) && \ - (elem->GetType() < TStreamerInfo::kOffsetP) && \ - (elem->GetArrayLength() != n)) fExpectedChain = kTRUE; \ - if (fExpectedChain) { \ - TStreamerInfo* info = Stack(1)->fInfo; \ - Int_t startnumber = Stack(0)->fElemNumber; \ - fExpectedChain = kFALSE; \ - Int_t index(0); \ - while (indexGetElements()->At(startnumber++);\ - if (index>0) JsonStartElement(elem); \ - if (elem->GetType()GetArrayLength(),typname); \ - index+=elem->GetArrayLength(); \ + if ((elem!=0) && (elem->GetArrayDim()>1) && (elem->GetArrayLength()==n)) { \ + TArrayI indexes(elem->GetArrayDim() - 1); \ + indexes.Reset(0); \ + Int_t cnt = 0, shift = 0, len = elem->GetMaxIndex(indexes.GetSize()); \ + while (cnt >= 0) { \ + if (indexes[cnt] >= elem->GetMaxIndex(cnt)) { \ + fValue.Append("]"); \ + indexes[cnt--] = 0; \ + if (cnt >= 0) indexes[cnt]++; \ + continue; \ + } \ + fValue.Append(indexes[cnt] == 0 ? "[" : fArraySepar.Data()); \ + if (++cnt == indexes.GetSize()) { \ + method((vname+shift), len, typname); \ + indexes[--cnt]++; \ + shift+=len; \ } \ - PerformPostProcessing(Stack(0), elem); \ } \ - } else \ - if ((elem!=0) && (elem->GetArrayDim()>1) && (elem->GetArrayLength()==n)) { \ - TArrayI indexes(elem->GetArrayDim() - 1); \ - indexes.Reset(0); \ - Int_t cnt = 0, shift = 0, len = elem->GetMaxIndex(indexes.GetSize()); \ - while (cnt >= 0) { \ - if (indexes[cnt] >= elem->GetMaxIndex(cnt)) { \ - fValue.Append("]"); \ - indexes[cnt--] = 0; \ - if (cnt >= 0) indexes[cnt]++; \ - continue; \ - } \ - fValue.Append(indexes[cnt] == 0 ? "[" : fArraySepar.Data()); \ - if (++cnt == indexes.GetSize()) { \ - method((vname+shift), len, typname); \ - indexes[--cnt]++; \ - shift+=len; \ - } \ - } \ - } else { \ - method(vname, n, typname); \ - } \ + } else { \ + method(vname, n, typname); \ + } \ } //////////////////////////////////////////////////////////////////////////////// @@ -2675,31 +2667,38 @@ void TBufferJSON::WriteFastArray(void *start, const TClass *cl, Int_t n, return; } - char *obj = (char *)start; - if (!n) n = 1; - int size = cl->Size(); + if (n<0) { + // special handling of empty StreamLoop + AppendOutput("null"); + JsonDisablePostprocessing(); + } else { - TArrayIndexProducer indexes(Stack(0)->fElem, n, fArraySepar.Data()); + char *obj = (char *)start; + if (!n) n = 1; + int size = cl->Size(); - if (indexes.IsArray()) { - JsonDisablePostprocessing(); - AppendOutput(indexes.GetBegin()); - } + TArrayIndexProducer indexes(Stack(0)->fElem, n, fArraySepar.Data()); - for (Int_t j = 0; j < n; j++, obj += size) { + if (indexes.IsArray()) { + JsonDisablePostprocessing(); + AppendOutput(indexes.GetBegin()); + } - if (j>0) AppendOutput(indexes.NextSeparator()); + for (Int_t j = 0; j < n; j++, obj += size) { - JsonWriteObject(obj, cl, kFALSE); + if (j>0) AppendOutput(indexes.NextSeparator()); - if (indexes.IsArray() && (fValue.Length() > 0)) { - AppendOutput(fValue.Data()); - fValue.Clear(); + JsonWriteObject(obj, cl, kFALSE); + + if (indexes.IsArray() && (fValue.Length() > 0)) { + AppendOutput(fValue.Data()); + fValue.Clear(); + } } - } - if (indexes.IsArray()) - AppendOutput(indexes.GetEnd()); + if (indexes.IsArray()) + AppendOutput(indexes.GetEnd()); + } if (Stack(0)->fIndx) AppendOutput(Stack(0)->fIndx->NextSeparator()); @@ -3613,7 +3612,7 @@ Int_t TBufferJSON::WriteClassBuffer(const TClass *cl, void *pointer) //NOTE: In the future Philippe wants this to happen via a custom action TagStreamerInfo(sinfo); - ApplySequence(*(sinfo->GetWriteObjectWiseActions()), (char *)pointer); + ApplySequence(*(sinfo->GetWriteTextActions()), (char *)pointer); //write the byte count at the start of the buffer // SetByteCount(R__c, kTRUE); diff --git a/io/io/src/TStreamerInfo.cxx b/io/io/src/TStreamerInfo.cxx index 02f5158c1935c..193f76bb0b022 100644 --- a/io/io/src/TStreamerInfo.cxx +++ b/io/io/src/TStreamerInfo.cxx @@ -166,6 +166,7 @@ TStreamerInfo::TStreamerInfo() fWriteObjectWise = 0; fWriteMemberWise = 0; fWriteMemberWiseVecPtr = 0; + fWriteText = 0; } //////////////////////////////////////////////////////////////////////////////// @@ -199,6 +200,7 @@ TStreamerInfo::TStreamerInfo(TClass *cl) fWriteObjectWise = 0; fWriteMemberWise = 0; fWriteMemberWiseVecPtr = 0; + fWriteText = 0; } //////////////////////////////////////////////////////////////////////////////// @@ -217,6 +219,7 @@ TStreamerInfo::~TStreamerInfo() delete fWriteObjectWise; delete fWriteMemberWise; delete fWriteMemberWiseVecPtr; + delete fWriteText; if (!fElements) return; fElements->Delete(); @@ -2534,6 +2537,7 @@ void TStreamerInfo::Clear(Option_t *option) if (fWriteObjectWise) fWriteObjectWise->fActions.clear(); if (fWriteMemberWise) fWriteMemberWise->fActions.clear(); if (fWriteMemberWiseVecPtr) fWriteMemberWiseVecPtr->fActions.clear(); + if (fWriteText) fWriteText->fActions.clear(); } } diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 641a9948bc902..7e0fddde5c129 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -23,6 +23,7 @@ #include "TClassEdit.h" #include "TVirtualCollectionIterators.h" #include "TProcessID.h" +#include "TFile.h" static const Int_t kRegrouped = TStreamerInfo::kOffsetL; @@ -226,6 +227,220 @@ namespace TStreamerInfoActions return 0; } + INLINE_TEMPLATE_ARGS Int_t WriteTextTNamed(TBuffer &buf, void *addr, const TConfiguration *config) + { + void *x = (void*)( ((char*)addr) + config->fOffset ); + // Idea: Implement buf.ReadBasic/Primitive to avoid the return value + buf.StreamObject(x, TNamed::Class(), TNamed::Class()); + return 0; + } + + INLINE_TEMPLATE_ARGS Int_t WriteTextTObject(TBuffer &buf, void *addr, const TConfiguration *config) + { + void *x = (void*)( ((char*)addr) + config->fOffset ); + // Idea: Implement buf.ReadBasic/Primitive to avoid the return value + buf.StreamObject(x, TObject::Class(), TObject::Class()); + return 0; + } + + /** Direct copy of code from TStreamerInfo::WriteBufferAux, + * potentially can be used later for non-text streaming */ + template + INLINE_TEMPLATE_ARGS Int_t WriteSTLp(TBuffer &buf, void *addr, const TConfiguration *config) + { + TClass *cl = config->fCompInfo->fClass; + TMemberStreamer *pstreamer = config->fCompInfo->fStreamer; + TVirtualCollectionProxy *proxy = cl->GetCollectionProxy(); + TClass* vClass = proxy ? proxy->GetValueClass() : 0; + UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing + UInt_t ioffset = eoffset + config->fOffset; + + if (!buf.TestBit(TBuffer::kCannotHandleMemberWiseStreaming) + && proxy && vClass + && config->fInfo->GetStreamMemberWise() + && cl->CanSplit() + && !(strspn(config->fCompInfo->fElem->GetTitle(),"||") == 2) + && !(vClass->TestBit(TClass::kHasCustomStreamerMember)) ) { + // Let's save the collection member-wise. + + UInt_t pos = buf.WriteVersionMemberWise(config->fInfo->IsA(),kTRUE); + buf.WriteVersion( vClass, kFALSE ); + + // TODO: subinfo used for WriteBufferSTL call, which is private for the moment + //TStreamerInfo *subinfo = (TStreamerInfo*)vClass->GetStreamerInfo(); + + //for (int k = 0; k < narr; ++k) { + char **contp = (char **)((char *)addr + ioffset); + for(int j=0;jfCompInfo->fLength;++j) { + char *cont = contp[j]; + TVirtualCollectionProxy::TPushPop helper( proxy, cont ); + Int_t nobjects = cont ? proxy->Size() : 0; + buf << nobjects; + + // TODO: method is private, should be made accesible from here + // subinfo->WriteBufferSTL(buf,proxy,nobjects); + } + //} + buf.SetByteCount(pos,kTRUE); + return 0; + } + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(),kTRUE); + if (kIsTextT) { + // use same method which is used in kSTL + buf.WriteFastArray((void **)((char *) addr + ioffset), cl, config->fCompInfo->fLength, kFALSE, 0); + } else + if (pstreamer == 0) { + //for (int k = 0; k < narr; ++k) { + char **contp = (char**)((char *) addr + ioffset); + for(int j=0; jfCompInfo->fLength; ++j) { + char *cont = contp[j]; + cl->Streamer( cont, buf ); + } + // } + } else { + //for (int k = 0; k < narr; ++k) { + (*pstreamer)(buf,(char *) addr + ioffset, config->fCompInfo->fLength); + //} + } + buf.SetByteCount(pos,kTRUE); + return 0; + } + + + /** Direct copy of code from TStreamerInfo::WriteBufferAux, + * potentially can be used later for non-text streaming */ + template + INLINE_TEMPLATE_ARGS Int_t WriteStreamerLoop(TBuffer &buf, void *addr, const TConfiguration *config) + { + UInt_t eoffset = 0; // extra parameter of TStreamerInfo::WriteBufferAux, 0 for all kind of objects writing + UInt_t ioffset = eoffset + config->fOffset; + + if (!kIsTextT && config->fCompInfo->fStreamer) { + // Get any private streamer which was set for the data member. + TMemberStreamer* pstreamer = config->fCompInfo->fStreamer; + // -- We have a private streamer. + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + // Loop over the entries in the clones array or the STL container. + //for (int k = 0; k < narr; ++k) { + // Get a pointer to the counter for the varying length array. + Int_t* counter = (Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/); + + // And call the private streamer, passing it the buffer, the object, and the counter. + (*pstreamer)(buf, (char *) addr /*entry pointer*/ + ioffset /*object offset*/, *counter); + //} for k + buf.SetByteCount(pos, kTRUE); + // We are done, next streamer element. + return 0; + } + + // Get the class of the data member. + TClass* cl = config->fCompInfo->fClass; + // Which are we, an array of objects or an array of pointers to objects? + Bool_t isPtrPtr = (strstr(config->fCompInfo->fElem->GetTypeName(), "**") != 0); + + // By default assume the file version is the newest. + Int_t fileVersion = kMaxInt; + + if (!kIsTextT) { + // At this point we do *not* have a private streamer. + // Get the version of the file we are writing to. + TFile* file = (TFile*) buf.GetParent(); + if (file) { + fileVersion = file->GetVersion(); + } + } + // Write the class version to the buffer. + UInt_t pos = buf.WriteVersion(config->fInfo->IsA(), kTRUE); + if (fileVersion > 51508) { + // -- Newer versions allow polymorphic pointers to objects. + // Loop over the entries in the clones array or the STL container. + //for (int k = 0; k < narr; ++k) { + // Get the counter for the varying length array. + Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); + + //b << vlen; + if (vlen) { + // Get a pointer to the array of pointers. + char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + // Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // ::ErrorHandler(kError, "::WriteStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); + printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); + continue; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Write the entire array of objects to the buffer. + // Note: Polymorphism is not allowed here. + buf.WriteFastArray(pp[ndx], cl, vlen, 0); + } + else { + // -- We are a varying-length array of pointers to objects. + // Write the entire array of object pointers to the buffer. + // Note: The object pointers are allowed to be polymorphic. + buf.WriteFastArray((void**) pp[ndx], cl, vlen, kFALSE, 0); + } // isPtrPtr + } // ndx + } else // vlen + if (kIsTextT) { + // special handling for the text-based streamers + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) + buf.WriteFastArray((void *) 0, cl, -1, 0); + } + //} // k + } + else { + // -- Older versions do *not* allow polymorphic pointers to objects. + // Loop over the entries in the clones array or the STL container. + //for (int k = 0; k < narr; ++k) { + // Get the counter for the varying length array. + Int_t vlen = *((Int_t*) ((char *) addr /*entry pointer*/ + eoffset /*entry offset*/ + config->fCompInfo->fMethod /*counter offset*/)); + //b << vlen; + if (vlen) { + // Get a pointer to the array of pointers. + char** pp = (char**) ((char *) addr /*entry pointer*/ + ioffset /*object offset*/); + // -- Older versions do *not* allow polymorphic pointers to objects. + // Loop over each element of the array of pointers to varying-length arrays. + for (Int_t ndx = 0; ndx < config->fCompInfo->fLength; ++ndx) { + if (!pp[ndx]) { + // -- We do not have a pointer to a varying-length array. + //Error("WriteBufferAux", "The pointer to element %s::%s type %d (%s) is null\n", GetName(), aElement->GetFullName(), compinfo[i]->fType, aElement->GetTypeName()); + // ::ErrorHandler(kError, "::WriteTextStreamerLoop", Form("The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName())); + printf("WriteStreamerLoop - The pointer to element %s::%s type %d (%s) is null\n", config->fInfo->GetName(), config->fCompInfo->fElem->GetFullName(), config->fCompInfo->fType, config->fCompInfo->fElem->GetTypeName()); + continue; + } + if (!isPtrPtr) { + // -- We are a varying-length array of objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Write the object to the buffer. + cl->Streamer(pp[ndx] + (v * cl->Size()), buf); + } // v + } + else { + // -- We are a varying-length array of pointers to objects. + // Loop over the elements of the varying length array. + for (Int_t v = 0; v < vlen; ++v) { + // Get a pointer to the object pointer. + char** r = (char**) pp[ndx]; + // Write the object to the buffer. + cl->Streamer(r[v], buf); + } // v + } // isPtrPtr + } // ndx + } // vlen + //} // k + } // fileVersion + // Backpatch the byte count into the buffer. + buf.SetByteCount(pos, kTRUE); + + return 0; + } + + class TConfWithFactor : public TConfiguration { // Configuration object for the Float16/Double32 where a factor has been specified. public: @@ -2299,6 +2514,9 @@ void TStreamerInfo::Compile() if (fWriteMemberWiseVecPtr) fWriteMemberWiseVecPtr->fActions.clear(); else fWriteMemberWiseVecPtr = new TStreamerInfoActions::TActionSequence(this,ndata); + if (fWriteText) fWriteText->fActions.clear(); + else fWriteText = new TStreamerInfoActions::TActionSequence(this,ndata); + if (!ndata) { // This may be the case for empty classes (e.g., TAtt3D). // We still need to properly set the size of emulated classes (i.e. add the virtual table) @@ -2469,6 +2687,8 @@ void TStreamerInfo::Compile() AddWriteAction(fWriteMemberWise, i, fCompFull[i]); AddReadMemberWiseVecPtrAction(fReadMemberWiseVecPtr, i, fCompFull[i]); AddWriteMemberWiseVecPtrAction(fWriteMemberWiseVecPtr, i, fCompFull[i]); + + AddWriteTextAction(fWriteText, i, fCompFull[i]); } ComputeSize(); @@ -2859,6 +3079,145 @@ void TStreamerInfo::AddWriteAction(TStreamerInfoActions::TActionSequence *writeS #endif } +//////////////////////////////////////////////////////////////////////////////// + +void TStreamerInfo::AddWriteTextAction(TStreamerInfoActions::TActionSequence *writeSequence, Int_t i, TStreamerInfo::TCompInfo *compinfo) +{ + TStreamerElement *element = compinfo->fElem; + if (element->TestBit(TStreamerElement::kCache) && !element->TestBit(TStreamerElement::kWrite)) { + // Skip element cached for reading purposes. + return; + } + if (element->GetType() >= kArtificial && !element->TestBit(TStreamerElement::kWrite)) { + // Skip artificial element used for reading purposes. + return; + } + + Bool_t generic = kFALSE; + + switch (compinfo->fType) { + // write basic types + case TStreamerInfo::kBool: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kChar: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kShort: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kInt: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kLong: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kLong64: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kFloat: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kDouble: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kUChar: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kUShort: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kUInt: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kULong: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + case TStreamerInfo::kULong64: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + + case TStreamerInfo::kTObject: + if (element->IsBase()) + generic = kTRUE; + else + writeSequence->AddAction( WriteTextTObject, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + + case TStreamerInfo::kTNamed: + if (element->IsBase()) + generic = kTRUE; + else + writeSequence->AddAction( WriteTextTNamed, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + + case TStreamerInfo::kSTLp: // Pointer to container with no virtual table (stl) and no comment + case TStreamerInfo::kSTLp + TStreamerInfo::kOffsetL: // array of pointers to container with no virtual table (stl) and no comment + writeSequence->AddAction( WriteSTLp, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + + case TStreamerInfo::kStreamLoop: + case TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop: + writeSequence->AddAction( WriteStreamerLoop, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + break; + + + // case TStreamerInfo::kBits: writeSequence->AddAction( WriteBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + /*case TStreamerInfo::kFloat16: { + if (element->GetFactor() != 0) { + writeSequence->AddAction( WriteBasicType_WithFactor, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) ); + } else { + Int_t nbits = (Int_t)element->GetXmin(); + if (!nbits) nbits = 12; + writeSequence->AddAction( WriteBasicType_NoFactor, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) ); + } + break; + } */ + /*case TStreamerInfo::kDouble32: { + if (element->GetFactor() != 0) { + writeSequence->AddAction( WriteBasicType_WithFactor, new TConfWithFactor(this,i,compinfo,compinfo->fOffset,element->GetFactor(),element->GetXmin()) ); + } else { + Int_t nbits = (Int_t)element->GetXmin(); + if (!nbits) { + writeSequence->AddAction( ConvertBasicType, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); + } else { + writeSequence->AddAction( WriteBasicType_NoFactor, new TConfNoFactor(this,i,compinfo,compinfo->fOffset,nbits) ); + } + } + break; + } */ + //case TStreamerInfo::kTNamed: writeSequence->AddAction( WriteTNamed, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + // Idea: We should calculate the CanIgnoreTObjectStreamer here and avoid calling the + // Streamer alltogether. + //case TStreamerInfo::kTObject: writeSequence->AddAction( WriteTObject, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + //case TStreamerInfo::kTString: writeSequence->AddAction( WriteTString, new TConfiguration(this,i,compinfo,compinfo->fOffset) ); break; + /*case TStreamerInfo::kSTL: { + TClass *newClass = element->GetNewClass(); + TClass *oldClass = element->GetClassPointer(); + Bool_t isSTLbase = element->IsBase() && element->IsA()!=TStreamerBase::Class(); + + if (element->GetArrayLength() <= 1) { + if (newClass && newClass != oldClass) { + if (element->GetStreamer()) { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + } else { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,newClass,element->GetTypeName(),isSTLbase)); + } + } else { + if (element->GetStreamer()) { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + } else { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,1,oldClass,element->GetTypeName(),isSTLbase)); + } + } + } else { + if (newClass && newClass != oldClass) { + if (element->GetStreamer()) { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + } else { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,newClass,element->GetTypeName(),isSTLbase)); + } + } else { + if (element->GetStreamer()) { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetStreamer(),element->GetTypeName(),isSTLbase)); + } else { + writeSequence->AddAction(WriteSTL, new TConfigSTL(this,i,compinfo,compinfo->fOffset,element->GetArrayLength(),oldClass,element->GetTypeName(),isSTLbase)); + } + } + } + break; + } */ + default: + generic = kTRUE; + break; + } + + // use generic write action when special handling is not provided + if (generic) writeSequence->AddAction( GenericWriteAction, new TGenericConfiguration(this,i,compinfo) ); + +#if defined(CDJ_NO_COMPILE) + if (element->TestBit(TStreamerElement::kCache)) { + TConfiguredAction action( writeSequence->fActions.back() ); // Action is moved, we must pop it next. + writeSequence->fActions.pop_back(); + writeSequence->AddAction( UseCache, new TConfigurationUseCache(this,action,element->TestBit(TStreamerElement::kRepeat)) ); + } +#endif +} + //////////////////////////////////////////////////////////////////////////////// /// This is for streaming via a TClonesArray (or a vector of pointers of this type).