Improve XML documentation coverage across core server components and refresh checker reports.
This commit is contained in:
@@ -6,24 +6,87 @@ namespace NATS.Server.Internal.SubjectTree;
|
||||
/// </summary>
|
||||
internal interface INode
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets whether this node is a terminal subject node that directly stores a subscription value.
|
||||
/// </summary>
|
||||
bool IsLeaf { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets structural metadata for branch nodes, including compressed path prefix and child count.
|
||||
/// </summary>
|
||||
NodeMeta? Base { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the compressed path fragment represented by this node.
|
||||
/// </summary>
|
||||
/// <param name="pre">Subject bytes shared by all descendants below this node.</param>
|
||||
void SetPrefix(ReadOnlySpan<byte> pre);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a child edge for the next subject byte in the adaptive radix tree.
|
||||
/// </summary>
|
||||
/// <param name="c">Subject byte used to route lookups to the child node.</param>
|
||||
/// <param name="n">Child node that owns the remaining subject suffix for this edge.</param>
|
||||
void AddChild(byte c, INode n);
|
||||
/// <summary>
|
||||
/// Returns the child node for the given key byte, or null if not found.
|
||||
/// The returned wrapper allows in-place replacement of the child reference.
|
||||
/// </summary>
|
||||
/// <param name="c">Subject byte to look up in the node's child index.</param>
|
||||
ChildRef? FindChild(byte c);
|
||||
|
||||
/// <summary>
|
||||
/// Removes the child edge for the provided subject byte.
|
||||
/// </summary>
|
||||
/// <param name="c">Subject byte whose child mapping should be removed.</param>
|
||||
void DeleteChild(byte c);
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether this node has reached its capacity and must grow to the next node shape.
|
||||
/// </summary>
|
||||
bool IsFull { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Expands this node to a larger branching factor to accept more distinct subject bytes.
|
||||
/// </summary>
|
||||
INode Grow();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to shrink this node to a smaller branching representation when sparse.
|
||||
/// </summary>
|
||||
INode? Shrink();
|
||||
|
||||
/// <summary>
|
||||
/// Matches a subject split into tokens against this node's compressed path fragment.
|
||||
/// </summary>
|
||||
/// <param name="parts">Remaining subject tokens to match from this node downward.</param>
|
||||
/// <returns>The remaining tokens after consuming this node, and whether the fragment matched.</returns>
|
||||
(ReadOnlyMemory<byte>[] RemainingParts, bool Matched) MatchParts(ReadOnlyMemory<byte>[] parts);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a short node kind name used by diagnostics and debugging tools.
|
||||
/// </summary>
|
||||
string Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Iterates child nodes until the callback returns <see langword="false" />.
|
||||
/// </summary>
|
||||
/// <param name="f">Callback invoked for each child node in this branch.</param>
|
||||
void Iter(Func<INode, bool> f);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current child nodes for traversal or inspection.
|
||||
/// </summary>
|
||||
INode?[] Children();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of active child edges in this node.
|
||||
/// </summary>
|
||||
ushort NumChildren { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the compressed path bytes represented by this node.
|
||||
/// </summary>
|
||||
byte[] Path();
|
||||
}
|
||||
|
||||
@@ -33,6 +96,9 @@ internal interface INode
|
||||
/// </summary>
|
||||
internal sealed class ChildRef(Func<INode?> getter, Action<INode?> setter)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or replaces the child node reference stored at a specific branch slot.
|
||||
/// </summary>
|
||||
public INode? Node
|
||||
{
|
||||
get => getter();
|
||||
@@ -45,7 +111,14 @@ internal sealed class ChildRef(Func<INode?> getter, Action<INode?> setter)
|
||||
/// </summary>
|
||||
internal sealed class NodeMeta
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the compressed subject prefix shared by descendants of this branch node.
|
||||
/// </summary>
|
||||
public byte[] Prefix { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of child edges currently populated for this branch node.
|
||||
/// </summary>
|
||||
public ushort Size { get; set; }
|
||||
}
|
||||
|
||||
@@ -60,28 +133,51 @@ internal sealed class Leaf<T> : INode
|
||||
public T Value;
|
||||
public byte[] Suffix;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a terminal subject-tree node that stores a value for an exact suffix match.
|
||||
/// </summary>
|
||||
/// <param name="suffix">Remaining subject bytes that must match to resolve this leaf.</param>
|
||||
/// <param name="value">Subscription payload or state associated with the matched subject.</param>
|
||||
public Leaf(ReadOnlySpan<byte> suffix, T value)
|
||||
{
|
||||
Value = value;
|
||||
Suffix = Parts.CopyBytes(suffix);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLeaf => true;
|
||||
/// <inheritdoc />
|
||||
public NodeMeta? Base => null;
|
||||
/// <inheritdoc />
|
||||
public bool IsFull => true;
|
||||
/// <inheritdoc />
|
||||
public ushort NumChildren => 0;
|
||||
/// <inheritdoc />
|
||||
public string Kind => "LEAF";
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the provided subject bytes exactly match this leaf suffix.
|
||||
/// </summary>
|
||||
/// <param name="subject">Subject bytes remaining after traversing parent branch prefixes.</param>
|
||||
/// <returns><see langword="true" /> when the subject resolves to this exact leaf.</returns>
|
||||
public bool Match(ReadOnlySpan<byte> subject) => subject.SequenceEqual(Suffix);
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the stored suffix when leaf content is split or merged during tree updates.
|
||||
/// </summary>
|
||||
/// <param name="suffix">New exact-match suffix bytes for this leaf.</param>
|
||||
public void SetSuffix(ReadOnlySpan<byte> suffix) => Suffix = Parts.CopyBytes(suffix);
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte[] Path() => Suffix;
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode?[] Children() => [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Iter(Func<INode, bool> f) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public (ReadOnlyMemory<byte>[] RemainingParts, bool Matched) MatchParts(ReadOnlyMemory<byte>[] parts)
|
||||
=> Parts.MatchPartsAgainstFragment(parts, Suffix);
|
||||
|
||||
@@ -108,23 +204,35 @@ internal sealed class Node4 : INode
|
||||
private readonly byte[] _key = new byte[4];
|
||||
internal readonly NodeMeta Meta = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a small branch node for up to four subject-byte fan-out edges.
|
||||
/// </summary>
|
||||
/// <param name="prefix">Compressed subject prefix represented by this branch.</param>
|
||||
public Node4(ReadOnlySpan<byte> prefix)
|
||||
{
|
||||
SetPrefix(prefix);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLeaf => false;
|
||||
/// <inheritdoc />
|
||||
public NodeMeta? Base => Meta;
|
||||
/// <inheritdoc />
|
||||
public ushort NumChildren => Meta.Size;
|
||||
/// <inheritdoc />
|
||||
public bool IsFull => Meta.Size >= 4;
|
||||
/// <inheritdoc />
|
||||
public string Kind => "NODE4";
|
||||
/// <inheritdoc />
|
||||
public byte[] Path() => Meta.Prefix;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetPrefix(ReadOnlySpan<byte> pre)
|
||||
{
|
||||
Meta.Prefix = pre.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddChild(byte c, INode n)
|
||||
{
|
||||
if (Meta.Size >= 4) throw new InvalidOperationException("node4 full!");
|
||||
@@ -133,6 +241,7 @@ internal sealed class Node4 : INode
|
||||
Meta.Size++;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ChildRef? FindChild(byte c)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -146,6 +255,7 @@ internal sealed class Node4 : INode
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteChild(byte c)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -171,6 +281,7 @@ internal sealed class Node4 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode Grow()
|
||||
{
|
||||
var nn = new Node10(Meta.Prefix);
|
||||
@@ -181,12 +292,14 @@ internal sealed class Node4 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode? Shrink()
|
||||
{
|
||||
if (Meta.Size == 1) return _child[0];
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Iter(Func<INode, bool> f)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -195,6 +308,7 @@ internal sealed class Node4 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode?[] Children()
|
||||
{
|
||||
var result = new INode?[Meta.Size];
|
||||
@@ -202,6 +316,7 @@ internal sealed class Node4 : INode
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public (ReadOnlyMemory<byte>[] RemainingParts, bool Matched) MatchParts(ReadOnlyMemory<byte>[] parts)
|
||||
=> Parts.MatchPartsAgainstFragment(parts, Meta.Prefix);
|
||||
}
|
||||
@@ -220,23 +335,35 @@ internal sealed class Node10 : INode
|
||||
private readonly byte[] _key = new byte[10];
|
||||
internal readonly NodeMeta Meta = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a branch node tuned for numeric token fan-out, common in ordered stream subjects.
|
||||
/// </summary>
|
||||
/// <param name="prefix">Compressed subject prefix represented by this branch.</param>
|
||||
public Node10(ReadOnlySpan<byte> prefix)
|
||||
{
|
||||
SetPrefix(prefix);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLeaf => false;
|
||||
/// <inheritdoc />
|
||||
public NodeMeta? Base => Meta;
|
||||
/// <inheritdoc />
|
||||
public ushort NumChildren => Meta.Size;
|
||||
/// <inheritdoc />
|
||||
public bool IsFull => Meta.Size >= 10;
|
||||
/// <inheritdoc />
|
||||
public string Kind => "NODE10";
|
||||
/// <inheritdoc />
|
||||
public byte[] Path() => Meta.Prefix;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetPrefix(ReadOnlySpan<byte> pre)
|
||||
{
|
||||
Meta.Prefix = pre.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddChild(byte c, INode n)
|
||||
{
|
||||
if (Meta.Size >= 10) throw new InvalidOperationException("node10 full!");
|
||||
@@ -245,6 +372,7 @@ internal sealed class Node10 : INode
|
||||
Meta.Size++;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ChildRef? FindChild(byte c)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -258,6 +386,7 @@ internal sealed class Node10 : INode
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteChild(byte c)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -283,6 +412,7 @@ internal sealed class Node10 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode Grow()
|
||||
{
|
||||
var nn = new Node16(Meta.Prefix);
|
||||
@@ -293,6 +423,7 @@ internal sealed class Node10 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode? Shrink()
|
||||
{
|
||||
if (Meta.Size > 4) return null;
|
||||
@@ -304,6 +435,7 @@ internal sealed class Node10 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Iter(Func<INode, bool> f)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -312,6 +444,7 @@ internal sealed class Node10 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode?[] Children()
|
||||
{
|
||||
var result = new INode?[Meta.Size];
|
||||
@@ -319,6 +452,7 @@ internal sealed class Node10 : INode
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public (ReadOnlyMemory<byte>[] RemainingParts, bool Matched) MatchParts(ReadOnlyMemory<byte>[] parts)
|
||||
=> Parts.MatchPartsAgainstFragment(parts, Meta.Prefix);
|
||||
}
|
||||
@@ -337,23 +471,35 @@ internal sealed class Node16 : INode
|
||||
private readonly byte[] _key = new byte[16];
|
||||
internal readonly NodeMeta Meta = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a medium branch node for moderate subject fan-out without index indirection.
|
||||
/// </summary>
|
||||
/// <param name="prefix">Compressed subject prefix represented by this branch.</param>
|
||||
public Node16(ReadOnlySpan<byte> prefix)
|
||||
{
|
||||
SetPrefix(prefix);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLeaf => false;
|
||||
/// <inheritdoc />
|
||||
public NodeMeta? Base => Meta;
|
||||
/// <inheritdoc />
|
||||
public ushort NumChildren => Meta.Size;
|
||||
/// <inheritdoc />
|
||||
public bool IsFull => Meta.Size >= 16;
|
||||
/// <inheritdoc />
|
||||
public string Kind => "NODE16";
|
||||
/// <inheritdoc />
|
||||
public byte[] Path() => Meta.Prefix;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetPrefix(ReadOnlySpan<byte> pre)
|
||||
{
|
||||
Meta.Prefix = pre.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddChild(byte c, INode n)
|
||||
{
|
||||
if (Meta.Size >= 16) throw new InvalidOperationException("node16 full!");
|
||||
@@ -362,6 +508,7 @@ internal sealed class Node16 : INode
|
||||
Meta.Size++;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ChildRef? FindChild(byte c)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -375,6 +522,7 @@ internal sealed class Node16 : INode
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteChild(byte c)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -400,6 +548,7 @@ internal sealed class Node16 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode Grow()
|
||||
{
|
||||
var nn = new Node48(Meta.Prefix);
|
||||
@@ -410,6 +559,7 @@ internal sealed class Node16 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode? Shrink()
|
||||
{
|
||||
if (Meta.Size > 10) return null;
|
||||
@@ -421,6 +571,7 @@ internal sealed class Node16 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Iter(Func<INode, bool> f)
|
||||
{
|
||||
for (int i = 0; i < Meta.Size; i++)
|
||||
@@ -429,6 +580,7 @@ internal sealed class Node16 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode?[] Children()
|
||||
{
|
||||
var result = new INode?[Meta.Size];
|
||||
@@ -436,6 +588,7 @@ internal sealed class Node16 : INode
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public (ReadOnlyMemory<byte>[] RemainingParts, bool Matched) MatchParts(ReadOnlyMemory<byte>[] parts)
|
||||
=> Parts.MatchPartsAgainstFragment(parts, Meta.Prefix);
|
||||
}
|
||||
@@ -454,23 +607,35 @@ internal sealed class Node48 : INode
|
||||
internal readonly byte[] Key = new byte[256]; // 1-indexed: 0 means no entry
|
||||
internal readonly NodeMeta Meta = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a high fan-out branch node that trades memory for faster byte-key lookups.
|
||||
/// </summary>
|
||||
/// <param name="prefix">Compressed subject prefix represented by this branch.</param>
|
||||
public Node48(ReadOnlySpan<byte> prefix)
|
||||
{
|
||||
SetPrefix(prefix);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLeaf => false;
|
||||
/// <inheritdoc />
|
||||
public NodeMeta? Base => Meta;
|
||||
/// <inheritdoc />
|
||||
public ushort NumChildren => Meta.Size;
|
||||
/// <inheritdoc />
|
||||
public bool IsFull => Meta.Size >= 48;
|
||||
/// <inheritdoc />
|
||||
public string Kind => "NODE48";
|
||||
/// <inheritdoc />
|
||||
public byte[] Path() => Meta.Prefix;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetPrefix(ReadOnlySpan<byte> pre)
|
||||
{
|
||||
Meta.Prefix = pre.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddChild(byte c, INode n)
|
||||
{
|
||||
if (Meta.Size >= 48) throw new InvalidOperationException("node48 full!");
|
||||
@@ -479,6 +644,7 @@ internal sealed class Node48 : INode
|
||||
Meta.Size++;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ChildRef? FindChild(byte c)
|
||||
{
|
||||
var i = Key[c];
|
||||
@@ -487,6 +653,7 @@ internal sealed class Node48 : INode
|
||||
return new ChildRef(() => Child[idx], v => Child[idx] = v);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteChild(byte c)
|
||||
{
|
||||
var i = Key[c];
|
||||
@@ -510,6 +677,7 @@ internal sealed class Node48 : INode
|
||||
Meta.Size--;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode Grow()
|
||||
{
|
||||
var nn = new Node256(Meta.Prefix);
|
||||
@@ -524,6 +692,7 @@ internal sealed class Node48 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode? Shrink()
|
||||
{
|
||||
if (Meta.Size > 16) return null;
|
||||
@@ -539,6 +708,7 @@ internal sealed class Node48 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Iter(Func<INode, bool> f)
|
||||
{
|
||||
foreach (var c in Child)
|
||||
@@ -547,6 +717,7 @@ internal sealed class Node48 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode?[] Children()
|
||||
{
|
||||
var result = new INode?[Meta.Size];
|
||||
@@ -554,6 +725,7 @@ internal sealed class Node48 : INode
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public (ReadOnlyMemory<byte>[] RemainingParts, bool Matched) MatchParts(ReadOnlyMemory<byte>[] parts)
|
||||
=> Parts.MatchPartsAgainstFragment(parts, Meta.Prefix);
|
||||
}
|
||||
@@ -571,35 +743,49 @@ internal sealed class Node256 : INode
|
||||
internal readonly INode?[] Child = new INode?[256];
|
||||
internal readonly NodeMeta Meta = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the maximum fan-out branch node with direct byte-to-child indexing.
|
||||
/// </summary>
|
||||
/// <param name="prefix">Compressed subject prefix represented by this branch.</param>
|
||||
public Node256(ReadOnlySpan<byte> prefix)
|
||||
{
|
||||
SetPrefix(prefix);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLeaf => false;
|
||||
/// <inheritdoc />
|
||||
public NodeMeta? Base => Meta;
|
||||
/// <inheritdoc />
|
||||
public ushort NumChildren => Meta.Size;
|
||||
/// <inheritdoc />
|
||||
public bool IsFull => false; // node256 is never full
|
||||
/// <inheritdoc />
|
||||
public string Kind => "NODE256";
|
||||
/// <inheritdoc />
|
||||
public byte[] Path() => Meta.Prefix;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetPrefix(ReadOnlySpan<byte> pre)
|
||||
{
|
||||
Meta.Prefix = pre.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AddChild(byte c, INode n)
|
||||
{
|
||||
Child[c] = n;
|
||||
Meta.Size++;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ChildRef? FindChild(byte c)
|
||||
{
|
||||
if (Child[c] == null) return null;
|
||||
return new ChildRef(() => Child[c], v => Child[c] = v);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DeleteChild(byte c)
|
||||
{
|
||||
if (Child[c] != null)
|
||||
@@ -609,8 +795,10 @@ internal sealed class Node256 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode Grow() => throw new InvalidOperationException("grow can not be called on node256");
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode? Shrink()
|
||||
{
|
||||
if (Meta.Size > 48) return null;
|
||||
@@ -625,6 +813,7 @@ internal sealed class Node256 : INode
|
||||
return nn;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Iter(Func<INode, bool> f)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
@@ -636,12 +825,14 @@ internal sealed class Node256 : INode
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public INode?[] Children()
|
||||
{
|
||||
// Return the full 256 array, same as Go
|
||||
return (INode?[])Child.Clone();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public (ReadOnlyMemory<byte>[] RemainingParts, bool Matched) MatchParts(ReadOnlyMemory<byte>[] parts)
|
||||
=> Parts.MatchPartsAgainstFragment(parts, Meta.Prefix);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user