/// <summary> /// Extract info for a sub-class from a branch! The last one is the top level class we are currently parsing! /// </summary> /// <param name="branch"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> ExtractClass(ROOTClassShell container, ROOTNET.Interface.NTBranch branch) { /// /// First, figure out what kind of class this is. For example, might it be a stl vector? If so, /// then we need to parse that up! /// if (branch.GetClassName().Contains("<")) { return(ExtractROOTTemplateClass(container, branch)); } else { return(ExtractROOTPlainClass(container, branch)); } }
/// <summary> /// A class has been defined only in the local tree. We need to parse through it and extract /// enough into to build a class on our own so that it can be correctly referenced in LINQ. /// </summary> /// <param name="container"></param> /// <param name="branch"></param> /// <param name="cls"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> BuildMetadataForTTreeClassFromBranches(ROOTClassShell container, ROOTNET.Interface.NTBranch branch, ROOTNET.Interface.NTClass cls) { // // Get a unique classname. Attempt to do "the right thing". In particular, if this is a clones array of some // struct, it is not a "named" class, so use the name of the clones array instead. // string className = cls.Name; bool mightBeClonesArray = false; if (branch is ROOTNET.Interface.NTBranchElement) { var cn = (branch as ROOTNET.Interface.NTBranchElement).ClonesName.SanitizedName(); if (!string.IsNullOrWhiteSpace(cn)) { className = cn; mightBeClonesArray = true; } } if (_classNameCounter.ContainsKey(className)) { _classNameCounter[className] += 1; className = string.Format("{0}_{1}", className, _classNameCounter[className]); } else { _classNameCounter[className] = 0; } // // We will define the class, and it will be exactly what is given to use by the // tree. // var varName = branch.Name.SanitizedName(); container.Add(new ItemSimpleType(varName, className) { NotAPointer = true }); // // We are going to build our own class type here. // var treeClass = new ROOTClassShell(className) { IsTopLevelClass = false }; // // Now, loop over the branches and add them in, returning any classes we had to generate. // foreach (var c in ExtractClassesFromBranchList(treeClass, branch.ListOfBranches.Cast <ROOTNET.Interface.NTBranch>())) { yield return(c); } // // The arrays in a tclones arrays are funny. The proxy generated parses them as seperate arrays, but their length is // basically the size of the tclonesarray. So we have to use that as the length. This is implied be cause we've marked // this class as a tclones array class already (above - the IsTTreeSubClass). So for the index we mark it as an index, // but we just marked the bound as "implied" - this will be picked up by the code when it is generated later on. // if (mightBeClonesArray) { var cBoundName = string.Format("{0}_", varName); var cstyleArrayIndicies = from item in treeClass.Items where item is ItemCStyleArray let citem = item as ItemCStyleArray from index in citem.Indicies where !index.indexConst && index.indexBoundName == cBoundName select index; bool foundTClonesArray = false; foreach (var item in cstyleArrayIndicies) { item.indexBoundName = "implied"; foundTClonesArray = true; } treeClass.IsTClonesArrayClass = foundTClonesArray; } // // If this is a tclones array - and it is a real array, then we don't want to de-reference anything. // if (treeClass.IsTClonesArrayClass) { foreach (var item in treeClass.Items) { item.NotAPointer = true; } } // // Finally, the one we just built! // yield return(treeClass); }
/// <summary> /// There is a plain class that needs to be extracted. We usually end up here becuase it is a split class of /// some sort. For now, we will assume it is a real root class. /// </summary> /// <param name="branch"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> ExtractROOTPlainClass(ROOTClassShell container, ROOTNET.Interface.NTBranch branch) { // // Double chekc that this is a root class. Since we are looking at the Tree, ROOT's system would certianly have declared it // internally. If we can't find the cls info, then we are in trouble. // var cls = ROOTNET.NTClass.GetClass(branch.GetClassName()); if (cls == null) { throw new NotImplementedException("The class '" + branch.GetClassName() + "' is not known to ROOT's type systems - and I can't proceed unless it is"); } if (cls.Name == "string") { throw new NotImplementedException("The class 'string' is not translated yet!"); } // // There are several ways this class can be encoded in the file. They broadly break down // into two classes: // // 1) A class that is fully defined by ROOT. TLorentzVector would be such a thing. // Custom classes that ROOT has a full dictionary for are equivalent and that // we have a good wrapper for. // 2) A class that is only defined by the contents of the ROOT file. This could be // as a series of leaves in the TTree (this would be the case of a split class) // or in the streamer, which is a non-split class' case. // // // If it has some public data members, then it is a real ROOT class, and whatever was done to define it and make it known // to ROOT here we assume will also be done when the full blown LINQ interface is run (i.e. some loaded C++ files). // if (!cls.IsShellTClass()) { container.Add(new ItemROOTClass(branch.Name, branch.GetClassName())); return(Enumerable.Empty <ROOTClassShell>()); } // // If we are here, then we are dealing with a locally defined class. One that ROOT made up on the fly. In short, not one // that we are going to have a translation for. So, we have to build the meta data for it. This // meta data can come from the tree branch list or from the streamer. // return(BuildMetadataForTTreeClassFromBranches(container, branch, cls)); }
/// <summary> /// Given a branch that is a template, parse it and add to the class hierarchy. /// </summary> /// <param name="branch"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> ExtractROOTTemplateClass(ROOTClassShell container, ROOTNET.Interface.NTBranch branch) { return(ExtractROOTTemplateClass(container, branch.Name, branch.GetClassName())); }