@@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Internal.Dictionary
12
12
/// <summary>
13
13
/// An <see cref="IDictionary{String, Object}"/> type to hold a small amount of items (4 or less in the common case).
14
14
/// </summary>
15
- internal class SmallCapacityDictionary < TKey , TValue > : IDictionary < TKey , TValue > , IReadOnlyDictionary < TKey , TValue > where TKey : notnull
15
+ internal struct SmallCapacityDictionary < TKey , TValue > : IDictionary < TKey , TValue > , IReadOnlyDictionary < TKey , TValue > where TKey : notnull
16
16
{
17
17
// Threshold for size of array to use.
18
18
private static readonly int DefaultArrayThreshold = 4 ;
@@ -91,17 +91,10 @@ public static SmallCapacityDictionary<TKey, TValue> FromArray(KeyValuePair<TKey,
91
91
{
92
92
_arrayStorage = items ! ,
93
93
_count = start ,
94
+ _comparer = comparer
94
95
} ;
95
96
}
96
97
97
- /// <summary>
98
- /// Creates an empty <see cref="SmallCapacityDictionary{TKey, TValue}"/>.
99
- /// </summary>
100
- public SmallCapacityDictionary ( )
101
- : this ( 0 , EqualityComparer < TKey > . Default )
102
- {
103
- }
104
-
105
98
/// <summary>
106
99
/// Creates a <see cref="SmallCapacityDictionary{TKey, TValue}"/>.
107
100
/// </summary>
@@ -127,6 +120,9 @@ public SmallCapacityDictionary(int capacity)
127
120
/// <param name="comparer">Equality comparison.</param>
128
121
public SmallCapacityDictionary ( int capacity , IEqualityComparer < TKey > comparer )
129
122
{
123
+ _backup = null ;
124
+ _count = 0 ;
125
+
130
126
if ( comparer is not null && comparer != EqualityComparer < TKey > . Default ) // first check for null to avoid forcing default comparer instantiation unnecessarily
131
127
{
132
128
_comparer = comparer ;
@@ -162,6 +158,9 @@ public SmallCapacityDictionary(int capacity, IEqualityComparer<TKey> comparer)
162
158
/// <param name="capacity">Initial capacity.</param>
163
159
public SmallCapacityDictionary ( IEnumerable < KeyValuePair < TKey , TValue > > values , int capacity , IEqualityComparer < TKey > comparer )
164
160
{
161
+ _backup = null ;
162
+ _count = 0 ;
163
+
165
164
_comparer = comparer ?? EqualityComparer < TKey > . Default ;
166
165
167
166
_arrayStorage = new KeyValuePair < TKey , TValue > [ capacity ] ;
@@ -600,13 +599,18 @@ private static void ThrowArgumentNullExceptionForKey()
600
599
}
601
600
602
601
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
603
- private void EnsureCapacity ( int capacity )
602
+ private void EnsureCapacity ( int capacity )
604
603
{
605
604
EnsureCapacitySlow ( capacity ) ;
606
605
}
607
606
608
607
private void EnsureCapacitySlow ( int capacity )
609
608
{
609
+ if ( _arrayStorage == null )
610
+ {
611
+ _arrayStorage = Array . Empty < KeyValuePair < TKey , TValue > > ( ) ;
612
+ }
613
+
610
614
if ( _arrayStorage . Length < capacity )
611
615
{
612
616
if ( capacity > DefaultArrayThreshold )
@@ -644,7 +648,7 @@ private int FindIndex(TKey key)
644
648
645
649
for ( var i = 0 ; i < count ; i ++ )
646
650
{
647
- if ( _comparer . Equals ( array [ i ] . Key , key ) )
651
+ if ( Comparer . Equals ( array [ i ] . Key , key ) )
648
652
{
649
653
return i ;
650
654
}
@@ -658,21 +662,26 @@ private bool TryFindItem(TKey key, out TValue? value)
658
662
{
659
663
var array = _arrayStorage ;
660
664
var count = _count ;
665
+ value = default ;
666
+
667
+ if ( _arrayStorage == null )
668
+ {
669
+ return false ;
670
+ }
661
671
662
672
// Elide bounds check for indexing.
663
673
if ( ( uint ) count <= ( uint ) array . Length )
664
674
{
665
675
for ( var i = 0 ; i < count ; i ++ )
666
676
{
667
- if ( _comparer . Equals ( array [ i ] . Key , key ) )
677
+ if ( Comparer . Equals ( array [ i ] . Key , key ) )
668
678
{
669
679
value = array [ i ] . Value ;
670
680
return true ;
671
681
}
672
682
}
673
683
}
674
684
675
- value = default ;
676
685
return false ;
677
686
}
678
687
@@ -682,12 +691,17 @@ private bool ContainsKeyArray(TKey key)
682
691
var array = _arrayStorage ;
683
692
var count = _count ;
684
693
694
+ if ( array == null )
695
+ {
696
+ return false ;
697
+ }
698
+
685
699
// Elide bounds check for indexing.
686
700
if ( ( uint ) count <= ( uint ) array . Length )
687
701
{
688
702
for ( var i = 0 ; i < count ; i ++ )
689
703
{
690
- if ( _comparer . Equals ( array [ i ] . Key , key ) )
704
+ if ( Comparer . Equals ( array [ i ] . Key , key ) )
691
705
{
692
706
return true ;
693
707
}
@@ -700,7 +714,7 @@ private bool ContainsKeyArray(TKey key)
700
714
/// <inheritdoc />
701
715
public struct Enumerator : IEnumerator < KeyValuePair < TKey , TValue > >
702
716
{
703
- private readonly SmallCapacityDictionary < TKey , TValue > _dictionary ;
717
+ private SmallCapacityDictionary < TKey , TValue > _dictionary ;
704
718
private int _index ;
705
719
706
720
/// <summary>
@@ -709,11 +723,6 @@ public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
709
723
/// <param name="dictionary">A <see cref="SmallCapacityDictionary{TKey, TValue}"/>.</param>
710
724
public Enumerator ( SmallCapacityDictionary < TKey , TValue > dictionary )
711
725
{
712
- if ( dictionary == null )
713
- {
714
- throw new ArgumentNullException ( ) ;
715
- }
716
-
717
726
_dictionary = dictionary ;
718
727
719
728
Current = default ;
@@ -738,7 +747,7 @@ public void Dispose()
738
747
public bool MoveNext ( )
739
748
{
740
749
var dictionary = _dictionary ;
741
- if ( dictionary . _arrayStorage . Length >= _index )
750
+ if ( dictionary . _arrayStorage == null || dictionary . _arrayStorage . Length >= _index )
742
751
{
743
752
return false ;
744
753
}
0 commit comments