Skip to content

Commit caa736d

Browse files
committed
Fix build on net4, add some comments, improve readablity
1 parent 598b852 commit caa736d

18 files changed

+462
-210
lines changed

src/Framework/Framework/Binding/DotvvmProperty.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ public bool IsOwnedByCapability(DotvvmCapabilityProperty capability) =>
233233
return DefaultValue;
234234
}
235235

236-
private bool IsSetInHierarchy(DotvvmBindableObject control)
236+
private bool IsSetInherited(DotvvmBindableObject control)
237237
{
238238
for (var p = control.Parent; p is not null; p = p.Parent)
239239
{
@@ -255,7 +255,7 @@ public virtual bool IsSet(DotvvmBindableObject control, bool inherit = true)
255255

256256
if (IsValueInherited && inherit)
257257
{
258-
return IsSetInHierarchy(control);
258+
return IsSetInherited(control);
259259
}
260260

261261
return false;
Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,67 @@
11
using System;
22
using System.Diagnostics.CodeAnalysis;
3+
using System.Runtime.CompilerServices;
34
using DotVVM.Framework.Compilation.ControlTree;
5+
using DotVVM.Framework.Controls;
46

57
namespace DotVVM.Framework.Binding
68
{
9+
/// <summary>
10+
/// Represents a unique <see cref="DotvvmProperty"/> ID, used as a key for <see cref="DotvvmPropertyDictionary" />.
11+
/// </summary>
12+
/// <remarks>
13+
/// The ID is a 32-bit unsigned integer, where:
14+
/// - the most significant bit indicates whether the ID is of a property group (1) or a classic property (0)
15+
/// - the next upper 15 bits are the <see cref="TypeId"/> (for classic properties) or <see cref="GroupId"/> (for property groups)
16+
/// - the lower 16 bits are the <see cref="MemberId"/>, ID of the string key for property groups or the ID of the property for classic properties
17+
/// - in case of classic properties, the LSB bit of the member ID indicates whether the property has GetValue/SetValue overrides and is not inherited (see <see cref="CanUseFastAccessors"/>)
18+
/// </remarks>
719
public readonly struct DotvvmPropertyId: IEquatable<DotvvmPropertyId>, IEquatable<uint>, IComparable<DotvvmPropertyId>
820
{
21+
/// <summary> Numeric representation of the property ID. </summary>
922
public readonly uint Id;
23+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1024
public DotvvmPropertyId(uint id)
1125
{
1226
Id = id;
1327
}
1428

29+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1530
public DotvvmPropertyId(ushort typeOrGroupId, ushort memberId)
1631
{
1732
Id = ((uint)typeOrGroupId << 16) | memberId;
1833
}
1934

35+
/// <summary> Returns true if the property is a <see cref="GroupedDotvvmProperty"/> other type of property. </summary>
2036
[MemberNotNullWhen(true, nameof(PropertyGroupInstance), nameof(GroupMemberName))]
21-
public bool IsPropertyGroup => (int)Id < 0;
22-
public ushort TypeId => (ushort)(Id >> 16);
23-
public ushort GroupId => (ushort)((Id >> 16) ^ 0x80_00);
24-
public ushort MemberId => (ushort)(Id & 0xFFFF);
37+
public bool IsPropertyGroup
38+
{
39+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
40+
get => (int)Id < 0;
41+
}
42+
/// <summary> Returns the ID of the property declaring type </summary>
43+
public ushort TypeId
44+
{
45+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
46+
get => (ushort)(Id >> 16);
47+
}
48+
/// <summary> Returns the ID of the property group. </summary>
49+
public ushort GroupId
50+
{
51+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
52+
get => (ushort)((Id >> 16) ^ 0x8000);
53+
}
54+
/// <summary> Returns the ID of the property member, i.e. property-in-type id for classic properties, or the name ID for property groups. </summary>
55+
public ushort MemberId
56+
{
57+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
58+
get => (ushort)(Id & 0xFFFF);
59+
}
2560

26-
/// <summary> Returns true if the property does not have GetValue/SetValue overrides and is not inherited. That means it is sufficient </summary>
61+
/// <summary> Returns true if the property does not have GetValue/SetValue overrides and is not inherited. That means it is sufficient to call properties.TryGet instead going through the DotvvmProperty.GetValue dynamic dispatch </summary>
2762
public bool CanUseFastAccessors
2863
{
64+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2965
get
3066
{
3167
// properties: we encode this information as the LSB bit of the member ID (i.e. odd/even numbers)
@@ -36,41 +72,75 @@ public bool CanUseFastAccessors
3672
}
3773
}
3874

39-
public bool IsZero => Id == 0;
75+
/// <summary> Returns true if the ID is default. This ID is invalid for most purposes and can be used as a sentinel value. </summary>
76+
public bool IsZero
77+
{
78+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
79+
get => Id == 0;
80+
}
4081

82+
/// <summary> Returns the <see cref="DotvvmProperty"/> instance for this ID. Note that a new <see cref="GroupedDotvvmProperty"/> might need to be allocated. </summary>
4183
public DotvvmProperty PropertyInstance => DotvvmPropertyIdAssignment.GetProperty(Id) ?? throw new Exception($"Property with ID {Id} not registered.");
84+
85+
/// <summary> Returns the <see cref="GroupedDotvvmProperty"/> instance for this ID, or <c>null</c> if the ID is of a classic property. </summary>
86+
4287
public DotvvmPropertyGroup? PropertyGroupInstance => !IsPropertyGroup ? null : DotvvmPropertyIdAssignment.GetPropertyGroup(GroupId);
88+
89+
/// <summary> Returns the name (string dictionary key) of the property group member, or <c>null</c> if the ID is of a classic property. </summary>
4390
public string? GroupMemberName => !IsPropertyGroup ? null : DotvvmPropertyIdAssignment.GetGroupMemberName(MemberId);
4491

92+
/// <summary> Returns the type of the property. </summary>
4593
public Type PropertyType => IsPropertyGroup ? PropertyGroupInstance.PropertyType : PropertyInstance.PropertyType;
94+
95+
/// <summary> Returns the property declaring type. </summary>
4696
public Type DeclaringType => IsPropertyGroup ? PropertyGroupInstance.DeclaringType : DotvvmPropertyIdAssignment.GetControlType(TypeId);
4797

98+
/// <summary> Returns the property declaring type. </summary>
99+
[MemberNotNullWhen(true, nameof(PropertyGroupInstance), nameof(GroupMemberName))]
100+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
48101
public bool IsInPropertyGroup(ushort id) => (this.Id >> 16) == ((uint)id | 0x80_00u);
49102

103+
/// <summary> Constucts property ID from a property group name and a name ID. </summary>
104+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
50105
public static DotvvmPropertyId CreatePropertyGroupId(ushort groupId, ushort memberId) => new DotvvmPropertyId((ushort)(groupId | 0x80_00), memberId);
51106

107+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
52108
public static implicit operator DotvvmPropertyId(uint id) => new DotvvmPropertyId(id);
53109

110+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
111+
public static explicit operator uint(DotvvmPropertyId id) => id.Id;
112+
113+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
54114
public bool Equals(DotvvmPropertyId other) => Id == other.Id;
115+
116+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
55117
public bool Equals(uint other) => Id == other;
118+
56119
public override bool Equals(object? obj) => obj is DotvvmPropertyId id && Equals(id);
120+
121+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
57122
public override int GetHashCode() => (int)Id;
58123

124+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
59125
public static bool operator ==(DotvvmPropertyId left, DotvvmPropertyId right) => left.Equals(right);
126+
127+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
60128
public static bool operator !=(DotvvmPropertyId left, DotvvmPropertyId right) => !left.Equals(right);
61129

62130
public override string ToString()
63131
{
64132
if (IsPropertyGroup)
65133
{
66134
var pg = PropertyGroupInstance;
67-
return $"[{Id:x8}]{pg.DeclaringType.Name}.{pg.Name}:{GroupMemberName}";
135+
return $"[{TypeId:x4}_{MemberId:x4}]{pg.DeclaringType.Name}.{pg.Name}:{GroupMemberName}";
68136
}
69137
else
70138
{
71-
return $"[{Id:x8}]{PropertyInstance.FullName}";
139+
return $"[{TypeId:x4}_{MemberId:x4}]{PropertyInstance.FullName}";
72140
}
73141
}
142+
143+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
74144
public int CompareTo(DotvvmPropertyId other) => Id.CompareTo(other.Id);
75145
}
76146
}

src/Framework/Framework/Binding/DotvvmPropertyIdAssignment.GroupMembers.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public static ushort TryGetId(ReadOnlySpan<char> attr) =>
3131
"data-bind" => data_bind,
3232
_ => 0,
3333
};
34+
35+
// TODO
3436
}
3537
}
3638
}

