diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CompilerServices/Bindings.cs | 5 | ||||
| -rw-r--r-- | src/CompilerServices/CompilerServices.cs | 249 | ||||
| -rw-r--r-- | src/GraphicObjects/Container.cs | 4 | ||||
| -rw-r--r-- | src/GraphicObjects/GraphicObject.cs | 195 | ||||
| -rw-r--r-- | src/GraphicObjects/Grid.cs | 5 | ||||
| -rw-r--r-- | src/GraphicObjects/Group.cs | 11 | ||||
| -rw-r--r-- | src/GraphicObjects/PrivateContainer.cs | 4 | ||||
| -rw-r--r-- | src/GraphicObjects/Scroller.cs | 4 | ||||
| -rw-r--r-- | src/GraphicObjects/TabView.cs | 4 | ||||
| -rw-r--r-- | src/IMLInstantiatorBuilder.cs | 100 | ||||
| -rw-r--r-- | src/IMLStream.cs | 10 | ||||
| -rw-r--r-- | src/Instantiator.cs | 41 | ||||
| -rw-r--r-- | src/Interface.cs | 83 |
13 files changed, 505 insertions, 210 deletions
diff --git a/src/CompilerServices/Bindings.cs b/src/CompilerServices/Bindings.cs index 8ece856c..953f1492 100644 --- a/src/CompilerServices/Bindings.cs +++ b/src/CompilerServices/Bindings.cs @@ -41,6 +41,11 @@ namespace Crow public string DynMethodId { get { return dynMethodId; } } + public Type SourceType { + get { return Source == null ? null + : Source.Instance == null ? null + : Source.Instance.GetType();} + } public bool Resolved { get { return resolved; } diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 0b69f970..ebb365c9 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -5,12 +5,261 @@ using System.Diagnostics; using System.Linq; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Xml; namespace Crow { public static class CompilerServices { + public static void BuildInstanciator(IMLInstantiatorBuilder builder, Type crowType){ + string tmpXml = builder.ReadOuterXml (); + + builder.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added + + if (typeof(TemplatedControl).IsAssignableFrom (crowType)) { + //if its a template, first read template elements + using (IMLInstantiatorBuilder reader = new IMLInstantiatorBuilder (builder.il, tmpXml)) { + + string template = reader.GetAttribute ("Template"); + + bool inlineTemplate = false; + if (string.IsNullOrEmpty (template)) { + reader.Read (); + + while (reader.Read ()) { + if (!reader.IsStartElement ()) + continue; + if (reader.Name == "Template") { + inlineTemplate = true; + reader.Read (); + + readChildren (reader, crowType); + continue; + } + } + if (!inlineTemplate) { + DefaultTemplate dt = (DefaultTemplate)crowType.GetCustomAttributes (typeof(DefaultTemplate), true).FirstOrDefault(); + template = dt.Path; + } + } + if (!inlineTemplate) { + reader.il.Emit (OpCodes.Ldloc_0);//Load this templateControl ref + + reader.il.Emit (OpCodes.Ldstr, template); //Load template path string + reader.il.Emit (OpCodes.Callvirt,//call Interface.Load(path) + typeof(Interface).GetMethod ("Load", BindingFlags.Static | BindingFlags.Public)); + reader.il.Emit (OpCodes.Callvirt,//add child + typeof(PrivateContainer).GetMethod ("SetChild", BindingFlags.Instance | BindingFlags.NonPublic)); + } + } + } + + using (IMLInstantiatorBuilder reader = new IMLInstantiatorBuilder(builder.il,tmpXml)){ + reader.Read (); + + if (reader.HasAttributes) { + string style = reader.GetAttribute ("Style"); + if (!string.IsNullOrEmpty (style)) { + PropertyInfo pi = crowType.GetProperty ("Style"); + CompilerServices.EmitSetValue (reader.il, pi, style); + } + } + if (reader.HasAttributes) { + reader.il.Emit (OpCodes.Ldloc_0); + reader.il.Emit (OpCodes.Callvirt, typeof(GraphicObject).GetMethod ("loadDefaultValues")); + + while (reader.MoveToNextAttribute ()) { + if (reader.Name == "Style") + continue; + + PropertyInfo pi = crowType.GetProperty (reader.Name); + + if (pi == null) + throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name); + + if (reader.Value.StartsWith("{")) + Debug.WriteLine("Binding => " + pi.Name + ": " + reader.Value); + else + CompilerServices.EmitSetValue (reader.il, pi, reader.Value); + + } + reader.MoveToElement (); + } + + if (reader.IsEmptyElement) { + reader.il.Emit (OpCodes.Pop);//pop saved ref to current object + return; + } + + readChildren (reader, crowType); + } + builder.il.Emit (OpCodes.Pop);//pop saved ref to current object + } + static void readChildren(IMLInstantiatorBuilder reader, Type crowType){ + MethodInfo miAddChild = null; + bool endTagReached = false; + while (reader.Read()){ + switch (reader.NodeType) { + case XmlNodeType.EndElement: + endTagReached = true; + break; + case XmlNodeType.Element: + //Templates + + + if (miAddChild == null) { + if (typeof(Group).IsAssignableFrom (crowType)) + miAddChild = typeof(Group).GetMethod ("AddChild"); + else if (typeof(Container).IsAssignableFrom (crowType)) + miAddChild = typeof(Container).GetMethod ("SetChild"); + else if (typeof(PrivateContainer).IsAssignableFrom (crowType)) + miAddChild = typeof(PrivateContainer).GetMethod ("SetChild", + BindingFlags.Instance | BindingFlags.NonPublic); + } + + //push current instance on stack for parenting + //loc_0 will be used for child + reader.il.Emit (OpCodes.Ldloc_0); + + Type t = Type.GetType ("Crow." + reader.Name); + if (t == null) { + Assembly a = Assembly.GetEntryAssembly (); + foreach (Type expT in a.GetExportedTypes ()) { + if (expT.Name == reader.Name) + t = expT; + } + } + if (t == null) + throw new Exception (reader.Name + " type not found"); + + reader.il.Emit(OpCodes.Newobj, t.GetConstructors () [0]); + reader.il.Emit (OpCodes.Stloc_0);//child is now loc_0 + + BuildInstanciator(reader, t); + + reader.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting + reader.il.Emit (OpCodes.Callvirt, miAddChild); + reader.il.Emit (OpCodes.Stloc_0); //reset local to current go + reader.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added + break; + } + if (endTagReached) + break; + } + } + public static void EmitSetValue(ILGenerator il, PropertyInfo pi, object val){ + il.Emit (OpCodes.Ldloc_0); + + if (val == null) { + il.Emit (OpCodes.Ldnull); + il.Emit (OpCodes.Callvirt, pi.GetSetMethod ()); + return; + } + Type dvType = val.GetType (); + + if (dvType.IsValueType) { + if (pi.PropertyType.IsValueType) { + if (pi.PropertyType.IsEnum) { + if (pi.PropertyType != dvType) + throw new Exception ("Enum mismatch in default values: " + pi.PropertyType.FullName); + il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (val)); + } else { + switch (Type.GetTypeCode (dvType)) { + case TypeCode.Boolean: + if ((bool)val == true) + il.Emit (OpCodes.Ldc_I4_1); + else + il.Emit (OpCodes.Ldc_I4_0); + break; + // case TypeCode.Empty: + // break; + // case TypeCode.Object: + // break; + // case TypeCode.DBNull: + // break; + // case TypeCode.SByte: + // break; + // case TypeCode.Decimal: + // break; + // case TypeCode.DateTime: + // break; + case TypeCode.Char: + il.Emit (OpCodes.Ldc_I4, Convert.ToChar (val)); + break; + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.Int32: + il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (val)); + break; + case TypeCode.UInt16: + case TypeCode.UInt32: + il.Emit (OpCodes.Ldc_I4, Convert.ToUInt32 (val)); + break; + case TypeCode.Int64: + il.Emit (OpCodes.Ldc_I8, Convert.ToInt64 (val)); + break; + case TypeCode.UInt64: + il.Emit (OpCodes.Ldc_I8, Convert.ToUInt64 (val)); + break; + case TypeCode.Single: + il.Emit (OpCodes.Ldc_R4, Convert.ToSingle (val)); + break; + case TypeCode.Double: + il.Emit (OpCodes.Ldc_R8, Convert.ToDouble (val)); + break; + case TypeCode.String: + il.Emit (OpCodes.Ldstr, Convert.ToString (val)); + break; + default: + il.Emit (OpCodes.Pop); + return; + } + } + } else + throw new Exception ("Expecting valuetype in default values for: " + pi.Name); + }else{ + //surely a class or struct + if (dvType != typeof(string)) + throw new Exception ("Expecting String in default values for: " + pi.Name); + if (pi.PropertyType == typeof(string)) + il.Emit (OpCodes.Ldstr, Convert.ToString (val)); + else if (pi.PropertyType.IsEnum) { + MethodInfo miParse = typeof(Enum).GetMethod + ("Parse", BindingFlags.Static | BindingFlags.Public, + Type.DefaultBinder, new Type [] {typeof (Type), typeof (string), typeof (bool)}, null); + + if (miParse == null) + throw new Exception ("Enum Parse method not found"); + + //load type of enum + il.Emit(OpCodes.Ldtoken, pi.PropertyType); + il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new + Type[1]{typeof(RuntimeTypeHandle)})); + //load enum value name + il.Emit (OpCodes.Ldstr, Convert.ToString (val));//TODO:is this convert required? + //load false + il.Emit (OpCodes.Ldc_I4_0); + il.Emit (OpCodes.Callvirt, miParse); + + if (miParse.ReturnType != pi.PropertyType) + il.Emit (OpCodes.Unbox_Any, pi.PropertyType); + } else { + MethodInfo miParse = pi.PropertyType.GetMethod + ("Parse", BindingFlags.Static | BindingFlags.Public, + Type.DefaultBinder, new Type [] {typeof (string)},null); + if (miParse == null) + throw new Exception ("no Parse method found for: " + pi.PropertyType.FullName); + + il.Emit (OpCodes.Ldstr, Convert.ToString (val));//TODO:is this convert required? + il.Emit (OpCodes.Callvirt, miParse); + + if (miParse.ReturnType != pi.PropertyType) + il.Emit (OpCodes.Unbox_Any, pi.PropertyType); + } + } + il.Emit (OpCodes.Callvirt, pi.GetSetMethod ()); + } public static void ResolveBindings (List<Binding> Bindings) { if (Bindings == null) diff --git a/src/GraphicObjects/Container.cs b/src/GraphicObjects/Container.cs index 69e3a3b4..fb4a7834 100644 --- a/src/GraphicObjects/Container.cs +++ b/src/GraphicObjects/Container.cs @@ -25,9 +25,9 @@ namespace Crow get { return child; } set { child = value; } } - public virtual T SetChild<T> (T _child) + public virtual void SetChild(GraphicObject _child) { - return base.SetChild (_child); + base.SetChild (_child); } #region IXmlSerializable diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 8966acf6..94e3f5e7 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -513,7 +513,7 @@ namespace Crow #endregion /// <summary> Loads the default values from XML attributes default </summary> - protected virtual void loadDefaultValues() + public void loadDefaultValues() { #if DEBUG_LOAD Debug.WriteLine ("LoadDefValues for " + this.ToString ()); @@ -581,151 +581,70 @@ namespace Crow typeof(void),new Type[] {typeof(object)},thisType,true); il = dm.GetILGenerator(256); - + il.DeclareLocal(typeof(GraphicObject)); il.Emit(OpCodes.Nop); + //set local GraphicObject to root object passed as 1st argument + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Stloc_0); - foreach (PropertyInfo pi in thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { - string name = ""; - object defaultValue = null; - - #region retrieve custom attributes + foreach (PropertyInfo pi in thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (pi.GetSetMethod () == null) continue; - - XmlIgnoreAttribute xia = (XmlIgnoreAttribute)pi.GetCustomAttribute (typeof(XmlIgnoreAttribute)); - if (xia != null) - continue; - XmlAttributeAttribute xaa = (XmlAttributeAttribute)pi.GetCustomAttribute (typeof(XmlAttributeAttribute)); - if (xaa != null) { - if (string.IsNullOrEmpty (xaa.AttributeName)) - name = pi.Name; - else - name = xaa.AttributeName; - } - - int styleIndex = -1; - if (styling.Count > 0){ - for (int i = 0; i < styling.Count; i++) { - if (styling[i].ContainsKey (name)){ - styleIndex = i; - break; - } - } - } - if (styleIndex >= 0){ - if (pi.PropertyType.IsEnum)//maybe should be in parser.. - defaultValue = Enum.Parse(pi.PropertyType, (string)styling[styleIndex] [name], true); - else - defaultValue = styling[styleIndex] [name]; - }else { - DefaultValueAttribute dv = (DefaultValueAttribute)pi.GetCustomAttribute (typeof (DefaultValueAttribute)); - if (dv == null) - continue; - defaultValue = dv.Value; - } - #endregion - - il.Emit (OpCodes.Ldarg_0); - - if (defaultValue == null) { - il.Emit (OpCodes.Ldnull); - il.Emit (OpCodes.Callvirt, pi.GetSetMethod ()); + object defaultValue; + if (!getDefaultValue (pi, styling, out defaultValue)) continue; - } - Type dvType = defaultValue.GetType (); - - if (dvType.IsValueType) { - if (pi.PropertyType.IsValueType) { - if (pi.PropertyType.IsEnum) { - if (pi.PropertyType != dvType) - throw new Exception ("Enum mismatch in default values: " + pi.PropertyType.FullName); - il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (defaultValue)); - } else { - switch (Type.GetTypeCode (dvType)) { - case TypeCode.Boolean: - if ((bool)defaultValue == true) - il.Emit (OpCodes.Ldc_I4_1); - else - il.Emit (OpCodes.Ldc_I4_0); - break; -// case TypeCode.Empty: -// break; -// case TypeCode.Object: -// break; -// case TypeCode.DBNull: -// break; -// case TypeCode.SByte: -// break; -// case TypeCode.Decimal: -// break; -// case TypeCode.DateTime: -// break; - case TypeCode.Char: - il.Emit (OpCodes.Ldc_I4, Convert.ToChar (defaultValue)); - break; - case TypeCode.Byte: - case TypeCode.Int16: - case TypeCode.Int32: - il.Emit (OpCodes.Ldc_I4, Convert.ToInt32 (defaultValue)); - break; - case TypeCode.UInt16: - case TypeCode.UInt32: - il.Emit (OpCodes.Ldc_I4, Convert.ToUInt32 (defaultValue)); - break; - case TypeCode.Int64: - il.Emit (OpCodes.Ldc_I8, Convert.ToInt64 (defaultValue)); - break; - case TypeCode.UInt64: - il.Emit (OpCodes.Ldc_I8, Convert.ToUInt64 (defaultValue)); - break; - case TypeCode.Single: - il.Emit (OpCodes.Ldc_R4, Convert.ToSingle (defaultValue)); - break; - case TypeCode.Double: - il.Emit (OpCodes.Ldc_R8, Convert.ToDouble (defaultValue)); - break; - case TypeCode.String: - il.Emit (OpCodes.Ldstr, Convert.ToString (defaultValue)); - break; - default: - il.Emit (OpCodes.Pop); - continue; - } - } - } else - throw new Exception ("Expecting valuetype in default values for: " + pi.Name); - }else{ - //surely a class or struct - if (dvType != typeof(string)) - throw new Exception ("Expecting String in default values for: " + pi.Name); - if (pi.PropertyType == typeof (string)) - il.Emit (OpCodes.Ldstr, Convert.ToString (defaultValue)); - else { - MethodInfo miParse = pi.PropertyType.GetMethod - ("Parse", BindingFlags.Static | BindingFlags.Public, - Type.DefaultBinder, new Type [] {typeof (string)},null); - if (miParse == null) - throw new Exception ("no Parse method found for: " + pi.PropertyType.FullName); - il.Emit (OpCodes.Ldstr, Convert.ToString (defaultValue)); - il.Emit (OpCodes.Callvirt, miParse); - - if (miParse.ReturnType != pi.PropertyType) - il.Emit (OpCodes.Unbox_Any, pi.PropertyType); - } - } - il.Emit (OpCodes.Callvirt, pi.GetSetMethod ()); + CompilerServices.EmitSetValue (il, pi, defaultValue); } il.Emit(OpCodes.Ret); #endregion try { - Interface.DefaultValuesLoader[styleKey] = (Interface.loadDefaultInvoker)dm.CreateDelegate(typeof(Interface.loadDefaultInvoker)); + Interface.DefaultValuesLoader[styleKey] = (Interface.LoaderInvoker)dm.CreateDelegate(typeof(Interface.LoaderInvoker)); Interface.DefaultValuesLoader[styleKey] (this); } catch (Exception ex) { throw new Exception ("Error applying style <" + styleKey + ">:", ex); } } + bool getDefaultValue(PropertyInfo pi, List<Dictionary<string, object>> styling, + out object defaultValue){ + defaultValue = null; + string name = ""; + + XmlIgnoreAttribute xia = (XmlIgnoreAttribute)pi.GetCustomAttribute (typeof(XmlIgnoreAttribute)); + if (xia != null) + return false; + XmlAttributeAttribute xaa = (XmlAttributeAttribute)pi.GetCustomAttribute (typeof(XmlAttributeAttribute)); + if (xaa != null) { + if (string.IsNullOrEmpty (xaa.AttributeName)) + name = pi.Name; + else + name = xaa.AttributeName; + } + + int styleIndex = -1; + if (styling.Count > 0){ + for (int i = 0; i < styling.Count; i++) { + if (styling[i].ContainsKey (name)){ + styleIndex = i; + break; + } + } + } + if (styleIndex >= 0){ + if (pi.PropertyType.IsEnum)//maybe should be in parser.. + defaultValue = Enum.Parse(pi.PropertyType, (string)styling[styleIndex] [name], true); + else + defaultValue = styling[styleIndex] [name]; + }else { + DefaultValueAttribute dv = (DefaultValueAttribute)pi.GetCustomAttribute (typeof (DefaultValueAttribute)); + if (dv == null) + return false; + defaultValue = dv.Value; + } + return true; + } + public virtual GraphicObject FindByName(string nameToFind){ return string.Equals(nameToFind, _name, StringComparison.Ordinal) ? this : null; @@ -747,7 +666,7 @@ namespace Crow if (Width == Measure.Fit || Height == Measure.Fit) RegisterForLayouting (LayoutingType.Sizing); else if (RegisteredLayoutings == LayoutingType.None) - Interface.CurrentInterface.EnqueueForRepaint (this); + CurrentInterface.EnqueueForRepaint (this); } /// <summary> query an update of the content, a redraw </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -755,8 +674,20 @@ namespace Crow { bmp = null; if (RegisteredLayoutings == LayoutingType.None) - Interface.CurrentInterface.EnqueueForRepaint (this); + CurrentInterface.EnqueueForRepaint (this); } + public Interface CurrentInterface { + get { + ILayoutable tmp = this.Parent; + while (tmp != null) { + if (tmp is Interface) + return tmp as Interface; + tmp = tmp.Parent; + } + return null; + } + } + #region Layouting #if DEBUG_LAYOUTING diff --git a/src/GraphicObjects/Grid.cs b/src/GraphicObjects/Grid.cs index 525827e0..ed0cd986 100644 --- a/src/GraphicObjects/Grid.cs +++ b/src/GraphicObjects/Grid.cs @@ -29,11 +29,10 @@ namespace Crow int _rowCount; #endregion - public override T AddChild<T> (T child) + public override void AddChild (GraphicObject child) { - T tmp = base.AddChild (child); + base.AddChild (child); this.RegisterForLayouting (LayoutingType.ArrangeChildren); - return tmp; } public override void RemoveChild (GraphicObject child) { diff --git a/src/GraphicObjects/Group.cs b/src/GraphicObjects/Group.cs index a6ca5758..4c8d0537 100644 --- a/src/GraphicObjects/Group.cs +++ b/src/GraphicObjects/Group.cs @@ -38,19 +38,14 @@ namespace Crow get { return _multiSelect; } set { _multiSelect = value; } } - - - public virtual T AddChild<T>(T child) - { - GraphicObject g = child as GraphicObject; + public virtual void AddChild(GraphicObject g){ Children.Add(g); - g.Parent = this as GraphicObject; + g.Parent = this; g.ResolveBindings (); g.RegisteredLayoutings = LayoutingType.None; g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren); g.LayoutChanged += OnChildLayoutChanges; - return (T)child; - } + } public virtual void RemoveChild(GraphicObject child) { child.LayoutChanged -= OnChildLayoutChanges; diff --git a/src/GraphicObjects/PrivateContainer.cs b/src/GraphicObjects/PrivateContainer.cs index 8793ba45..a6f52f29 100644 --- a/src/GraphicObjects/PrivateContainer.cs +++ b/src/GraphicObjects/PrivateContainer.cs @@ -47,7 +47,7 @@ namespace Crow protected GraphicObject child; - protected virtual T SetChild<T>(T _child) + internal virtual void SetChild(GraphicObject _child) { if (child != null) { @@ -67,8 +67,6 @@ namespace Crow child.RegisteredLayoutings = LayoutingType.None; child.RegisterForLayouting (LayoutingType.Sizing); } - - return (T)_child; } #region GraphicObject Overrides diff --git a/src/GraphicObjects/Scroller.cs b/src/GraphicObjects/Scroller.cs index 3eaff5f4..c248595d 100644 --- a/src/GraphicObjects/Scroller.cs +++ b/src/GraphicObjects/Scroller.cs @@ -148,7 +148,7 @@ namespace Crow ScrollY = 0; ScrollX = 0; } - public override T SetChild<T> (T _child) + public override void SetChild (GraphicObject _child) { GraphicObject c = child as GraphicObject; Group g = child as Group; @@ -164,7 +164,7 @@ namespace Crow if (g != null) g.ChildrenCleared += onChildListCleared; } - return base.SetChild (_child); + base.SetChild (_child); } #endregion diff --git a/src/GraphicObjects/TabView.cs b/src/GraphicObjects/TabView.cs index d616ffc6..015f5f4f 100644 --- a/src/GraphicObjects/TabView.cs +++ b/src/GraphicObjects/TabView.cs @@ -100,7 +100,7 @@ namespace Crow set { } } - public override T AddChild<T> (T child) + public override void AddChild (GraphicObject child) { TabItem ti = child as TabItem; if (ti == null) @@ -113,7 +113,7 @@ namespace Crow SelectedTab = 0; } - return base.AddChild (child); + base.AddChild (child); } public override void RemoveChild (GraphicObject child) { diff --git a/src/IMLInstantiatorBuilder.cs b/src/IMLInstantiatorBuilder.cs new file mode 100644 index 00000000..a9c078d4 --- /dev/null +++ b/src/IMLInstantiatorBuilder.cs @@ -0,0 +1,100 @@ +// +// IMLReader.cs +// +// Author: +// Jean-Philippe Bruyère <jp.bruyere@hotmail.com> +// +// Copyright (c) 2016 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +using System; +using System.Xml; +using System.IO; +using System.Reflection; +using System.Reflection.Emit; + +namespace Crow +{ + public class IMLInstantiatorBuilder : XmlTextReader + { + public Stream ImlStream; + public Type RootType = null; + + DynamicMethod dm = null; + public ILGenerator il = null; + + public IMLInstantiatorBuilder (Stream stream) + : base(stream) + { + ImlStream = stream; + } + public IMLInstantiatorBuilder (ILGenerator ilGen, string xmlFragment) + : base(xmlFragment, XmlNodeType.Element,null){ + il = ilGen; + } + /// <summary> + /// Inits il generator, RootType must have been read first + /// </summary> + public void InitEmitter(){ + + dm = new DynamicMethod("dyn_instantiator", + MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot, + CallingConventions.Standard, + typeof(void),new Type[] {typeof(object)}, RootType, true); + + il = dm.GetILGenerator(256); + il.DeclareLocal(typeof(GraphicObject)); + il.Emit(OpCodes.Nop); + //set local GraphicObject to root object passed as 1st argument + il.Emit (OpCodes.Ldarg_0); + il.Emit (OpCodes.Stloc_0); + } + + /// <summary> + /// read first node to set GraphicObject class for loading + /// and let reader position on that node + /// </summary> + public Type ReadRootType () + { + string root = "Object"; + while (Read()) { + if (NodeType == XmlNodeType.Element) { + root = this.Name; + break; + } + } + + Type t = Type.GetType ("Crow." + root); + if (t == null) { + Assembly a = Assembly.GetEntryAssembly (); + foreach (Type expT in a.GetExportedTypes ()) { + if (expT.Name == root) + t = expT; + } + } + RootType = t; + return t; + } + /// <summary> + /// Finalize instatiator MSIL and return LoaderInvoker delegate + /// </summary> + public Instantiator GetInstanciator(){ + il.Emit(OpCodes.Ret); + + return new Instantiator (RootType, + (Interface.LoaderInvoker)dm.CreateDelegate (typeof(Interface.LoaderInvoker))); + } + } +} + diff --git a/src/IMLStream.cs b/src/IMLStream.cs index 542797a1..290c5355 100644 --- a/src/IMLStream.cs +++ b/src/IMLStream.cs @@ -23,6 +23,10 @@ using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Threading; +using System.Xml.Serialization; +using System.Xml; +using System.Collections.Generic; +using System.Diagnostics; namespace Crow { @@ -33,10 +37,10 @@ namespace Crow Path = path; using (Stream stream = Interface.GetStreamFromPath (path)) stream.CopyTo (this); - RootType = Interface.GetTopContainerOfXMLStream (this); + //RootType = Interface.GetTopContainerOfXMLStream (this); } public IMLStream(Byte[] b) : base (b){ - RootType = Interface.GetTopContainerOfXMLStream (this); + //RootType = Interface.GetTopContainerOfXMLStream (this); } /// <summary> /// Create a graphicObject instance from the this XML stream. @@ -47,7 +51,7 @@ namespace Crow Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; Seek (0, SeekOrigin.Begin); - GraphicObject tmp = Interface.Load (this, this.RootType); + GraphicObject tmp = null;//Interface.Load (this, this.RootType); Thread.CurrentThread.CurrentCulture = savedCulture; return tmp; diff --git a/src/Instantiator.cs b/src/Instantiator.cs new file mode 100644 index 00000000..e54e744e --- /dev/null +++ b/src/Instantiator.cs @@ -0,0 +1,41 @@ +// +// Instantiator.cs +// +// Author: +// Jean-Philippe Bruyère <jp.bruyere@hotmail.com> +// +// Copyright (c) 2016 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +using System; + +namespace Crow +{ + public class Instantiator + { + Type RootType; + Interface.LoaderInvoker Loader; + public Instantiator (Type _root, Interface.LoaderInvoker loader) + { + RootType = _root; + Loader = loader; + } + public GraphicObject CreateInstance(){ + GraphicObject tmp = (GraphicObject)Activator.CreateInstance(RootType); + Loader (tmp); + return tmp; + } + } +} + diff --git a/src/Interface.cs b/src/Interface.cs index 7b324de7..57291370 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -107,14 +107,16 @@ namespace Crow g.IsQueueForRedraw = true; } } + //fast compiled IML instantiators + public static Dictionary<String, Instantiator> Instantiators = new Dictionary<string, Instantiator>(); #region Default values and Style loading /// Default values of properties from GraphicObjects are retrieve from XML Attributes. /// The reflexion process used to retrieve those values being very slow, it is compiled in MSIL /// and injected as a dynamic method referenced in the DefaultValuesLoader Dictionnary. /// The compilation is done on the first object instancing, and is also done for custom widgets - public delegate void loadDefaultInvoker(object instance); - public static Dictionary<String, loadDefaultInvoker> DefaultValuesLoader = new Dictionary<string, loadDefaultInvoker>(); + public delegate void LoaderInvoker(object instance); + public static Dictionary<String, LoaderInvoker> DefaultValuesLoader = new Dictionary<string, LoaderInvoker>(); public static Dictionary<string, Dictionary<string, object>> Styling; /// <summary> parse all styling data's and build global Styling Dictionary </summary> static void LoadStyling() { @@ -176,36 +178,6 @@ namespace Crow return stream; } - /// <summary> - /// Pre-read first node to set GraphicObject class for loading - /// and reset stream position to 0 - /// </summary> - public static Type GetTopContainerOfXMLStream (Stream stream) - { - string root = "Object"; - stream.Seek (0, SeekOrigin.Begin); - using (XmlReader reader = XmlReader.Create (stream)) { - while (reader.Read ()) { - // first element is the root element - if (reader.NodeType == XmlNodeType.Element) { - root = reader.Name; - break; - } - } - } - - Type t = Type.GetType ("Crow." + root); - if (t == null) { - Assembly a = Assembly.GetEntryAssembly (); - foreach (Type expT in a.GetExportedTypes ()) { - if (expT.Name == root) - t = expT; - } - } - - stream.Seek (0, SeekOrigin.Begin); - return t; - } public static void Save<T> (string file, T graphicObject) { @@ -225,9 +197,10 @@ namespace Crow GraphicObject tmp = null; try { - using (Stream stream = GetStreamFromPath (path)) { - tmp = Load(stream, GetTopContainerOfXMLStream(stream)); - } + if (!Instantiators.ContainsKey(path)) + BuildInstaciator(path); + tmp = Instantiators [path].CreateInstance (); + } catch (Exception ex) { throw new Exception ("Error loading <" + path + ">:", ex); } @@ -236,37 +209,37 @@ namespace Crow return tmp; } - internal static GraphicObject Load (Stream stream, Type type) + public static void BuildInstaciator (string path) { + System.Globalization.CultureInfo savedCulture = Thread.CurrentThread.CurrentCulture; + Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; + #if DEBUG_LOAD Stopwatch loadingTime = new Stopwatch (); loadingTime.Start (); #endif - GraphicObject result; - - CurrentInterface.XmlLoading = true; - - XmlSerializerNamespaces xn = new XmlSerializerNamespaces (); - xn.Add ("", ""); - - XmlSerializer xs = new XmlSerializer (type); - - result = (GraphicObject)xs.Deserialize (stream); - CurrentInterface.XmlLoading = false; + try { + using (Stream stream = GetStreamFromPath (path)) { + using (IMLInstantiatorBuilder itr = new IMLInstantiatorBuilder (stream)){ + itr.ReadRootType(); + itr.InitEmitter(); + CompilerServices.BuildInstanciator(itr, itr.RootType); + itr.Read();//close tag + Instantiators[path] = itr.GetInstanciator(); + } + } + } catch (Exception ex) { + throw new Exception ("Error loading <" + path + ">:", ex); + } #if DEBUG_LOAD - FileStream fs = stream as FileStream; - if (fs!=null) - CurrentGOMLPath = fs.Name; loadingTime.Stop (); - Debug.WriteLine ("GOML Loading ({2}->{3}): {0} ticks, {1} ms", - loadingTime.ElapsedTicks, - loadingTime.ElapsedMilliseconds, - CurrentGOMLPath, result.ToString()); + Debug.WriteLine ("IML Loading '{2}' : {0} ticks, {1} ms", + loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, path); #endif - return result; + Thread.CurrentThread.CurrentCulture = savedCulture; } public GraphicObject LoadInterface (string path) |