Skip to content

Commit b4f66bd

Browse files
committed
Memory improvements for weak messenger on NS2.0
1 parent cfc7865 commit b4f66bd

File tree

1 file changed

+77
-10
lines changed

1 file changed

+77
-10
lines changed

Microsoft.Toolkit.Mvvm/Messaging/WeakReferenceMessenger.cs

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -346,25 +346,92 @@ public bool Remove(TKey key)
346346
}
347347

348348
/// <inheritdoc cref="IEnumerable{T}.GetEnumerator"/>
349-
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
349+
[Pure]
350+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
351+
public Enumerator GetEnumerator() => new(this);
352+
353+
/// <summary>
354+
/// A custom enumerator that traverses items in a <see cref="ConditionalWeakTable{TKey, TValue}"/> instance.
355+
/// </summary>
356+
public ref struct Enumerator
350357
{
351-
for (LinkedListNode<WeakReference<TKey>>? node = this.keys.First; !(node is null);)
358+
/// <summary>
359+
/// The owner <see cref="ConditionalWeakTable{TKey, TValue}"/> instance for the enumerator.
360+
/// </summary>
361+
private readonly ConditionalWeakTable<TKey, TValue> owner;
362+
363+
/// <summary>
364+
/// The current <see cref="LinkedListNode{T}"/>, if any.
365+
/// </summary>
366+
private LinkedListNode<WeakReference<TKey>>? node;
367+
368+
/// <summary>
369+
/// The current <see cref="KeyValuePair{TKey, TValue}"/> to return.
370+
/// </summary>
371+
private KeyValuePair<TKey, TValue> current;
372+
373+
/// <summary>
374+
/// Indicates whether or not <see cref="MoveNext"/> has been called at least once.
375+
/// </summary>
376+
private bool isFirstMoveNextPending;
377+
378+
/// <summary>
379+
/// Initializes a new instance of the <see cref="Enumerator"/> struct.
380+
/// </summary>
381+
/// <param name="owner">The owner <see cref="ConditionalWeakTable{TKey, TValue}"/> instance for the enumerator.</param>
382+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
383+
public Enumerator(ConditionalWeakTable<TKey, TValue> owner)
352384
{
353-
LinkedListNode<WeakReference<TKey>>? next = node.Next;
385+
this.owner = owner;
386+
this.node = null;
387+
this.current = default;
388+
this.isFirstMoveNextPending = true;
389+
}
390+
391+
/// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
392+
public bool MoveNext()
393+
{
394+
LinkedListNode<WeakReference<TKey>>? node;
354395

355-
// Get the key and value for the current node
356-
if (node.Value.TryGetTarget(out TKey? target) &&
357-
this.table.TryGetValue(target!, out TValue value))
396+
if (!isFirstMoveNextPending)
358397
{
359-
yield return new(target, value);
398+
node = this.node!.Next;
360399
}
361400
else
362401
{
363-
// If the current key has been collected, trim the list
364-
this.keys.Remove(node);
402+
node = this.owner.keys.First;
403+
404+
this.isFirstMoveNextPending = false;
365405
}
366406

367-
node = next;
407+
while (node is not null)
408+
{
409+
// Get the key and value for the current node
410+
if (node.Value.TryGetTarget(out TKey? target) &&
411+
this.owner.table.TryGetValue(target!, out TValue value))
412+
{
413+
this.node = node;
414+
this.current = new KeyValuePair<TKey, TValue>(target, value);
415+
416+
return true;
417+
}
418+
else
419+
{
420+
// If the current key has been collected, trim the list
421+
this.owner.keys.Remove(node);
422+
}
423+
424+
node = node.Next;
425+
}
426+
427+
return false;
428+
}
429+
430+
/// <inheritdoc cref="System.Collections.IEnumerator.MoveNext"/>
431+
public readonly KeyValuePair<TKey, TValue> Current
432+
{
433+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
434+
get => this.current;
368435
}
369436
}
370437
}

0 commit comments

Comments
 (0)