src/Framework/Framework/Binding/DotvvmPropertyIdAssignment.PropertyIds.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ public static class PropertyIds
6767
public const uint TextBox_Enabled = TypeIds.TextBox << 16 | 1;
6868
/// <seealso cref="TextBox.UpdateTextOnInputProperty" />
6969
public const uint TextBox_UpdateTextOnInput = TypeIds.TextBox << 16 | 3;
70+
/// <seealso cref="RenderSettings.ModeProperty" />
71+
public const uint RenderSettings_Mode = TypeIds.RenderSettings << 16 | 1;
72+
73+
// TODO
7074
}
7175
}
7276
}

src/Framework/Framework/Binding/DotvvmPropertyIdAssignment.TypeIds.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static class TypeIds
2626
public const ushort Validation = 14;
2727
public const ushort ValidationSummary = 15;
2828
public const ushort Internal = 16;
29+
public const ushort RenderSettings = 17;
2930

3031
public static readonly ImmutableArray<(Type type, ushort id)> List = ImmutableArray.Create(
3132
(typeof(DotvvmBindableObject), DotvvmBindableObject),
@@ -43,7 +44,8 @@ public static class TypeIds
4344
(typeof(Validator), Validator),
4445
(typeof(Validation), Validation),
4546
(typeof(ValidationSummary), ValidationSummary),
46-
(typeof(Internal), Internal)
47+
(typeof(Internal), Internal),
48+
(typeof(RenderSettings), RenderSettings)
4749
);
4850
}
4951
}

