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