Skip to content

Commit 5ba348f

Browse files
Use array instead of List<T>
1 parent e29fe81 commit 5ba348f

File tree

1 file changed

+46
-24
lines changed

1 file changed

+46
-24
lines changed

src/libraries/Common/src/System/Runtime/InteropServices/ComEventsMethod.cs

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ private void PreProcessSignature()
100100
/// Since multicast delegate's built-in chaining supports only chaining instances of the same type,
101101
/// we need to complement this design by using an explicit linked list data structure.
102102
/// </summary>
103-
private List<DelegateWrapper> _delegateWrappers = new List<DelegateWrapper>();
103+
private DelegateWrapper[] _delegateWrappers = Array.Empty<DelegateWrapper>();
104104

105105
private readonly int _dispid;
106106
private ComEventsMethod? _next;
@@ -157,15 +157,15 @@ public bool Empty
157157
{
158158
get
159159
{
160-
List<DelegateWrapper> wrappers = _delegateWrappers;
161-
return wrappers.Count == 0;
160+
DelegateWrapper[] wrappers = _delegateWrappers;
161+
return wrappers.Length == 0;
162162
}
163163
}
164164

165165
public void AddDelegate(Delegate d, bool wrapArgs = false)
166166
{
167-
List<DelegateWrapper> wrappers;
168-
List<DelegateWrapper> newWrappers;
167+
DelegateWrapper[] wrappers;
168+
DelegateWrapper[] newWrappers;
169169
do
170170
{
171171
wrappers = _delegateWrappers;
@@ -180,26 +180,25 @@ public void AddDelegate(Delegate d, bool wrapArgs = false)
180180
}
181181
}
182182

183-
newWrappers = wrappers.Count == 0
184-
? new List<DelegateWrapper>()
185-
: wrappers.GetRange(0, wrappers.Count);
183+
newWrappers = new DelegateWrapper[wrappers.Length + 1];
184+
wrappers.CopyTo(newWrappers, 0);
186185

187-
newWrappers.Add(new DelegateWrapper(d, wrapArgs));
186+
newWrappers[newWrappers.Length - 1] = new DelegateWrapper(d, wrapArgs);
188187
} while (!PublishNewWrappers(newWrappers, wrappers));
189188
}
190189

191190
public void RemoveDelegate(Delegate d, bool wrapArgs = false)
192191
{
193-
List<DelegateWrapper> wrappers;
194-
List<DelegateWrapper> newWrappers;
192+
DelegateWrapper[] wrappers;
193+
DelegateWrapper[] newWrappers;
195194
do
196195
{
197196
wrappers = _delegateWrappers;
198197

199198
// Find delegate wrapper index
200199
int removeIdx = -1;
201200
DelegateWrapper? wrapper = null;
202-
for (int i = 0; i < wrappers.Count; i++)
201+
for (int i = 0; i < wrappers.Length; i++)
203202
{
204203
DelegateWrapper wrapperMaybe = wrappers[i];
205204
if (wrapperMaybe.Delegate.GetType() == d.GetType() && wrapperMaybe.WrapArgs == wrapArgs)
@@ -224,22 +223,22 @@ public void RemoveDelegate(Delegate d, bool wrapArgs = false)
224223
return; // No need to update collection
225224
}
226225

227-
newWrappers = wrappers.GetRange(0, wrappers.Count);
228-
newWrappers.RemoveAt(removeIdx);
226+
newWrappers = new DelegateWrapper[wrappers.Length - 1];
227+
wrappers.AsSpan(0, removeIdx).CopyTo(newWrappers);
228+
wrappers.AsSpan(removeIdx + 1).CopyTo(newWrappers.AsSpan(removeIdx));
229229
} while (!PublishNewWrappers(newWrappers, wrappers));
230230
}
231231

232232
public void RemoveDelegates(Func<Delegate, bool> condition)
233233
{
234-
List<DelegateWrapper> wrappers;
235-
List<DelegateWrapper> newWrappers;
234+
DelegateWrapper[] wrappers;
235+
DelegateWrapper[] newWrappers;
236236
do
237237
{
238238
wrappers = _delegateWrappers;
239239

240-
// Find delegate wrapper indexes. Iterate in reverse such that the list to remove is sorted by high to low index.
241240
List<int> toRemove = new List<int>();
242-
for (int i = wrappers.Count - 1; i >= 0; i--)
241+
for (int i = 0; i < wrappers.Length; i++)
243242
{
244243
DelegateWrapper wrapper = wrappers[i];
245244
Delegate[] invocationList = wrapper.Delegate.GetInvocationList();
@@ -266,20 +265,43 @@ public void RemoveDelegates(Func<Delegate, bool> condition)
266265
return;
267266
}
268267

269-
newWrappers = wrappers.GetRange(0, wrappers.Count);
270-
foreach (int idx in toRemove)
268+
newWrappers = RemoveAll(wrappers, CollectionsMarshal.AsSpan(toRemove));
269+
} while (!PublishNewWrappers(newWrappers, wrappers));
270+
271+
// The list of indices is assumed to be sorted in ascending order
272+
static DelegateWrapper[] RemoveAll(DelegateWrapper[] oldCol, ReadOnlySpan<int> toRemove)
273+
{
274+
// Allocate new collection
275+
var newCol = new DelegateWrapper[oldCol.Length - toRemove.Length];
276+
if (newCol.Length == 0)
271277
{
272-
newWrappers.RemoveAt(idx);
278+
return newCol;
273279
}
274-
} while (!PublishNewWrappers(newWrappers, wrappers));
280+
281+
// Iterate over collection, skipping elements that should be removed.
282+
int ri = 0;
283+
for (int oi = 0, ni = 0; oi < oldCol.Length; oi++)
284+
{
285+
if (ri < toRemove.Length && oi == toRemove[ri])
286+
{
287+
ri++;
288+
continue;
289+
}
290+
291+
newCol[ni] = oldCol[oi];
292+
ni++;
293+
}
294+
295+
return newCol;
296+
}
275297
}
276298

277299
public object? Invoke(object[] args)
278300
{
279301
Debug.Assert(!Empty);
280302
object? result = null;
281303

282-
List<DelegateWrapper> wrappers = _delegateWrappers;
304+
DelegateWrapper[] wrappers = _delegateWrappers;
283305
foreach (DelegateWrapper wrapper in wrappers)
284306
{
285307
result = wrapper.Invoke(args);
@@ -289,7 +311,7 @@ public void RemoveDelegates(Func<Delegate, bool> condition)
289311
}
290312

291313
// Attempt to update the member wrapper field
292-
private bool PublishNewWrappers(List<DelegateWrapper> newWrappers, List<DelegateWrapper> currentMaybe)
314+
private bool PublishNewWrappers(DelegateWrapper[] newWrappers, DelegateWrapper[] currentMaybe)
293315
{
294316
return Interlocked.CompareExchange(ref _delegateWrappers, newWrappers, currentMaybe) == currentMaybe;
295317
}

0 commit comments

Comments
 (0)