You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
6.3 KiB
232 lines
6.3 KiB
5 years ago
|
#if FAT
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
|
||
|
namespace LinqInternal.Threading.Needles
|
||
|
{
|
||
|
[System.Diagnostics.DebuggerNonUserCode]
|
||
|
internal sealed class ReadOnlyDisposableNeedle<T> : IReadOnlyNeedle<T>
|
||
|
{
|
||
|
private readonly int _hashCode;
|
||
|
private bool _isAlive;
|
||
|
private int _status;
|
||
|
private T _target;
|
||
|
|
||
|
public ReadOnlyDisposableNeedle()
|
||
|
{
|
||
|
_isAlive = false;
|
||
|
_hashCode = EqualityComparer<T>.Default.GetHashCode(default(T));
|
||
|
}
|
||
|
|
||
|
public ReadOnlyDisposableNeedle(T target)
|
||
|
{
|
||
|
_isAlive = true;
|
||
|
_target = target;
|
||
|
_hashCode = EqualityComparer<T>.Default.GetHashCode(target);
|
||
|
}
|
||
|
|
||
|
public bool IsAlive
|
||
|
{
|
||
|
get { return _isAlive; }
|
||
|
}
|
||
|
|
||
|
public bool IsDisposed
|
||
|
{
|
||
|
get { return _status == -1; }
|
||
|
}
|
||
|
|
||
|
public T Value
|
||
|
{
|
||
|
get { return _target; }
|
||
|
}
|
||
|
|
||
|
public static explicit operator T(ReadOnlyDisposableNeedle<T> needle)
|
||
|
{
|
||
|
if (needle == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("needle");
|
||
|
}
|
||
|
return needle.Value;
|
||
|
}
|
||
|
|
||
|
public static implicit operator ReadOnlyDisposableNeedle<T>(T field)
|
||
|
{
|
||
|
return new ReadOnlyDisposableNeedle<T>(field);
|
||
|
}
|
||
|
|
||
|
public static bool operator !=(ReadOnlyDisposableNeedle<T> left, ReadOnlyDisposableNeedle<T> right)
|
||
|
{
|
||
|
if (left == null && right == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (left == null || right == null)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
return !EqualityComparer<T>.Default.Equals(left._target, right._target);
|
||
|
}
|
||
|
|
||
|
public static bool operator ==(ReadOnlyDisposableNeedle<T> left, ReadOnlyDisposableNeedle<T> right)
|
||
|
{
|
||
|
if (left == null && right == null)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
if (left == null || right == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return EqualityComparer<T>.Default.Equals(left._target, right._target);
|
||
|
}
|
||
|
|
||
|
[System.Diagnostics.DebuggerNonUserCode]
|
||
|
public void Dispose()
|
||
|
{
|
||
|
if (TakeDisposalExecution())
|
||
|
{
|
||
|
Kill();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[System.Diagnostics.DebuggerNonUserCode]
|
||
|
public void DisposedConditional(Action whenDisposed, Action whenNotDisposed)
|
||
|
{
|
||
|
if (_status == -1)
|
||
|
{
|
||
|
if (whenDisposed == null)
|
||
|
{
|
||
|
whenDisposed.Invoke();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (whenNotDisposed != null)
|
||
|
{
|
||
|
if (ThreadingHelper.SpinWaitRelativeSet(ref _status, 1, -1))
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
whenNotDisposed.Invoke();
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
System.Threading.Interlocked.Decrement(ref _status);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (whenDisposed == null)
|
||
|
{
|
||
|
whenDisposed.Invoke();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[System.Diagnostics.DebuggerNonUserCode]
|
||
|
public TReturn DisposedConditional<TReturn>(Func<TReturn> whenDisposed, Func<TReturn> whenNotDisposed)
|
||
|
{
|
||
|
if (_status == -1)
|
||
|
{
|
||
|
if (whenDisposed == null)
|
||
|
{
|
||
|
return default(TReturn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return whenDisposed.Invoke();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (whenNotDisposed == null)
|
||
|
{
|
||
|
return default(TReturn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ThreadingHelper.SpinWaitRelativeSet(ref _status, 1, -1))
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
return whenNotDisposed.Invoke();
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
System.Threading.Interlocked.Decrement(ref _status);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (whenDisposed == null)
|
||
|
{
|
||
|
return default(TReturn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return whenDisposed.Invoke();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override bool Equals(object obj)
|
||
|
{
|
||
|
var needle = obj as ReadOnlyDisposableNeedle<T>;
|
||
|
if (needle != null)
|
||
|
{
|
||
|
return EqualityComparer<T>.Default.Equals(_target, needle._target);
|
||
|
}
|
||
|
// Keep the "is" operator
|
||
|
if (obj is T)
|
||
|
{
|
||
|
return EqualityComparer<T>.Default.Equals(_target, (T)obj);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public bool Equals(ReadOnlyDisposableNeedle<T> other)
|
||
|
{
|
||
|
return !ReferenceEquals(_target, null) && EqualityComparer<T>.Default.Equals(_target, other.Value);
|
||
|
}
|
||
|
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
return _hashCode;
|
||
|
}
|
||
|
|
||
|
public override string ToString()
|
||
|
{
|
||
|
var target = Value;
|
||
|
if (_isAlive)
|
||
|
{
|
||
|
return target.ToString();
|
||
|
}
|
||
|
return "<Dead Needle>";
|
||
|
}
|
||
|
|
||
|
private void Kill()
|
||
|
{
|
||
|
_isAlive = false;
|
||
|
_target = default(T);
|
||
|
}
|
||
|
|
||
|
private bool TakeDisposalExecution()
|
||
|
{
|
||
|
if (_status == -1)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return ThreadingHelper.SpinWaitSetUnless(ref _status, -1, 0, -1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|