src/Framework/Framework/Binding/DotvvmPropertyIdAssignment.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
namespace DotVVM.Framework.Binding
1414
{
1515

16-
static partial class DotvvmPropertyIdAssignment
16+
internal static partial class DotvvmPropertyIdAssignment
1717
{
1818
/// Type and property group IDs bellow this are reserved for manual ID assignment
1919
const int RESERVED_CONTROL_TYPES = 256;
@@ -46,6 +46,7 @@ static DotvvmPropertyIdAssignment()
4646
}
4747

4848
#region Optimized metadata accessors
49+
/// <summary> Equivalent to <see cref="DotvvmProperty.IsValueInherited" /> </summary>
4950
public static bool IsInherited(DotvvmPropertyId propertyId)
5051
{
5152
if (propertyId.CanUseFastAccessors)
@@ -54,6 +55,8 @@ public static bool IsInherited(DotvvmPropertyId propertyId)
5455
return BitmapRead(controls[propertyId.TypeId].inheritedBitmap, propertyId.MemberId);
5556
}
5657

58+
/// <summary> Returns if the DotvvmProperty uses standard GetValue/SetValue method and we can avoid the dynamic dispatch </summary>
59+
/// <seealso cref="TypeCanUseAnyDirectAccess(Type)" />
5760
public static bool UsesStandardAccessors(DotvvmPropertyId propertyId)
5861
{
5962
if (propertyId.CanUseFastAccessors)
@@ -68,9 +71,10 @@ public static bool UsesStandardAccessors(DotvvmPropertyId propertyId)
6871
}
6972
}
7073

74+
/// <summary> Returns if the given property is of the <see cref="ActiveDotvvmProperty"/> or <see cref="ActiveDotvvmPropertyGroup" /> type </summary>
7175
public static bool IsActive(DotvvmPropertyId propertyId)
7276
{
73-
Debug.Assert(DotvvmPropertyIdAssignment.GetProperty(propertyId) != null, $"Property {propertyId} not registered.");
77+
Debug.Assert(GetProperty(propertyId) != null, $"Property {propertyId} not registered.");
7478
ulong[] bitmap;
7579
uint index;
7680
if (propertyId.IsPropertyGroup)
@@ -85,7 +89,8 @@ public static bool IsActive(DotvvmPropertyId propertyId)
8589
}
8690
return BitmapRead(bitmap, index);
8791
}
88-
92+
93+
/// <summary> Returns the DotvvmProperty with a given ID, or returns null if no such property exists. New instance of <see cref="GroupedDotvvmProperty"/> might be created. </summary>
8994
public static DotvvmProperty? GetProperty(DotvvmPropertyId id)
9095
{
9196
if (id.IsPropertyGroup)
@@ -111,6 +116,7 @@ public static bool IsActive(DotvvmPropertyId propertyId)
111116
}
112117
}
113118

119+
/// <summary> Returns the <see cref="DotvvmProperty"/> or <see cref="DotvvmPropertyGroup"/> with the given id </summary>
114120
public static Compilation.IControlAttributeDescriptor? GetPropertyOrPropertyGroup(DotvvmPropertyId id)
115121
{
116122
if (id.IsPropertyGroup)
@@ -132,6 +138,7 @@ public static bool IsActive(DotvvmPropertyId propertyId)
132138
}
133139
}
134140

141+
/// <summary> Returns the value of the property or property group. If the property is not set, returns the default value. </summary>
135142
public static object? GetValueRaw(DotvvmBindableObject obj, DotvvmPropertyId id, bool inherit = true)
136143
{
137144
if (id.CanUseFastAccessors)
@@ -148,6 +155,7 @@ public static bool IsActive(DotvvmPropertyId propertyId)
148155
}
149156
}
150157

