Browse Source

[Text] [Optimization] [Alloc] Bidi Pooling

pull/9952/head
Sergey Mikolaitis 3 years ago
parent
commit
ae8e6cc120
  1. 4
      src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs
  2. 10
      src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiAlgorithm.cs
  3. 12
      src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiData.cs
  4. 18
      src/Avalonia.Base/Utilities/ArrayBuilder.cs

4
src/Avalonia.Base/Media/TextFormatting/TextFormatterImpl.cs

@ -159,7 +159,7 @@ namespace Avalonia.Media.TextFormatting
{
var flowDirection = paragraphProperties.FlowDirection;
var drawableTextRuns = new List<DrawableTextRun>();
var biDiData = new BidiData((sbyte)flowDirection);
using var biDiData = new BidiData((sbyte)flowDirection);
foreach (var textRun in textRuns)
{
@ -177,7 +177,7 @@ namespace Avalonia.Media.TextFormatting
}
}
var biDi = new BidiAlgorithm();
using var biDi = new BidiAlgorithm();
biDi.Process(biDiData);

10
src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiAlgorithm.cs

@ -27,7 +27,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// as much as possible.
/// </para>
/// </remarks>
internal sealed class BidiAlgorithm
internal sealed class BidiAlgorithm : IDisposable
{
/// <summary>
/// The original BiDiClass classes as provided by the caller
@ -1714,5 +1714,13 @@ namespace Avalonia.Media.TextFormatting.Unicode
public BidiClass Eos { get; }
}
public void Dispose()
{
_workingClassesBuffer.Dispose();
_resolvedLevelsBuffer.Dispose();
_x9Map.Dispose();
_isolatedRunMapping.Dispose();
}
}
}

12
src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiData.cs

@ -11,7 +11,7 @@ namespace Avalonia.Media.TextFormatting.Unicode
/// Represents a unicode string and all associated attributes
/// for each character required for the bidirectional Unicode algorithm
/// </summary>
internal class BidiData
internal class BidiData : IDisposable
{
private ArrayBuilder<BidiClass> _classes;
private ArrayBuilder<BidiPairedBracketType> _pairedBracketTypes;
@ -181,5 +181,15 @@ namespace Avalonia.Media.TextFormatting.Unicode
return _tempLevelBuffer.Add(length, false);
}
public void Dispose()
{
_classes.Dispose();
_pairedBracketTypes.Dispose();
_pairedBracketValues.Dispose();
_savedClasses.Dispose();
_savedPairedBracketTypes.Dispose();
_tempLevelBuffer.Dispose();
}
}
}

18
src/Avalonia.Base/Utilities/ArrayBuilder.cs

@ -3,6 +3,7 @@
// Ported from: https://github.com/SixLabors/Fonts/
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
namespace Avalonia.Utilities
@ -11,7 +12,7 @@ namespace Avalonia.Utilities
/// A helper type for avoiding allocations while building arrays.
/// </summary>
/// <typeparam name="T">The type of item contained in the array.</typeparam>
internal struct ArrayBuilder<T>
internal struct ArrayBuilder<T> : IDisposable
where T : struct
{
private const int DefaultCapacity = 4;
@ -135,7 +136,7 @@ namespace Avalonia.Utilities
}
// Same expansion algorithm as List<T>.
var newCapacity = length == 0 ? DefaultCapacity : (uint)length * 2u;
var newCapacity = length == 0 ? DefaultCapacity : length * 2;
if (newCapacity > MaxCoreClrArrayLength)
{
@ -144,10 +145,11 @@ namespace Avalonia.Utilities
if (newCapacity < min)
{
newCapacity = (uint)min;
newCapacity = min;
}
var array = new T[newCapacity];
Dispose();
var array = ArrayPool<T>.Shared.Rent(newCapacity);
if (_size > 0)
{
@ -180,5 +182,13 @@ namespace Avalonia.Utilities
/// <returns>The <see cref="ArraySlice{T}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ArraySlice<T> AsSlice(int start, int length) => new ArraySlice<T>(_data!, start, length);
public void Dispose()
{
if (_data != null)
{
ArrayPool<T>.Shared.Return(_data);
}
}
}
}

Loading…
Cancel
Save