aspnetcore/src/Microsoft.AspNetCore.Routing/Matching/DfaNode.cs

92 lines
2.8 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing.Matching
{
// Intermediate data structure used to build the DFA. Not used at runtime.
[DebuggerDisplay("{DebuggerToString(),nq}")]
internal class DfaNode
{
public DfaNode()
{
Literals = new Dictionary<string, DfaNode>(StringComparer.OrdinalIgnoreCase);
Matches = new List<Endpoint>();
PolicyEdges = new Dictionary<object, DfaNode>();
}
// The depth of the node. The depth indicates the number of segments
// that must be processed to arrive at this node.
//
// This value is not computed for Policy nodes and will be set to -1.
public int PathDepth { get; set; } = -1;
// Just for diagnostics and debugging
public string Label { get; set; }
public List<Endpoint> Matches { get; }
public Dictionary<string, DfaNode> Literals { get; }
public DfaNode Parameters { get; set; }
public DfaNode CatchAll { get; set; }
public INodeBuilderPolicy NodeBuilder { get; set; }
public Dictionary<object, DfaNode> PolicyEdges { get; }
public void Visit(Action<DfaNode> visitor)
{
foreach (var kvp in Literals)
{
kvp.Value.Visit(visitor);
}
// Break cycles
if (Parameters != null && !ReferenceEquals(this, Parameters))
{
Parameters.Visit(visitor);
}
// Break cycles
if (CatchAll != null && !ReferenceEquals(this, CatchAll))
{
CatchAll.Visit(visitor);
}
foreach (var kvp in PolicyEdges)
{
kvp.Value.Visit(visitor);
}
visitor(this);
}
private string DebuggerToString()
{
var builder = new StringBuilder();
builder.Append(Label);
builder.Append(" d:");
builder.Append(PathDepth);
builder.Append(" m:");
builder.Append(Matches.Count);
builder.Append(" c: ");
builder.Append(string.Join(", ", Literals.Select(kvp => $"{kvp.Key}->({FormatNode(kvp.Value)})")));
return builder.ToString();
// DfaNodes can be self-referential, don't traverse cycles.
string FormatNode(DfaNode other)
{
return ReferenceEquals(this, other) ? "this" : other.DebuggerToString();
}
}
}
}