mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-04 13:54:44 +00:00
Cache StringLine[]s in StringLineGroup with a custom ArrayPool
This commit is contained in:
86
src/Markdig/Helpers/CustomArrayPool.cs
Normal file
86
src/Markdig/Helpers/CustomArrayPool.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.Threading;
|
||||
|
||||
namespace Markdig.Helpers
|
||||
{
|
||||
internal sealed class CustomArrayPool<T>
|
||||
{
|
||||
private sealed class Bucket
|
||||
{
|
||||
private readonly T[][] _buffers;
|
||||
|
||||
private int _index;
|
||||
private int _lock;
|
||||
|
||||
public Bucket(int numberOfBuffers)
|
||||
{
|
||||
_buffers = new T[numberOfBuffers][];
|
||||
}
|
||||
|
||||
public T[] Rent()
|
||||
{
|
||||
T[][] buffers = _buffers;
|
||||
T[] buffer = null;
|
||||
if (Interlocked.CompareExchange(ref _lock, 1, 0) == 0)
|
||||
{
|
||||
int index = _index;
|
||||
if ((uint)index < (uint)buffers.Length)
|
||||
{
|
||||
buffer = buffers[index];
|
||||
buffers[index] = null;
|
||||
_index = index + 1;
|
||||
}
|
||||
Interlocked.Decrement(ref _lock);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void Return(T[] array)
|
||||
{
|
||||
var buffers = _buffers;
|
||||
if (Interlocked.CompareExchange(ref _lock, 1, 0) == 0)
|
||||
{
|
||||
int index = _index - 1;
|
||||
if ((uint)index < (uint)buffers.Length)
|
||||
{
|
||||
buffers[index] = array;
|
||||
_index = index;
|
||||
}
|
||||
Interlocked.Decrement(ref _lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Bucket _bucket4, _bucket8, _bucket16, _bucket32;
|
||||
|
||||
public CustomArrayPool(int size4, int size8, int size16, int size32)
|
||||
{
|
||||
_bucket4 = new Bucket(size4);
|
||||
_bucket8 = new Bucket(size8);
|
||||
_bucket16 = new Bucket(size16);
|
||||
_bucket32 = new Bucket(size32);
|
||||
}
|
||||
|
||||
private Bucket SelectBucket(int length)
|
||||
{
|
||||
switch (length)
|
||||
{
|
||||
case 4: return _bucket4;
|
||||
case 8: return _bucket8;
|
||||
case 16: return _bucket16;
|
||||
case 32: return _bucket32;
|
||||
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public T[] Rent(int length)
|
||||
{
|
||||
return SelectBucket(length)?.Rent() ?? new T[length];
|
||||
}
|
||||
|
||||
public void Return(T[] array)
|
||||
{
|
||||
SelectBucket(array.Length)?.Return(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using System.Text;
|
||||
namespace Markdig.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for StringBuilder with <see cref="StringSlice"/>
|
||||
/// Extensions for StringBuilder
|
||||
/// </summary>
|
||||
public static class StringBuilderExtensions
|
||||
{
|
||||
@@ -19,5 +19,12 @@ namespace Markdig.Helpers
|
||||
{
|
||||
return builder.Append(slice.Text, slice.Start, slice.Length);
|
||||
}
|
||||
|
||||
internal static string GetStringAndReset(this StringBuilder builder)
|
||||
{
|
||||
string text = builder.ToString();
|
||||
builder.Length = 0;
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,28 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Markdig.Extensions.Tables;
|
||||
|
||||
namespace Markdig.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A group of <see cref="StringLine"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="System.Collections.IEnumerable" />
|
||||
/// <seealso cref="IEnumerable" />
|
||||
public struct StringLineGroup : IEnumerable
|
||||
{
|
||||
// Feel free to change these numbers if you see a positive change
|
||||
private static readonly CustomArrayPool<StringLine> _pool
|
||||
= new CustomArrayPool<StringLine>(512, 386, 128, 64);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StringLineGroup"/> class.
|
||||
/// </summary>
|
||||
/// <param name="capacity"></param>
|
||||
public StringLineGroup(int capacity)
|
||||
public StringLineGroup(int capacity, bool willRelease = false)
|
||||
{
|
||||
if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity));
|
||||
Lines = new StringLine[capacity];
|
||||
Lines = _pool.Rent(willRelease ? Math.Max(8, capacity) : capacity);
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
@@ -183,14 +185,24 @@ namespace Markdig.Helpers
|
||||
|
||||
private void IncreaseCapacity()
|
||||
{
|
||||
var newItems = new StringLine[Lines.Length * 2];
|
||||
var newItems = _pool.Rent(Lines.Length * 2);
|
||||
if (Count > 0)
|
||||
{
|
||||
Array.Copy(Lines, 0, newItems, 0, Count);
|
||||
Array.Clear(Lines, 0, Count);
|
||||
}
|
||||
_pool.Return(Lines);
|
||||
Lines = newItems;
|
||||
}
|
||||
|
||||
internal void Release()
|
||||
{
|
||||
Array.Clear(Lines, 0, Count);
|
||||
_pool.Return(Lines);
|
||||
Lines = null;
|
||||
Count = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The iterator used to iterate other the lines.
|
||||
/// </summary>
|
||||
@@ -207,7 +219,7 @@ namespace Markdig.Helpers
|
||||
_offset = -1;
|
||||
SliceIndex = 0;
|
||||
CurrentChar = '\0';
|
||||
End = -2;
|
||||
End = -2;
|
||||
for (int i = 0; i < lines.Count; i++)
|
||||
{
|
||||
End += lines.Lines[i].Slice.Length + 1; // Add chars
|
||||
|
||||
@@ -500,6 +500,11 @@ namespace Markdig.Parsers
|
||||
if (!block.Parser.Close(this, block))
|
||||
{
|
||||
block.Parent?.Remove(block);
|
||||
|
||||
if (block is LeafBlock leaf)
|
||||
{
|
||||
leaf.Lines.Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace Markdig.Parsers
|
||||
previousLineIndexForSliceOffset = 0;
|
||||
lineOffsets.Clear();
|
||||
var text = leafBlock.Lines.ToSlice(lineOffsets);
|
||||
leafBlock.Lines = new StringLineGroup();
|
||||
leafBlock.Lines.Release();
|
||||
|
||||
int previousStart = -1;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using System.Diagnostics;
|
||||
@@ -51,7 +51,7 @@ namespace Markdig.Syntax
|
||||
{
|
||||
if (Lines.Lines == null)
|
||||
{
|
||||
Lines = new StringLineGroup(4);
|
||||
Lines = new StringLineGroup(4, ProcessInlines);
|
||||
}
|
||||
|
||||
var stringLine = new StringLine(ref slice, line, column, sourceLinePosition);
|
||||
@@ -64,12 +64,9 @@ namespace Markdig.Syntax
|
||||
{
|
||||
// We need to expand tabs to spaces
|
||||
var builder = StringBuilderCache.Local();
|
||||
for (int i = column; i < CharHelper.AddTab(column); i++)
|
||||
{
|
||||
builder.Append(' ');
|
||||
}
|
||||
builder.Append(' ', CharHelper.AddTab(column) - column);
|
||||
builder.Append(slice.Text, slice.Start + 1, slice.Length - 1);
|
||||
stringLine.Slice = new StringSlice(builder.ToString());
|
||||
stringLine.Slice = new StringSlice(builder.GetStringAndReset());
|
||||
Lines.Add(ref stringLine);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user