Hello all,

If my previous 12% speed improvement patch wasn't enough for you, you
are in good company ;-), it was not enough for me either. So I went in
and ripped out all the XPath and XmlDocument stuff from the guts of
ecma-provider and replaced it with cool, clean XmlTextReader.

As a result, I was able to half both the amount of time it takes to
assemble the class libraries and the amount of memory that the assembler
takes up.

May I commit?

-- Ben
Index: ChangeLog
===================================================================
RCS file: /cvs/public/monodoc/browser/ChangeLog,v
retrieving revision 1.35
diff -u -r1.35 ChangeLog
--- ChangeLog	6 Jun 2003 04:22:30 -0000	1.35
+++ ChangeLog	19 Jun 2003 20:14:14 -0000
@@ -1,3 +1,7 @@
+2003-06-19  Ben Maurer <[EMAIL PROTECTED]>
+	* ecma-provider.cs, provider.cs: Added tons of performance
+	related stuff. Doubles speed, halfs memory allocation!
+
 2003-06-02  Miguel de Icaza  <[EMAIL PROTECTED]>
 
 	* ecma-provider.cs (PopulateIndex): Add full type names.
Index: ecma-provider.cs
===================================================================
RCS file: /cvs/public/monodoc/browser/ecma-provider.cs,v
retrieving revision 1.49
diff -u -r1.49 ecma-provider.cs
--- ecma-provider.cs	15 Jun 2003 18:53:27 -0000	1.49
+++ ecma-provider.cs	19 Jun 2003 20:14:14 -0000
@@ -4,9 +4,11 @@
 // Authors:
 //   Miguel de Icaza ([EMAIL PROTECTED])
 //   Joshua Tauberer ([EMAIL PROTECTED])
+//   Ben Maurer ([EMAIL PROTECTED])
 //
 // (C) 2002, 2003 Ximian, Inc.
 // (C) 2003 Joshua Tauberer.
+// (C) 2003 Ben Maurer
 //
 // TODO:
 //   Should cluster together constructors
@@ -27,58 +29,8 @@
 
 using BF = System.Reflection.BindingFlags;
 
-//
-// Helper routines to extract information from an Ecma XML document
-//
 public class EcmaDoc {
-	public static string GetFullClassName (XmlDocument doc)
-	{
-		return doc.SelectSingleNode ("/Type").Attributes ["FullName"].InnerText;
-	}
-	
-	public static string GetClassName (XmlDocument doc)
-	{
-		return doc.SelectSingleNode ("/Type").Attributes ["Name"].InnerText;
-	}
-
-	public static string GetClassAssembly (XmlDocument doc)
-	{
-		return doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName").InnerText;
-	}
-
-	public static string GetClassNamespace (XmlDocument doc)
-	{
-		string s = doc.SelectSingleNode ("/Type").Attributes ["FullName"].InnerText;
-
-		return s.Substring (0, s.LastIndexOf ("."));
-	}
-	
-	public static string GetTypeKind (XmlDocument doc)
-	{
-		XmlNode node = doc.SelectSingleNode ("/Type/Base/BaseTypeName");
-
-		if (node == null){
-			if (GetFullClassName (doc) == "System.Object")
-				return "Class";
-			return "Interface";
-		}
-
-		switch (node.InnerText){
-
-		case "System.Delegate":
-			return "Delegate";
-		case "System.ValueType":
-			return "Structure";
-		case "System.Enum":
-			return "Enumeration";
-		default:
-			return "Class";
-		}
-	}
-
-	//
-	// Utility function: converts a fully .NET qualified type name into a C#-looking one
-	//
+		
 	public static string ConvertCTSName (string type)
 	{
 		if (!type.StartsWith ("System."))
@@ -115,7 +67,6 @@
 		return type;
 	}
 }
-
 //
 // The Ecma documentation provider:
 //
@@ -160,125 +111,381 @@
 		}
 	}
 
