In tree diffs, omit trailing Continue entries and skip over unmodified subtrees
This commit is contained in:
parent
b021e19598
commit
7c30d51be9
|
|
@ -9,7 +9,7 @@ namespace Microsoft.Blazor.RenderTree
|
|||
{
|
||||
private const int MinBufferLength = 10;
|
||||
private RenderTreeDiffEntry[] _entries = new RenderTreeDiffEntry[10];
|
||||
private int _entriesInUse = 0;
|
||||
private int _entriesInUse;
|
||||
|
||||
public ArraySegment<RenderTreeDiffEntry> ComputeDifference(
|
||||
ArraySegment<RenderTreeNode> oldTree,
|
||||
|
|
@ -17,6 +17,7 @@ namespace Microsoft.Blazor.RenderTree
|
|||
{
|
||||
_entriesInUse = 0;
|
||||
AppendDiffEntriesForRange(oldTree.Array, 0, oldTree.Count, newTree.Array, 0, newTree.Count);
|
||||
TrimTrailingContinueNodes();
|
||||
|
||||
// If the previous usage of the buffer showed that we have allocated
|
||||
// much more space than needed, free up the excess memory
|
||||
|
|
@ -292,6 +293,19 @@ namespace Microsoft.Blazor.RenderTree
|
|||
|
||||
private void Append(RenderTreeDiffEntry entry)
|
||||
{
|
||||
if (entry.Type == RenderTreeDiffEntryType.StepOut)
|
||||
{
|
||||
TrimTrailingContinueNodes();
|
||||
|
||||
// If the preceding node is now a StepIn, then we can coalesce the StepIn+StepOut
|
||||
// down to a single Continue
|
||||
if (_entriesInUse > 0 && _entries[_entriesInUse - 1].Type == RenderTreeDiffEntryType.StepIn)
|
||||
{
|
||||
_entriesInUse--;
|
||||
entry = RenderTreeDiffEntry.Continue();
|
||||
}
|
||||
}
|
||||
|
||||
if (_entriesInUse == _entries.Length)
|
||||
{
|
||||
Array.Resize(ref _entries, _entries.Length * 2);
|
||||
|
|
@ -299,5 +313,13 @@ namespace Microsoft.Blazor.RenderTree
|
|||
|
||||
_entries[_entriesInUse++] = entry;
|
||||
}
|
||||
|
||||
private void TrimTrailingContinueNodes()
|
||||
{
|
||||
while (_entriesInUse > 0 && _entries[_entriesInUse - 1].Type == RenderTreeDiffEntryType.Continue)
|
||||
{
|
||||
_entriesInUse--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ namespace Microsoft.Blazor.Test
|
|||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
||||
|
||||
// Assert
|
||||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> RecognizesEquivalentNodesAsSameCases()
|
||||
|
|
@ -69,8 +68,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.PrependNode, entry.Type);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -92,8 +90,7 @@ namespace Microsoft.Blazor.Test
|
|||
// Assert
|
||||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -117,8 +114,7 @@ namespace Microsoft.Blazor.Test
|
|||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -150,8 +146,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.PrependNode, entry.Type);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -241,8 +236,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.PrependNode, entry.Type);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -266,8 +260,7 @@ namespace Microsoft.Blazor.Test
|
|||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type),
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.RemoveNode, entry.Type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -387,8 +380,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.SetAttribute, entry.Type);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -415,8 +407,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.RemoveAttribute, entry.Type);
|
||||
Assert.Equal("will be removed", entry.RemovedAttributeName);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -444,8 +435,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.SetAttribute, entry.Type);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -476,8 +466,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.SetAttribute, entry.Type);
|
||||
Assert.Equal(2, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -508,8 +497,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.RemoveAttribute, entry.Type);
|
||||
Assert.Equal("oldname", entry.RemovedAttributeName);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -553,6 +541,74 @@ namespace Microsoft.Blazor.Test
|
|||
entry => Assert.Equal(RenderTreeDiffEntryType.StepOut, entry.Type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkipsUnmodifiedSubtrees()
|
||||
{
|
||||
// Arrange
|
||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var diff = new RenderTreeDiff();
|
||||
oldTree.OpenElement(10, "root");
|
||||
oldTree.AddText(11, "Text that will change");
|
||||
oldTree.OpenElement(12, "Subtree that will not change");
|
||||
oldTree.OpenElement(13, "Another");
|
||||
oldTree.AddText(14, "Text that will not change");
|
||||
oldTree.CloseElement();
|
||||
oldTree.CloseElement();
|
||||
oldTree.CloseElement();
|
||||
|
||||
newTree.OpenElement(10, "root");
|
||||
newTree.AddText(11, "Text that has changed");
|
||||
newTree.OpenElement(12, "Subtree that will not change");
|
||||
newTree.OpenElement(13, "Another");
|
||||
newTree.AddText(14, "Text that will not change");
|
||||
newTree.CloseElement();
|
||||
newTree.CloseElement();
|
||||
newTree.CloseElement();
|
||||
|
||||
// Act
|
||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
||||
|
||||
// Assert
|
||||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.StepIn, entry.Type),
|
||||
entry =>
|
||||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.UpdateText, entry.Type);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
},
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.StepOut, entry.Type));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkipsUnmodifiedTrailingSiblings()
|
||||
{
|
||||
// Arrange
|
||||
var oldTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var newTree = new RenderTreeBuilder(new FakeRenderer());
|
||||
var diff = new RenderTreeDiff();
|
||||
oldTree.AddText(10, "text1");
|
||||
oldTree.AddText(11, "text2");
|
||||
oldTree.AddText(12, "text3");
|
||||
oldTree.AddText(13, "text4");
|
||||
newTree.AddText(10, "text1");
|
||||
newTree.AddText(11, "text2modified");
|
||||
newTree.AddText(12, "text3");
|
||||
newTree.AddText(13, "text4");
|
||||
|
||||
// Act
|
||||
var result = diff.ComputeDifference(oldTree.GetNodes(), newTree.GetNodes());
|
||||
|
||||
// Assert
|
||||
Assert.Collection(result,
|
||||
entry => Assert.Equal(RenderTreeDiffEntryType.Continue, entry.Type),
|
||||
entry =>
|
||||
{
|
||||
Assert.Equal(RenderTreeDiffEntryType.UpdateText, entry.Type);
|
||||
Assert.Equal(1, entry.NewTreeIndex);
|
||||
});
|
||||
}
|
||||
|
||||
private class FakeRenderer : Renderer
|
||||
{
|
||||
internal protected override void UpdateDisplay(int componentId, ArraySegment<RenderTreeNode> renderTree)
|
||||
|
|
|
|||
Loading…
Reference in New Issue