Skip to content

Commit 9a4ec4f

Browse files
PropertyTable: Simplify a bit
- Remove the index consts because they don't really add much value, since they're just used once and its clear what they mean. - Make Property<T> reference the _values slot directly on modern .NET with a ref field. - Make BoxedProperty<T>.StrongBox a readonly field. - Add comments
1 parent e9e3e78 commit 9a4ec4f

File tree

1 file changed

+55
-37
lines changed

1 file changed

+55
-37
lines changed

src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/RazorCodeDocument.PropertyTable.cs

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Collections.Immutable;
7+
using System.ComponentModel;
78
using System.Diagnostics.CodeAnalysis;
89
using System.Runtime.CompilerServices;
910
using Microsoft.AspNetCore.Razor.Language.Intermediate;
@@ -15,28 +16,28 @@ public sealed partial class RazorCodeDocument
1516
/// <summary>
1617
/// Represents a set of mutable values associated with a <see cref="RazorCodeDocument"/>.
1718
/// </summary>
18-
private readonly struct PropertyTable
19+
private readonly struct PropertyTable()
1920
{
20-
public const int Size = 10;
21-
22-
private const int TagHelpersIndex = 0;
23-
private const int ReferencedTagHelpersIndex = 1;
24-
private const int PreTagHelperSyntaxTreeIndex = 2;
25-
private const int SyntaxTreeIndex = 3;
26-
private const int ImportSyntaxTreesIndex = 4;
27-
private const int TagHelperContextIndex = 5;
28-
private const int DocumentIntermediateNodeIndex = 6;
29-
private const int CSharpDocumentIndex = 7;
30-
private const int HtmlDocumentIndex = 8;
31-
private const int NamespaceInfoIndex = 9;
32-
33-
private readonly object?[] _values;
34-
35-
public PropertyTable()
36-
{
37-
_values = new object?[Size];
38-
}
39-
21+
// To add a mutable value, increase Size by 1 and add a new property below.
22+
// Use a Property<T> for reference types or a BoxedProperty<T> for value types.
23+
24+
private const int Size = 10;
25+
26+
private readonly object?[] _values = new object?[Size];
27+
28+
public Property<IReadOnlyList<TagHelperDescriptor>> TagHelpers => new(_values, 0);
29+
public Property<ISet<TagHelperDescriptor>> ReferencedTagHelpers => new(_values, 1);
30+
public Property<RazorSyntaxTree> PreTagHelperSyntaxTree => new(_values, 2);
31+
public Property<RazorSyntaxTree> SyntaxTree => new(_values, 3);
32+
public BoxedProperty<ImmutableArray<RazorSyntaxTree>> ImportSyntaxTrees => new(_values, 4);
33+
public Property<TagHelperDocumentContext> TagHelperContext => new(_values, 5);
34+
public Property<DocumentIntermediateNode> DocumentNode => new(_values, 6);
35+
public Property<RazorCSharpDocument> CSharpDocument => new(_values, 7);
36+
public Property<RazorHtmlDocument> HtmlDocument => new(_values, 8);
37+
public BoxedProperty<(string name, SourceSpan? span)> NamespaceInfo => new(_values, 9);
38+
39+
[EditorBrowsable(EditorBrowsableState.Never)]
40+
[Obsolete("Do not use. Present to support the legacy editor", error: false)]
4041
public PropertyTable Clone()
4142
{
4243
var clone = new PropertyTable();
@@ -45,25 +46,36 @@ public PropertyTable Clone()
4546
return clone;
4647
}
4748

48-
public Property<IReadOnlyList<TagHelperDescriptor>> TagHelpers => new(_values, TagHelpersIndex);
49-
public Property<ISet<TagHelperDescriptor>> ReferencedTagHelpers => new(_values, ReferencedTagHelpersIndex);
50-
public Property<RazorSyntaxTree> PreTagHelperSyntaxTree => new(_values, PreTagHelperSyntaxTreeIndex);
51-
public Property<RazorSyntaxTree> SyntaxTree => new(_values, SyntaxTreeIndex);
52-
public BoxedProperty<ImmutableArray<RazorSyntaxTree>> ImportSyntaxTrees => new(_values, ImportSyntaxTreesIndex);
53-
public Property<TagHelperDocumentContext> TagHelperContext => new(_values, TagHelperContextIndex);
54-
public Property<DocumentIntermediateNode> DocumentNode => new(_values, DocumentIntermediateNodeIndex);
55-
public Property<RazorCSharpDocument> CSharpDocument => new(_values, CSharpDocumentIndex);
56-
public Property<RazorHtmlDocument> HtmlDocument => new(_values, HtmlDocumentIndex);
57-
public BoxedProperty<(string name, SourceSpan? span)> NamespaceInfo => new(_values, NamespaceInfoIndex);
58-
49+
/// <summary>
50+
/// Provides access to a specific slot within an array for a given reference type.
51+
/// </summary>
52+
/// <param name="values">The array of values.</param>
53+
/// <param name="index">The index within <paramref name="values"/> to access.</param>
54+
/// <remarks>
55+
/// A <see langword="null"/> value in the slot indicates that the value is not present.
56+
/// </remarks>
5957
public readonly ref struct Property<T>(object?[] values, int index)
6058
where T : class
6159
{
60+
// We can use a ref field to access the array slot directly on modern .NET.
61+
// On NetFx, we index into the array for each access.
62+
#if NET
63+
private readonly ref object? _value = ref values[index];
64+
#endif
65+
6266
public T? Value
67+
#if NET
68+
=> (T?)_value;
69+
#else
6370
=> (T?)values[index];
71+
#endif
6472

6573
public void SetValue(T? value)
74+
#if NET
75+
=> _value = value;
76+
#else
6677
=> values[index] = value;
78+
#endif
6779

6880
public bool TryGetValue([NotNullWhen(true)] out T? result)
6981
{
@@ -75,16 +87,22 @@ public T RequiredValue
7587
=> Value.AssumeNotNull();
7688
}
7789

90+
/// <summary>
91+
/// Provides access to a specific slot within an array for a given value type.
92+
/// A <see cref="StrongBox{T}"/> is employed to avoid boxing and unboxing the value.
93+
/// </summary>
94+
/// <param name="values">The array of values.</param>
95+
/// <param name="index">The index within <paramref name="values"/> to access.</param>
7896
public readonly ref struct BoxedProperty<T>(object?[] values, int index)
7997
where T : struct
8098
{
81-
private Property<StrongBox<T>> StrongBox => new(values, index);
99+
private readonly Property<StrongBox<T>> _box = new(values, index);
82100

83-
public T? Value => StrongBox.Value?.Value;
101+
public T? Value => _box.Value?.Value;
84102

85103
public bool TryGetValue(out T result)
86104
{
87-
if (StrongBox.TryGetValue(out var box))
105+
if (_box.TryGetValue(out var box))
88106
{
89107
result = box.Value;
90108
return true;
@@ -96,7 +114,7 @@ public bool TryGetValue(out T result)
96114

97115
public void SetValue(T value)
98116
{
99-
if (StrongBox.TryGetValue(out var box))
117+
if (_box.TryGetValue(out var box))
100118
{
101119
// If we've already created a StrongBox, just update the value.
102120
box.Value = value;
@@ -105,7 +123,7 @@ public void SetValue(T value)
105123
{
106124
// Otherwise, create a new StrongBox.
107125
box = new(value);
108-
StrongBox.SetValue(box);
126+
_box.SetValue(box);
109127
}
110128
}
111129
}

0 commit comments

Comments
 (0)