-	struct TypeInfo : IComparable {
-		public string type_assembly;
-		public string type_name;
-		public string type_full;
-		public string type_kind;
-		public XmlNode type_doc;
-
-		public TypeInfo (string k, string a, string f, string s, XmlNode n)
-		{
-			type_assembly = a;
-			type_name = s;
-			type_doc = n;
-			type_kind = k;
-			type_full = f;
+	
+	public class TypeInfo : IComparable {
+		public string name, assembly, kind, fullclassname, baseType;
+		public string summary;
+		
+		public ArrayList constructors, methods, properties, fields, events;
+		
+		TypeInfo (XmlTextReader r) 
+		{
+			constructors = new ArrayList ();
+			methods = new ArrayList ();
+			properties = new ArrayList ();
+			fields = new ArrayList ();
+			events = new ArrayList ();
+			
+			r.MoveToContent ();
+			ReadAttributes (r);
+			r.ReadStartElement ("Type");
+			
+			ReadElements (r);
+			kind = GetTypeKind ();
 		}
-
+		
 		public int CompareTo (object b)
 		{
 			TypeInfo na = this;
 			TypeInfo nb = (TypeInfo) b;
+	
+			return String.Compare (na.fullclassname, nb.fullclassname);
+		}
+			
+		public static TypeInfo Parse (string file)
+		{
+			XmlTextReader r = new XmlTextReader (file);
+			r.WhitespaceHandling = WhitespaceHandling.Significant;
+	
+			return new TypeInfo (r);
+		}
+		
+		
+		string GetTypeKind ()
+		{
+	
+			switch (baseType) {
+				case null:
+					if (fullclassname == "System.Object")
+						return "Class";
+					else
+						return "Interface";
+				
+				case "System.Delegate":
+					return "Delegate";
+				case "System.ValueType":
+					return "Structure";
+				case "System.Enum":
+					return "Enumeration";
+				default:
+					return "Class";
+				
+			}
+		}
+		
+		void ReadAttributes (XmlTextReader r)
+		{
+			name = r.GetAttribute ("Name");
+			fullclassname = r.GetAttribute ("FullName");
+		}
+		
+		void ReadElements (XmlTextReader r)
+		{
+			while (r.MoveToContent () == XmlNodeType.Element) {
+				
+				switch (r.LocalName) {
 
-			return String.Compare (na.type_full, nb.type_full);
+					
+					case "AssemblyInfo":
+						ReadAssemblyInfo (r);
+						break;
+					
+					case "Docs":
+						ReadDocs (r);
+						break;
+					case "Base":
+						ReadBase (r);
+						break;
+						
+					case "Members":
+						ReadMembers (r);
+						break;
+					/*
+					case "TypeSignature":
+					case "MemberOfLibrary":
+					case "ThreadingSafetyStatement":
+					case "ThreadSafetyStatement":
+					case "Interfaces":
+					case "TypeExcluded":
+					case "Attributes":
+					*/
+					default:
+						r.Skip ();
+						r.MoveToContent ();
+						break;
+						
+				}
+			}
+		}
+		
+		void ReadAssemblyInfo (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("AssemblyInfo");
+			while (r.MoveToContent () == XmlNodeType.Element) {
+				
+				if (r.LocalName == "AssemblyName") {
+					assembly = r.ReadString ();
+					r.ReadEndElement ();
+				} else {
+					r.Skip ();
+					r.MoveToContent ();
+				}
+			}
+			r.ReadEndElement ();
 		}
+		
+		
+		void ReadDocs (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("Docs");
+			while (r.MoveToContent () == XmlNodeType.Element) {
+				if (r.LocalName == "summary") 
+					summary = r.ReadOuterXml ();
+				else 
+					r.Skip ();
+					r.MoveToContent ();
+			}
+			r.ReadEndElement ();
+		}
+		
+	
+		void ReadBase (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("Base");
+			while (r.MoveToContent () == XmlNodeType.Element) {
+				if (r.LocalName == "BaseTypeName") {
+					baseType = r.ReadString ();
+					r.ReadEndElement ();
+				} else {
+					r.Skip ();
+					r.MoveToContent ();
+				}
+			}
+			r.ReadEndElement ();
+		}
+		
+		void ReadMembers (XmlTextReader r)
+		{
+			if (r.IsEmptyElement) {
+				r.Skip ();
+				return;
+			}
+			r.ReadStartElement ("Members");
+				
+			while (r.MoveToContent () == XmlNodeType.Element) {
+				string mName, type, sig, paramsStr;
+				
+				mName = r.GetAttribute ("MemberName");
+				r.MoveToElement ();
+				r.ReadStartElement ("Member");
+	
+				while (r.MoveToContent () == XmlNodeType.Element) {
+					switch (r.LocalName) {
+
+						case "MemberType":
+							type = r.ReadString ();
+							r.ReadEndElement ();
+							break;						
+						case "Parameters":
+							if (r.IsEmptyElement) {
+								r.Skip ();
+								r.MoveToContent ();
+							} else {
+								r.ReadStartElement ("Parameters");
+								StringBuilder b = new StringBuilder ();
+								
+								b.Append ('(');
+								
+								bool first = true;
+	
+								while (r.MoveToContent () == XmlNodeType.Element) {
+									if (!first) b.Append (',');
+									first = false;									
+									b.Append (EcmaDoc.ConvertCTSName (r.GetAttribute ("Type")));
+									r.Skip ();
+								}
+								
+								b.Append (')');
+								r.ReadEndElement ();
+								paramsStr = b.ToString ();
+							}
+							break;
+						/*
+						case "Attributes":
+						case "Docs":
+						case "Excluded":
+						case "ExcludedLibrary":
+						case "MemberSignature":
+						case "MemberValue":
+						case "ReturnValue":
+						*/
+						default:
+							r.Skip ();
+							r.MoveToContent ();
+							break;
+					}
+				}
+				
+				r.ReadEndElement ();
+				switch (type) {
+					case "Event":
+						events.Add (mName);
+						break;
+					
+					case "Property":
+						properties.Add (mName);
+						break;
+					
+					case "Field":
+						fields.Add (mName);
+						break;
+		
+					case "Constructor":
+						constructors.Add (name + paramsStr);
+						break;
+		
+					case "Method":
+						methods.Add (mName + paramsStr);
+						break;
+				}
+			}
+			r.ReadEndElement ();
+			
+			events.Sort ();
+			properties.Sort ();
+			fields.Sort ();
+			constructors.Sort ();
+			methods.Sort ();
+	
+		}
+
 	}
 	
+	
+        struct TypeSummary : IComparable {
+                public string type_assembly;
+                public string type_name;
+                public string type_full;
+                public string type_kind;
+                public string type_doc;
+
+                public TypeSummary (string k, string a, string f, string s, string n)
+                {
+                        type_assembly = a;
+                        type_name = s;
+                        type_doc = n;
+                        type_kind = k;
+                        type_full = f;
+                }
+
+                public int CompareTo (object b)
+                {
+                        TypeSummary na = this;
+                        TypeSummary nb = (TypeSummary) b;
+
+                        return String.Compare (na.type_full, nb.type_full);
+                }
+        }
 	//
 	// Packs a file with the summary data
 	//
 	public override void CloseTree (HelpSource hs, Tree tree)
 	{
 		foreach (DictionaryEntry de in class_summaries){
-			XmlDocument doc = new XmlDocument ();
 			string ns = (string) de.Key;
-			
 			ArrayList list = (ArrayList) de.Value;
-			list.Sort();
-
-			XmlElement elements = doc.CreateElement ("elements");
-			doc.AppendChild (elements);
+			list.Sort ();
 			
-			string file = "xml.summary." + ns;
 			Console.Error.WriteLine ("Have {0} elements in the {1}", list.Count, ns);
-			foreach (TypeInfo p in list){
-				XmlElement e = null;
-				
+			
+			XmlTextWriter w = hs.PackXmlWriter ("xml.summary." + ns);
+			
+			w.WriteStartElement ("elements");
+
+			foreach (TypeSummary p in list){
 				switch (p.type_kind){
 				case "Class":
-					e = doc.CreateElement ("class"); 
+					w.WriteStartElement ("class"); 
 					break;
 					
 				case "Enumeration":
-					e = doc.CreateElement ("enum");
+					w.WriteStartElement ("enum");
 					break;
 					
 				case "Structure":
-					e = doc.CreateElement ("struct");
+					w.WriteStartElement ("struct");
 					break;
 					
 				case "Delegate":
-					e = doc.CreateElement ("delegate");
+					w.WriteStartElement ("delegate");
 					break;
 					
 				case "Interface":
-					e = doc.CreateElement ("interface");
+					w.WriteStartElement ("interface");
 					break;
 				}
-				
-				e.SetAttribute ("name", p.type_name);
-				e.SetAttribute ("fullname", p.type_full);
-				e.SetAttribute ("assembly", p.type_assembly);
-				XmlNode copy = doc.ImportNode (p.type_doc, true);
-				e.AppendChild (copy);
-				elements.AppendChild (e);
+				w.WriteAttributeString ("name", p.type_name);
+				w.WriteAttributeString ("fullname", p.type_full);
+				w.WriteAttributeString ("assembly", p.type_assembly);
+
+				w.WriteRaw (p.type_doc);
+				w.WriteEndElement ();
 			}
-			hs.PackXml ("xml.summary." + ns, doc);
+			
+			w.WriteEndDocument();
+			w.Flush ();
 		}
 	}
 	       
 	static Hashtable class_summaries = new Hashtable ();
 					     
-	XmlDocument doc;
+	XmlNode typeNode;
 	
 	void PopulateClass (string ns, Node ns_node, string file)
 	{
-		doc = new XmlDocument ();
-		doc.Load (file);
-		
-		string name = EcmaDoc.GetClassName (doc);
-		string assembly = EcmaDoc.GetClassAssembly (doc);
-		string kind = EcmaDoc.GetTypeKind (doc);
-		string full = EcmaDoc.GetFullClassName (doc);
-
-		Node class_node;
+		TypeInfo t = TypeInfo.Parse (file);
 		string file_code = ns_node.tree.HelpSource.PackFile (file);
-
-		XmlNode class_summary = doc.SelectSingleNode ("/Type/Docs/summary");
+		string name = t.name;
+		string assembly = t.assembly;
+		string kind = t.kind;
+		string full = t.fullclassname;
+		string class_summary = t.summary;
+		
 		ArrayList l = (ArrayList) class_summaries [ns];
 		if (l == null)
 			l = class_summaries [ns] = new ArrayList ();
-		l.Add (new TypeInfo (kind, assembly, full, name, class_summary));
-	       
-		class_node = ns_node.LookupNode (String.Format ("{0} {1}", name, kind), "ecma:" + file_code + "#" + name + "/");
+		
+		l.Add (new TypeSummary (kind, assembly, full, name, class_summary));
 
-		if (kind == "Enumeration")
-			return;
 
-		if (kind == "Delegate")
+		Node class_node = ns_node.LookupNode (String.Format ("{0} {1}", name, kind), "ecma:" + file_code + "#" + name + "/");
+
+		if (kind == "Enumeration" || kind == "Delegate") 
 			return;
 		
 		//
 		// Always add the Members node
 		//
 		class_node.CreateNode ("Members", "*");
+		
 
-		PopulateMember (name, class_node, "Constructor", "Constructors");
-		PopulateMember (name, class_node, "Method", "Methods");
-		PopulateMember (name, class_node, "Property", "Properties");
-		PopulateMember (name, class_node, "Field", "Fields");
-		PopulateMember (name, class_node, "Event", "Events");
+		PopulateMember (t.constructors, class_node, "Constructor", "Constructors");
+		PopulateMember (t.methods, class_node, "Method", "Methods");
+		PopulateMember (t.properties, class_node, "Property", "Properties");
+		PopulateMember (t.fields, class_node, "Field", "Fields");
+		PopulateMember (t.events, class_node, "Event", "Events");
 	}
 
 	class NodeIndex {
@@ -314,59 +521,19 @@
 	// Performs an XPath query on the document to extract the nodes for the various members
 	// we also use some extra text to pluralize the caption
 	//
-	void PopulateMember (string typename, Node node, string text, string plural_text)
+	void PopulateMember (ArrayList items, Node node, string text, string plural_text)
 	{
-		XmlNodeList list = doc.SelectNodes (String.Format ("/Type/Members/Member[MemberType=\"{0}\"]", text));
-		int count = list.Count;
-		
-		if (count == 0)
-			return;
-
 		Node nodes_node;
 		string key = text.Substring (0, 1);
-		if (count == 1)
-			nodes_node = node.CreateNode (text, key);
-		else
-			nodes_node = node.CreateNode (plural_text, key);
-
-		NodeIndex [] node_array = new NodeIndex [count];
+                if (items.Count == 1)
+                        nodes_node = node.CreateNode (text, key);
+                else
+                        nodes_node = node.CreateNode (plural_text, key);
+		
+		
 		int i = 0;
-		foreach (XmlNode n in list)
-			node_array [i] = new NodeIndex (n, i++);
-			
-		Array.Sort (node_array, NodeComparer);
-
-		foreach (NodeIndex ni in node_array){
-			string signature;
-
-			switch (text){
-			case "Event":
-			case "Property":
-			case "Field":
-				signature = GetMemberName (ni.node);
-				break;
-
-			case "Constructor":
-				signature = EcmaHelpSource.MakeSignature(ni.node, typename);
-				break;
-
-			case "Method":
-				signature = EcmaHelpSource.MakeSignature(ni.node, null);
-				break;
-				
-			default:
-				XmlNode signode = ni.node.SelectSingleNode ("[EMAIL PROTECTED]'C#']");
-			
-				if (signode == null)
-					signature = GetMemberName (ni.node);
-				else
-					signature = signode.Attributes ["Value"].InnerText;
-				break;
-			}
-			
-			//signature = CleanSignature (ni.node, signature);
-
-			nodes_node.CreateNode (signature, ni.index.ToString ());
+		foreach (string s in items) {
+			nodes_node.CreateNode (s, (i++).ToString ());
 		}
 	}
 
Index: provider.cs
===================================================================
RCS file: /cvs/public/monodoc/browser/provider.cs,v
retrieving revision 1.28
diff -u -r1.28 provider.cs
--- provider.cs	1 Jun 2003 15:26:45 -0000	1.28
+++ provider.cs	19 Jun 2003 20:14:14 -0000
@@ -470,11 +470,12 @@
 
 		return entry_name;
 	}
-	
-	public void PackXml (string fname, XmlDocument doc)
+		
+	public System.Xml.XmlTextWriter PackXmlWriter (string entry_name)
 	{
-		doc.Save ("tmp");
-		PackFile ("tmp", fname);
+		ZipEntry entry = new ZipEntry (entry_name);
+		zip_output.PutNextEntry (entry);
+		return new System.Xml.XmlTextWriter (zip_output, null);
 	}
 	
 	public virtual string GetText (string url, out Node n)

Reply via email to