From 967afc3b0ff2c5ee9ecd64b1e4d46c5397246c1a Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Wed, 22 Aug 2018 10:01:52 +1200 Subject: [PATCH] Optimize RoutePattern allocations (#706) --- .../Patterns/RoutePattern.cs | 8 ++--- .../Patterns/RoutePatternFactory.cs | 34 ++++++++++++++++--- .../Patterns/RoutePatternParser.cs | 2 +- .../Patterns/RoutePatternPathSegment.cs | 2 +- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs index c6d80b0a06..80c2dfd801 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs @@ -21,10 +21,10 @@ namespace Microsoft.AspNetCore.Routing.Patterns internal RoutePattern( string rawText, - Dictionary defaults, - Dictionary> constraints, - RoutePatternParameterPart[] parameters, - RoutePatternPathSegment[] pathSegments) + IReadOnlyDictionary defaults, + IReadOnlyDictionary> constraints, + IReadOnlyList parameters, + IReadOnlyList pathSegments) { Debug.Assert(defaults != null); Debug.Assert(constraints != null); diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs index 44dd675543..f34007481e 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs @@ -298,19 +298,35 @@ namespace Microsoft.AspNetCore.Routing.Patterns rawText, updatedDefaults, updatedConstraints.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value.ToArray()), - parameters.ToArray(), - updatedSegments.ToArray()); + parameters, + updatedSegments); RoutePatternPathSegment VisitSegment(RoutePatternPathSegment segment) { - var updatedParts = new RoutePatternPart[segment.Parts.Count]; + RoutePatternPart[] updatedParts = null; for (var i = 0; i < segment.Parts.Count; i++) { var part = segment.Parts[i]; - updatedParts[i] = VisitPart(part); + var updatedPart = VisitPart(part); + + if (part != updatedPart) + { + if (updatedParts == null) + { + updatedParts = segment.Parts.ToArray(); + } + + updatedParts[i] = updatedPart; + } } - return SegmentCore(updatedParts); + if (updatedParts == null) + { + // Segment has not changed + return segment; + } + + return new RoutePatternPathSegment(updatedParts); } RoutePatternPart VisitPart(RoutePatternPart part) @@ -357,6 +373,14 @@ namespace Microsoft.AspNetCore.Routing.Patterns parameterConstraints.AddRange(parameter.Constraints); } + if (Equals(parameter.Default, @default) + && parameter.Constraints.Count == 0 + && (parameterConstraints?.Count ?? 0) == 0) + { + // Part has not changed + return part; + } + return ParameterPartCore( parameter.Name, @default, diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs index 0af65b286c..990d1854fc 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs @@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns if (IsSegmentValid(context, parts)) { - segments.Add(new RoutePatternPathSegment(parts.ToArray())); + segments.Add(new RoutePatternPathSegment(parts)); return true; } else diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs index 1fd65f45d7..4e7b010518 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns [DebuggerDisplay("{DebuggerToString()}")] public sealed class RoutePatternPathSegment { - internal RoutePatternPathSegment(RoutePatternPart[] parts) + internal RoutePatternPathSegment(IReadOnlyList parts) { Parts = parts; }