From d243780e67b5c6325390dacf8629196c597134bf Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Fri, 9 Nov 2018 16:41:20 +0200 Subject: [PATCH] Optimized the generation of C# by not splitting any strings. Our indention of lines in blocks was inadequate so we used to split strings by new lines, indent each line and put it back together. Creation of new strings is incredibly slow so this bogged our code generation down. I have now fixed indention properly and we no longer need to split already written blocks to indent them. Signed-off-by: Dimitar Dobrev --- src/Generator/Generators/CLI/CLIMarshal.cs | 2 +- src/Generator/Generators/CLI/CLISources.cs | 22 +++--- .../Generators/CSharp/CSharpMarshal.cs | 9 ++- .../Generators/CSharp/CSharpSources.cs | 73 ++++++++++--------- src/Generator/Generators/Marshal.cs | 15 ++-- src/Generator/Types/Std/Stdlib.cs | 4 +- src/Generator/Utils/BlockGenerator.cs | 14 +--- src/Generator/Utils/TextGenerator.cs | 19 ++--- src/Generator/Utils/Utils.cs | 21 ++++-- 9 files changed, 89 insertions(+), 90 deletions(-) diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index 9f14f7ad..041d4bb4 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -775,7 +775,7 @@ namespace CppSharp.Generators.CLI var fieldRef = string.Format("{0}.{1}", Context.Parameter.Name, property.Name); - var marshalCtx = new MarshalContext(Context.Context) + var marshalCtx = new MarshalContext(Context.Context, Context.Indent) { ArgName = fieldRef, ParameterIndex = Context.ParameterIndex++, diff --git a/src/Generator/Generators/CLI/CLISources.cs b/src/Generator/Generators/CLI/CLISources.cs index 76e7b098..bf1afa08 100644 --- a/src/Generator/Generators/CLI/CLISources.cs +++ b/src/Generator/Generators/CLI/CLISources.cs @@ -396,7 +396,7 @@ namespace CppSharp.Generators.CLI else variable = $"((::{@class.QualifiedOriginalName}*)NativePtr)->{decl.OriginalName}"; - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { Parameter = param, ArgName = param.Name, @@ -408,7 +408,7 @@ namespace CppSharp.Generators.CLI if (isIndexer) { - var ctx2 = new MarshalContext(Context) + var ctx2 = new MarshalContext(Context, CurrentIndent) { Parameter = indexParameter, ArgName = indexParameter.Name @@ -483,7 +483,7 @@ namespace CppSharp.Generators.CLI variable = string.Format("((::{0}*)NativePtr)->{1}", @class.QualifiedOriginalName, decl.OriginalName); - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { Declaration = decl, ArgName = decl.Name, @@ -592,7 +592,7 @@ namespace CppSharp.Generators.CLI var returns = new List(); foreach (var param in @event.Parameters) { - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { ReturnVarName = param.Name, ReturnType = param.QualifiedType @@ -686,7 +686,7 @@ namespace CppSharp.Generators.CLI var nativeField = string.Format("{0}{1}", nativeVar, property.Field.OriginalName); - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { ArgName = property.Name, ReturnVarName = nativeField, @@ -834,7 +834,7 @@ namespace CppSharp.Generators.CLI var paramIndex = 0; foreach (var param in method.Parameters) { - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { Function = method, Parameter = param, @@ -870,7 +870,7 @@ namespace CppSharp.Generators.CLI var varName = string.Format("_native.{0}", property.Field.OriginalName); - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { ReturnVarName = varName, ReturnType = property.QualifiedType @@ -946,7 +946,7 @@ namespace CppSharp.Generators.CLI WriteLine("auto {0} = ::{1}();", valueMarshalName, @class.QualifiedOriginalName); var param = new Parameter { Name = "(*this)" , Namespace = function.Namespace }; - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { MarshalVarPrefix = valueMarshalName, Parameter = param @@ -1021,7 +1021,7 @@ namespace CppSharp.Generators.CLI var nativeVarName = paramInfo.Name; - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { ArgName = nativeVarName, ReturnVarName = nativeVarName, @@ -1054,7 +1054,7 @@ namespace CppSharp.Generators.CLI isIntPtr ? "System::IntPtr()" : "nullptr"); } - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { ArgName = returnIdentifier, ReturnVarName = returnIdentifier, @@ -1167,7 +1167,7 @@ namespace CppSharp.Generators.CLI QualifiedType = new QualifiedType(paramType) }; - var ctx = new MarshalContext(Context) + var ctx = new MarshalContext(Context, CurrentIndent) { Parameter = effectiveParam, ParameterIndex = paramIndex, diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index ef759635..98714182 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Text; using CppSharp.AST; @@ -10,11 +11,13 @@ namespace CppSharp.Generators.CSharp { public class CSharpMarshalContext : MarshalContext { - public CSharpMarshalContext(BindingContext context) - : base(context) + public CSharpMarshalContext(BindingContext context, Stack indent) + : base(context, indent) { ArgumentPrefix = new TextGenerator(); + indent.PushTo(ArgumentPrefix.CurrentIndent); Cleanup = new TextGenerator(); + indent.PushTo(Cleanup.CurrentIndent); } public TextGenerator ArgumentPrefix { get; private set; } @@ -335,7 +338,7 @@ namespace CppSharp.Generators.CSharp if (parameter.Usage == ParameterUsage.Unknown || parameter.IsIn) return base.VisitParameterDecl(parameter); - var ctx = new CSharpMarshalContext(Context.Context) + var ctx = new CSharpMarshalContext(Context.Context, Context.Indent) { ReturnType = Context.ReturnType, ReturnVarName = Context.ReturnVarName diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index 49046628..ac60b9ef 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -820,7 +820,7 @@ namespace CppSharp.Generators.CSharp QualifiedType = var.QualifiedType }; - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { Parameter = param, ArgName = param.Name, @@ -880,38 +880,40 @@ namespace CppSharp.Generators.CSharp private void GenerateFieldSetter(Field field, Class @class, QualifiedType fieldType) { + string returnVar; + Type type = field.Type.Desugar(); + var arrayType = type as ArrayType; + if (arrayType != null && @class.IsValueType) + { + returnVar = HandleValueArray(arrayType, field); + } + else + { + var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name; + var identifier = SafeIdentifier(name); + if (@class.IsValueType) + returnVar = $"{Helpers.InstanceField}.{identifier}"; + else + returnVar = $"(({TypePrinter.PrintNative(@class)}*){Helpers.InstanceIdentifier})->{identifier}"; + } + var param = new Parameter { Name = "value", QualifiedType = field.QualifiedType }; - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { Parameter = param, ArgName = param.Name, + ReturnVarName = returnVar }; ctx.PushMarshalKind(MarshalKind.NativeField); var marshal = new CSharpMarshalManagedToNativePrinter(ctx); ctx.Declaration = field; - Type type = field.Type.Desugar(); - var arrayType = type as ArrayType; - - if (arrayType != null && @class.IsValueType) - { - ctx.ReturnVarName = HandleValueArray(arrayType, field); - } - else - { - var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name; - var identifier = SafeIdentifier(name); - if (@class.IsValueType) - ctx.ReturnVarName = $"{Helpers.InstanceField}.{identifier}"; - else - ctx.ReturnVarName = $"(({TypePrinter.PrintNative(@class)}*){Helpers.InstanceIdentifier})->{identifier}"; - } param.Visit(marshal); if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) @@ -987,7 +989,7 @@ namespace CppSharp.Generators.CSharp function.OriginalReturnType.Type.IsPointerTo(out type); var @internal = TypePrinter.PrintNative(function.Namespace); - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { Parameter = new Parameter { @@ -1108,7 +1110,7 @@ namespace CppSharp.Generators.CSharp TypePrinter.PopContext(); - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { ArgName = var.Name, ReturnType = new QualifiedType(var.Type) @@ -1171,12 +1173,18 @@ namespace CppSharp.Generators.CSharp private void GenerateFieldGetter(Field field, Class @class, QualifiedType returnType) { var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name; - String returnVar; + string returnVar; + var arrayType = field.Type.Desugar() as ArrayType; if (@class.IsValueType) - returnVar = $@"{Helpers.InstanceField}.{SafeIdentifier(name)}"; + { + if (arrayType != null) + returnVar = HandleValueArray(arrayType, field); + else + returnVar = $"{Helpers.InstanceField}.{SafeIdentifier(name)}"; + } else { - returnVar = $@"(({TypePrinter.PrintNative(@class)}*) {Helpers.InstanceIdentifier})->{SafeIdentifier(name)}"; + returnVar = $"(({TypePrinter.PrintNative(@class)}*) {Helpers.InstanceIdentifier})->{SafeIdentifier(name)}"; // Class field getter should return a reference object instead of a copy. Wrapping `returnVar` in // IntPtr ensures that non-copying object constructor is invoked. Class typeClass; @@ -1185,7 +1193,7 @@ namespace CppSharp.Generators.CSharp returnVar = $"new {CSharpTypePrinter.IntPtrType}(&{returnVar})"; } - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { ArgName = field.Name, Declaration = field, @@ -1194,11 +1202,6 @@ namespace CppSharp.Generators.CSharp }; ctx.PushMarshalKind(MarshalKind.NativeField); - var arrayType = field.Type.Desugar() as ArrayType; - - if (arrayType != null && @class.IsValueType) - ctx.ReturnVarName = HandleValueArray(arrayType, field); - var marshal = new CSharpMarshalNativeToManagedPrinter(ctx); field.QualifiedType.Visit(marshal); @@ -1666,7 +1669,7 @@ namespace CppSharp.Generators.CSharp if (param.Kind == ParameterKind.IndirectReturnType) continue; - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { ReturnType = param.QualifiedType, ReturnVarName = param.Name, @@ -1723,7 +1726,7 @@ namespace CppSharp.Generators.CSharp }; // Marshal the managed result to native - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { ArgName = Helpers.ReturnIdentifier, Parameter = param, @@ -1901,7 +1904,7 @@ namespace CppSharp.Generators.CSharp var returns = new List(); foreach (var param in @event.Parameters) { - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { ReturnVarName = param.Name, ReturnType = param.QualifiedType @@ -2853,7 +2856,7 @@ namespace CppSharp.Generators.CSharp if (needsReturn) { - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { ArgName = Helpers.ReturnIdentifier, ReturnVarName = Helpers.ReturnIdentifier, @@ -2944,7 +2947,7 @@ namespace CppSharp.Generators.CSharp var nativeVarName = paramInfo.Name; - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { Parameter = param, ArgName = nativeVarName, @@ -3012,7 +3015,7 @@ namespace CppSharp.Generators.CSharp } } - var ctx = new CSharpMarshalContext(Context) + var ctx = new CSharpMarshalContext(Context, CurrentIndent) { Parameter = param, ParameterIndex = paramIndex, diff --git a/src/Generator/Generators/Marshal.cs b/src/Generator/Generators/Marshal.cs index 7eda5902..649fe4cf 100644 --- a/src/Generator/Generators/Marshal.cs +++ b/src/Generator/Generators/Marshal.cs @@ -1,23 +1,27 @@ using CppSharp.AST; +using System.Collections.Generic; namespace CppSharp.Generators { public class MarshalContext : TypePrinter { - public MarshalContext(BindingContext context) + public MarshalContext(BindingContext context, Stack indent) { Context = context; Before = new TextGenerator(); + indent.PushTo(Before.CurrentIndent); Return = new TextGenerator(); + indent.PushTo(Return.CurrentIndent); MarshalVarPrefix = string.Empty; + this.Indent = indent; } - public BindingContext Context { get; private set; } + public BindingContext Context { get; } public MarshalPrinter MarshalToNative; - public TextGenerator Before { get; private set; } - public TextGenerator Return { get; private set; } + public TextGenerator Before { get; } + public TextGenerator Return { get; } public string ReturnVarName { get; set; } public QualifiedType ReturnType { get; set; } @@ -27,11 +31,12 @@ namespace CppSharp.Generators public Function Function { get; set; } public string MarshalVarPrefix { get; set; } + public Stack Indent { get; } } public abstract class MarshalPrinter : AstVisitor where T : MarshalContext { - public T Context { get; private set; } + public T Context { get; } protected MarshalPrinter(T ctx) { diff --git a/src/Generator/Types/Std/Stdlib.cs b/src/Generator/Types/Std/Stdlib.cs index 5f82d1b3..a241c9a1 100644 --- a/src/Generator/Types/Std/Stdlib.cs +++ b/src/Generator/Types/Std/Stdlib.cs @@ -235,7 +235,7 @@ namespace CppSharp.Types.Std QualifiedType = type }; - var elementCtx = new MarshalContext(ctx.Context) + var elementCtx = new MarshalContext(ctx.Context, ctx.Indent) { Parameter = param, ArgName = param.Name, @@ -280,7 +280,7 @@ namespace CppSharp.Types.Std ctx.ReturnVarName); ctx.Before.WriteStartBraceIndent(); { - var elementCtx = new MarshalContext(ctx.Context) + var elementCtx = new MarshalContext(ctx.Context, ctx.Indent) { ReturnVarName = "_element", ReturnType = type diff --git a/src/Generator/Utils/BlockGenerator.cs b/src/Generator/Utils/BlockGenerator.cs index 041c7499..511b66a9 100644 --- a/src/Generator/Utils/BlockGenerator.cs +++ b/src/Generator/Utils/BlockGenerator.cs @@ -176,8 +176,6 @@ namespace CppSharp #region ITextGenerator implementation - public uint Indent { get { return Text.Indent; } } - public void Write(string msg, params object[] args) { Text.Write(msg, args); @@ -240,8 +238,9 @@ namespace CppSharp public abstract class BlockGenerator : ITextGenerator { - public Block RootBlock { get; private set; } + public Block RootBlock { get; } public Block ActiveBlock { get; private set; } + public Stack CurrentIndent => ActiveBlock.Text.CurrentIndent; protected BlockGenerator() { @@ -264,12 +263,7 @@ namespace CppSharp public void PushBlock(BlockKind kind = BlockKind.Unknown, object obj = null) { var block = new Block { Kind = kind, Object = obj }; - var array = new uint[ActiveBlock.Text.CurrentIndent.Count]; - ActiveBlock.Text.CurrentIndent.CopyTo(array, 0); - foreach (var indent in array.Reverse()) - { - block.Text.CurrentIndent.Push(indent); - } + CurrentIndent.PushTo(block.Text.CurrentIndent); block.Text.IsStartOfLine = ActiveBlock.Text.IsStartOfLine; block.Text.NeedsNewLine = ActiveBlock.Text.NeedsNewLine; PushBlock(block); @@ -306,8 +300,6 @@ namespace CppSharp #region ITextGenerator implementation - public uint Indent { get { return ActiveBlock.Indent; } } - public void Write(string msg, params object[] args) { ActiveBlock.Write(msg, args); diff --git a/src/Generator/Utils/TextGenerator.cs b/src/Generator/Utils/TextGenerator.cs index 308849a7..faf3c6da 100644 --- a/src/Generator/Utils/TextGenerator.cs +++ b/src/Generator/Utils/TextGenerator.cs @@ -7,7 +7,6 @@ namespace CppSharp { public interface ITextGenerator { - uint Indent { get; } void Write(string msg, params object[] args); void WriteLine(string msg, params object[] args); void WriteLineIndent(string msg, params object[] args); @@ -30,11 +29,6 @@ namespace CppSharp public bool NeedsNewLine { get; set; } public Stack CurrentIndent { get; } = new Stack(); - public uint Indent - { - get { return (uint)CurrentIndent.Sum(u => (int)u); } - } - public TextGenerator() { } @@ -60,16 +54,13 @@ namespace CppSharp if (args.Length > 0) msg = string.Format(msg, args); - foreach(var line in msg.SplitAndKeep(Environment.NewLine)) - { - if (IsStartOfLine && !string.IsNullOrWhiteSpace(line)) - StringBuilder.Append(new string(' ', (int) CurrentIndent.Sum(u => u))); + if (IsStartOfLine && !string.IsNullOrWhiteSpace(msg)) + StringBuilder.Append(new string(' ', (int) CurrentIndent.Sum(u => u))); - if (line.Length > 0) - IsStartOfLine = line.EndsWith(Environment.NewLine); + if (msg.Length > 0) + IsStartOfLine = msg.EndsWith(Environment.NewLine); - StringBuilder.Append(line); - } + StringBuilder.Append(msg); } public void WriteLine(string msg, params object[] args) diff --git a/src/Generator/Utils/Utils.cs b/src/Generator/Utils/Utils.cs index b8f8ed17..a651a58a 100644 --- a/src/Generator/Utils/Utils.cs +++ b/src/Generator/Utils/Utils.cs @@ -49,13 +49,6 @@ namespace CppSharp return str.Trim().Split(); } - public static IEnumerable SplitAndKeep(this string s, string seperator) - { - string[] obj = s.Split(new[] { seperator }, StringSplitOptions.None); - - return obj.Select((t, i) => i == obj.Length - 1 ? t : t + seperator); - } - public static string Capitalize(string s) { // Check for empty string. @@ -134,6 +127,18 @@ namespace CppSharp return uri1.MakeRelativeUri(uri2).ToString(); } - + } + + public static class CollectionExtensions + { + public static void PushTo(this Stack source, Stack destination) + { + var array = new T[source.Count]; + source.CopyTo(array, 0); + foreach (var indent in array.Reverse()) + { + destination.Push(indent); + } + } } }