Browse Source
* Switch to a set as backing for _listeners on Classes. Via the `SafeEnumerableHashSet` * Update docspull/16677/head
committed by
GitHub
4 changed files with 100 additions and 109 deletions
@ -0,0 +1,80 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Avalonia.Utilities |
|||
{ |
|||
/// <summary>
|
|||
/// Implements a simple set which is safe to modify during enumeration.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The item type.</typeparam>
|
|||
/// <remarks>
|
|||
/// Implements a set which, when written to while enumerating, performs a copy of the set
|
|||
/// items. Note this class doesn't actually implement <see cref="ISet{T}"/> as it's not
|
|||
/// currently needed - feel free to add missing methods etc.
|
|||
/// </remarks>
|
|||
internal class SafeEnumerableHashSet<T> : IEnumerable<T> |
|||
{ |
|||
private HashSet<T> _hashSet = new(); |
|||
private int _generation; |
|||
private int _enumCount = 0; |
|||
|
|||
public int Count => _hashSet.Count; |
|||
internal HashSet<T> Inner => _hashSet; |
|||
|
|||
public void Add(T item) => GetSet().Add(item); |
|||
public bool Remove(T item) => GetSet().Remove(item); |
|||
|
|||
public Enumerator GetEnumerator() => new(this, _hashSet); |
|||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator(); |
|||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); |
|||
|
|||
private HashSet<T> GetSet() |
|||
{ |
|||
if (_enumCount > 0) |
|||
{ |
|||
// .NET has a fastpath for cloning a hashset when passed in via the constructor
|
|||
_hashSet = new(_hashSet); |
|||
++_generation; |
|||
_enumCount = 0; |
|||
} |
|||
|
|||
return _hashSet; |
|||
} |
|||
|
|||
public struct Enumerator : IEnumerator<T>, IEnumerator |
|||
{ |
|||
private readonly SafeEnumerableHashSet<T> _owner; |
|||
private readonly int _generation; |
|||
private HashSet<T>.Enumerator _enumerator; |
|||
|
|||
internal Enumerator(SafeEnumerableHashSet<T> owner, HashSet<T> list) |
|||
{ |
|||
_owner = owner; |
|||
_generation = owner._generation; |
|||
++_owner._enumCount; |
|||
_enumerator = list.GetEnumerator(); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_enumerator.Dispose(); |
|||
if (_owner._generation == _generation) |
|||
--_owner._enumCount; |
|||
} |
|||
|
|||
public bool MoveNext() |
|||
{ |
|||
return _enumerator.MoveNext(); |
|||
} |
|||
|
|||
public T Current => _enumerator.Current; |
|||
object? IEnumerator.Current => _enumerator.Current; |
|||
|
|||
void IEnumerator.Reset() |
|||
{ |
|||
throw new NotSupportedException(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,89 +0,0 @@ |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Avalonia.Utilities |
|||
{ |
|||
/// <summary>
|
|||
/// Implements a simple list which is safe to modify during enumeration.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The item type.</typeparam>
|
|||
/// <remarks>
|
|||
/// Implements a list which, when written to while enumerating, performs a copy of the list
|
|||
/// items. Note this this class doesn't actually implement <see cref="IList{T}"/> as it's not
|
|||
/// currently needed - feel free to add missing methods etc.
|
|||
/// </remarks>
|
|||
internal class SafeEnumerableList<T> : IEnumerable<T> |
|||
{ |
|||
private List<T> _list = new(); |
|||
private int _generation; |
|||
private int _enumCount = 0; |
|||
|
|||
public int Count => _list.Count; |
|||
internal List<T> Inner => _list; |
|||
|
|||
public void Add(T item) => GetList().Add(item); |
|||
public bool Remove(T item) => GetList().Remove(item); |
|||
|
|||
public Enumerator GetEnumerator() => new(this, _list); |
|||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator(); |
|||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); |
|||
|
|||
private List<T> GetList() |
|||
{ |
|||
if (_enumCount > 0) |
|||
{ |
|||
_list = new(_list); |
|||
++_generation; |
|||
_enumCount = 0; |
|||
} |
|||
|
|||
return _list; |
|||
} |
|||
|
|||
public struct Enumerator : IEnumerator<T>, IEnumerator |
|||
{ |
|||
private readonly SafeEnumerableList<T> _owner; |
|||
private readonly List<T> _list; |
|||
private readonly int _generation; |
|||
private int _index; |
|||
private T? _current; |
|||
|
|||
internal Enumerator(SafeEnumerableList<T> owner, List<T> list) |
|||
{ |
|||
_owner = owner; |
|||
_list = list; |
|||
_generation = owner._generation; |
|||
_index = 0; |
|||
_current = default; |
|||
++_owner._enumCount; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
if (_owner._generation == _generation) |
|||
--_owner._enumCount; |
|||
} |
|||
|
|||
public bool MoveNext() |
|||
{ |
|||
if (_index < _list.Count) |
|||
{ |
|||
_current = _list[_index++]; |
|||
return true; |
|||
} |
|||
|
|||
_current = default; |
|||
return false; |
|||
} |
|||
|
|||
public T Current => _current!; |
|||
object? IEnumerator.Current => _current; |
|||
|
|||
void IEnumerator.Reset() |
|||
{ |
|||
_index = 0; |
|||
_current = default; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue