Slim down CandidateSet

This commit is contained in:
Ryan Nowak 2019-04-14 18:57:01 -07:00 committed by Ryan Nowak
parent 6eeda774ef
commit e47fbbab9e
2 changed files with 14 additions and 170 deletions

View File

@ -18,19 +18,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
private const int BitVectorSize = 32; private const int BitVectorSize = 32;
// Cannot be readonly because we need to modify it in place. private readonly CandidateState[] _candidates;
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;
/// <summary> /// <summary>
/// <para> /// <para>
@ -69,56 +57,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
Count = endpoints.Length; Count = endpoints.Length;
switch (endpoints.Length) _candidates = new CandidateState[endpoints.Length];
for (var i = 0; i < endpoints.Length; i++)
{ {
case 0: _candidates[i] = new CandidateState(endpoints[i], values[i], scores[i]);
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);
} }
} }
@ -126,56 +68,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
Count = candidates.Length; Count = candidates.Length;
switch (candidates.Length) _candidates = new CandidateState[candidates.Length];
for (var i = 0; i < candidates.Length; i++)
{ {
case 0: _candidates[i] = new CandidateState(candidates[i].Endpoint, candidates[i].Score);
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);
} }
} }
@ -207,23 +103,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
ThrowIndexArgumentOutOfRangeException(); ThrowIndexArgumentOutOfRangeException();
} }
switch (index) return ref _candidates[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];
}
} }
} }
@ -233,7 +113,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// </summary> /// </summary>
/// <param name="index">The candidate index.</param> /// <param name="index">The candidate index.</param>
/// <returns> /// <returns>
/// <c>true</c> if the candidate at position <paramref name="index"/> is considered value /// <c>true</c> if the candidate at position <paramref name="index"/> is considered valid
/// for the current request, otherwise <c>false</c>. /// for the current request, otherwise <c>false</c>.
/// </returns> /// </returns>
public bool IsValidCandidate(int index) public bool IsValidCandidate(int index)
@ -244,15 +124,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
ThrowIndexArgumentOutOfRangeException(); ThrowIndexArgumentOutOfRangeException();
} }
if (Count < BitVectorSize) return _candidates[index].Score >= 0;
{
// Get the n-th bit
return _validity[0x00000001 << index];
}
else
{
return _largeCapactityValidity[index];
}
} }
/// <summary> /// <summary>
@ -270,15 +142,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
ThrowIndexArgumentOutOfRangeException(); ThrowIndexArgumentOutOfRangeException();
} }
if (Count < BitVectorSize) ref var original = ref _candidates[index];
{ _candidates[index] = new CandidateState(original.Endpoint, original.Values, original.Score >= 0 ^ value ? ~original.Score : original.Score);
// Set the n-th bit
_validity[0x00000001 << index] = value;
}
else
{
_largeCapactityValidity[index] = value;
}
} }
/// <summary> /// <summary>
@ -303,28 +168,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
ThrowIndexArgumentOutOfRangeException(); ThrowIndexArgumentOutOfRangeException();
} }
switch (index) _candidates[index] = new CandidateState(endpoint, values, _candidates[index].Score);
{
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;
}
if (endpoint == null) if (endpoint == null)
{ {

View File

@ -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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;