<commit_before>// @(#)root/meta:$Id$
// Author: <NAME>   12/10/2000

/*************************************************************************
 * Copyright (C) 1995-2000, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


#include "TROOT.h"
#include "TStreamerElement.h"
#include "TVirtualStreamerInfo.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TBaseClass.h"
#include "TDataMember.h"
#include "TDataType.h"
#include "TMethodCall.h"
#include "TRealData.h"
#include "TFolder.h"
#include "TRef.h"
#include "TInterpreter.h"
#include "TError.h"
#include "TDataType.h"
#include "TVirtualMutex.h"
#include <iostream>

#include <string>
namespace std {} using namespace std;

const Int_t kMaxLen = 1024;
static char gIncludeName[kMaxLen];


//______________________________________________________________________________
static TStreamerBasicType *InitCounter(const char *countClass, const char *countName)
{
   // Helper function to initialize the 'index/counter' value of
   // the Pointer streamerElements.

   TClass *cl = TClass::GetClass(countClass);

   if (cl==0) return 0;

   TStreamerBasicType *counter = TVirtualStreamerInfo::GetElementCounter(countName,cl);

   //at this point the counter is may be declared to skip
   if (counter) {
      if (counter->GetType() < TVirtualStreamerInfo::kCounter) counter->SetType(TVirtualStreamerInfo::kCounter);
   }
   return counter;
}


//______________________________________________________________________________
static void GetRange(const char *comments, Double_t &xmin, Double_t &xmax, Double_t &factor)
{
   // Parse comments to search for a range specifier of the style:
   //  [xmin,xmax] or [xmin,xmax,nbits]
   //  [0,1]
   //  [-10,100];
   //  [-pi,pi], [-pi/2,pi/4],[-2pi,2*pi]
   //  [-10,100,16]
   //  [0,0,8]
   // if nbits is not specified, or nbits <2 or nbits>32 it is set to 32
   // if (xmin==0 and xmax==0 and nbits <=16) the double word will be converted
   // to a float and its mantissa truncated to nbits significative bits.
   //
   //  see comments in TBufferFile::WriteDouble32.

   const Double_t kPi =3.14159265358979323846 ;
   factor = xmin = xmax = 0;
   if (!comments) return;
   const char *left = strstr(comments,"[");
   if (!left) return;
   const char *right = strstr(left,"]");
   if (!right) return;
   const char *comma = strstr(left,",");
   if (!comma || comma > right) {
      //may be first bracket was a dimension specifier
      left = strstr(right,"[");
      if (!left) return;
      right = strstr(left,"]");
      if (!right) return;
      comma = strstr(left,",");
      if (!comma || comma >right) return;
   }
   //search if nbits is specified
   const char *comma2 = 0;
   if (comma) comma2 = strstr(comma+1,",");
   if (comma2 > right) comma2 = 0;
   Int_t nbits = 32;
   if (comma2) {
      TString sbits(comma2+1,right-comma2-1);
      sscanf(sbits.Data(),"%d",&nbits);
      if (nbits < 2 || nbits > 32) {
         ::Error("GetRange","Illegal specification for the number of bits; %d. reset to 32.",nbits);
         nbits = 32;
      }
      right = comma2;
   }
   TString range(left+1,right-left-1);
   TString sxmin(left+1,comma-left-1);
   sxmin.ToLower();
   sxmin.ReplaceAll(" ","");
   if (sxmin.Contains("pi")) {
      if      (sxmin.Contains("2pi"))   xmin = 2*kPi;
      else if (sxmin.Contains("2*pi"))  xmin = 2*kPi;
      else if (sxmin.Contains("twopi")) xmin = 2*kPi;
      else if (sxmin.Contains("pi/2"))  xmin = kPi/2;
      else if (sxmin.Contains("pi/4"))  xmin = kPi/4;
      else if (sxmin.Contains("pi"))    xmin = kPi;
      if (sxmin.Contains("-"))          xmin = -xmin;
   } else {
      sscanf(sxmin.Data(),"%lg",&xmin);
   }
   TString sxmax(comma+1,right-comma-1);
   sxmax.ToLower();
   sxmax.ReplaceAll(" ","");
   if (sxmax.Contains("pi")) {
      if      (sxmax.Contains("2pi"))   xmax = 2*kPi;
      else if (sxmax.Contains("2*pi"))  xmax = 2*kPi;
      else if (sxmax.Contains("twopi")) xmax = 2*kPi;
      else if (sxmax.Contains("pi/2"))  xmax = kPi/2;
      else if (sxmax.Contains("pi/4"))  xmax = kPi/4;
      else if (sxmax.Contains("pi"))    xmax = kPi;
      if (sxmax.Contains("-"))          xmax = -xmax;
   } else {
      sscanf(sxmax.Data(),"%lg",&xmax);
   }
   UInt_t bigint;
   if (nbits < 32)  bigint = 1<<nbits;
   else             bigint = 0xffffffff;
   if (xmin < xmax) factor = bigint/(xmax-xmin);
   if (xmin >= xmax && nbits <15) xmin = nbits+0.1;
}

ClassImp(TStreamerElement)

//______________________________________________________________________________
TStreamerElement::TStreamerElement()
{
   // Default ctor.

   fType        = 0;
   fSize        = 0;
   fNewType     = 0;
   fArrayDim    = 0;
   fArrayLength = 0;
   fStreamer    = 0;
   fMethod      = 0;
   fOffset      = 0;
   fClassObject = (TClass*)(-1);
   fNewClass    = 0;
   fTObjectOffset = 0;
   fFactor      = 0;
   fXmin        = 0;
   fXmax        = 0;
   for (Int_t i=0;i<5;i++) fMaxIndex[i] = 0;
}

//______________________________________________________________________________
TStreamerElement::TStreamerElement(const char *name, const char *title, Int_t offset, Int_t dtype, const char *typeName)
        : TNamed(name,title)
{
   // Create a TStreamerElement object.

   fOffset      = offset;
   fType        = dtype;
   fSize        = 0;
   fNewType     = fType;
   fArrayDim    = 0;
   fArrayLength = 0;
   fTypeName    = TClassEdit::ResolveTypedef(typeName);
   fStreamer    = 0;
   fMethod      = 0;
   fClassObject = (TClass*)(-1);
   fNewClass    = 0;
   fTObjectOffset = 0;
   fFactor      = 0;
   fXmin        = 0;
   fXmax        = 0;
   for (Int_t i=0;i<5;i++) fMaxIndex[i] = 0;
   if (fTypeName == "Float16_t" || fTypeName == "Float16_t*") {
      GetRange(title,fXmin,fXmax,fFactor);
      if (fFactor > 0 || fXmin > 0) SetBit(kHasRange);
   }
   if (fTypeName == "Double32_t" || fTypeName == "Double32_t*") {
      GetRange(title,fXmin,fXmax,fFactor);
      if (fFactor > 0 || fXmin > 0) SetBit(kHasRange);
   }
}

//______________________________________________________________________________
TStreamerElement::~TStreamerElement()
{
   // TStreamerElement dtor.
   delete fMethod;
}


//______________________________________________________________________________
Bool_t TStreamerElement::CannotSplit() const
{
   // Returns true if the element cannot be split, false otherwise.
   // An element cannot be split if the corresponding class member has
   // the special characters "||" as the first characters in the
   // comment field.

   if (strspn(GetTitle(),"||") == 2) return kTRUE;
   TClass *cl = GetClassPointer();
   if (!cl) return kFALSE;  //basic type

   switch(fType) {
      case TVirtualStreamerInfo::kAny    +TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kObject +TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kTObject+TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kTString+TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kTNamed +TVirtualStreamerInfo::kOffsetL:
         return kTRUE;
   }

   if ( !cl->CanSplit() ) return kTRUE;

   return kFALSE;
}

//______________________________________________________________________________
TClass *TStreamerElement::GetClassPointer() const
{
   // Returns a pointer to the TClass of this element.

   if (fClassObject!=(TClass*)(-1)) return fClassObject;
   TString className = fTypeName.Strip(TString::kTrailing, '*');
   if (className.Index("const ")==0) className.Remove(0,6);
   ((TStreamerElement*)this)->fClassObject = TClass::GetClass(className);
   return fClassObject;
}

//______________________________________________________________________________
Int_t TStreamerElement::GetExecID() const
{
   // Returns the TExec id for the EXEC instruction in the comment field
   // of a TRef data member.

   //check if element is a TRef or TRefArray
   if (strncmp(fTypeName.Data(),"TRef",4) != 0) return 0;

   //if the UniqueID of this element has already been set, we assume
   //that it contains the exec id of a TRef object.
   if (GetUniqueID()) return GetUniqueID();

   //check if an Exec is specified in the comment field
   char *action = (char*)strstr(GetTitle(),"EXEC:");
   if (!action) return 0;
   char caction[512];
   strcpy(caction,action+5);
   char *blank = (char*)strchr(caction,' ');
   if (blank) *blank = 0;
   //we have found the Exec name in the comment
   //we register this Exec to the list of Execs.
   Int_t index = TRef::AddExec(caction);
   //we save the Exec index as the uniqueid of this STreamerElement
   ((TStreamerElement*)this)->SetUniqueID(index+1);
   return index+1;
}

//______________________________________________________________________________
const char *TStreamerElement::GetFullName() const
{
   // Return element name including dimensions, if any
   // Note that this function stores the name into a static array.
   // You should copy the result.

   static char name[kMaxLen];
   char cdim[20];
   sprintf(name,"%s",GetName());
   for (Int_t i=0;i<fArrayDim;i++) {
      sprintf(cdim,"[%d]",fMaxIndex[i]);
      strcat(name,cdim);
   }
   return name;
}

//______________________________________________________________________________
Int_t TStreamerElement::GetSize() const
{
   // Returns size of this element in bytes.

   return fSize;
}

//______________________________________________________________________________
TMemberStreamer *TStreamerElement::GetStreamer() const
{
   // Return the local streamer object.

   return fStreamer;
}

//______________________________________________________________________________
const char *TStreamerElement::GetTypeNameBasic() const
{
   // Return type name of this element
   // in case the type name is not a standard basic type, return
   // the basic type name known to CINT.

   TDataType *dt = gROOT->GetType(fTypeName.Data());
   if (fType < 1 || fType > 55) return fTypeName.Data();
   if (dt && dt->GetType() > 0) return fTypeName.Data();
   Int_t dtype = fType%20;
   return TDataType::GetTypeName((EDataType)dtype);
}

//______________________________________________________________________________
void TStreamerElement::Init(TObject *)
{
   // Initliaze the element.

   fClassObject = GetClassPointer();
   if (fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
      fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
   }
}

//______________________________________________________________________________
Bool_t TStreamerElement::IsOldFormat(const char *newTypeName)
{
   // The early 3.00/00 and 3.01/01 versions used to store
   // dm->GetTypeName instead of dm->GetFullTypename
   // if this case is detected, the element type name is modified.

   //if (!IsaPointer()) return kFALSE;
   if (!strstr(newTypeName,fTypeName.Data())) return kFALSE;
   //if (!strstr(fTypeName.Data(),newTypeName)) return kFALSE;
   fTypeName = newTypeName;
   return kTRUE;
}

//______________________________________________________________________________
Bool_t TStreamerElement::IsBase() const
{
   // Return kTRUE if the element represent a base class.

   return kFALSE;
}

//______________________________________________________________________________
void TStreamerElement::ls(Option_t *) const
{
   // Print the content of the element.

   sprintf(gIncludeName,"%s",GetTypeName());
   if (IsaPointer() && !fTypeName.Contains("*")) strcat(gIncludeName,"*");
   printf("  %-14s %-15s offset=%3d type=%2d %s%-20s\n",
      gIncludeName,GetFullName(),fOffset,fType,TestBit(kCache)?"(cached) ":"",
      GetTitle());
}

//______________________________________________________________________________
void TStreamerElement::SetArrayDim(Int_t dim)
{
   // Set number of array dimensions.

   fArrayDim = dim;
   if (dim) fType += TVirtualStreamerInfo::kOffsetL;
   fNewType = fType;
}

//______________________________________________________________________________
void TStreamerElement::SetMaxIndex(Int_t dim, Int_t max)
{
   //set maximum index for array with dimension dim

   if (dim < 0 || dim > 4) return;
   fMaxIndex[dim] = max;
   if (fArrayLength == 0)  fArrayLength  = max;
   else                    fArrayLength *= max;
}

//______________________________________________________________________________
void TStreamerElement::SetStreamer(TMemberStreamer *streamer)
{
   //set pointer to Streamer function for this element

   fStreamer = streamer;
}

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

   UInt_t R__s, R__c;
   if (R__b.IsReading()) {
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      //NOTE that when reading, one cannot use Class()->ReadBuffer
      // TBuffer::Class methods used for reading streamerinfos from SQL database
      // Any changes of class structure should be reflected by them starting from version 4
      
      R__b.ClassBegin(TStreamerElement::Class(), R__v);
      R__b.ClassMember("TNamed");
      TNamed::Streamer(R__b);
      R__b.ClassMember("fType","Int_t");
      R__b >> fType;
      R__b.ClassMember("fSize","Int_t");
      R__b >> fSize;
      R__b.ClassMember("fArrayLength","Int_t");
      R__b >> fArrayLength;
      R__b.ClassMember("fArrayDim","Int_t");
      R__b >> fArrayDim;
      R__b.ClassMember("fMaxIndex","Int_t", 5);
      if (R__v == 1) R__b.ReadStaticArray(fMaxIndex);
      else           R__b.ReadFastArray(fMaxIndex,5);
      R__b.ClassMember("fTypeName","TString");
      fTypeName.Streamer(R__b);
      if (fType==11&&(fTypeName=="Bool_t"||fTypeName=="bool")) fType = 18;
      if (R__v > 1) {
         SetUniqueID(0);
         //check if element is a TRef or TRefArray
         GetExecID();
      }
      if (R__v <= 2 && this->IsA()==TStreamerBasicType::Class()) {
         // In TStreamerElement v2, fSize was holding the size of
         // the underlying data type.  In later version it contains 
         // the full length of the data member.
         TDataType *type = gROOT->GetType(GetTypeName());
         if (type && fArrayLength) fSize = fArrayLength * type->Size();
      }
      if (R__v == 3) {
         R__b >> fXmin;
         R__b >> fXmax;
         R__b >> fFactor;
         if (fFactor > 0) SetBit(kHasRange);
      }
      if (R__v > 3) {
         if (TestBit(kHasRange)) GetRange(GetTitle(),fXmin,fXmax,fFactor);
      }
      //R__b.CheckByteCount(R__s, R__c, TStreamerElement::IsA());
      R__b.ClassEnd(TStreamerElement::Class());
      R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
   } else {
      R__b.WriteClassBuffer(TStreamerElement::Class(),this);
   }
}

//______________________________________________________________________________
void TStreamerElement::Update(const TClass *oldClass, TClass *newClass)
{
   //function called by the TClass constructor when replacing an emulated class
   //by the real class

   if (fClassObject == oldClass) {
      fClassObject = newClass;
      if (fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
         fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
      }
   } else if (fClassObject==0) {
      // Well since some emulated class is replaced by a real class, we can
      // assume a new library has been loaded.  If this is the case, we should
      // check whether the class now exist (this would be the case for example
      // for reading STL containers).
      fClassObject = (TClass*)-1;
      GetClassPointer(); //force fClassObject
      if (fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
         fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
      }
   }
}

//______________________________________________________________________________

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStreamerBase implement the streamer of the base class               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

ClassImp(TStreamerBase)

//______________________________________________________________________________
TStreamerBase::TStreamerBase()
{
   // Default ctor.

   fBaseClass = (TClass*)(-1);
   fBaseVersion = 0;
   fNewBaseClass = 0;
}

//______________________________________________________________________________
TStreamerBase::TStreamerBase(const char *name, const char *title, Int_t offset)
        : TStreamerElement(name,title,offset,TVirtualStreamerInfo::kBase,"BASE")
{
   // Create a TStreamerBase object.

   if (strcmp(name,"TObject") == 0) fType = TVirtualStreamerInfo::kTObject;
   if (strcmp(name,"TNamed")  == 0) fType = TVirtualStreamerInfo::kTNamed;
   fNewType = fType;
   fBaseClass = TClass::GetClass(GetName());
   fBaseVersion = fBaseClass->GetClassVersion();
   fNewBaseClass = 0;
   Init();
}

//______________________________________________________________________________
TStreamerBase::~TStreamerBase()
{
   // TStreamerBase dtor
}

//______________________________________________________________________________
TClass *TStreamerBase::GetClassPointer() const
{
   // Returns a pointer to the TClass of this element.
   if (fBaseClass!=(TClass*)(-1)) return fBaseClass;
   ((TStreamerBase*)this)->fBaseClass = TClass::GetClass(GetName());
   return fBaseClass;
}

//______________________________________________________________________________
Int_t TStreamerBase::GetSize() const
{
   // Returns size of baseclass in bytes.

   TClass *cl = GetClassPointer();
   if (cl) return cl->Size();
   return 0;
}

//______________________________________________________________________________
void TStreamerBase::Init(TObject *)
{
   // Setup the element.

   if (fType == TVirtualStreamerInfo::kTObject || fType == TVirtualStreamerInfo::kTNamed) return;
   fBaseClass = TClass::GetClass(GetName());
   if (!fBaseClass) return;
   if (!fBaseClass->GetMethodAny("StreamerNVirtual")) return;
   delete fMethod;
   fMethod = new TMethodCall();
   fMethod->InitWithPrototype(fBaseClass,"StreamerNVirtual","TBuffer &");
   //fBaseClass = TClass::GetClass(GetName());
}

//______________________________________________________________________________
Bool_t TStreamerBase::IsBase() const
{
   // Return kTRUE if the element represent a base class.

   return kTRUE;
}

//______________________________________________________________________________
const char *TStreamerBase::GetInclude() const
{
   // Return the proper include for this element.

   if (GetClassPointer() && fBaseClass->GetClassInfo()) {
      sprintf(gIncludeName,"\"%s\"",fBaseClass->GetDeclFileName());
   } else {
      std::string shortname( TClassEdit::ShortType( GetName(), 1 ) );
      sprintf(gIncludeName,"\"%s.h\"",shortname.c_str());
   }
   return gIncludeName;
}

//______________________________________________________________________________
void TStreamerBase::ls(Option_t *) const
{
   // Print the content of the element.

   printf("  %-14s %-15s offset=%3d type=%2d %s%-20s\n",GetFullName(),GetTypeName(),fOffset,fType,TestBit(kCache)?"(cached) ":"",GetTitle());
}

//______________________________________________________________________________
Int_t TStreamerBase::ReadBuffer (TBuffer &b, char *pointer)
{
   // Read the content of the buffer.

   if (fMethod) {
      ULong_t args[1];
      args[0] = (ULong_t)&b;
      R__LOCKGUARD2(gCINTMutex);
      fMethod->SetParamPtrs(args);
      fMethod->Execute((void*)(pointer+fOffset));
   } else {
     // printf("Reading baseclass:%s via ReadBuffer\n",fBaseClass->GetName());
      //fBaseClass->ReadBuffer(b,pointer+fOffset);
      if( fNewBaseClass )
         b.ReadClassBuffer( fNewBaseClass, pointer+fOffset, fBaseClass );
      else
         b.ReadClassBuffer( fBaseClass, pointer+fOffset );
   }
   return 0;
}

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

   UInt_t R__s, R__c;
   if (R__b.IsReading()) {
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      
      R__b.ClassBegin(TStreamerBase::Class(), R__v);
      
      R__b.ClassMember("TStreamerElement");
      TStreamerElement::Streamer(R__b);
      // If the class owning the TStreamerElement and the base class are not
      // loaded, on the file their streamer info might be in the following 
      // order (derived class,base class) and hence the base class is not
      // yet emulated.
      fBaseClass = (TClass*)-1;
      fNewBaseClass = 0;
      if (R__v > 2) {
         R__b.ClassMember("fBaseVersion","Int_t");
         R__b >> fBaseVersion;
      } else {
         // could have been: fBaseVersion = GetClassPointer()->GetClassVersion();
         fBaseClass = TClass::GetClass(GetName());         
         fBaseVersion = fBaseClass->GetClassVersion();
      }
      R__b.ClassEnd(TStreamerBase::Class());
      R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
   } else {
      R__b.WriteClassBuffer(TStreamerBase::Class(),this);
   }
}

//______________________________________________________________________________
void TStreamerBase::Update(const TClass *oldClass, TClass *newClass)
{
   //function called by the TClass constructor when replacing an emulated class
   //by the real class

   if (fClassObject == oldClass) fClassObject = newClass;
   else if (fClassObject == 0) {
      fClassObject = (TClass*)-1;
      GetClassPointer(); //force fClassObject
   }
   if (fBaseClass   == oldClass) fBaseClass   = newClass;
   else if (fBaseClass == 0 ) {
      fBaseClass = (TClass*)-1;
      GetClassPointer(); //force fClassObject
   }
   if (fClassObject != (TClass*)-1 &&
       fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
      fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
   }
}

//______________________________________________________________________________
Int_t TStreamerBase::WriteBuffer (TBuffer &b, char *pointer)
{
   // Write the base class into the buffer.

   if (!fMethod) {
      //      if (fBaseClass->GetClassInfo()) fBaseClass->WriteBuffer(b,pointer);
      // now always write ... the previous implementation did not even match
      // the ReadBuffer?
      fBaseClass->WriteBuffer(b,pointer+fOffset);
      return 0;
   }
   ULong_t args[1];
   args[0] = (ULong_t)&b;
   R__LOCKGUARD2(gCINTMutex);
   fMethod->SetParamPtrs(args);
   fMethod->Execute((void*)(pointer+fOffset));
   b.ForceWriteInfo(fBaseClass->GetStreamerInfo(),kFALSE);
   return 0;
}

//______________________________________________________________________________

//////////////////////////////////////////////////////////////////////////<commit_msg>From Axel and Philippe: When streaming a base class without StreamerNVirtual() use an external streamer if it was set. Fixes Savannah #59093.<commit_after>// @(#)root/meta:$Id$
// Author: <NAME>   12/10/2000

/*************************************************************************
 * Copyright (C) 1995-2000, <NAME> and <NAME>.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


#include "TROOT.h"
#include "TStreamerElement.h"
#include "TVirtualStreamerInfo.h"
#include "TClass.h"
#include "TClassEdit.h"
#include "TClassStreamer.h"
#include "TBaseClass.h"
#include "TDataMember.h"
#include "TDataType.h"
#include "TMethodCall.h"
#include "TRealData.h"
#include "TFolder.h"
#include "TRef.h"
#include "TInterpreter.h"
#include "TError.h"
#include "TDataType.h"
#include "TVirtualMutex.h"
#include <iostream>

#include <string>
namespace std {} using namespace std;

const Int_t kMaxLen = 1024;
static char gIncludeName[kMaxLen];


//______________________________________________________________________________
static TStreamerBasicType *InitCounter(const char *countClass, const char *countName)
{
   // Helper function to initialize the 'index/counter' value of
   // the Pointer streamerElements.

   TClass *cl = TClass::GetClass(countClass);

   if (cl==0) return 0;

   TStreamerBasicType *counter = TVirtualStreamerInfo::GetElementCounter(countName,cl);

   //at this point the counter is may be declared to skip
   if (counter) {
      if (counter->GetType() < TVirtualStreamerInfo::kCounter) counter->SetType(TVirtualStreamerInfo::kCounter);
   }
   return counter;
}


//______________________________________________________________________________
static void GetRange(const char *comments, Double_t &xmin, Double_t &xmax, Double_t &factor)
{
   // Parse comments to search for a range specifier of the style:
   //  [xmin,xmax] or [xmin,xmax,nbits]
   //  [0,1]
   //  [-10,100];
   //  [-pi,pi], [-pi/2,pi/4],[-2pi,2*pi]
   //  [-10,100,16]
   //  [0,0,8]
   // if nbits is not specified, or nbits <2 or nbits>32 it is set to 32
   // if (xmin==0 and xmax==0 and nbits <=16) the double word will be converted
   // to a float and its mantissa truncated to nbits significative bits.
   //
   //  see comments in TBufferFile::WriteDouble32.

   const Double_t kPi =3.14159265358979323846 ;
   factor = xmin = xmax = 0;
   if (!comments) return;
   const char *left = strstr(comments,"[");
   if (!left) return;
   const char *right = strstr(left,"]");
   if (!right) return;
   const char *comma = strstr(left,",");
   if (!comma || comma > right) {
      //may be first bracket was a dimension specifier
      left = strstr(right,"[");
      if (!left) return;
      right = strstr(left,"]");
      if (!right) return;
      comma = strstr(left,",");
      if (!comma || comma >right) return;
   }
   //search if nbits is specified
   const char *comma2 = 0;
   if (comma) comma2 = strstr(comma+1,",");
   if (comma2 > right) comma2 = 0;
   Int_t nbits = 32;
   if (comma2) {
      TString sbits(comma2+1,right-comma2-1);
      sscanf(sbits.Data(),"%d",&nbits);
      if (nbits < 2 || nbits > 32) {
         ::Error("GetRange","Illegal specification for the number of bits; %d. reset to 32.",nbits);
         nbits = 32;
      }
      right = comma2;
   }
   TString range(left+1,right-left-1);
   TString sxmin(left+1,comma-left-1);
   sxmin.ToLower();
   sxmin.ReplaceAll(" ","");
   if (sxmin.Contains("pi")) {
      if      (sxmin.Contains("2pi"))   xmin = 2*kPi;
      else if (sxmin.Contains("2*pi"))  xmin = 2*kPi;
      else if (sxmin.Contains("twopi")) xmin = 2*kPi;
      else if (sxmin.Contains("pi/2"))  xmin = kPi/2;
      else if (sxmin.Contains("pi/4"))  xmin = kPi/4;
      else if (sxmin.Contains("pi"))    xmin = kPi;
      if (sxmin.Contains("-"))          xmin = -xmin;
   } else {
      sscanf(sxmin.Data(),"%lg",&xmin);
   }
   TString sxmax(comma+1,right-comma-1);
   sxmax.ToLower();
   sxmax.ReplaceAll(" ","");
   if (sxmax.Contains("pi")) {
      if      (sxmax.Contains("2pi"))   xmax = 2*kPi;
      else if (sxmax.Contains("2*pi"))  xmax = 2*kPi;
      else if (sxmax.Contains("twopi")) xmax = 2*kPi;
      else if (sxmax.Contains("pi/2"))  xmax = kPi/2;
      else if (sxmax.Contains("pi/4"))  xmax = kPi/4;
      else if (sxmax.Contains("pi"))    xmax = kPi;
      if (sxmax.Contains("-"))          xmax = -xmax;
   } else {
      sscanf(sxmax.Data(),"%lg",&xmax);
   }
   UInt_t bigint;
   if (nbits < 32)  bigint = 1<<nbits;
   else             bigint = 0xffffffff;
   if (xmin < xmax) factor = bigint/(xmax-xmin);
   if (xmin >= xmax && nbits <15) xmin = nbits+0.1;
}

ClassImp(TStreamerElement)

//______________________________________________________________________________
TStreamerElement::TStreamerElement()
{
   // Default ctor.

   fType        = 0;
   fSize        = 0;
   fNewType     = 0;
   fArrayDim    = 0;
   fArrayLength = 0;
   fStreamer    = 0;
   fMethod      = 0;
   fOffset      = 0;
   fClassObject = (TClass*)(-1);
   fNewClass    = 0;
   fTObjectOffset = 0;
   fFactor      = 0;
   fXmin        = 0;
   fXmax        = 0;
   for (Int_t i=0;i<5;i++) fMaxIndex[i] = 0;
}

//______________________________________________________________________________
TStreamerElement::TStreamerElement(const char *name, const char *title, Int_t offset, Int_t dtype, const char *typeName)
        : TNamed(name,title)
{
   // Create a TStreamerElement object.

   fOffset      = offset;
   fType        = dtype;
   fSize        = 0;
   fNewType     = fType;
   fArrayDim    = 0;
   fArrayLength = 0;
   fTypeName    = TClassEdit::ResolveTypedef(typeName);
   fStreamer    = 0;
   fMethod      = 0;
   fClassObject = (TClass*)(-1);
   fNewClass    = 0;
   fTObjectOffset = 0;
   fFactor      = 0;
   fXmin        = 0;
   fXmax        = 0;
   for (Int_t i=0;i<5;i++) fMaxIndex[i] = 0;
   if (fTypeName == "Float16_t" || fTypeName == "Float16_t*") {
      GetRange(title,fXmin,fXmax,fFactor);
      if (fFactor > 0 || fXmin > 0) SetBit(kHasRange);
   }
   if (fTypeName == "Double32_t" || fTypeName == "Double32_t*") {
      GetRange(title,fXmin,fXmax,fFactor);
      if (fFactor > 0 || fXmin > 0) SetBit(kHasRange);
   }
}

//______________________________________________________________________________
TStreamerElement::~TStreamerElement()
{
   // TStreamerElement dtor.
   delete fMethod;
}


//______________________________________________________________________________
Bool_t TStreamerElement::CannotSplit() const
{
   // Returns true if the element cannot be split, false otherwise.
   // An element cannot be split if the corresponding class member has
   // the special characters "||" as the first characters in the
   // comment field.

   if (strspn(GetTitle(),"||") == 2) return kTRUE;
   TClass *cl = GetClassPointer();
   if (!cl) return kFALSE;  //basic type

   switch(fType) {
      case TVirtualStreamerInfo::kAny    +TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kObject +TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kTObject+TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kTString+TVirtualStreamerInfo::kOffsetL:
      case TVirtualStreamerInfo::kTNamed +TVirtualStreamerInfo::kOffsetL:
         return kTRUE;
   }

   if ( !cl->CanSplit() ) return kTRUE;

   return kFALSE;
}

//______________________________________________________________________________
TClass *TStreamerElement::GetClassPointer() const
{
   // Returns a pointer to the TClass of this element.

   if (fClassObject!=(TClass*)(-1)) return fClassObject;
   TString className = fTypeName.Strip(TString::kTrailing, '*');
   if (className.Index("const ")==0) className.Remove(0,6);
   ((TStreamerElement*)this)->fClassObject = TClass::GetClass(className);
   return fClassObject;
}

//______________________________________________________________________________
Int_t TStreamerElement::GetExecID() const
{
   // Returns the TExec id for the EXEC instruction in the comment field
   // of a TRef data member.

   //check if element is a TRef or TRefArray
   if (strncmp(fTypeName.Data(),"TRef",4) != 0) return 0;

   //if the UniqueID of this element has already been set, we assume
   //that it contains the exec id of a TRef object.
   if (GetUniqueID()) return GetUniqueID();

   //check if an Exec is specified in the comment field
   char *action = (char*)strstr(GetTitle(),"EXEC:");
   if (!action) return 0;
   char caction[512];
   strcpy(caction,action+5);
   char *blank = (char*)strchr(caction,' ');
   if (blank) *blank = 0;
   //we have found the Exec name in the comment
   //we register this Exec to the list of Execs.
   Int_t index = TRef::AddExec(caction);
   //we save the Exec index as the uniqueid of this STreamerElement
   ((TStreamerElement*)this)->SetUniqueID(index+1);
   return index+1;
}

//______________________________________________________________________________
const char *TStreamerElement::GetFullName() const
{
   // Return element name including dimensions, if any
   // Note that this function stores the name into a static array.
   // You should copy the result.

   static char name[kMaxLen];
   char cdim[20];
   sprintf(name,"%s",GetName());
   for (Int_t i=0;i<fArrayDim;i++) {
      sprintf(cdim,"[%d]",fMaxIndex[i]);
      strcat(name,cdim);
   }
   return name;
}

//______________________________________________________________________________
Int_t TStreamerElement::GetSize() const
{
   // Returns size of this element in bytes.

   return fSize;
}

//______________________________________________________________________________
TMemberStreamer *TStreamerElement::GetStreamer() const
{
   // Return the local streamer object.

   return fStreamer;
}

//______________________________________________________________________________
const char *TStreamerElement::GetTypeNameBasic() const
{
   // Return type name of this element
   // in case the type name is not a standard basic type, return
   // the basic type name known to CINT.

   TDataType *dt = gROOT->GetType(fTypeName.Data());
   if (fType < 1 || fType > 55) return fTypeName.Data();
   if (dt && dt->GetType() > 0) return fTypeName.Data();
   Int_t dtype = fType%20;
   return TDataType::GetTypeName((EDataType)dtype);
}

//______________________________________________________________________________
void TStreamerElement::Init(TObject *)
{
   // Initliaze the element.

   fClassObject = GetClassPointer();
   if (fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
      fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
   }
}

//______________________________________________________________________________
Bool_t TStreamerElement::IsOldFormat(const char *newTypeName)
{
   // The early 3.00/00 and 3.01/01 versions used to store
   // dm->GetTypeName instead of dm->GetFullTypename
   // if this case is detected, the element type name is modified.

   //if (!IsaPointer()) return kFALSE;
   if (!strstr(newTypeName,fTypeName.Data())) return kFALSE;
   //if (!strstr(fTypeName.Data(),newTypeName)) return kFALSE;
   fTypeName = newTypeName;
   return kTRUE;
}

//______________________________________________________________________________
Bool_t TStreamerElement::IsBase() const
{
   // Return kTRUE if the element represent a base class.

   return kFALSE;
}

//______________________________________________________________________________
void TStreamerElement::ls(Option_t *) const
{
   // Print the content of the element.

   sprintf(gIncludeName,"%s",GetTypeName());
   if (IsaPointer() && !fTypeName.Contains("*")) strcat(gIncludeName,"*");
   printf("  %-14s %-15s offset=%3d type=%2d %s%-20s\n",
      gIncludeName,GetFullName(),fOffset,fType,TestBit(kCache)?"(cached) ":"",
      GetTitle());
}

//______________________________________________________________________________
void TStreamerElement::SetArrayDim(Int_t dim)
{
   // Set number of array dimensions.

   fArrayDim = dim;
   if (dim) fType += TVirtualStreamerInfo::kOffsetL;
   fNewType = fType;
}

//______________________________________________________________________________
void TStreamerElement::SetMaxIndex(Int_t dim, Int_t max)
{
   //set maximum index for array with dimension dim

   if (dim < 0 || dim > 4) return;
   fMaxIndex[dim] = max;
   if (fArrayLength == 0)  fArrayLength  = max;
   else                    fArrayLength *= max;
}

//______________________________________________________________________________
void TStreamerElement::SetStreamer(TMemberStreamer *streamer)
{
   //set pointer to Streamer function for this element

   fStreamer = streamer;
}

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

   UInt_t R__s, R__c;
   if (R__b.IsReading()) {
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      //NOTE that when reading, one cannot use Class()->ReadBuffer
      // TBuffer::Class methods used for reading streamerinfos from SQL database
      // Any changes of class structure should be reflected by them starting from version 4
      
      R__b.ClassBegin(TStreamerElement::Class(), R__v);
      R__b.ClassMember("TNamed");
      TNamed::Streamer(R__b);
      R__b.ClassMember("fType","Int_t");
      R__b >> fType;
      R__b.ClassMember("fSize","Int_t");
      R__b >> fSize;
      R__b.ClassMember("fArrayLength","Int_t");
      R__b >> fArrayLength;
      R__b.ClassMember("fArrayDim","Int_t");
      R__b >> fArrayDim;
      R__b.ClassMember("fMaxIndex","Int_t", 5);
      if (R__v == 1) R__b.ReadStaticArray(fMaxIndex);
      else           R__b.ReadFastArray(fMaxIndex,5);
      R__b.ClassMember("fTypeName","TString");
      fTypeName.Streamer(R__b);
      if (fType==11&&(fTypeName=="Bool_t"||fTypeName=="bool")) fType = 18;
      if (R__v > 1) {
         SetUniqueID(0);
         //check if element is a TRef or TRefArray
         GetExecID();
      }
      if (R__v <= 2 && this->IsA()==TStreamerBasicType::Class()) {
         // In TStreamerElement v2, fSize was holding the size of
         // the underlying data type.  In later version it contains 
         // the full length of the data member.
         TDataType *type = gROOT->GetType(GetTypeName());
         if (type && fArrayLength) fSize = fArrayLength * type->Size();
      }
      if (R__v == 3) {
         R__b >> fXmin;
         R__b >> fXmax;
         R__b >> fFactor;
         if (fFactor > 0) SetBit(kHasRange);
      }
      if (R__v > 3) {
         if (TestBit(kHasRange)) GetRange(GetTitle(),fXmin,fXmax,fFactor);
      }
      //R__b.CheckByteCount(R__s, R__c, TStreamerElement::IsA());
      R__b.ClassEnd(TStreamerElement::Class());
      R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
   } else {
      R__b.WriteClassBuffer(TStreamerElement::Class(),this);
   }
}

//______________________________________________________________________________
void TStreamerElement::Update(const TClass *oldClass, TClass *newClass)
{
   //function called by the TClass constructor when replacing an emulated class
   //by the real class

   if (fClassObject == oldClass) {
      fClassObject = newClass;
      if (fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
         fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
      }
   } else if (fClassObject==0) {
      // Well since some emulated class is replaced by a real class, we can
      // assume a new library has been loaded.  If this is the case, we should
      // check whether the class now exist (this would be the case for example
      // for reading STL containers).
      fClassObject = (TClass*)-1;
      GetClassPointer(); //force fClassObject
      if (fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
         fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
      }
   }
}

//______________________________________________________________________________

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStreamerBase implement the streamer of the base class               //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

ClassImp(TStreamerBase)

//______________________________________________________________________________
TStreamerBase::TStreamerBase()
{
   // Default ctor.

   fBaseClass = (TClass*)(-1);
   fBaseVersion = 0;
   fNewBaseClass = 0;
}

//______________________________________________________________________________
TStreamerBase::TStreamerBase(const char *name, const char *title, Int_t offset)
        : TStreamerElement(name,title,offset,TVirtualStreamerInfo::kBase,"BASE")
{
   // Create a TStreamerBase object.

   if (strcmp(name,"TObject") == 0) fType = TVirtualStreamerInfo::kTObject;
   if (strcmp(name,"TNamed")  == 0) fType = TVirtualStreamerInfo::kTNamed;
   fNewType = fType;
   fBaseClass = TClass::GetClass(GetName());
   fBaseVersion = fBaseClass->GetClassVersion();
   fNewBaseClass = 0;
   Init();
}

//______________________________________________________________________________
TStreamerBase::~TStreamerBase()
{
   // TStreamerBase dtor
}

//______________________________________________________________________________
TClass *TStreamerBase::GetClassPointer() const
{
   // Returns a pointer to the TClass of this element.
   if (fBaseClass!=(TClass*)(-1)) return fBaseClass;
   ((TStreamerBase*)this)->fBaseClass = TClass::GetClass(GetName());
   return fBaseClass;
}

//______________________________________________________________________________
Int_t TStreamerBase::GetSize() const
{
   // Returns size of baseclass in bytes.

   TClass *cl = GetClassPointer();
   if (cl) return cl->Size();
   return 0;
}

//______________________________________________________________________________
void TStreamerBase::Init(TObject *)
{
   // Setup the element.

   if (fType == TVirtualStreamerInfo::kTObject || fType == TVirtualStreamerInfo::kTNamed) return;
   fBaseClass = TClass::GetClass(GetName());
   if (!fBaseClass) return;
   if (!fBaseClass->GetMethodAny("StreamerNVirtual")) return;
   delete fMethod;
   fMethod = new TMethodCall();
   fMethod->InitWithPrototype(fBaseClass,"StreamerNVirtual","TBuffer &");
   //fBaseClass = TClass::GetClass(GetName());
}

//______________________________________________________________________________
Bool_t TStreamerBase::IsBase() const
{
   // Return kTRUE if the element represent a base class.

   return kTRUE;
}

//______________________________________________________________________________
const char *TStreamerBase::GetInclude() const
{
   // Return the proper include for this element.

   if (GetClassPointer() && fBaseClass->GetClassInfo()) {
      sprintf(gIncludeName,"\"%s\"",fBaseClass->GetDeclFileName());
   } else {
      std::string shortname( TClassEdit::ShortType( GetName(), 1 ) );
      sprintf(gIncludeName,"\"%s.h\"",shortname.c_str());
   }
   return gIncludeName;
}

//______________________________________________________________________________
void TStreamerBase::ls(Option_t *) const
{
   // Print the content of the element.

   printf("  %-14s %-15s offset=%3d type=%2d %s%-20s\n",GetFullName(),GetTypeName(),fOffset,fType,TestBit(kCache)?"(cached) ":"",GetTitle());
}

//______________________________________________________________________________
Int_t TStreamerBase::ReadBuffer (TBuffer &b, char *pointer)
{
   // Read the content of the buffer.

   if (fMethod) {
      ULong_t args[1];
      args[0] = (ULong_t)&b;
      R__LOCKGUARD2(gCINTMutex);
      fMethod->SetParamPtrs(args);
      fMethod->Execute((void*)(pointer+fOffset));
   } else {
      // We don't have a StreamerNVirtual(). That still doesn't mean
      // that there is no streamer - it could be an external one:
      // If the old base class has an adopted streamer we take that
      // one instead of the new base class:
      if( fNewBaseClass ) {
         TClassStreamer* extstrm = fNewBaseClass->GetStreamer();                  
         if (extstrm) {
            // The new base class has an adopted streamer:
            extstrm->SetOnFileClass(fBaseClass);
            (*extstrm)(b, pointer);
         } else {
            b.ReadClassBuffer( fNewBaseClass, pointer+fOffset, fBaseClass ); 
         }
      } else {
         TClassStreamer* extstrm = fBaseClass->GetStreamer();         
         if (extstrm) {
            // The class has an adopted streamer:
            (*extstrm)(b, pointer);
         } else {
            b.ReadClassBuffer( fBaseClass, pointer+fOffset );
         }
      }
   }
   return 0;
}

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

   UInt_t R__s, R__c;
   if (R__b.IsReading()) {
      Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
      
      R__b.ClassBegin(TStreamerBase::Class(), R__v);
      
      R__b.ClassMember("TStreamerElement");
      TStreamerElement::Streamer(R__b);
      // If the class owning the TStreamerElement and the base class are not
      // loaded, on the file their streamer info might be in the following 
      // order (derived class,base class) and hence the base class is not
      // yet emulated.
      fBaseClass = (TClass*)-1;
      fNewBaseClass = 0;
      if (R__v > 2) {
         R__b.ClassMember("fBaseVersion","Int_t");
         R__b >> fBaseVersion;
      } else {
         // could have been: fBaseVersion = GetClassPointer()->GetClassVersion();
         fBaseClass = TClass::GetClass(GetName());         
         fBaseVersion = fBaseClass->GetClassVersion();
      }
      R__b.ClassEnd(TStreamerBase::Class());
      R__b.SetBufferOffset(R__s+R__c+sizeof(UInt_t));
   } else {
      R__b.WriteClassBuffer(TStreamerBase::Class(),this);
   }
}

//______________________________________________________________________________
void TStreamerBase::Update(const TClass *oldClass, TClass *newClass)
{
   //function called by the TClass constructor when replacing an emulated class
   //by the real class

   if (fClassObject == oldClass) fClassObject = newClass;
   else if (fClassObject == 0) {
      fClassObject = (TClass*)-1;
      GetClassPointer(); //force fClassObject
   }
   if (fBaseClass   == oldClass) fBaseClass   = newClass;
   else if (fBaseClass == 0 ) {
      fBaseClass = (TClass*)-1;
      GetClassPointer(); //force fClassObject
   }
   if (fClassObject != (TClass*)-1 &&
       fClassObject && fClassObject->InheritsFrom(TObject::Class())) {
      fTObjectOffset = fClassObject->GetBaseClassOffset(TObject::Class());
   }
}

//______________________________________________________________________________
Int_t TStreamerBase::WriteBuffer (TBuffer &b, char *pointer)
{
   // Write the base class into the buffer.

   if (!fMethod) {
      // We don't have a StreamerNVirtual(). That still doesn't mean
      // that there is no streamer - it could be an external one:
      // If the old base class has an adopted streamer we take that
      // one instead of the new base class:
      if (fNewBaseClass) {
         TClassStreamer* extstrm = fNewBaseClass->GetStreamer();
         if (extstrm) {
            // The new base class has an adopted streamer:
            extstrm->SetOnFileClass(fBaseClass);
            (*extstrm)(b, pointer);
            return 0;
         } else {
            fNewBaseClass->WriteBuffer(b,pointer+fOffset);
            return 0;
         }
      } else {
         TClassStreamer* extstrm = fBaseClass->GetStreamer();
         if (extstrm) {
            (*extstrm)(b, pointer);
            return 0;
         } else {
            fBaseClass->WriteBuffer(b,pointer+fOffset);
            return 0;
         }
      }
   }
   ULong_t args[1];
   args[0] = (ULong_t)&b;
   R__LOCKGUARD2(gCINTMutex);
   fMethod->SetParamPtrs(args);
   fMethod->Execute((void*)(pointer+fOffset));
   b.ForceWriteInfo(fBaseClass->GetStreamerInfo(),kFALSE);
   return 0;
}

//______________________________________________________________________________

//////////////////////////////////////////////////////////////////////////
{'fraction_non_alphanumeric': 0.13962839997525417, 'fraction_numerical': 0.011300600086610438, 'mean_word_length': 3.099932363882313, 'pattern_counts': {'":': 4, '<': 43, '<?xml version=': 0, '>': 162, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5088928', 'n_tokens_mistral': 14660, 'n_tokens_neox': 14173, 'n_words': 3441}