Skip to content

Commit d223353

Browse files
authored
Replace XmlSchema ContentValidator Hashtables that are boxing lots of ints (#66908)
1 parent c3fa765 commit d223353

File tree

1 file changed

+48
-73
lines changed

1 file changed

+48
-73
lines changed

src/libraries/System.Private.Xml/src/System/Xml/Schema/ContentValidator.cs

Lines changed: 48 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ public UpaException(object? particle1, object? particle2)
3939
internal sealed class SymbolsDictionary
4040
{
4141
private int _last;
42-
private readonly Hashtable _names;
43-
private Hashtable? _wildcards;
42+
private readonly Dictionary<XmlQualifiedName, int> _names;
43+
private Dictionary<string, int>? _wildcards;
4444
private readonly ArrayList _particles;
4545
private object? _particleLast;
4646
private bool _isUpaEnforced = true;
4747

4848
public SymbolsDictionary()
4949
{
50-
_names = new Hashtable();
50+
_names = new Dictionary<XmlQualifiedName, int>();
5151
_particles = new ArrayList();
5252
}
5353

@@ -71,10 +71,8 @@ public bool IsUpaEnforced
7171
/// </summary>
7272
public int AddName(XmlQualifiedName name, object? particle)
7373
{
74-
object? lookup = _names[name];
75-
if (lookup != null)
74+
if (_names.TryGetValue(name, out int symbol))
7675
{
77-
int symbol = (int)lookup;
7876
if (_particles[symbol] != particle)
7977
{
8078
_isUpaEnforced = false;
@@ -116,13 +114,9 @@ public void AddNamespaceList(NamespaceList list, object particle, bool allowLoca
116114

117115
private void AddWildcard(string wildcard, object? particle)
118116
{
119-
if (_wildcards == null)
120-
{
121-
_wildcards = new Hashtable();
122-
}
117+
_wildcards ??= new Dictionary<string, int>();
123118

124-
object? lookup = _wildcards[wildcard];
125-
if (lookup == null)
119+
if (!_wildcards.TryGetValue(wildcard, out int lookup))
126120
{
127121
_wildcards.Add(wildcard, _last);
128122
_particles.Add(particle);
@@ -131,15 +125,16 @@ private void AddWildcard(string wildcard, object? particle)
131125
}
132126
else if (particle != null)
133127
{
134-
_particles[(int)lookup] = particle;
128+
_particles[lookup] = particle;
135129
}
136130
}
137131

138132
public ICollection GetNamespaceListSymbols(NamespaceList list)
139133
{
140134
ArrayList match = new ArrayList();
141-
foreach (XmlQualifiedName? name in _names.Keys)
135+
foreach (KeyValuePair<XmlQualifiedName, int> entry in _names)
142136
{
137+
XmlQualifiedName name = entry.Key;
143138
Debug.Assert(name != null);
144139
if (name != XmlQualifiedName.Empty && list.Allows(name))
145140
{
@@ -149,11 +144,11 @@ public ICollection GetNamespaceListSymbols(NamespaceList list)
149144

150145
if (_wildcards != null)
151146
{
152-
foreach (string wildcard in _wildcards.Keys)
147+
foreach (KeyValuePair<string, int> wildcard in _wildcards)
153148
{
154-
if (list.Allows(wildcard))
149+
if (list.Allows(wildcard.Key))
155150
{
156-
match.Add(_wildcards[wildcard]);
151+
match.Add(wildcard.Value);
157152
}
158153
}
159154
}
@@ -173,19 +168,14 @@ public int this[XmlQualifiedName name]
173168
{
174169
get
175170
{
176-
object? lookup = _names[name];
177-
if (lookup != null)
171+
if (_names.TryGetValue(name, out int symbol))
178172
{
179-
return (int)lookup;
173+
return symbol;
180174
}
181175

182-
if (_wildcards != null)
176+
if (_wildcards != null && _wildcards.TryGetValue(name.Namespace, out int lookup))
183177
{
184-
lookup = _wildcards[name.Namespace];
185-
if (lookup != null)
186-
{
187-
return (int)lookup;
188-
}
178+
return lookup;
189179
}
190180

191181
return _last; // true wildcard
@@ -195,16 +185,7 @@ public int this[XmlQualifiedName name]
195185
/// <summary>
196186
/// Check if a name exists in the symbol dictionary
197187
/// </summary>
198-
public bool Exists(XmlQualifiedName name)
199-
{
200-
object? lookup = _names[name];
201-
if (lookup != null)
202-
{
203-
return true;
204-
}
205-
206-
return false;
207-
}
188+
public bool Exists(XmlQualifiedName name) => _names.ContainsKey(name);
208189

209190
/// <summary>
210191
/// Return content processing mode for the symbol
@@ -219,21 +200,21 @@ public bool Exists(XmlQualifiedName name)
219200
/// </summary>
220201
public string NameOf(int symbol)
221202
{
222-
foreach (DictionaryEntry de in _names)
203+
foreach (KeyValuePair<XmlQualifiedName, int> name in _names)
223204
{
224-
if ((int)de.Value! == symbol)
205+
if (name.Value == symbol)
225206
{
226-
return ((XmlQualifiedName)de.Key).ToString();
207+
return name.Key.ToString();
227208
}
228209
}
229210

230211
if (_wildcards != null)
231212
{
232-
foreach (DictionaryEntry de in _wildcards)
213+
foreach (KeyValuePair<string, int> wildcard in _wildcards)
233214
{
234-
if ((int)de!.Value! == symbol)
215+
if (wildcard.Value == symbol)
235216
{
236-
return $"{(string)de.Key}:*";
217+
return $"{wildcard.Key}:*";
237218
}
238219
}
239220
}
@@ -1467,7 +1448,7 @@ private void CheckUniqueParticleAttribution(BitSet curpos)
14671448
ArrayList transitionTable = new ArrayList();
14681449

14691450
// state lookup table (Dstate in the book)
1470-
Hashtable stateTable = new Hashtable();
1451+
Dictionary<BitSet, int> stateTable = new();
14711452

14721453
// Add empty set that would signal an error
14731454
stateTable.Add(new BitSet(positionsCount), -1);
@@ -1485,7 +1466,7 @@ private void CheckUniqueParticleAttribution(BitSet curpos)
14851466
while (unmarked.Count > 0)
14861467
{
14871468
BitSet statePosSet = unmarked.Dequeue(); // all positions that constitute DFA state
1488-
Debug.Assert(state == (int)stateTable[statePosSet]!); // just make sure that statePosSet is for correct state
1469+
Debug.Assert(state == stateTable[statePosSet]); // just make sure that statePosSet is for correct state
14891470
int[] transition = (int[])transitionTable[state]!;
14901471
if (statePosSet[endMarkerPos])
14911472
{
@@ -1509,10 +1490,9 @@ private void CheckUniqueParticleAttribution(BitSet curpos)
15091490

15101491
// if U is not empty and is not in Dstates then
15111492
// add U as an unmarked state to Dstates
1512-
object? lookup = stateTable[newset];
1513-
if (lookup != null)
1493+
if (stateTable.TryGetValue(newset, out int lookup))
15141494
{
1515-
transition[symbol] = (int)lookup;
1495+
transition[symbol] = lookup;
15161496
}
15171497
else
15181498
{
@@ -2151,33 +2131,33 @@ public override ArrayList ExpectedParticles(ValidationState context, bool isRequ
21512131

21522132
internal sealed class AllElementsContentValidator : ContentValidator
21532133
{
2154-
private readonly Hashtable _elements; // unique terminal names to positions in Bitset mapping
2134+
private readonly Dictionary<XmlQualifiedName, int> _elements; // unique terminal names to positions in Bitset mapping
21552135
private readonly object[] _particles;
21562136
private readonly BitSet _isRequired; // required flags
21572137
private int _countRequired;
21582138

21592139
public AllElementsContentValidator(XmlSchemaContentType contentType, int size, bool isEmptiable) : base(contentType, false, isEmptiable)
21602140
{
2161-
_elements = new Hashtable(size);
2141+
_elements = new Dictionary<XmlQualifiedName, int>(size);
21622142
_particles = new object[size];
21632143
_isRequired = new BitSet(size);
21642144
}
21652145

21662146
public bool AddElement(XmlQualifiedName name, object particle, bool isEmptiable)
21672147
{
2168-
if (_elements[name] != null)
2169-
{
2170-
return false;
2171-
}
21722148
int i = _elements.Count;
2173-
_elements.Add(name, i);
2174-
_particles[i] = particle;
2175-
if (!isEmptiable)
2149+
if (_elements.TryAdd(name, i))
21762150
{
2177-
_isRequired.Set(i);
2178-
_countRequired++;
2151+
_particles[i] = particle;
2152+
if (!isEmptiable)
2153+
{
2154+
_isRequired.Set(i);
2155+
_countRequired++;
2156+
}
2157+
return true;
21792158
}
2180-
return true;
2159+
2160+
return false;
21812161
}
21822162

21832163
public override bool IsEmptiable
@@ -2194,15 +2174,14 @@ public override void InitValidation(ValidationState context)
21942174

21952175
public override object? ValidateElement(XmlQualifiedName name, ValidationState context, out int errorCode)
21962176
{
2197-
object? lookup = _elements[name];
21982177
errorCode = 0;
2199-
if (lookup == null)
2178+
2179+
if (!_elements.TryGetValue(name, out int index))
22002180
{
22012181
context.NeedValidateChildren = false;
22022182
return null;
22032183
}
22042184

2205-
int index = (int)lookup;
22062185
if (context.AllElementsSet![index])
22072186
{
22082187
errorCode = -2;
@@ -2236,16 +2215,12 @@ public override bool CompleteValidation(ValidationState context)
22362215
public override ArrayList? ExpectedElements(ValidationState context, bool isRequiredOnly)
22372216
{
22382217
ArrayList? names = null;
2239-
foreach (DictionaryEntry entry in _elements)
2218+
foreach (KeyValuePair<XmlQualifiedName, int> element in _elements)
22402219
{
2241-
if (!context.AllElementsSet![(int)entry.Value!] && (!isRequiredOnly || _isRequired[(int)entry.Value]))
2220+
if (!context.AllElementsSet![element.Value] && (!isRequiredOnly || _isRequired[element.Value]))
22422221
{
2243-
if (names == null)
2244-
{
2245-
names = new ArrayList();
2246-
}
2247-
2248-
names.Add(entry.Key);
2222+
names ??= new ArrayList();
2223+
names.Add(element.Key);
22492224
}
22502225
}
22512226

@@ -2255,11 +2230,11 @@ public override bool CompleteValidation(ValidationState context)
22552230
public override ArrayList ExpectedParticles(ValidationState context, bool isRequiredOnly, XmlSchemaSet schemaSet)
22562231
{
22572232
ArrayList expectedParticles = new ArrayList();
2258-
foreach (DictionaryEntry entry in _elements)
2233+
foreach (KeyValuePair<XmlQualifiedName, int> element in _elements)
22592234
{
2260-
if (!context.AllElementsSet![(int)entry.Value!] && (!isRequiredOnly || _isRequired[(int)entry.Value]))
2235+
if (!context.AllElementsSet![element.Value] && (!isRequiredOnly || _isRequired[element.Value]))
22612236
{
2262-
AddParticleToExpected((_particles[(int)entry.Value] as XmlSchemaParticle)!, schemaSet, expectedParticles);
2237+
AddParticleToExpected((_particles[element.Value] as XmlSchemaParticle)!, schemaSet, expectedParticles);
22632238
}
22642239
}
22652240

0 commit comments

Comments
 (0)