Small memory allocation optimization in DefaultRazorTagHelperBinderPhase.TrySplitNamespaceAndType
This method allocated multiple strings on every invocation when they were rarely needed. With this change, I see a reduction in memory allocated during RazorProjectEngine.ProcessDesignTime of 1.4%.
This commit is contained in:
parent
8c1bf1f1a3
commit
43a628e9fb
|
|
@ -247,7 +247,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
// If this is a child content tag helper, we want to add it if it's original type is in scope.
|
// If this is a child content tag helper, we want to add it if it's original type is in scope.
|
||||||
// E.g, if the type name is `Test.MyComponent.ChildContent`, we want to add it if `Test.MyComponent` is in scope.
|
// E.g, if the type name is `Test.MyComponent.ChildContent`, we want to add it if `Test.MyComponent` is in scope.
|
||||||
TrySplitNamespaceAndType(typeName, out typeName, out var _);
|
TrySplitNamespaceAndType(typeName, out var typeNameTextSpan, out var _);
|
||||||
|
typeName = GetTextSpanContent(typeNameTextSpan, typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentNamespace != null && IsTypeInScope(typeName, currentNamespace))
|
if (currentNamespace != null && IsTypeInScope(typeName, currentNamespace))
|
||||||
|
|
@ -336,7 +337,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
// If this is a child content tag helper, we want to add it if it's original type is in scope of the given namespace.
|
// If this is a child content tag helper, we want to add it if it's original type is in scope of the given namespace.
|
||||||
// E.g, if the type name is `Test.MyComponent.ChildContent`, we want to add it if `Test.MyComponent` is in this namespace.
|
// E.g, if the type name is `Test.MyComponent.ChildContent`, we want to add it if `Test.MyComponent` is in this namespace.
|
||||||
TrySplitNamespaceAndType(typeName, out typeName, out var _);
|
TrySplitNamespaceAndType(typeName, out var typeNameTextSpan, out var _);
|
||||||
|
typeName = GetTextSpanContent(typeNameTextSpan, typeName);
|
||||||
}
|
}
|
||||||
if (typeName != null && IsTypeInNamespace(typeName, @namespace))
|
if (typeName != null && IsTypeInNamespace(typeName, @namespace))
|
||||||
{
|
{
|
||||||
|
|
@ -350,13 +352,13 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
internal static bool IsTypeInNamespace(string typeName, string @namespace)
|
internal static bool IsTypeInNamespace(string typeName, string @namespace)
|
||||||
{
|
{
|
||||||
if (!TrySplitNamespaceAndType(typeName, out var typeNamespace, out var _) || typeNamespace == string.Empty)
|
if (!TrySplitNamespaceAndType(typeName, out var typeNamespace, out var _) || typeNamespace.Length == 0)
|
||||||
{
|
{
|
||||||
// Either the typeName is not the full type name or this type is at the top level.
|
// Either the typeName is not the full type name or this type is at the top level.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeNamespace.Equals(@namespace, StringComparison.Ordinal);
|
return @namespace.Length == typeNamespace.Length && 0 == string.CompareOrdinal(typeName, typeNamespace.Start, @namespace, 0, @namespace.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the given type is already in scope given the namespace of the current document.
|
// Check if the given type is already in scope given the namespace of the current document.
|
||||||
|
|
@ -366,12 +368,13 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
// Whereas `MyComponents.SomethingElse.OtherComponent` is not in scope.
|
// Whereas `MyComponents.SomethingElse.OtherComponent` is not in scope.
|
||||||
internal static bool IsTypeInScope(string typeName, string currentNamespace)
|
internal static bool IsTypeInScope(string typeName, string currentNamespace)
|
||||||
{
|
{
|
||||||
if (!TrySplitNamespaceAndType(typeName, out var typeNamespace, out var _) || typeNamespace == string.Empty)
|
if (!TrySplitNamespaceAndType(typeName, out var typeNamespaceTextSpan, out var _) || typeNamespaceTextSpan.Length == 0)
|
||||||
{
|
{
|
||||||
// Either the typeName is not the full type name or this type is at the top level.
|
// Either the typeName is not the full type name or this type is at the top level.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var typeNamespace = GetTextSpanContent(typeNamespaceTextSpan, typeName);
|
||||||
var typeNamespaceSegments = typeNamespace.Split(NamespaceSeparators, StringSplitOptions.RemoveEmptyEntries);
|
var typeNamespaceSegments = typeNamespace.Split(NamespaceSeparators, StringSplitOptions.RemoveEmptyEntries);
|
||||||
var currentNamespaceSegments = currentNamespace.Split(NamespaceSeparators, StringSplitOptions.RemoveEmptyEntries);
|
var currentNamespaceSegments = currentNamespace.Split(NamespaceSeparators, StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (typeNamespaceSegments.Length > currentNamespaceSegments.Length)
|
if (typeNamespaceSegments.Length > currentNamespaceSegments.Length)
|
||||||
|
|
@ -399,21 +402,23 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
{
|
{
|
||||||
// If this is a child content tag helper, we want to look at it's original type.
|
// If this is a child content tag helper, we want to look at it's original type.
|
||||||
// E.g, if the type name is `Test.__generated__MyComponent.ChildContent`, we want to look at `Test.__generated__MyComponent`.
|
// E.g, if the type name is `Test.__generated__MyComponent.ChildContent`, we want to look at `Test.__generated__MyComponent`.
|
||||||
TrySplitNamespaceAndType(typeName, out typeName, out var _);
|
TrySplitNamespaceAndType(typeName, out var typeNameTextSpan, out var _);
|
||||||
|
typeName = GetTextSpanContent(typeNameTextSpan, typeName);
|
||||||
}
|
}
|
||||||
if (!TrySplitNamespaceAndType(typeName, out var _, out var className))
|
if (!TrySplitNamespaceAndType(typeName, out var _, out var classNameTextSpan))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
var className = GetTextSpanContent(classNameTextSpan, typeName);
|
||||||
|
|
||||||
return ComponentMetadata.IsMangledClass(className);
|
return ComponentMetadata.IsMangledClass(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal for testing.
|
// Internal for testing.
|
||||||
internal static bool TrySplitNamespaceAndType(string fullTypeName, out string @namespace, out string typeName)
|
internal static bool TrySplitNamespaceAndType(string fullTypeName, out TextSpan @namespace, out TextSpan typeName)
|
||||||
{
|
{
|
||||||
@namespace = string.Empty;
|
@namespace = default;
|
||||||
typeName = string.Empty;
|
typeName = default;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(fullTypeName))
|
if (string.IsNullOrEmpty(fullTypeName))
|
||||||
{
|
{
|
||||||
|
|
@ -442,20 +447,26 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
if (splitLocation == -1)
|
if (splitLocation == -1)
|
||||||
{
|
{
|
||||||
typeName = fullTypeName;
|
typeName = new TextSpan(0, fullTypeName.Length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@namespace = fullTypeName.Substring(0, splitLocation);
|
@namespace = new TextSpan(0, splitLocation);
|
||||||
|
|
||||||
var typeNameStartLocation = splitLocation + 1;
|
var typeNameStartLocation = splitLocation + 1;
|
||||||
if (typeNameStartLocation < fullTypeName.Length)
|
if (typeNameStartLocation < fullTypeName.Length)
|
||||||
{
|
{
|
||||||
typeName = fullTypeName.Substring(typeNameStartLocation, fullTypeName.Length - typeNameStartLocation);
|
typeName = new TextSpan(typeNameStartLocation, fullTypeName.Length - typeNameStartLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal for testing.
|
||||||
|
internal static string GetTextSpanContent(TextSpan textSpan, string s)
|
||||||
|
{
|
||||||
|
return s.Substring(textSpan.Start, textSpan.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1359,8 +1359,8 @@ namespace Microsoft.AspNetCore.Razor.Language
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(expectedResult, result);
|
Assert.Equal(expectedResult, result);
|
||||||
Assert.Equal(expectedNamespace, @namespace);
|
Assert.Equal(expectedNamespace, DefaultRazorTagHelperBinderPhase.ComponentDirectiveVisitor.GetTextSpanContent(@namespace, fullTypeName));
|
||||||
Assert.Equal(expectedTypeName, typeName);
|
Assert.Equal(expectedTypeName, DefaultRazorTagHelperBinderPhase.ComponentDirectiveVisitor.GetTextSpanContent(typeName, fullTypeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RazorSourceDocument CreateComponentTestSourceDocument(string content, string filePath = null)
|
private static RazorSourceDocument CreateComponentTestSourceDocument(string content, string filePath = null)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue