| File: Matching\Candidate.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. using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing.Patterns; namespace Microsoft.AspNetCore.Routing.Matching; internal readonly struct Candidate { public readonly Endpoint Endpoint; // Used to optimize out operations that modify route values. public readonly CandidateFlags Flags; // Data for creating the RouteValueDictionary. We assign each key its own slot // and we fill the values array with all of the default values. // // Then when we process parameters, we don't need to operate on the RouteValueDictionary // we can just operate on an array, which is much much faster. public readonly KeyValuePair<string, object>[] Slots; // List of parameters to capture. Segment is the segment index, index is the // index into the values array. public readonly (string parameterName, int segmentIndex, int slotIndex)[] Captures; // Catchall parameter to capture (limit one per template). public readonly (string parameterName, int segmentIndex, int slotIndex) CatchAll; // Complex segments are processed in a separate pass because they require a // RouteValueDictionary. public readonly (RoutePatternPathSegment pathSegment, int segmentIndex)[] ComplexSegments; public readonly KeyValuePair<string, IRouteConstraint>[] Constraints; // Score is a sequential integer value that in determines the priority of an Endpoint. // Scores are computed within the context of candidate set, and are meaningless when // applied to endpoints not in the set. // // The score concept boils down the system of comparisons done when ordering Endpoints // to a single value that can be compared easily. This can be defeated by having // int32.MaxValue + 1 endpoints in a single set, but you would have other problems by // that point. // // Score is not part of the Endpoint itself, because it's contextual based on where // the endpoint appears. An Endpoint is often be a member of multiple candidate sets. public readonly int Score; // Used in tests. public Candidate(Endpoint endpoint) { Endpoint = endpoint; Slots = Array.Empty<KeyValuePair<string, object>>(); Captures = Array.Empty<(string parameterName, int segmentIndex, int slotIndex)>(); CatchAll = default; ComplexSegments = Array.Empty<(RoutePatternPathSegment pathSegment, int segmentIndex)>(); Constraints = Array.Empty<KeyValuePair<string, IRouteConstraint>>(); Score = 0; Flags = CandidateFlags.None; } public Candidate( Endpoint endpoint, int score, KeyValuePair<string, object>[] slots, (string parameterName, int segmentIndex, int slotIndex)[] captures, in (string parameterName, int segmentIndex, int slotIndex) catchAll, (RoutePatternPathSegment pathSegment, int segmentIndex)[] complexSegments, KeyValuePair<string, IRouteConstraint>[] constraints) { Endpoint = endpoint; Score = score; Slots = slots; Captures = captures; CatchAll = catchAll; ComplexSegments = complexSegments; Constraints = constraints; Flags = CandidateFlags.None; for (var i = 0; i < slots.Length; i++) { if (slots[i].Key != null) { Flags |= CandidateFlags.HasDefaults; } } if (captures.Length > 0) { Flags |= CandidateFlags.HasCaptures; } if (catchAll.parameterName != null) { Flags |= CandidateFlags.HasCatchAll; } if (complexSegments.Length > 0) { Flags |= CandidateFlags.HasComplexSegments; } if (constraints.Length > 0) { Flags |= CandidateFlags.HasConstraints; } } [Flags] public enum CandidateFlags { None = 0, HasDefaults = 1, HasCaptures = 2, HasCatchAll = 4, HasSlots = HasDefaults | HasCaptures | HasCatchAll, HasComplexSegments = 8, HasConstraints = 16, } }