From e47fbbab9eb3602ced11d050ea3d6de5e8e0bacf Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Sun, 14 Apr 2019 18:57:01 -0700 Subject: [PATCH] Slim down CandidateSet --- src/Http/Routing/src/Matching/CandidateSet.cs | 182 ++---------------- .../src/Matching/DefaultEndpointSelector.cs | 2 +- 2 files changed, 14 insertions(+), 170 deletions(-) diff --git a/src/Http/Routing/src/Matching/CandidateSet.cs b/src/Http/Routing/src/Matching/CandidateSet.cs index 42392268fa..6f4ffb2197 100644 --- a/src/Http/Routing/src/Matching/CandidateSet.cs +++ b/src/Http/Routing/src/Matching/CandidateSet.cs @@ -18,19 +18,7 @@ namespace Microsoft.AspNetCore.Routing.Matching { private const int BitVectorSize = 32; - // Cannot be readonly because we need to modify it in place. - private BitVector32 _validity; - private readonly BitArray _largeCapactityValidity; - - // We inline storage for 4 candidates here to avoid allocations in common - // cases. There's no real reason why 4 is important, it just seemed like - // a plausible number. - private CandidateState _state0; - private CandidateState _state1; - private CandidateState _state2; - private CandidateState _state3; - - private CandidateState[] _additionalCandidates; + private readonly CandidateState[] _candidates; /// /// @@ -69,56 +57,10 @@ namespace Microsoft.AspNetCore.Routing.Matching Count = endpoints.Length; - switch (endpoints.Length) + _candidates = new CandidateState[endpoints.Length]; + for (var i = 0; i < endpoints.Length; i++) { - case 0: - return; - - case 1: - _state0 = new CandidateState(endpoints[0], values[0], scores[0]); - break; - - case 2: - _state0 = new CandidateState(endpoints[0], values[0], scores[0]); - _state1 = new CandidateState(endpoints[1], values[1], scores[1]); - break; - - case 3: - _state0 = new CandidateState(endpoints[0], values[0], scores[0]); - _state1 = new CandidateState(endpoints[1], values[1], scores[1]); - _state2 = new CandidateState(endpoints[2], values[2], scores[2]); - break; - - case 4: - _state0 = new CandidateState(endpoints[0], values[0], scores[0]); - _state1 = new CandidateState(endpoints[1], values[1], scores[1]); - _state2 = new CandidateState(endpoints[2], values[2], scores[2]); - _state3 = new CandidateState(endpoints[3], values[3], scores[3]); - break; - - default: - _state0 = new CandidateState(endpoints[0], values[0], scores[0]); - _state1 = new CandidateState(endpoints[1], values[1], scores[1]); - _state2 = new CandidateState(endpoints[2], values[2], scores[2]); - _state3 = new CandidateState(endpoints[3], values[3], scores[3]); - - _additionalCandidates = new CandidateState[endpoints.Length - 4]; - for (var i = 4; i < endpoints.Length; i++) - { - _additionalCandidates[i - 4] = new CandidateState(endpoints[i], values[i], scores[i]); - } - break; - } - - // Initialize validity to valid by default. - if (Count < BitVectorSize) - { - // Sets the bit for each candidate that exists (bits > Count will be 0). - _validity = new BitVector32(unchecked((int)~(0xFFFFFFFFu << Count))); - } - else - { - _largeCapactityValidity = new BitArray(Count, defaultValue: true); + _candidates[i] = new CandidateState(endpoints[i], values[i], scores[i]); } } @@ -126,56 +68,10 @@ namespace Microsoft.AspNetCore.Routing.Matching { Count = candidates.Length; - switch (candidates.Length) + _candidates = new CandidateState[candidates.Length]; + for (var i = 0; i < candidates.Length; i++) { - case 0: - return; - - case 1: - _state0 = new CandidateState(candidates[0].Endpoint, candidates[0].Score); - break; - - case 2: - _state0 = new CandidateState(candidates[0].Endpoint, candidates[0].Score); - _state1 = new CandidateState(candidates[1].Endpoint, candidates[1].Score); - break; - - case 3: - _state0 = new CandidateState(candidates[0].Endpoint, candidates[0].Score); - _state1 = new CandidateState(candidates[1].Endpoint, candidates[1].Score); - _state2 = new CandidateState(candidates[2].Endpoint, candidates[2].Score); - break; - - case 4: - _state0 = new CandidateState(candidates[0].Endpoint, candidates[0].Score); - _state1 = new CandidateState(candidates[1].Endpoint, candidates[1].Score); - _state2 = new CandidateState(candidates[2].Endpoint, candidates[2].Score); - _state3 = new CandidateState(candidates[3].Endpoint, candidates[3].Score); - break; - - default: - _state0 = new CandidateState(candidates[0].Endpoint, candidates[0].Score); - _state1 = new CandidateState(candidates[1].Endpoint, candidates[1].Score); - _state2 = new CandidateState(candidates[2].Endpoint, candidates[2].Score); - _state3 = new CandidateState(candidates[3].Endpoint, candidates[3].Score); - - _additionalCandidates = new CandidateState[candidates.Length - 4]; - for (var i = 4; i < candidates.Length; i++) - { - _additionalCandidates[i - 4] = new CandidateState(candidates[i].Endpoint, candidates[i].Score); - } - break; - } - - // Initialize validity to valid by default. - if (Count < BitVectorSize) - { - // Sets the bit for each candidate that exists (bits > Count will be 0). - _validity = new BitVector32(unchecked((int)~(0xFFFFFFFFu << Count))); - } - else - { - _largeCapactityValidity = new BitArray(Count, defaultValue: true); + _candidates[i] = new CandidateState(candidates[i].Endpoint, candidates[i].Score); } } @@ -207,23 +103,7 @@ namespace Microsoft.AspNetCore.Routing.Matching ThrowIndexArgumentOutOfRangeException(); } - switch (index) - { - case 0: - return ref _state0; - - case 1: - return ref _state1; - - case 2: - return ref _state2; - - case 3: - return ref _state3; - - default: - return ref _additionalCandidates[index - 4]; - } + return ref _candidates[index]; } } @@ -233,7 +113,7 @@ namespace Microsoft.AspNetCore.Routing.Matching /// /// The candidate index. /// - /// true if the candidate at position is considered value + /// true if the candidate at position is considered valid /// for the current request, otherwise false. /// public bool IsValidCandidate(int index) @@ -244,15 +124,7 @@ namespace Microsoft.AspNetCore.Routing.Matching ThrowIndexArgumentOutOfRangeException(); } - if (Count < BitVectorSize) - { - // Get the n-th bit - return _validity[0x00000001 << index]; - } - else - { - return _largeCapactityValidity[index]; - } + return _candidates[index].Score >= 0; } /// @@ -270,15 +142,8 @@ namespace Microsoft.AspNetCore.Routing.Matching ThrowIndexArgumentOutOfRangeException(); } - if (Count < BitVectorSize) - { - // Set the n-th bit - _validity[0x00000001 << index] = value; - } - else - { - _largeCapactityValidity[index] = value; - } + ref var original = ref _candidates[index]; + _candidates[index] = new CandidateState(original.Endpoint, original.Values, original.Score >= 0 ^ value ? ~original.Score : original.Score); } /// @@ -303,28 +168,7 @@ namespace Microsoft.AspNetCore.Routing.Matching ThrowIndexArgumentOutOfRangeException(); } - switch (index) - { - case 0: - _state0 = new CandidateState(endpoint, values, _state0.Score); - break; - - case 1: - _state1 = new CandidateState(endpoint, values, _state1.Score); - break; - - case 2: - _state2 = new CandidateState(endpoint, values, _state2.Score); - break; - - case 3: - _state3 = new CandidateState(endpoint, values, _state3.Score); - break; - - default: - _additionalCandidates[index - 4] = new CandidateState(endpoint, values, _additionalCandidates[index - 4].Score); - break; - } + _candidates[index] = new CandidateState(endpoint, values, _candidates[index].Score); if (endpoint == null) { diff --git a/src/Http/Routing/src/Matching/DefaultEndpointSelector.cs b/src/Http/Routing/src/Matching/DefaultEndpointSelector.cs index 30882cc5f2..113e0a4f01 100644 --- a/src/Http/Routing/src/Matching/DefaultEndpointSelector.cs +++ b/src/Http/Routing/src/Matching/DefaultEndpointSelector.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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;