| File: Matching\DfaNode.cs | Web Access |
| Project: src\aspnetcore\src\Http\Routing\src\Microsoft.AspNetCore.Routing.csproj (Microsoft.AspNetCore.Routing) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable 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 sealed class 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; private set; } public Dictionary<string, DfaNode> Literals { get; private set; } public DfaNode Parameters { get; set; } public DfaNode CatchAll { get; set; } public INodeBuilderPolicy NodeBuilder { get; set; } public Dictionary<object, DfaNode> PolicyEdges { get; private set; } public void AddPolicyEdge(object state, DfaNode node) { if (PolicyEdges == null) { PolicyEdges = new Dictionary<object, DfaNode>(); } PolicyEdges.Add(state, node); } public void AddLiteral(string literal, DfaNode node) { if (Literals == null) { Literals = new Dictionary<string, DfaNode>(StringComparer.OrdinalIgnoreCase); } Literals.Add(literal, node); } public void AddMatch(Endpoint endpoint) { if (Matches == null) { Matches = new List<Endpoint>(); } Matches.Add(endpoint); } public void AddMatches(IEnumerable<Endpoint> endpoints) { if (Matches == null) { Matches = new List<Endpoint>(endpoints); } else { Matches.AddRange(endpoints); } } public void Visit(Action<DfaNode> visitor) { if (Literals != null) { 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); } if (PolicyEdges != null) { 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 ?? 0); builder.Append(" c: "); if (Literals != null) { builder.AppendJoin(", ", 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(); } } }