Skip to content

Commit 60809c8

Browse files
committed
Optimize property group Clear
1 parent ddf5945 commit 60809c8

File tree

3 files changed

+74
-64
lines changed

3 files changed

+74
-64
lines changed

src/Framework/Framework/Controls/DotvvmControlProperties.cs

Lines changed: 71 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -312,75 +312,77 @@ private readonly int CountPropertyGroupOutlined(ushort groupId)
312312

313313
public void ClearPropertyGroup(ushort groupId)
314314
{
315-
switch (state)
315+
if (state == TableState.Empty)
316+
return;
317+
else if (state == TableState.Dictinary)
316318
{
317-
case TableState.Empty:
318-
return;
319-
case TableState.Array8:
320-
case TableState.Array16:
321-
{
322-
var bitmap = Impl.FindGroupBitmap(this.keys!, groupId);
323-
int index = 0;
324-
if (bitmap == 0)
325-
return;
326-
OwnKeys();
327-
OwnValues();
328-
do
329-
{
330-
int bit = BitOperations.TrailingZeroCount(bitmap);
331-
bitmap >>= (bit + 1);
332-
index += bit;
333-
Debug.Assert(keys![index].IsInPropertyGroup(groupId), $"Key {keys[index]} at index {index} is not in property group {groupId}");
334-
keys![index] = default;
335-
valuesAsArray[index] = null;
336-
index++;
337-
} while (bitmap != 0);
338-
CheckInvariant();
339-
return;
340-
}
341-
case TableState.Dictinary:
342-
{
343-
var dict = this.valuesAsDictionary;
344-
// we want to avoid allocating the list if there is only one property
345-
DotvvmPropertyId toRemove = default;
346-
List<DotvvmPropertyId>? toRemoveRest = null;
319+
ClearPropertyGroupOutlined(groupId);
320+
return;
321+
}
322+
323+
Debug.Assert(state is TableState.Array16 or TableState.Array8);
324+
var bitmap = Impl.FindGroupBitmap(this.keys!, groupId);
325+
if (bitmap == 0)
326+
return;
347327

348-
foreach (var (p, _) in dict)
349-
{
350-
if (p.IsInPropertyGroup(groupId))
351-
{
352-
if (toRemove.Id == 0)
353-
toRemove = p;
354-
else
355-
{
356-
toRemoveRest ??= new List<DotvvmPropertyId>();
357-
toRemoveRest.Add(p);
358-
}
359-
}
360-
}
328+
OwnKeys();
329+
OwnValues();
361330

362-
if (toRemove.Id != 0)
363-
{
364-
if (!ownsValues)
365-
{
366-
CloneValues();
367-
dict = this.valuesAsDictionary;
368-
}
331+
int index = 0;
332+
var values = Impl.UnsafeArrayReference(this.valuesAsArray);
333+
var keys = Impl.UnsafeArrayReference(this.keys!);
334+
do
335+
{
336+
int bit = BitOperations.TrailingZeroCount(bitmap);
337+
bitmap >>= (bit + 1);
338+
index += bit;
339+
Debug.Assert(this.keys![index].IsInPropertyGroup(groupId), $"Key {this.keys[index]} at index {index} is not in property group {groupId}");
340+
Unsafe.Add(ref keys, index) = default;
341+
Unsafe.Add(ref values, index) = null;
342+
index++;
343+
} while (bitmap != 0);
344+
CheckInvariant();
345+
}
369346

370-
dict.Remove(toRemove);
371-
}
347+
private void ClearPropertyGroupOutlined(ushort groupId)
348+
{
349+
var dict = this.valuesAsDictionary;
350+
// we want to avoid allocating the list if there is only one property
351+
DotvvmPropertyId toRemove = default;
352+
List<DotvvmPropertyId>? toRemoveRest = null;
372353

373-
if (toRemoveRest is {})
354+
foreach (var (p, _) in dict)
355+
{
356+
if (p.IsInPropertyGroup(groupId))
357+
{
358+
if (toRemove.Id == 0)
359+
toRemove = p;
360+
else
374361
{
375-
Debug.Assert(ownsValues);
376-
foreach (var p in toRemoveRest)
377-
dict.Remove(p);
362+
toRemoveRest ??= new List<DotvvmPropertyId>();
363+
toRemoveRest.Add(p);
378364
}
379-
CheckInvariant();
380-
return;
381365
}
382366
}
383-
Impl.Fail();
367+
368+
if (toRemove.Id != 0)
369+
{
370+
if (!ownsValues)
371+
{
372+
CloneValues();
373+
dict = this.valuesAsDictionary;
374+
}
375+
376+
dict.Remove(toRemove);
377+
}
378+
379+
if (toRemoveRest is {})
380+
{
381+
Debug.Assert(ownsValues);
382+
foreach (var p in toRemoveRest)
383+
dict.Remove(p);
384+
}
385+
CheckInvariant();
384386
}
385387

386388
[MethodImpl(Inline)]
@@ -396,9 +398,9 @@ public readonly bool TryGet(DotvvmPropertyId p, out object? value)
396398
if (index >= 0)
397399
{
398400
#if NET6_0_OR_GREATER
399-
value = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(valuesAsArray), index);
401+
value = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(valuesAsArrayUnsafe), index);
400402
#else
401-
value = valuesAsArray[index];
403+
value = valuesAsArrayUnsafe![index];
402404
#endif
403405
return true;
404406
}
@@ -422,7 +424,12 @@ private readonly bool TryGetOutlined(DotvvmPropertyId p, out object? value)
422424
var index = Impl.FindSlot16(this.keys!, p);
423425
if (index >= 0)
424426
{
425-
value = valuesAsArray[index];
427+
428+
#if NET6_0_OR_GREATER
429+
value = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(valuesAsArrayUnsafe), index);
430+
#else
431+
value = valuesAsArrayUnsafe![index];
432+
#endif
426433
return true;
427434
}
428435
else
@@ -463,7 +470,7 @@ private readonly bool TryGetOutlined(DotvvmPropertyId p, out object? value)
463470
public void Set(DotvvmPropertyId p, object? value)
464471
{
465472
CheckInvariant();
466-
if (p.MemberId == 0) ThrowZeroPropertyId();
473+
if (p.MemberId == 0) { ThrowZeroPropertyId(); return; }
467474

468475
if (state == TableState.Array8)
469476
{

src/Framework/Framework/Controls/PropertyImmutableHashtable.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ public static int FindSlotOrFree8(DotvvmPropertyId[] keys, DotvvmPropertyId p, o
277277
public static int FindSlotOrFree16(DotvvmPropertyId[] keys, DotvvmPropertyId p, out bool exists) =>
278278
FindSlotOrFree16(ref UnsafeArrayReference(keys), p, out exists);
279279

280+
[MethodImpl(Inline)]
280281
public static ushort FindGroupBitmap(ref DotvvmPropertyId keys, int length, ushort groupId)
281282
{
282283
Debug.Assert(length is AdhocTableSize or AdhocLargeTableSize);
@@ -312,6 +313,7 @@ public static ushort FindGroupBitmap(ref DotvvmPropertyId keys, int length, usho
312313
return bitmap;
313314
}
314315

316+
[MethodImpl(Inline)]
315317
public static ushort FindGroupBitmap(DotvvmPropertyId[] keys, ushort groupId)
316318
{
317319
return FindGroupBitmap(ref UnsafeArrayReference(keys), keys.Length, groupId);

src/Framework/Framework/Utils/BoxingUtils.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static object Box(int v)
2626
}
2727
public static object? Box(int? v) => v.HasValue ? Box(v.GetValueOrDefault()) : null;
2828

29+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2930
public static object? BoxGeneric<T>(T v)
3031
{
3132
if (typeof(T).IsValueType)

0 commit comments

Comments
 (0)