Skip to content

Commit 9949509

Browse files
Some improvements to FrugalList (#6280)
* Some improvements to FrugalList - FrugalStructList's `ICollection<T>`-based constructor uses foreach to enumerate the contents of the collection. If it's an `IList<T>`, we can instead index and avoid allocating the enumerator. - Avoid multiple interface calls to `ICollection<T>.Count` in FrugalStructList's ctor - Delete a dead ctor on `ArrayItemList<T>`. That ctor was the only reason an array field may have been left null, so we can also remove subsequent null checks when accessing that array. - Use Span/Array in ArrayItemList for Clear, Contains, IndexOf, ToArray, and CopyTo rather than open-coding them * Update src/Microsoft.DotNet.Wpf/src/Shared/MS/Utility/FrugalList.cs Co-authored-by: Bradley Grainger <[email protected]> Co-authored-by: Bradley Grainger <[email protected]>
1 parent f1cfb42 commit 9949509

File tree

1 file changed

+52
-100
lines changed

1 file changed

+52
-100
lines changed

src/Microsoft.DotNet.Wpf/src/Shared/MS/Utility/FrugalList.cs

Lines changed: 52 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
using System.Diagnostics;
77
using System.Collections;
88
using System.Collections.Generic;
9-
using System.Windows;
10-
using System.Diagnostics.CodeAnalysis;
119
#if SYSTEM_XAML
1210
using System.Xaml;
1311
#else
@@ -1284,10 +1282,6 @@ private void SetCount(int value)
12841282
/// </summary>
12851283
internal sealed class ArrayItemList<T> : FrugalListBase<T>
12861284
{
1287-
public ArrayItemList()
1288-
{
1289-
}
1290-
12911285
public ArrayItemList(int size)
12921286
{
12931287
// Make size a multiple of GROWTH
@@ -1298,74 +1292,53 @@ public ArrayItemList(int size)
12981292

12991293
public ArrayItemList(ICollection collection)
13001294
{
1301-
if (collection != null)
1302-
{
1303-
_count = collection.Count;
1304-
_entries = new T[_count];
1305-
collection.CopyTo(_entries, 0);
1306-
}
1295+
Debug.Assert(collection is not null);
1296+
_count = collection.Count;
1297+
_entries = new T[_count];
1298+
collection.CopyTo(_entries, 0);
13071299
}
13081300

13091301
public ArrayItemList(ICollection<T> collection)
13101302
{
1311-
if (collection != null)
1312-
{
1313-
_count = collection.Count;
1314-
_entries = new T[_count];
1315-
collection.CopyTo(_entries, 0);
1316-
}
1303+
Debug.Assert(collection is not null);
1304+
_count = collection.Count;
1305+
_entries = new T[_count];
1306+
collection.CopyTo(_entries, 0);
13171307
}
13181308

13191309
// Capacity of this store
1320-
public override int Capacity
1321-
{
1322-
get
1323-
{
1324-
if (_entries != null)
1325-
{
1326-
return _entries.Length;
1327-
}
1328-
return 0;
1329-
}
1330-
}
1310+
public override int Capacity => _entries.Length;
13311311

13321312
public override FrugalListStoreState Add(T value)
13331313
{
13341314
// If we don't have any entries or the existing entry is being overwritten,
13351315
// then we can use this store. Otherwise we have to promote.
1336-
if ((null != _entries) && (_count < _entries.Length))
1316+
if (_count < _entries.Length)
13371317
{
13381318
_entries[_count] = value;
13391319
++_count;
13401320
}
13411321
else
13421322
{
1343-
if (null != _entries)
1344-
{
1345-
int size = _entries.Length;
1323+
int size = _entries.Length;
13461324

1347-
// Grow the list slowly while it is small but
1348-
// faster once it reaches the LARGEGROWTH size
1349-
if (size < LARGEGROWTH)
1350-
{
1351-
size += GROWTH;
1352-
}
1353-
else
1354-
{
1355-
size += size >> 2;
1356-
}
1357-
1358-
T[] destEntries = new T[size];
1359-
1360-
// Copy old array
1361-
Array.Copy(_entries, 0, destEntries, 0, _entries.Length);
1362-
_entries = destEntries;
1325+
// Grow the list slowly while it is small but
1326+
// faster once it reaches the LARGEGROWTH size
1327+
if (size < LARGEGROWTH)
1328+
{
1329+
size += GROWTH;
13631330
}
13641331
else
13651332
{
1366-
_entries = new T[MINSIZE];
1333+
size += size >> 2;
13671334
}
13681335

1336+
T[] destEntries = new T[size];
1337+
1338+
// Copy old array
1339+
Array.Copy(_entries, 0, destEntries, 0, _entries.Length);
1340+
_entries = destEntries;
1341+
13691342
// Insert into new array
13701343
_entries[_count] = value;
13711344
++_count;
@@ -1375,34 +1348,17 @@ public override FrugalListStoreState Add(T value)
13751348

13761349
public override void Clear()
13771350
{
1378-
// Wipe out the info.
1379-
for (int i = 0; i < _count; ++i)
1380-
{
1381-
_entries[i] = default(T);
1382-
}
1351+
_entries.AsSpan(0, _count).Clear();
13831352
_count = 0;
13841353
}
13851354

1386-
public override bool Contains(T value)
1387-
{
1388-
return (-1 != IndexOf(value));
1389-
}
1355+
public override bool Contains(T value) => IndexOf(value) >= 0;
13901356

1391-
public override int IndexOf(T value)
1392-
{
1393-
for (int index = 0; index < _count; ++index)
1394-
{
1395-
if (EqualityComparer<T>.Default.Equals(_entries[index], value))
1396-
{
1397-
return index;
1398-
}
1399-
}
1400-
return -1;
1401-
}
1357+
public override int IndexOf(T value) => Array.IndexOf(_entries, value, 0, _count);
14021358

14031359
public override void Insert(int index, T value)
14041360
{
1405-
if ((null != _entries) && (_count < _entries.Length))
1361+
if (_count < _entries.Length)
14061362
{
14071363
// Move down the required number of items
14081364
Array.Copy(_entries, index, _entries, index + 1, _count - index);
@@ -1423,13 +1379,11 @@ public override void SetAt(int index, T value)
14231379

14241380
public override bool Remove(T value)
14251381
{
1426-
for (int index = 0; index < _count; ++index)
1382+
int index = IndexOf(value);
1383+
if (index >= 0)
14271384
{
1428-
if (EqualityComparer<T>.Default.Equals(_entries[index], value))
1429-
{
1430-
RemoveAt(index);
1431-
return true;
1432-
}
1385+
RemoveAt(index);
1386+
return true;
14331387
}
14341388

14351389
return false;
@@ -1543,24 +1497,9 @@ public void Promote(ArrayItemList<T> oldList)
15431497
}
15441498
}
15451499

1546-
public override T[] ToArray()
1547-
{
1548-
T[] array = new T[_count];
1500+
public override T[] ToArray() => _entries.AsSpan(0, _count).ToArray();
15491501

1550-
for (int i = 0; i < _count; ++i)
1551-
{
1552-
array[i] = _entries[i];
1553-
}
1554-
return array;
1555-
}
1556-
1557-
public override void CopyTo(T[] array, int index)
1558-
{
1559-
for (int i = 0; i < _count; ++i)
1560-
{
1561-
array[index+i] = _entries[i];
1562-
}
1563-
}
1502+
public override void CopyTo(T[] array, int index) => _entries.AsSpan(0, _count).CopyTo(array.AsSpan(index));
15641503

15651504
public override object Clone()
15661505
{
@@ -2032,14 +1971,15 @@ public FrugalStructList(int size)
20321971

20331972
public FrugalStructList(ICollection collection)
20341973
{
2035-
if (collection.Count > 6)
1974+
int count = collection.Count;
1975+
if (count > 6)
20361976
{
20371977
_listStore = new ArrayItemList<T>(collection);
20381978
}
20391979
else
20401980
{
20411981
_listStore = null;
2042-
Capacity = collection.Count;
1982+
Capacity = count;
20431983
foreach (T item in collection)
20441984
{
20451985
Add(item);
@@ -2049,17 +1989,29 @@ public FrugalStructList(ICollection collection)
20491989

20501990
public FrugalStructList(ICollection<T> collection)
20511991
{
2052-
if (collection.Count > 6)
1992+
int count = collection.Count;
1993+
if (count > 6)
20531994
{
20541995
_listStore = new ArrayItemList<T>(collection);
20551996
}
20561997
else
20571998
{
20581999
_listStore = null;
2059-
Capacity = collection.Count;
2060-
foreach (T item in collection)
2000+
Capacity = count;
2001+
2002+
if (collection is IList<T> list)
20612003
{
2062-
Add(item);
2004+
for (int i = 0; i < count; i++)
2005+
{
2006+
Add(list[i]);
2007+
}
2008+
}
2009+
else
2010+
{
2011+
foreach (T item in collection)
2012+
{
2013+
Add(item);
2014+
}
20632015
}
20642016
}
20652017
}

0 commit comments

Comments
 (0)