Skip to content

Commit 0b567e9

Browse files
committed
Single field StringValues
1 parent 595fef6 commit 0b567e9

File tree

1 file changed

+111
-46
lines changed

1 file changed

+111
-46
lines changed

src/Microsoft.Extensions.Primitives/StringValues.cs

Lines changed: 111 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections;
66
using System.Collections.Generic;
7+
using System.Runtime.CompilerServices;
78
using Microsoft.Extensions.Internal;
89

910
namespace Microsoft.Extensions.Primitives
@@ -16,19 +17,16 @@ public struct StringValues : IList<string>, IReadOnlyList<string>, IEquatable<St
1617
private static readonly string[] EmptyArray = new string[0];
1718
public static readonly StringValues Empty = new StringValues(EmptyArray);
1819

19-
private readonly string _value;
20-
private readonly string[] _values;
20+
private readonly object _value;
2121

2222
public StringValues(string value)
2323
{
2424
_value = value;
25-
_values = null;
2625
}
2726

2827
public StringValues(string[] values)
2928
{
30-
_value = null;
31-
_values = values;
29+
_value = values;
3230
}
3331

3432
public static implicit operator StringValues(string value)
@@ -51,8 +49,11 @@ public static implicit operator string[] (StringValues value)
5149
return value.GetArrayValue();
5250
}
5351

54-
public int Count => _value != null ? 1 : (_values?.Length ?? 0);
52+
public int Count => (_value is string) ? 1 : GetArrayCount();
5553

