/// <summary> /// Populate a class with the stuff we find in the branches we are looking at. /// </summary> /// <param name="container"></param> /// <param name="branches"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> ExtractClassesFromBranchList(ROOTClassShell container, IEnumerable <ROOTNET.Interface.NTBranch> branches) { /// /// Now, loop through each branch and see if we can't convert everything! /// foreach (var branch in branches) { /// /// What kind of branch is this? Is it a leaf branch or is it a "class" branch. That is, does it have /// sub leaves on it? The key question to ask is how many sub-branches are there here? /// if (branch.ListOfBranches.Entries == 0) { foreach (var leaf in branch.GetListOfLeaves().Cast <ROOTNET.Interface.NTLeaf>()) { var cls = ROOTNET.NTClass.GetClass(leaf.TypeName); if (cls == null || !cls.IsShellTClass() || cls.IsSTLClass()) { // This is a class known to ROOT or // it is something very simple (int, vector<int>, etc.). try { IClassItem toAdd = ExtractUnsplitKnownClass(leaf); if (toAdd != null) { container.Add(toAdd); } } catch (Exception e) { SimpleLogging.Log("Info: Unable to transltae ntuple leaf '" + leaf.Name + "': " + e.Message); } } else { // This is a class we will have to bulid metadata for - from the streamer (the # of leaves // is zero if we are here, so it can only be streamer defiend). foreach (var item in ExtractUnsplitUnknownClass(container, leaf.Name, cls)) { yield return(item); } } } } else { var rc = ExtractClass(container, branch); ROOTClassShell lastOne = null; foreach (var rootClass in rc) { yield return(rootClass); lastOne = rootClass; } } } }
public void TestWithOneConstIndexedArray() { var aa = new ArrayAnalyzer(); string filename = "TestWithOneConstIndexedArray.root"; var f = new ROOTNET.NTFile(filename, "RECREATE"); var tree = CreateTrees.CreateTreeWithConstIndexedSimpleVector(20); f.Write(); ROOTClassShell sh = new ROOTClassShell(); sh.Add(new Classitem() { ItemType = "int[]", Name = "arr" }); var result = aa.DetermineAllArrayLengths(sh, tree, 10); Assert.AreEqual(10, result.Length, "# of events"); Assert.IsTrue(result.All(x => x.Length == 1), "# of arrays"); Assert.IsTrue(result.All(x => x[0].Item2 == 20), "Length of array"); Assert.IsTrue(result.All(x => x[0].Item1 == "arr"), "variable name"); f.Close(); }
public void TestArrayAndNormalItem() { var aa = new ArrayAnalyzer(); // We get memory corruption if we create the tree and use it, rather // than writing it out to a file first. Not sure why... GC and other // things looked at, but they don't seem to be variables. { var f = ROOTNET.NTFile.Open("TestArrayAndNormalItem.root", "RECREATE"); var tree = CreateTrees.CreateTreeWithSimpleSingleVectorAndItem(20); f.Write(); f.Close(); } var f1 = ROOTNET.NTFile.Open("TestArrayAndNormalItem.root", "READ"); var tree1 = f1.Get("dude") as ROOTNET.NTTree; ROOTClassShell sh = new ROOTClassShell(); sh.Add(new Classitem() { ItemType = "int[]", Name = "myvectorofint" }); var result = aa.DetermineAllArrayLengths(sh, tree1, 10); Assert.AreEqual(10, result.Length, "# of events"); Assert.IsTrue(result.All(x => x.Length == 1), "incorrect individual variable list length list"); Assert.IsTrue(result.All(x => x[0].Item2 == 10), "incorrect individual variable list length list"); f1.Close(); }
/// <summary> /// Analyze a tree for a pattern. /// </summary> /// <param name="tree"></param> /// <param name="eventsToAnalyze"># of events to analyze. Zero means the whole tree</param> public List <ArrayGroup> AnalyzeTTree(ROOTClassShell classinfo, ROOTNET.Interface.NTTree tree, int eventsToAnalyze) { if (tree == null) { throw new ArgumentNullException("tree must not be null"); } if (eventsToAnalyze < 0) { throw new ArgumentException("# of events to analyze must be zero ore better."); } /// /// Get the raw numbers out /// var rawnumbers = DetermineAllArrayLengths(classinfo, tree, eventsToAnalyze); /// /// Next, parse the variables into groups /// var groups = DetermineGroups(rawnumbers); return(groups); }
public void TestWithNoArrays() { var aa = new ArrayAnalyzer(); var tree = CreateTrees.CreateWithIntOnly(10); ROOTClassShell sh = new ROOTClassShell(); var results = aa.DetermineAllArrayLengths(sh, tree, 10); Assert.AreEqual(1, results.Length, "# of events incorrect"); Assert.AreEqual(0, results[0].Length, "found an array!?"); }
public void TestArrayWithNoEntries() { ArrayAnalyzer target = new ArrayAnalyzer(); // TODO: Initialize to an appropriate value var tree = CreateTrees.CreateVectorTree(); ROOTClassShell sh = new ROOTClassShell(); target.DetermineAllArrayLengths(sh, tree, 10); }
/// <summary> /// Run a TTree analysis and get the array sizes for the ntuple. Returns an entry for each /// "event" that is analyzed, with the array names in each one. /// </summary> /// <param name="tree"></param> /// <param name="eventsToAnalyze"></param> /// <returns>The outter index is one per event, and the inner index is for all arrays. Each array has a name and its size in the tuple.</returns> internal Tuple <string, int>[][] DetermineAllArrayLengths(ROOTClassShell classinfo, ROOTNET.Interface.NTTree tree, long eventsToAnalyze) { if (tree.Entries == 0) { return new Tuple <string, int>[][] { new Tuple <string, int> [0] } } ; if (classinfo == null) { throw new ArgumentNullException("the class info cannot be null!"); } /// /// Create the counters /// var arrays = from item in classinfo.Items where item.ItemType.Contains("[]") select item.Name; // + "@.size()" var counterlist = (from item in arrays let treeForm = new ROOTNET.NTTreeFormula(item, string.Format("Length$({0})", item), tree) where treeForm.IsGoodFormula() select treeForm).ToArray(); /// /// Now run through everything /// long entriesToTry = eventsToAnalyze; if (entriesToTry == 0) { entriesToTry = tree.Entries; } if (entriesToTry > tree.Entries) { entriesToTry = tree.Entries; } var eventNtupleData = (from entry in Enumerable.Range(0, (int)entriesToTry) select ComputeCounters(counterlist, tree, entry)).ToArray(); /// /// Make sure to clean up /// foreach (var c in counterlist) { c.Delete(); } return(eventNtupleData); }
/// <summary> /// The class has no def in a TClass. It has no def in the way the branches and leaves are layed out. So, /// we, really, have only one option here. Parse the streamer! /// </summary> /// <param name="leaf"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> ExtractUnsplitUnknownClass(ROOTClassShell container, string itemName, ROOTNET.Interface.NTClass cls) { // Make sure that we are ok here. var streamer = cls.StreamerInfo; if (streamer == null) { return(Enumerable.Empty <ROOTClassShell>()); } return(ExtractClassFromStreamer(container, itemName, cls, streamer)); }
public void TestConstCStyleArray() { // Simple set of types for an index array var vArray = new ItemCStyleArray("int[]", new ItemSimpleType("arr", "int")); vArray.Add(0, "10", true); var vIndex = new ItemSimpleType("n", "int"); ROOTClassShell mainClass = new ROOTClassShell("TestSimpleRename") { }; mainClass.Add(vIndex); mainClass.Add(vArray); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "ungrouped", Variables = new VariableInfo[] { new VariableInfo() { NETName = "n", TTreeName = "n" }, new VariableInfo() { NETName = "arr", TTreeName = "arr" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestConstCStyleArray.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestSimpleRename", userinfo } }); CopyToOutput(outputFile); /// Look through this to see if we can make sure there are no renames! Assert.IsTrue(FindInFile(outputFile, "int[] arr"), "Array Decl missing"); Assert.IsTrue(FindInFile(outputFile, "int n"), "Index decl missing"); Assert.IsTrue(FindInFile(outputFile, "[ArraySizeIndex(\"10\", IsConstantExpression = true, Index = 0)]"), "Missing array size index attribute"); }
public void GroupWithArrayLengthSpecification() { ItemSimpleType simple1 = new ItemSimpleType("avar", "int[]"); ItemSimpleType simple2 = new ItemSimpleType("bvar", "int[]"); ROOTClassShell mainClass = new ROOTClassShell("GroupWithArrayLengthSpecification") { }; mainClass.Add(simple1); mainClass.Add(simple2); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "jets", NETNameOfVariableToUseAsArrayLength = "b", Variables = new VariableInfo[] { new VariableInfo() { NETName = "a", TTreeName = "avar" }, new VariableInfo() { NETName = "b", TTreeName = "bvar" }, } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("GroupWithArrayLengthSpecification.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "GroupWithArrayLengthSpecification", userinfo } }); DumpOutputFile(outputFile); /// Look through this to see if we can make sure there are no renames! Assert.IsTrue(FindInFile(outputFile, "UseAsArrayLength"), "Missing the UseAsArrayLength attribute!!"); }
public void TestNonIntIndex() { /// Create simple user info - but don't do anything with it! ItemSimpleType simpleIndex = new ItemSimpleType("index", "float[]"); ItemSimpleType simpleVal = new ItemSimpleType("var1", "float[]"); ROOTClassShell mainClass = new ROOTClassShell("TestNonIntIndex") { }; mainClass.Add(simpleIndex); mainClass.Add(simpleVal); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "jets", Variables = new VariableInfo[] { new VariableInfo() { NETName = "index", TTreeName = "index", IndexToGroup = "muons" } } }, new ArrayGroup() { Name = "muons", Variables = new VariableInfo[] { new VariableInfo() { NETName = "var1", TTreeName = "var1" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestNonIntIndex.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestNonIntIndex", userinfo } }); }
/// <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> /// 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> /// Similar to the filling in above - we fill in any defaults to make the code cleaner /// than might have been done above. /// </summary> /// <param name="cls"></param> /// <param name="userInfo"></param> /// <returns></returns> private TTreeUserInfo FillInDefaults(ROOTClassShell cls, TTreeUserInfo userInfo) { // // Group class names are often left up to use to determine. Fill in the defaults here. // foreach (var g in userInfo.Groups) { if (string.IsNullOrWhiteSpace(g.ClassName)) { g.ClassName = string.Format("{0}{1}", cls.Name, g.Name); } } return(userInfo); }
public void TestCStyleArrayBadIndexName() { // Simple set of types for an index array var vArray = new ItemCStyleArray("int[]", new ItemSimpleType("arr", "int")); vArray.Add(0, "i", false); var vIndex = new ItemSimpleType("n", "int"); ROOTClassShell mainClass = new ROOTClassShell("TestSimpleRename") { }; mainClass.Add(vIndex); mainClass.Add(vArray); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "ungrouped", Variables = new VariableInfo[] { new VariableInfo() { NETName = "n", TTreeName = "n" }, new VariableInfo() { NETName = "arr", TTreeName = "arr" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestCStyleArray.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestSimpleRename", userinfo } }); }
public void TestSimpleGroupWithCustomClassName() { /// Create simple user info - but don't do anything with it! ItemSimpleType simple = new ItemSimpleType("var1", "int[]"); ROOTClassShell mainClass = new ROOTClassShell("TestSimpleGroupAndRename") { }; mainClass.Add(simple); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "jets", ClassName = "Jet", Variables = new VariableInfo[] { new VariableInfo() { NETName = "myvar", TTreeName = "var1" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestSimpleGroupAndRename.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestSimpleGroupAndRename", userinfo } }); DumpOutputFile(outputFile); /// Look through this to see if we can make sure there are no renames! Assert.IsTrue(FindInFile(outputFile, "RenameVariable(\"var1\")"), "Rename missing!"); Assert.IsTrue(FindInFile(outputFile, "TTreeVariableGrouping"), "Missing TTreeVariableGrouping"); Assert.IsTrue(FindInFile(outputFile, "jets"), "missing a reference to jets"); Assert.IsTrue(FindInFile(outputFile, "int myvar"), "myvar missing"); Assert.IsTrue(FindInFile(outputFile, "int[] var1"), "val1 missing"); Assert.IsFalse(FindInFile(outputFile, "ungrouped"), "group found"); Assert.IsFalse(FindInFile(outputFile, "TestSimpleGroupAndRenamejets"), "Found the non-class name default class name"); Assert.IsTrue(FindInFile(outputFile, "Jet"), "Did not find the Jet custom class name"); }
/// <summary> /// Find all non-arrays and add them to our ungrouped group. Since this /// grouping is what drives the class generation, this is very much something /// we have to do! :-) /// </summary> /// <param name="masterClass"></param> /// <param name="groupToAddTo">What is the name of the group we should add them to?</param> private void AddNonArrays(ROOTClassShell masterClass, List <ArrayGroup> groups, string groupToAddTo) { /// /// First, get all non-arrays. Arrays are all declared with [] right now, /// so we need only look for that. /// var nonarrays = (from item in masterClass.Items where !item.ItemType.Contains("[]") select item.Name).ToArray(); if (nonarrays.Length == 0) { return; } /// /// Turn the names into variables /// var varInfo = nonarrays.ToVariableInfo(); /// /// See if the group we should add them to exists. /// var grp = (from g in groups where g.Name == groupToAddTo select g).FirstOrDefault(); if (grp == null) { grp = new ArrayGroup() { Name = groupToAddTo, Variables = varInfo.ToArray() }; groups.Add(grp); } else { grp.Variables = (grp.Variables.Concat(varInfo)).ToArray(); } }
public void TestDuplicateClassNames() { var vIndex = new ItemSimpleType("n", "int"); ROOTClassShell mainClass = new ROOTClassShell("TestSimpleRename") { }; mainClass.Add(vIndex); ROOTClassShell mainClass1 = new ROOTClassShell("TestSimpleRename") { }; mainClass1.Add(vIndex); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass, mainClass1 }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "ungrouped", Variables = new VariableInfo[] { new VariableInfo() { NETName = "n", TTreeName = "n" }, } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestDuplicateClassNames.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestDuplicateClassNames", userinfo } }); }
public void TestColonsInVarName() { ItemSimpleType simple = new ItemSimpleType("dude::fork", "int[]"); ROOTClassShell mainClass = new ROOTClassShell("TestSimpleGroupAndRename") { }; mainClass.Add(simple); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "jets", Variables = new VariableInfo[] { new VariableInfo() { NETName = "dude::fork", TTreeName = "dude::fork" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestSimpleGroupAndRename.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestSimpleGroupAndRename", userinfo } }); DumpOutputFile(outputFile); /// Look through this to see if we can make sure there are no renames! Assert.IsFalse(FindInFile(outputFile, "dude::fork"), "Saw the double colon!!"); Assert.IsTrue(FindInFile(outputFile, "dude__fork"), "Missing the variable!!"); }
public void TestNoGroups() { /// Create simple user info - but don't do anything with it! ItemSimpleType simple = new ItemSimpleType("var1", "int[]"); Assert.IsFalse(simple.NotAPointer, "not a pointer"); ROOTClassShell mainClass = new ROOTClassShell("TestSimpleRename") { }; mainClass.Add(simple); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "ungrouped", Variables = new VariableInfo[] { new VariableInfo() { NETName = "var1", TTreeName = "var1" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestNoGroups.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestSimpleRename", userinfo } }); /// Look through this to see if we can make sure there are no renames! Assert.IsFalse(FindInFile(outputFile, "RenameVariable"), "We saw a rename!"); Assert.IsFalse(FindInFile(outputFile, "ungrouped"), "group found"); }
public void TestCharactersInClassName() { ItemSimpleType simple = new ItemSimpleType("fork", "int"); ROOTClassShell mainClass = new ROOTClassShell("##Shapes") { }; mainClass.Add(simple); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "jets", Variables = new VariableInfo[] { new VariableInfo() { NETName = "fork", TTreeName = "fork" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestCharactersInClassName.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestSimpleGroupAndRename", userinfo } }); DumpOutputFile(outputFile); Assert.AreEqual(3, CountInFile(outputFile, "##Shapes"), "Missing reference ot the shapes object"); }
/// <summary> /// We extract the class info for a ROOT class that is a template. We properly deal with the class being templatized /// being another crazy class (or just a vector of int, etc.). /// </summary> /// <param name="container"></param> /// <param name="memberName"></param> /// <param name="className"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> ExtractROOTTemplateClass(ROOTClassShell container, string memberName, string className) { /// /// Currently only setup to deal with some very specific types of vectors! /// var parsedMatch = TemplateParser.ParseForTemplates(className) as TemplateParser.TemplateInfo; if (parsedMatch == null) { SimpleLogging.Log("Type '{0}' is a template, but we can't parse it, so '{1}' will be ignored", className, memberName); return(Enumerable.Empty <ROOTClassShell>()); } if (parsedMatch.TemplateName != "vector") { SimpleLogging.Log("We can only deal with the vector type (not '{0}'), so member '{1}' will be ignored", className, memberName); return(Enumerable.Empty <ROOTClassShell>()); } if (!(parsedMatch.Arguments[0] is TemplateParser.RegularDecl)) { SimpleLogging.Log("We can't yet deal with nested templates - '{0}' - so member '{1}' will be ignored", className, memberName); return(Enumerable.Empty <ROOTClassShell>()); } var templateArgClass = (parsedMatch.Arguments[0] as TemplateParser.RegularDecl).Type; // // Now we take a look at the class. // // One case is that it is a simple class, like "Unsigned int" that // isn't known to root at all. That means we hvae no dictionary for vector<unsigned int> - otherwise // we never would have gotten into here. So ignore it. :-) // var classInfo = ROOTNET.NTClass.GetClass(templateArgClass); if (classInfo == null) { return(Enumerable.Empty <ROOTClassShell>()); } // // If this class is known by root then we will have // a very easy time. No new classes are created or defined and there is nothing // extra to do other than making the element. if (!classInfo.IsShellTClass()) { container.Add(new ItemVector(TemplateParser.TranslateToCSharp(parsedMatch), memberName)); return(Enumerable.Empty <ROOTClassShell>()); } // // If the class isn't known by ROOT then we have only one hope - building it out of the // streamer (at this point, where we are in the code path, it is also the case that there // aren't leaf sub-branches here). // var newClassDefs = ExtractUnsplitUnknownClass(classInfo); container.Add(new ItemVector(TemplateParser.TranslateToCSharp(parsedMatch), memberName)); return(newClassDefs); }
/// <summary> /// Find the class item for a particular item. /// </summary> /// <param name="cls"></param> /// <param name="itemName"></param> /// <returns></returns> public static IClassItem FindItem(this ROOTClassShell cls, string itemName) { return(cls.Items.Where(i => i.Name == itemName).FirstOrDefault()); }
public void TestRenamedIndex() { /// Create simple user info - but don't do anything with it! ItemSimpleType simpleIndex = new ItemSimpleType("index", "int[]"); ItemSimpleType simpleVal = new ItemSimpleType("var1", "float[]"); ROOTClassShell mainClass = new ROOTClassShell("TestRenamedIndex") { }; mainClass.Add(simpleIndex); mainClass.Add(simpleVal); var ntup = new NtupleTreeInfo() { Classes = new ROOTClassShell[] { mainClass }, ClassImplimintationFiles = new string[0] }; var userinfo = new TTreeUserInfo() { Groups = new ArrayGroup[] { new ArrayGroup() { Name = "jets", Variables = new VariableInfo[] { new VariableInfo() { NETName = "muons", TTreeName = "index", IndexToGroup = "muons" } } }, new ArrayGroup() { Name = "muons", Variables = new VariableInfo[] { new VariableInfo() { NETName = "var1", TTreeName = "var1" } } } } }; var cg = new ClassGenerator(); var outputFile = new FileInfo("TestRenamedIndex.cs"); cg.GenerateClasss(ntup, outputFile, "junk", new Dictionary <string, TTreeUserInfo>() { { "TestRenamedIndex", userinfo } }); DumpOutputFile(outputFile); /// Look through this to see if we can make sure there are no renames! Assert.IsTrue(FindInFile(outputFile, "TTreeVariableGrouping"), "Missing TTreeVariableGrouping"); Assert.IsTrue(FindInFile(outputFile, "jets"), "missing a reference to jets"); Assert.IsTrue(FindInFile(outputFile, "muons"), "missing a reference to jets"); Assert.IsTrue(FindInFile(outputFile, "IndexToOtherObjectArray(typeof("), "Missing IndexToOtherObject"); Assert.IsTrue(FindInFile(outputFile, "TestRenamedIndexmuons muons"), "Muon reference is imporper"); Assert.IsTrue(FindInFile(outputFile, "float var1"), "var1 missing"); Assert.IsFalse(FindInFile(outputFile, "ungrouped"), "group found"); }
public void GenerateClassFromClasses( ClassGenerator target, int outputChoice, int numExtraFiles, int numExtraFilesToCreate, int extraFileIndexNull, string nameSName, int NumObjectCollection) { if (numExtraFiles < 0 || numExtraFilesToCreate < 0 || extraFileIndexNull < 0 || outputChoice < 0 || NumObjectCollection < 0) { return; } /// /// Kill off the directory we might have left behind from a previous run, and create a new one. /// DirectoryInfo testDir = new DirectoryInfo(".\\GenerateClassFromClasses"); if (testDir.Exists) { testDir.Delete(true); } testDir.Create(); /// /// Setup the input stuff so Pex can play /// FileInfo outputCSFile; if (outputChoice == 1) { outputCSFile = new FileInfo(testDir.FullName + "\\output.cs"); } else { outputCSFile = null; } ROOTClassShell[] objCollect = null; if (NumObjectCollection > 0) { List <ROOTClassShell> objs = new List <ROOTClassShell>(); for (int i = 0; i < NumObjectCollection; i++) { ROOTClassShell rcs = new ROOTClassShell(); rcs.Name = "dude_" + i.ToString(); for (int j = 0; j < i; j++) { IClassItem item = null; switch (NumObjectCollection % 4) { case 0: item = null; break; case 1: var itm = new ItemSimpleType() { ItemType = "int" }; item = itm; break; case 2: var itmv = new ItemVector() { ItemType = "int[]" }; item = itmv; break; case 3: var itmr = new ItemROOTClass() { ItemType = "TLorentzVector" }; item = itmr; break; } if (item != null) { item.Name = "item_" + j.ToString(); } rcs.Items.Add(item); } objs.Add(rcs); } objCollect = objs.ToArray(); } /// /// Create the final object, and any extra files needed! /// NtupleTreeInfo info = new NtupleTreeInfo() { Classes = objCollect }; info.ClassImplimintationFiles = (from c in Enumerable.Range(0, numExtraFiles) let f = new FileInfo(testDir.FullName + "\\GenerateClassFromClasses_extra_" + c.ToString() + ".cpp") select f.FullName ).ToArray(); int maxFilesToCreate = numExtraFilesToCreate > numExtraFiles ? numExtraFiles : numExtraFilesToCreate; for (int i = 0; i < maxFilesToCreate; i++) { using (var w = File.CreateText(info.ClassImplimintationFiles[i])) { w.WriteLine(); w.Close(); } } if (extraFileIndexNull < numExtraFiles) { info.ClassImplimintationFiles[extraFileIndexNull] = null; } /// /// Ok, do the investigation /// target.GenerateClasss(info, outputCSFile, nameSName); Assert.IsFalse(info.ClassImplimintationFiles.Any(c => c == null), "no null implementation files allowed"); Assert.IsFalse(info.ClassImplimintationFiles.Any(c => !File.Exists(c)), "all implimntation files must exist"); /// Check that all the ntuple proxy guys and the temp file guys appear in the file foreach (var item in info.ClassImplimintationFiles) { Assert.IsTrue(FindInFile(outputCSFile, item), "coul dnot find impl file '" + item + "'"); } }
/// <summary> /// Look at everything we have in this tree and see if we can't generate a class correctly. /// </summary> /// <param name="tree"></param> /// <returns></returns> public IEnumerable <ROOTClassShell> GenerateClasses(ROOTNET.Interface.NTTree tree) { if (tree == null) { throw new ArgumentNullException("tree must not be null"); } /// /// The outlying class is going to be called by the name of the tree. /// var masterClass = new ROOTClassShell(tree.Name); var subClassesByName = from sc in ExtractClassesFromBranchList(masterClass, tree.ListOfBranches.Cast <ROOTNET.Interface.NTBranch>()) group sc by sc.Name; var subClasses = from scg in subClassesByName where scg.ClassesAreIdnetical() select scg.First(); foreach (var sc in subClasses) { yield return(sc); } /// /// Work around a ROOT bug that doesn't allow for unloading of classes /// in the STL after a query is run. Actually, it will unload them, but somehow keeps /// references in memory. /// var f = MakeProxy(tree); masterClass.ClassesToGenerate = ExtractSTLDictionaryReferences(f); /// /// Analyze the TTree arrays. /// var at = new ArrayAnalyzer(); var groupInfo = at.AnalyzeTTree(masterClass, tree, 100); /// /// Any item that isn't an array should be added to the list and /// put in the "ungrouped" array. /// AddNonArrays(masterClass, groupInfo, "ungrouped"); /// /// Write out the user info /// masterClass.UserInfoPath = WriteUserInfo(groupInfo, tree.SanitizedName()).FullName; /// /// Return the master class /// yield return(masterClass); }
/// <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> /// Extract a class from a "good" streamer. /// </summary> /// <param name="cls"></param> /// <param name="streamer"></param> /// <returns></returns> private IEnumerable <ROOTClassShell> ExtractClassFromStreamer(ROOTClassShell container, string itemName, ROOTNET.Interface.NTClass cls, ROOTNET.Interface.NTVirtualStreamerInfo sInfo) { // This guy is a class with elements, so go get the elements... var c = new ROOTClassShell(cls.Name.SanitizedName()) { IsTopLevelClass = false }; if (container != null) { container.Add(new ItemROOTClass() { Name = itemName, ItemType = cls.Name.SanitizedName(), NotAPointer = false }); } var clist = new List <ROOTClassShell> { c }; foreach (var item in sInfo.Elements.Cast <ROOTNET.Interface.NTStreamerElement>()) { if (item == null) { throw new ArgumentNullException("Streamer element was null"); } if (item.TypeName == "BASE") { SimpleLogging.Log(string.Format("Item '{0}' has a subclass of type '{1}' - we can't parse inherritance yet", itemName, item.FullName)); continue; } var itemCls = item.ClassPointer; if (itemCls == null) { // This is going to be something like "int", or totally unknown! c.Add(ExtractSimpleItem(new SimpleLeafInfo() { Name = item.FullName, TypeName = item.TypeName, Title = item.FullName })); } else if (!itemCls.IsShellTClass()) { try { // We know about this class, and can use ROOT infrasturcutre to do the parsing for it. // Protect against funny template arguments we can't deal with now - just skip them. var itemC = ExtractSimpleItem(new SimpleLeafInfo() { Name = item.FullName, TypeName = itemCls.Name, Title = item.FullName }); c.Add(itemC); } catch (Exception e) { SimpleLogging.Log(string.Format("Unable to deal with streamer type '{0}', skiping member '{1}': {2}", itemCls.Name, item.FullName, e.Message)); } } else { // Unknown to ROOT class. How we handle this, exactly, depends if it is a template class or if it is // a raw class. if (itemCls.IsTemplateClass()) { var newClassDefs = ExtractROOTTemplateClass(c, item.FullName, itemCls.Name); clist.AddRange(newClassDefs); } else { var newClassDefs = new List <ROOTClassShell>(ExtractUnsplitUnknownClass(c, item.FullName, itemCls)); clist.AddRange(newClassDefs); } } } return(clist); }
/// <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())); }