15 changed files with 241 additions and 59 deletions
@ -0,0 +1,143 @@ |
|||
using System; |
|||
using System.Runtime.ConstrainedExecution; |
|||
using System.Threading; |
|||
|
|||
namespace Avalonia.Utilities |
|||
{ |
|||
public interface IRef<out T> : IDisposable where T : class |
|||
{ |
|||
T Item { get; } |
|||
IRef<T> Clone(); |
|||
IRef<TResult> CloneAs<TResult>() where TResult : class; |
|||
} |
|||
|
|||
|
|||
|
|||
public static class RefCountable |
|||
{ |
|||
public static IRef<T> Create<T>(T item) where T : class, IDisposable |
|||
{ |
|||
return new Ref<T>(item, new RefCounter(item)); |
|||
} |
|||
|
|||
public static IRef<T> CreateUnownedNotClonable<T>(T item) where T : class |
|||
=> new TempRef<T>(item); |
|||
|
|||
class TempRef<T> : IRef<T> where T : class |
|||
{ |
|||
public void Dispose() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public TempRef(T item) |
|||
{ |
|||
Item = item; |
|||
} |
|||
|
|||
public T Item { get; } |
|||
public IRef<T> Clone() => throw new NotSupportedException(); |
|||
|
|||
public IRef<TResult> CloneAs<TResult>() where TResult : class |
|||
=> throw new NotSupportedException(); |
|||
} |
|||
|
|||
class RefCounter |
|||
{ |
|||
private IDisposable _item; |
|||
private volatile int _refs; |
|||
private object _lock = new object(); |
|||
|
|||
public RefCounter(IDisposable item) |
|||
{ |
|||
_item = item; |
|||
} |
|||
|
|||
public void AddRef() |
|||
{ |
|||
Interlocked.Increment(ref _refs); |
|||
} |
|||
|
|||
public void Release() |
|||
{ |
|||
if (Interlocked.Decrement(ref _refs) == 0) |
|||
{ |
|||
lock (_lock) |
|||
{ |
|||
_item?.Dispose(); |
|||
_item = null; |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
class Ref<T> : CriticalFinalizerObject, IRef<T> where T : class |
|||
{ |
|||
private T _item; |
|||
private RefCounter _counter; |
|||
private object _lock = new object(); |
|||
|
|||
public Ref(T item, RefCounter counter) |
|||
{ |
|||
_item = item; |
|||
_counter = counter; |
|||
Thread.MemoryBarrier(); |
|||
_counter.AddRef(); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
lock (_lock) |
|||
{ |
|||
if (_item != null) |
|||
{ |
|||
_counter.Release(); |
|||
_item = null; |
|||
} |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
} |
|||
|
|||
~Ref() |
|||
{ |
|||
_counter?.Release(); |
|||
} |
|||
|
|||
public T Item |
|||
{ |
|||
get |
|||
{ |
|||
lock (_lock) |
|||
{ |
|||
return _item; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public IRef<T> Clone() |
|||
{ |
|||
lock (_lock) |
|||
{ |
|||
if (_item != null) |
|||
return new Ref<T>(_item, _counter); |
|||
throw new ObjectDisposedException("Ref<" + typeof(T) + ">"); |
|||
} |
|||
} |
|||
|
|||
public IRef<TResult> CloneAs<TResult>() where TResult : class |
|||
{ |
|||
lock (_lock) |
|||
{ |
|||
lock (_lock) |
|||
{ |
|||
if (_item != null) |
|||
return new Ref<TResult>((TResult) (object) _item, _counter); |
|||
throw new ObjectDisposedException("Ref<" + typeof(T) + ">"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue