mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-17 17:32:50 +08:00
Adds a segment builder for merging multiple segments
When merging a large amount of segments together we were doing a tremendous amount of allocation especially related to strings due to concatination. This adds an internal SegmentBuilder that uses a stringbuilder for building up the text rather than creating a new instance and doing a concat operation for each segment.
This commit is contained in:
parent
64f444114a
commit
ad23855b0a
@ -449,36 +449,36 @@ namespace Spectre.Console.Rendering
|
|||||||
|
|
||||||
var result = new List<Segment>();
|
var result = new List<Segment>();
|
||||||
|
|
||||||
var previous = (Segment?)null;
|
var segmentBuilder = (SegmentBuilder?)null;
|
||||||
foreach (var segment in segments)
|
foreach (var segment in segments)
|
||||||
{
|
{
|
||||||
if (previous == null)
|
if (segmentBuilder == null)
|
||||||
{
|
{
|
||||||
previous = segment;
|
segmentBuilder = new SegmentBuilder(segment);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Both control codes?
|
// Both control codes?
|
||||||
if (segment.IsControlCode && previous.IsControlCode)
|
if (segment.IsControlCode && segmentBuilder.IsControlCode())
|
||||||
{
|
{
|
||||||
previous = Control(previous.Text + segment.Text);
|
segmentBuilder.Append(segment.Text);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same style?
|
// Same style?
|
||||||
if (previous.Style.Equals(segment.Style) && !previous.IsLineBreak && !previous.IsControlCode)
|
if (segmentBuilder.StyleEquals(segment.Style) && !segmentBuilder.IsLineBreak() && !segmentBuilder.IsControlCode())
|
||||||
{
|
{
|
||||||
previous = new Segment(previous.Text + segment.Text, previous.Style);
|
segmentBuilder.Append(segment.Text);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Add(previous);
|
result.Add(segmentBuilder.Build());
|
||||||
previous = segment;
|
segmentBuilder.Reset(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (previous != null)
|
if (segmentBuilder != null)
|
||||||
{
|
{
|
||||||
result.Add(previous);
|
result.Add(segmentBuilder.Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -579,5 +579,39 @@ namespace Spectre.Console.Rendering
|
|||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SegmentBuilder
|
||||||
|
{
|
||||||
|
private readonly StringBuilder _textBuilder = new();
|
||||||
|
private Segment _originalSegment;
|
||||||
|
|
||||||
|
public SegmentBuilder(Segment originalSegment)
|
||||||
|
{
|
||||||
|
_originalSegment = originalSegment;
|
||||||
|
Reset(originalSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsControlCode() => _originalSegment.IsControlCode;
|
||||||
|
public bool IsLineBreak() => _originalSegment.IsLineBreak;
|
||||||
|
public bool StyleEquals(Style segmentStyle) => segmentStyle.Equals(_originalSegment.Style);
|
||||||
|
|
||||||
|
public void Append(string text)
|
||||||
|
{
|
||||||
|
_textBuilder.Append(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Segment Build()
|
||||||
|
{
|
||||||
|
return new Segment(_textBuilder.ToString(), _originalSegment.Style, _originalSegment.IsLineBreak,
|
||||||
|
_originalSegment.IsControlCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset(Segment segment)
|
||||||
|
{
|
||||||
|
_textBuilder.Clear();
|
||||||
|
_textBuilder.Append(segment.Text);
|
||||||
|
_originalSegment = segment;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user