diff --git a/src/Markdig/Renderers/RendererBase.cs b/src/Markdig/Renderers/RendererBase.cs
index fe9ce855..fde4b5d3 100644
--- a/src/Markdig/Renderers/RendererBase.cs
+++ b/src/Markdig/Renderers/RendererBase.cs
@@ -3,7 +3,7 @@
// See the license.txt file in the project root for more information.
using System.Runtime.CompilerServices;
-
+using System.Runtime.InteropServices;
using Markdig.Helpers;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
@@ -16,31 +16,64 @@ namespace Markdig.Renderers;
///
public abstract class RendererBase : IMarkdownRenderer
{
- private readonly Dictionary _renderersPerType = new();
+ private const int SubTableCount = 32;
+
+ private readonly struct RendererEntry
+ {
+ public readonly IntPtr Key;
+ public readonly IMarkdownObjectRenderer? Renderer;
+
+ public RendererEntry(IntPtr key, IMarkdownObjectRenderer? renderer)
+ {
+ Key = key;
+ Renderer = renderer;
+ }
+ }
+
+ private readonly RendererEntry[][] _renderersPerType;
+
internal int _childrenDepth = 0;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static IntPtr GetKeyForType(MarkdownObject obj) => Type.GetTypeHandle(obj).Value;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int SubTableIndex(IntPtr key) => (int)((((ulong)key) / 64) & (SubTableCount - 1));
+
///
/// Initializes a new instance of the class.
///
- protected RendererBase() { }
+ protected RendererBase()
+ {
+ var entries = _renderersPerType = new RendererEntry[SubTableCount][];
+ for (int i = 0; i < entries.Length; i++)
+ {
+ entries[i] ??= [];
+ }
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
private IMarkdownObjectRenderer? GetRendererInstance(MarkdownObject obj)
{
- KeyWrapper key = GetKeyForType(obj);
Type objectType = obj.GetType();
+ IMarkdownObjectRenderer? renderer = null;
- for (int i = 0; i < ObjectRenderers.Count; i++)
+ foreach (var potentialRenderer in ObjectRenderers)
{
- var renderer = ObjectRenderers[i];
- if (renderer.Accept(this, objectType))
+ if (potentialRenderer.Accept(this, objectType))
{
- _renderersPerType[key] = renderer;
- return renderer;
+ renderer = potentialRenderer;
+ break;
}
}
- _renderersPerType[key] = null;
- return null;
+ IntPtr key = GetKeyForType(obj);
+
+ ref RendererEntry[] entries = ref _renderersPerType[SubTableIndex(key)];
+ Array.Resize(ref entries, entries.Length + 1);
+ entries[entries.Length - 1] = new RendererEntry(key, renderer);
+
+ return renderer;
}
public ObjectRendererCollection ObjectRenderers { get; } = new();
@@ -77,12 +110,11 @@ public void WriteChildren(ContainerBlock containerBlock)
bool saveIsFirstInContainer = IsFirstInContainer;
bool saveIsLastInContainer = IsLastInContainer;
- var children = containerBlock;
- for (int i = 0; i < children.Count; i++)
+ for (int i = 0; i < containerBlock.Count; i++)
{
IsFirstInContainer = i == 0;
- IsLastInContainer = i + 1 == children.Count;
- Write(children[i]);
+ IsLastInContainer = i + 1 == containerBlock.Count;
+ Write(containerBlock[i]);
}
IsFirstInContainer = saveIsFirstInContainer;
@@ -140,11 +172,27 @@ public void Write(MarkdownObject obj)
// Calls before writing an object
ObjectWriteBefore?.Invoke(this, obj);
- if (!_renderersPerType.TryGetValue(GetKeyForType(obj), out IMarkdownObjectRenderer? renderer))
+ IMarkdownObjectRenderer? renderer = null;
+ IntPtr key = GetKeyForType(obj);
+
+#if NETFRAMEWORK || NETSTANDARD
+ RendererEntry[] renderers = _renderersPerType[SubTableIndex(key)];
+#else
+ RendererEntry[] renderers = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_renderersPerType), SubTableIndex(key));
+#endif
+
+ foreach (RendererEntry entry in renderers)
{
- renderer = GetRendererInstance(obj);
+ if (key == entry.Key)
+ {
+ renderer = entry.Renderer;
+ goto Render;
+ }
}
+ renderer = GetRendererInstance(obj);
+
+ Render:
if (renderer is not null)
{
renderer.Write(this, obj);
@@ -161,24 +209,4 @@ public void Write(MarkdownObject obj)
// Calls after writing an object
ObjectWriteAfter?.Invoke(this, obj);
}
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static KeyWrapper GetKeyForType(MarkdownObject obj)
- {
- IntPtr typeHandle = Type.GetTypeHandle(obj).Value;
- return new KeyWrapper(typeHandle);
- }
-
- private readonly struct KeyWrapper : IEquatable
- {
- public readonly IntPtr Key;
-
- public KeyWrapper(IntPtr key) => Key = key;
-
- public bool Equals(KeyWrapper other) => Key == other.Key;
-
- public override int GetHashCode() => Key.GetHashCode();
-
- public override bool Equals(object? obj) => throw new NotImplementedException();
- }
}
\ No newline at end of file