54+
[MethodImpl(MethodImplOptions.NoInlining)]
55+
private int GetArrayCount() => ((_value as string[])?.Length ?? 0);
56+
5657
bool ICollection<string>.IsReadOnly
5758
{
5859
get { return true; }
@@ -68,49 +69,88 @@ public string this[int index]
6869
{
6970
get
7071
{
71-
if (_values != null)
72-
{
73-
return _values[index]; // may throw
74-
}
75-
if (index == 0 && _value != null)
72+
if (index == 0)
7673
{
77-
return _value;
74+
var stringVal = _value as string;
75+
if (stringVal != null)
76+
{
77+
return stringVal;
78+
}
7879
}
79-
return EmptyArray[0]; // throws
80+
81+
return GetArrayItem(index);
8082
}
8183
}
8284

85+
[MethodImpl(MethodImplOptions.NoInlining)]
86+
private string GetArrayItem(int index)
87+
{
88+
var arrayValue = _value as string[];
89+
if (arrayValue != null)
90+
{
91+
return arrayValue[index]; // may throw
92+
}
93+
94+
return EmptyArray[0]; // throws
95+
}
96+
8397
public override string ToString()
8498
{
8599
return GetStringValue() ?? string.Empty;
86100
}
87101

88102
private string GetStringValue()
89103
{
90-
if (_values == null)
104+
var stringVal = _value as string;
105+
if (stringVal != null)
91106
{
92-
return _value;
107+
return stringVal;
93108
}
94-
switch (_values.Length)
109+
110+
return GetArrayStringValue();
111+
}
112+
113+
[MethodImpl(MethodImplOptions.NoInlining)]
114+
private string GetArrayStringValue()
115+
{
116+
var arrayValue = _value as string[];
117+
if (arrayValue != null)
95118
{
96-
case 0: return null;
97-
case 1: return _values[0];
98-
default: return string.Join(",", _values);
119+
switch (arrayValue.Length)
120+
{
121+
case 0: return null;
122+
case 1: return arrayValue[0];
123+
default: return string.Join(",", arrayValue);
124+
}
99125
}
126+
return null;
100127
}
101-
128+
102129
public string[] ToArray()
103130
{
104131
return GetArrayValue() ?? EmptyArray;
105132
}
106133

107134
private string[] GetArrayValue()
108135
{
109-
if (_value != null)
136+
var arrayValue = _value as string[];
137+
if (arrayValue != null)
110138
{
111-
return new[] { _value };
139+
return arrayValue;
112140
}
113-
return _values;
141+
142+
return GetStringArrayValue();
143+
}
144+
145+
[MethodImpl(MethodImplOptions.NoInlining)]
146+
private string[] GetStringArrayValue()
147+
{
148+
var stringVal = _value as string;
149+
if (stringVal != null)
150+
{
151+
return new[] { stringVal };
152+
}
153+
return null;
114154
}
115155

116156
int IList<string>.IndexOf(string item)
@@ -120,22 +160,29 @@ int IList<string>.IndexOf(string item)
120160

121161
private int IndexOf(string item)
122162
{
123-
if (_values != null)
163+
var arrayValue = _value as string[];
164+
if (arrayValue != null)
124165
{
125-
var values = _values;
126-
for (int i = 0; i < values.Length; i++)
166+
for (int i = 0; i < arrayValue.Length; i++)
127167
{
128-
if (string.Equals(values[i], item, StringComparison.Ordinal))
168+
if (string.Equals(arrayValue[i], item, StringComparison.Ordinal))
129169
{
130170
return i;
131171
}
132172
}
133173
return -1;
134174
}
135175

136-
if (_value != null)
176+
return IndexOfString(item);
177+
}
178+
179+
[MethodImpl(MethodImplOptions.NoInlining)]
180+
private int IndexOfString(string item)
181+
{
182+
var stringVal = _value as string;
183+
if (stringVal != null)
137184
{
138-
return string.Equals(_value, item, StringComparison.Ordinal) ? 0 : -1;
185+
return string.Equals(stringVal, item, StringComparison.Ordinal) ? 0 : -1;
139186
}
140187

141188
return -1;
@@ -153,13 +200,15 @@ void ICollection<string>.CopyTo(string[] array, int arrayIndex)
153200

154201
private void CopyTo(string[] array, int arrayIndex)
155202
{
156-
if (_values != null)
203+
var arrayValue = _value as string[];
204+
if (arrayValue != null)
157205
{
158-
Array.Copy(_values, 0, array, arrayIndex, _values.Length);
206+
Array.Copy(arrayValue, 0, array, arrayIndex, arrayValue.Length);
159207
return;
160208
}
161209

162-
if (_value != null)
210+
var stringVal = _value as string;
211+
if (stringVal != null)
163212
{
164213
if (array == null)
165214
{
@@ -175,7 +224,7 @@ private void CopyTo(string[] array, int arrayIndex)
175224
$"'{nameof(array)}' is not long enough to copy all the items in the collection. Check '{nameof(arrayIndex)}' and '{nameof(array)}' length.");
176225
}
177226

178-
array[arrayIndex] = _value;
227+
array[arrayIndex] = stringVal;
179228
}
180229
}
181230

@@ -221,18 +270,27 @@ IEnumerator IEnumerable.GetEnumerator()
221270

222271
public static bool IsNullOrEmpty(StringValues value)
223272
{
224-
if (value._values == null)
273+
var stringVal = value._value as string;
274+
if (stringVal != null)
225275
{
226-
return string.IsNullOrEmpty(value._value);
276+
return string.IsNullOrEmpty(stringVal);
227277
}
228-
switch (value._values.Length)
278+
279+
return value.IsNullOrEmptyArray();
280+
}
281+
282+
[MethodImpl(MethodImplOptions.NoInlining)]
283+
private bool IsNullOrEmptyArray()
284+
{
285+
var arrayValue = _value as string[];
286+
switch (arrayValue.Length)
229287
{
230288
case 0: return true;
231-
case 1: return string.IsNullOrEmpty(value._values[0]);
289+
case 1: return string.IsNullOrEmpty(arrayValue[0]);
232290
default: return false;
233291
}
234292
}
235-
293+
236294
public static StringValues Concat(StringValues values1, StringValues values2)
237295
{
238296
var count1 = values1.Count;
@@ -405,17 +463,24 @@ public override bool Equals(object obj)
405463

406464
public override int GetHashCode()
407465
{
408-
if (_values == null)
466+
var stringVal = _value as string;
467+
if (stringVal != null)
409468
{
410-
return _value == null ? 0 : _value.GetHashCode();
469+
return stringVal.GetHashCode();
411470
}
412471

413-
var hcc = new HashCodeCombiner();
414-
for (var i = 0; i < _values.Length; i++)
472+
var arrayValue = _value as string[];
473+
if (arrayValue != null)
415474
{
416-
hcc.Add(_values[i]);
475+
var hcc = new HashCodeCombiner();
476+
for (var i = 0; i < arrayValue.Length; i++)
477+
{
478+
hcc.Add(arrayValue[i]);
479+
}
480+
return hcc.CombinedHash;
417481
}
418-
return hcc.CombinedHash;
482+
483+
return 0;
419484
}
420485

421486
public struct Enumerator : IEnumerator<string>
@@ -426,8 +491,8 @@ public struct Enumerator : IEnumerator<string>
426491

427492
public Enumerator(ref StringValues values)
428493
{
429-
_values = values._values;
430-
_current = values._value;
494+
_current = values._value as string;
495+
_values = values._value as string[];
431496
_index = 0;
432497
}
433498

0 commit comments

Comments
 (0)