@@ -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