using System;
using System.Collections.Generic;
using System.Threading;
namespace UniRx
{
///
/// Represents a group of disposable resources that are disposed together.
///
public abstract class StableCompositeDisposable : ICancelable
{
///
/// Creates a new group containing two disposable resources that are disposed together.
///
/// The first disposable resoruce to add to the group.
/// The second disposable resoruce to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2)
{
if (disposable1 == null) throw new ArgumentNullException("disposable1");
if (disposable2 == null) throw new ArgumentNullException("disposable2");
return new Binary(disposable1, disposable2);
}
///
/// Creates a new group containing three disposable resources that are disposed together.
///
/// The first disposable resoruce to add to the group.
/// The second disposable resoruce to add to the group.
/// The third disposable resoruce to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
{
if (disposable1 == null) throw new ArgumentNullException("disposable1");
if (disposable2 == null) throw new ArgumentNullException("disposable2");
if (disposable3 == null) throw new ArgumentNullException("disposable3");
return new Trinary(disposable1, disposable2, disposable3);
}
///
/// Creates a new group containing four disposable resources that are disposed together.
///
/// The first disposable resoruce to add to the group.
/// The second disposable resoruce to add to the group.
/// The three disposable resoruce to add to the group.
/// The four disposable resoruce to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
{
if (disposable1 == null) throw new ArgumentNullException("disposable1");
if (disposable2 == null) throw new ArgumentNullException("disposable2");
if (disposable3 == null) throw new ArgumentNullException("disposable3");
if (disposable4 == null) throw new ArgumentNullException("disposable4");
return new Quaternary(disposable1, disposable2, disposable3, disposable4);
}
///
/// Creates a new group of disposable resources that are disposed together.
///
/// Disposable resources to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(params IDisposable[] disposables)
{
if (disposables == null) throw new ArgumentNullException("disposables");
return new NAry(disposables);
}
///
/// Creates a new group of disposable resources that are disposed together. Array is not copied, it's unsafe but optimized.
///
/// Disposable resources to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable CreateUnsafe(IDisposable[] disposables)
{
return new NAryUnsafe(disposables);
}
///
/// Creates a new group of disposable resources that are disposed together.
///
/// Disposable resources to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(IEnumerable disposables)
{
if (disposables == null) throw new ArgumentNullException("disposables");
return new NAry(disposables);
}
///
/// Disposes all disposables in the group.
///
public abstract void Dispose();
///
/// Gets a value that indicates whether the object is disposed.
///
public abstract bool IsDisposed
{
get;
}
class Binary : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable _disposable1;
private volatile IDisposable _disposable2;
public Binary(IDisposable disposable1, IDisposable disposable2)
{
_disposable1 = disposable1;
_disposable2 = disposable2;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
_disposable1.Dispose();
_disposable2.Dispose();
}
}
}
class Trinary : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable _disposable1;
private volatile IDisposable _disposable2;
private volatile IDisposable _disposable3;
public Trinary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
{
_disposable1 = disposable1;
_disposable2 = disposable2;
_disposable3 = disposable3;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
_disposable1.Dispose();
_disposable2.Dispose();
_disposable3.Dispose();
}
}
}
class Quaternary : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable _disposable1;
private volatile IDisposable _disposable2;
private volatile IDisposable _disposable3;
private volatile IDisposable _disposable4;
public Quaternary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
{
_disposable1 = disposable1;
_disposable2 = disposable2;
_disposable3 = disposable3;
_disposable4 = disposable4;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
_disposable1.Dispose();
_disposable2.Dispose();
_disposable3.Dispose();
_disposable4.Dispose();
}
}
}
class NAry : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile List _disposables;
public NAry(IDisposable[] disposables)
: this((IEnumerable)disposables)
{
}
public NAry(IEnumerable disposables)
{
_disposables = new List(disposables);
//
// Doing this on the list to avoid duplicate enumeration of disposables.
//
if (_disposables.Contains(null)) throw new ArgumentException("Disposables can't contains null", "disposables");
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
foreach (var d in _disposables)
{
d.Dispose();
}
}
}
}
class NAryUnsafe : StableCompositeDisposable
{
int disposedCallCount = -1;
private volatile IDisposable[] _disposables;
public NAryUnsafe(IDisposable[] disposables)
{
_disposables = disposables;
}
public override bool IsDisposed
{
get
{
return disposedCallCount != -1;
}
}
public override void Dispose()
{
if (Interlocked.Increment(ref disposedCallCount) == 0)
{
var len = _disposables.Length;
for (int i = 0; i < len; i++)
{
_disposables[i].Dispose();
}
}
}
}
}
}