From 0f68209638ed24c7d0e75cba75718637bfc09232 Mon Sep 17 00:00:00 2001 From: Nikolay Pianikov Date: Fri, 5 Jan 2024 16:44:15 +0300 Subject: [PATCH] Improvements in code generation performance --- .../Core/ArgDependencyNodeBuilder.cs | 2 +- src/Pure.DI.Core/Core/BindingBuilder.cs | 95 ++++++++++++++++ .../Core/Code/DependencyNodeExtensions.cs | 14 +-- .../Core/ConstructDependencyNodeBuilder.cs | 2 +- .../Core/DependencyGraphBuilder.cs | 2 +- .../Core/FactoryDependencyNodeBuilder.cs | 2 +- .../ImplementationDependencyNodeBuilder.cs | 2 +- .../Core/Models/DependencyNode.cs | 7 +- src/Pure.DI.Core/Core/Models/MdBinding.cs | 4 +- src/Pure.DI.Core/Core/Names.cs | 2 +- .../Core/RootDependencyNodeBuilder.cs | 2 +- src/Pure.DI.Core/Core/SetupsBuilder.cs | 104 ++++-------------- src/Pure.DI/Pure.DI.csproj | 4 +- .../TestExtensions.cs | 1 - 14 files changed, 138 insertions(+), 105 deletions(-) create mode 100644 src/Pure.DI.Core/Core/BindingBuilder.cs diff --git a/src/Pure.DI.Core/Core/ArgDependencyNodeBuilder.cs b/src/Pure.DI.Core/Core/ArgDependencyNodeBuilder.cs index 346d617c..ed338fe5 100644 --- a/src/Pure.DI.Core/Core/ArgDependencyNodeBuilder.cs +++ b/src/Pure.DI.Core/Core/ArgDependencyNodeBuilder.cs @@ -11,7 +11,7 @@ public IEnumerable Build(MdSetup setup) continue; } - yield return new DependencyNode(0, Arg: new DpArg(arg, binding)); + yield return new DependencyNode(0, binding, Arg: new DpArg(arg, binding)); } } } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/BindingBuilder.cs b/src/Pure.DI.Core/Core/BindingBuilder.cs new file mode 100644 index 00000000..56f2a9ab --- /dev/null +++ b/src/Pure.DI.Core/Core/BindingBuilder.cs @@ -0,0 +1,95 @@ +namespace Pure.DI.Core; + +internal class BindingBuilder +{ + private MdDefaultLifetime? _defaultLifetime; + private SemanticModel? _semanticModel; + private SyntaxNode? _source; + private MdLifetime? _lifetime; + private MdImplementation? _implementation; + private MdFactory? _factory; + private MdArg? _arg; + private readonly List _contracts = []; + private readonly List _tags = []; + + public MdDefaultLifetime DefaultLifetime + { + set => _defaultLifetime = value; + } + + public MdLifetime Lifetime + { + set => _lifetime = value; + } + + public MdImplementation Implementation + { + set + { + _source = value.Source; + _semanticModel = value.SemanticModel; + _implementation = value; + } + } + + public MdFactory Factory + { + set + { + _source = value.Source; + _semanticModel = value.SemanticModel; + _factory = value; + } + } + + public MdArg Arg + { + set + { + _source = value.Source; + _semanticModel = value.SemanticModel; + _arg = value; + } + } + + public void AddContract(in MdContract contract) => + _contracts.Add(contract); + + public void AddTag(in MdTag tag) => + _tags.Add(tag); + + public MdBinding Build(MdSetup setup) + { + try + { + if (_semanticModel is { } semanticModel + && _source is { } source) + { + return new MdBinding( + 0, + source, + setup, + semanticModel, + _contracts.ToImmutableArray(), + _tags.ToImmutableArray(), + _lifetime ?? _defaultLifetime?.Lifetime, + _implementation, + _factory, + _arg); + } + + throw new CompileErrorException($"The binding is defined incorrectly.", setup.Source.GetLocation(), LogId.ErrorInvalidMetadata); + } + finally + { + _contracts.Clear(); + _tags.Clear(); + _source = default; + _semanticModel = default; + _lifetime = default; + _implementation = default; + _factory = default; + _arg = default; + } + } +} \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/Code/DependencyNodeExtensions.cs b/src/Pure.DI.Core/Core/Code/DependencyNodeExtensions.cs index 5cdbfab0..7c48fd33 100644 --- a/src/Pure.DI.Core/Core/Code/DependencyNodeExtensions.cs +++ b/src/Pure.DI.Core/Core/Code/DependencyNodeExtensions.cs @@ -2,24 +2,24 @@ namespace Pure.DI.Core.Code; internal static class DependencyNodeExtensions { - public static bool IsArg(this in DependencyNode node) => + public static bool IsArg(this DependencyNode node) => node.Arg is not null; - public static bool IsFactory(this in DependencyNode node) => + public static bool IsFactory(this DependencyNode node) => node.Factory is not null; - public static bool IsEnumerable(this in DependencyNode node) => + public static bool IsEnumerable(this DependencyNode node) => node.Construct is { Source.Kind: MdConstructKind.Enumerable }; - public static bool IsAsyncEnumerable(this in DependencyNode node) => + public static bool IsAsyncEnumerable(this DependencyNode node) => node.Construct is { Source.Kind: MdConstructKind.AsyncEnumerable }; - private static bool IsDelegate(this in DependencyNode node) => + private static bool IsDelegate(this DependencyNode node) => node.Type.TypeKind == TypeKind.Delegate; - public static bool IsLazy(this in DependencyNode node) => + public static bool IsLazy(this DependencyNode node) => node.IsDelegate() || node.IsEnumerable() || node.IsAsyncEnumerable(); - public static bool IsDisposable(this in DependencyNode node) => + public static bool IsDisposable(this DependencyNode node) => node.Type.AllInterfaces.Any(i => i.SpecialType == SpecialType.System_IDisposable); } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/ConstructDependencyNodeBuilder.cs b/src/Pure.DI.Core/Core/ConstructDependencyNodeBuilder.cs index afacb32e..c38689bd 100644 --- a/src/Pure.DI.Core/Core/ConstructDependencyNodeBuilder.cs +++ b/src/Pure.DI.Core/Core/ConstructDependencyNodeBuilder.cs @@ -19,7 +19,7 @@ public IEnumerable Build(MdSetup setup) injections.Add(new Injection(contract.ContractType.WithNullableAnnotation(NullableAnnotation.NotAnnotated), tag)); } - yield return new DependencyNode(0, Construct: new DpConstruct(construct, binding, injections.ToImmutableArray())); + yield return new DependencyNode(0, binding, Construct: new DpConstruct(construct, binding, injections.ToImmutableArray())); } } } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/DependencyGraphBuilder.cs b/src/Pure.DI.Core/Core/DependencyGraphBuilder.cs index 876bfeac..48a6379f 100644 --- a/src/Pure.DI.Core/Core/DependencyGraphBuilder.cs +++ b/src/Pure.DI.Core/Core/DependencyGraphBuilder.cs @@ -229,7 +229,7 @@ bool TryCreateOnCannotResolve(MdSetup mdSetup, DependencyNode ownerNode, Injecti var injection = injectionInfo.Injection; var dependency = map.TryGetValue(injection, out var sourceNode) ? new Dependency(true, sourceNode, injection, node.Node) - : new Dependency(false, new DependencyNode(0), injection, node.Node); + : new Dependency(false, new DependencyNode(0, node.Node.Binding), injection, node.Node); edges.Add(dependency); } diff --git a/src/Pure.DI.Core/Core/FactoryDependencyNodeBuilder.cs b/src/Pure.DI.Core/Core/FactoryDependencyNodeBuilder.cs index 5c56f43c..3d86f8a9 100644 --- a/src/Pure.DI.Core/Core/FactoryDependencyNodeBuilder.cs +++ b/src/Pure.DI.Core/Core/FactoryDependencyNodeBuilder.cs @@ -18,7 +18,7 @@ public IEnumerable Build(MdSetup setup) injections.Add(new Injection(resolver.ContractType.WithNullableAnnotation(NullableAnnotation.NotAnnotated), resolver.Tag?.Value)); } - yield return new DependencyNode(0, Factory: new DpFactory(factory, binding, injections.ToImmutableArray())); + yield return new DependencyNode(0, binding, Factory: new DpFactory(factory, binding, injections.ToImmutableArray())); } } } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/ImplementationDependencyNodeBuilder.cs b/src/Pure.DI.Core/Core/ImplementationDependencyNodeBuilder.cs index cefad025..b39a3e4f 100644 --- a/src/Pure.DI.Core/Core/ImplementationDependencyNodeBuilder.cs +++ b/src/Pure.DI.Core/Core/ImplementationDependencyNodeBuilder.cs @@ -161,7 +161,7 @@ public IEnumerable Build(MdSetup setup) } private static IEnumerable CreateNodes(IEnumerable implementations) => - implementations.Select((implementation, variantId) => new DependencyNode(variantId, Implementation: implementation)); + implementations.Select((implementation, variantId) => new DependencyNode(variantId, implementation.Binding, Implementation: implementation)); private static int GetInjectionsCount(in DpImplementation implementation) { diff --git a/src/Pure.DI.Core/Core/Models/DependencyNode.cs b/src/Pure.DI.Core/Core/Models/DependencyNode.cs index b13760ef..1a9fb286 100644 --- a/src/Pure.DI.Core/Core/Models/DependencyNode.cs +++ b/src/Pure.DI.Core/Core/Models/DependencyNode.cs @@ -1,6 +1,6 @@ namespace Pure.DI.Core.Models; -internal readonly record struct DependencyNode( +internal record DependencyNode( int Variation, in MdBinding Binding, ITypeSymbol Type, @@ -12,6 +12,7 @@ internal readonly record struct DependencyNode( { public DependencyNode( int Variation, + in MdBinding binding, in DpRoot? Root = default, in DpImplementation? Implementation = default, in DpFactory? Factory = default, @@ -19,7 +20,7 @@ public DependencyNode( in DpConstruct? Construct = default) :this( Variation, - Root?.Binding ?? Implementation?.Binding ?? Factory?.Binding ?? Arg?.Binding ?? Construct?.Binding ?? new MdBinding(), + binding, Root?.Source.RootType ?? Implementation?.Source.Type ?? Factory?.Source.Type ?? Arg?.Source.Type ?? Construct?.Source.Type!, Root, Implementation, @@ -41,7 +42,7 @@ private IEnumerable ToStrings(int indent) => public override string ToString() => string.Join(Environment.NewLine, ToStrings(0)); - public bool Equals(DependencyNode other) => Binding.Equals(other.Binding); + public virtual bool Equals(DependencyNode? other) => Binding.Equals(other?.Binding); public override int GetHashCode() => Binding.GetHashCode(); } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/Models/MdBinding.cs b/src/Pure.DI.Core/Core/Models/MdBinding.cs index fb3b8d0e..85e8e95d 100644 --- a/src/Pure.DI.Core/Core/Models/MdBinding.cs +++ b/src/Pure.DI.Core/Core/Models/MdBinding.cs @@ -1,6 +1,6 @@ namespace Pure.DI.Core.Models; -internal readonly record struct MdBinding( +internal record MdBinding( int Id, in SyntaxNode Source, in MdSetup SourceSetup, @@ -20,7 +20,7 @@ public override string ToString() return string.Join(Environment.NewLine, walker); } - public bool Equals(MdBinding other) => Id == other.Id; + public virtual bool Equals(MdBinding? other) => Id == other?.Id; public override int GetHashCode() => Id; } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/Names.cs b/src/Pure.DI.Core/Core/Names.cs index 7b64c69f..c76862e9 100644 --- a/src/Pure.DI.Core/Core/Names.cs +++ b/src/Pure.DI.Core/Core/Names.cs @@ -47,7 +47,7 @@ internal static class Names private const string SingletonVariablePrefix = "_singleton"; private const string ArgVariablePrefix = "_arg"; - public static string GetVariableName(this in DependencyNode Node, int PerLifetimeId) + public static string GetVariableName(this DependencyNode Node, int PerLifetimeId) { var baseName = Node.Type.Name; switch (Node) diff --git a/src/Pure.DI.Core/Core/RootDependencyNodeBuilder.cs b/src/Pure.DI.Core/Core/RootDependencyNodeBuilder.cs index 76bed1a9..8820e136 100644 --- a/src/Pure.DI.Core/Core/RootDependencyNodeBuilder.cs +++ b/src/Pure.DI.Core/Core/RootDependencyNodeBuilder.cs @@ -15,7 +15,7 @@ public IEnumerable Build(MdSetup setup) ImmutableArray.Empty, ImmutableArray.Empty); - yield return new DependencyNode(0, Root: new DpRoot(root, rootBinding, new Injection(root.RootType.WithNullableAnnotation(NullableAnnotation.NotAnnotated), root.Tag?.Value))); + yield return new DependencyNode(0, rootBinding, Root: new DpRoot(root, rootBinding, new Injection(root.RootType.WithNullableAnnotation(NullableAnnotation.NotAnnotated), root.Tag?.Value))); } } } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/SetupsBuilder.cs b/src/Pure.DI.Core/Core/SetupsBuilder.cs index ae3894d1..19c65392 100644 --- a/src/Pure.DI.Core/Core/SetupsBuilder.cs +++ b/src/Pure.DI.Core/Core/SetupsBuilder.cs @@ -13,34 +13,10 @@ internal sealed class SetupsBuilder( private readonly List _typeAttributes = []; private readonly List _tagAttributes = []; private readonly List _ordinalAttributes = []; - private readonly List _contracts = []; - private readonly List _tags = []; private readonly List _usingDirectives = []; + private BindingBuilder _bindingBuilder = new(); private MdSetup? _setup; - private MdBinding? _binding; - private MdDefaultLifetime? _defaultLifetime; - private MdBinding Binding - { - get - { - if (_binding is { } binding) - { - return binding; - } - - var newBinding = new MdBinding(); - if (_defaultLifetime.HasValue) - { - newBinding = newBinding with { Lifetime = _defaultLifetime.Value.Lifetime }; - } - - _binding = newBinding; - return newBinding; - } - - set => _binding = value; - } public IEnumerable Build(SyntaxUpdate update) { @@ -68,31 +44,27 @@ public void VisitSetup(in MdSetup setup) public void VisitUsingDirectives(in MdUsingDirectives usingDirectives) => _usingDirectives.Add(usingDirectives); - public void VisitBinding(in MdBinding binding) => _binding = binding; + public void VisitBinding(in MdBinding binding) + { + } - public void VisitContract(in MdContract contract) => _contracts.Add(contract); + public void VisitContract(in MdContract contract) => _bindingBuilder.AddContract(contract); public void VisitImplementation(in MdImplementation implementation) { - Binding = Binding with - { - SemanticModel = implementation.SemanticModel, - Implementation = implementation, - Source = implementation.Source - }; - + _bindingBuilder.Implementation = implementation; FinishBinding(); } public void VisitFactory(in MdFactory factory) { - Binding = Binding with - { - SemanticModel = factory.SemanticModel, - Factory = factory, - Source = factory.Source - }; + _bindingBuilder.Factory = factory; + FinishBinding(); + } + public void VisitArg(in MdArg arg) + { + _bindingBuilder.Arg = arg; FinishBinding(); } @@ -102,20 +74,8 @@ public void VisitResolve(MdResolver resolver) public void VisitRoot(in MdRoot root) => _roots.Add(root); - public void VisitArg(in MdArg arg) - { - Binding = Binding with - { - SemanticModel = arg.SemanticModel, - Arg = arg, - Source = arg.Source - }; - - FinishBinding(); - } - public void VisitDefaultLifetime(in MdDefaultLifetime defaultLifetime) => - _defaultLifetime = defaultLifetime; + _bindingBuilder.DefaultLifetime = defaultLifetime; public void VisitDependsOn(in MdDependsOn dependsOn) => _dependsOn.Add(dependsOn); @@ -129,50 +89,29 @@ public void VisitTagAttribute(in MdTagAttribute tagAttribute) => public void VisitOrdinalAttribute(in MdOrdinalAttribute ordinalAttribute) => _ordinalAttributes.Add(ordinalAttribute); - public void VisitLifetime(in MdLifetime lifetime) - { - Binding = Binding with { Lifetime = lifetime }; - } + public void VisitLifetime(in MdLifetime lifetime) => + _bindingBuilder.Lifetime = lifetime; - public void VisitTag(in MdTag tag) => _tags.Add(tag); + public void VisitTag(in MdTag tag) => _bindingBuilder.AddTag(tag); public void VisitFinish() => FinishSetup(); private void FinishBinding() { - if (!_binding.HasValue) - { - return; - } - - _bindings.Add( - _binding.Value with - { - Contracts = _contracts.ToImmutableArray(), - Tags = _tags.ToImmutableArray() - }); - - _contracts.Clear(); - _tags.Clear(); - _binding = default; + _bindings.Add(_bindingBuilder.Build(_setup!)); } private void FinishSetup() { - if (_setup == default) + if (_setup is not { } setup) { return; } - if (_binding.HasValue) - { - throw new CompileErrorException($"Binding {_binding} is not fully defined.", _binding.Value.Source.GetLocation(), LogId.ErrorInvalidMetadata); - } - _setups.Add( - _setup with + setup with { - Bindings = _bindings.Select(i => i with { SourceSetup = _setup }).ToImmutableArray(), + Bindings = _bindings.Select(i => i with { SourceSetup = setup }).ToImmutableArray(), Roots = _roots.ToImmutableArray(), DependsOn = _dependsOn.ToImmutableArray(), TypeAttributes = _typeAttributes.ToImmutableArray(), @@ -185,10 +124,9 @@ _setup with _roots.Clear(); _dependsOn.Clear(); _typeAttributes.Clear(); - _tags.Clear(); _ordinalAttributes.Clear(); _usingDirectives.Clear(); _setup = default; - _defaultLifetime = default; + _bindingBuilder = new BindingBuilder(); } } \ No newline at end of file diff --git a/src/Pure.DI/Pure.DI.csproj b/src/Pure.DI/Pure.DI.csproj index ad043614..e3232ce3 100644 --- a/src/Pure.DI/Pure.DI.csproj +++ b/src/Pure.DI/Pure.DI.csproj @@ -14,8 +14,8 @@ + TRACE_MODE + --> diff --git a/tests/Pure.DI.IntegrationTests/TestExtensions.cs b/tests/Pure.DI.IntegrationTests/TestExtensions.cs index be0e0882..2d3a4efc 100644 --- a/tests/Pure.DI.IntegrationTests/TestExtensions.cs +++ b/tests/Pure.DI.IntegrationTests/TestExtensions.cs @@ -220,7 +220,6 @@ private static CSharpCompilation CreateCompilation() => MetadataReference.CreateFromFile(typeof(SortedSet).Assembly.Location), MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), MetadataReference.CreateFromFile(typeof(Uri).Assembly.Location), - MetadataReference.CreateFromFile(typeof(SourceGenerator).Assembly.Location), MetadataReference.CreateFromFile(typeof(Regex).Assembly.Location), MetadataReference.CreateFromFile(typeof(IAsyncEnumerable<>).Assembly.Location));