158+
/// <summary> Returns the value of the property or property group. If the property is not set, returns the default value. </summary>
151159
public static MarkupOptionsAttribute GetMarkupOptions(DotvvmPropertyId id)
152160
{
153161
if (id.IsPropertyGroup)
@@ -164,6 +172,7 @@ public static MarkupOptionsAttribute GetMarkupOptions(DotvvmPropertyId id)
164172
}
165173

166174
/// <summary> Property or property group has type assignable to IBinding and bindings should not be evaluated in GetValue </summary>
175+
/// <seealso cref="DotvvmProperty.IsBindingProperty"/>
167176
public static bool IsBindingProperty(DotvvmPropertyId id)
168177
{
169178
if (id.IsPropertyGroup)
@@ -202,6 +211,7 @@ public static ushort RegisterType(Type type)
202211

203212
return unlikely(type);
204213

214+
[MethodImpl(MethodImplOptions.NoInlining)]
205215
static ushort unlikely(Type type)
206216
{
207217
var types = MemoryMarshal.CreateReadOnlySpan(ref type, 1);
@@ -219,7 +229,14 @@ public static void RegisterTypes(ReadOnlySpan<Type> types, Span<ushort> ids)
219229
{
220230
if (controlCounter + types.Length >= controls.Length)
221231
{
222-
VolatileResize(ref controls, 1 << (BitOperations.Log2((uint)(controlCounter + types.Length)) + 1));
232+
#if NET6_0_OR_GREATER
233+
var nextPow2 = 1 << (BitOperations.Log2((uint)(controlCounter + types.Length)) + 1);
234+
#else
235+
var nextPow2 = types.Length * 2;
236+
while (nextPow2 < controlCounter + types.Length)
237+
nextPow2 *= 2;
238+
#endif
239+
VolatileResize(ref controls, nextPow2);
223240
}
224241
for (int i = 0; i < types.Length; i++)
225242
{
@@ -247,6 +264,7 @@ public static void RegisterTypes(ReadOnlySpan<Type> types, Span<ushort> ids)
247264
}
248265
}
249266
}
267+
250268
public static DotvvmPropertyId RegisterProperty(DotvvmProperty property)
251269
{
252270
if (property.GetType() == typeof(GroupedDotvvmProperty))
@@ -318,6 +336,7 @@ static void ThrowTooManyException(DotvvmProperty property) =>
318336
}
319337

320338
private static readonly ConcurrentDictionary<Type, (bool getter, bool setter)> cacheTypeCanUseDirectAccess = new(concurrencyLevel: 1, capacity: 10);
339+
321340
/// <summary> Does the property use the default GetValue/SetValue methods? </summary>
322341
public static (bool getter, bool setter) TypeCanUseDirectAccess(Type propertyType)
323342
{
@@ -380,22 +399,9 @@ private static void VolatileResize<T>(ref T[] array, int newSize)
380399
#endregion Registration
381400

382401
#region Group members
383-
private static ushort PredefinedPropertyGroupMemberId(ReadOnlySpan<char> name)
384-
{
385-
switch (name)
386-
{
387-
case "class": return GroupMembers.@class;
388-
case "id": return GroupMembers.id;
389-
case "style": return GroupMembers.style;
390-
case "name": return GroupMembers.name;
391-
case "data-bind": return GroupMembers.data_bind;
392-
default: return 0;
393-
}
394-
}
395-
396402
public static ushort GetGroupMemberId(string name, bool registerIfNotFound)
397403
{
398-
var id = PredefinedPropertyGroupMemberId(name);
404+
var id = GroupMembers.TryGetId(name);
399405
if (id != 0)
400406
return id;
401407
if (propertyGroupMemberIds.TryGetValue(name, out id))
@@ -444,8 +450,11 @@ static void BitmapSet(ulong[] bitmap, uint index)
444450
private struct ControlTypeInfo
445451
{
446452
public DotvvmProperty?[] properties;
453+
/// <summary> Bitmap for <see cref="DotvvmProperty.IsValueInherited" /> </summary>
447454
public ulong[] inheritedBitmap;
455+
/// <summary> Bitmap for <see cref="TypeCanUseAnyDirectAccess(Type)" /> </summary>
448456
public ulong[] standardBitmap;
457+
/// <summary> Bitmap storing if property is <see cref="ActiveDotvvmProperty" /> </summary>
449458
public ulong[] activeBitmap;
450459
/// TODO split struct to part used during registration and part at runtime for lookups
451460
public object locker;

0 commit comments

Comments
 (0)