86 lines
2.7 KiB
C#
86 lines
2.7 KiB
C#
|
//------------------------------------------------------------------------------
|
|||
|
// <copyright file="SubscriptionQueue.cs" company="Microsoft">
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
// </copyright>
|
|||
|
//------------------------------------------------------------------------------
|
|||
|
|
|||
|
namespace System.Web.Util {
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Web;
|
|||
|
|
|||
|
// Similar to a Queue<T>, but allows unsubscribing from the underlying queue.
|
|||
|
//
|
|||
|
// !! WARNING !!
|
|||
|
// Mutable struct for performance reasons; optimized for case where Enqueue is never called.
|
|||
|
// Be careful with usage, e.g. no readonly declarations of this type.
|
|||
|
//
|
|||
|
// Type is not thread safe.
|
|||
|
|
|||
|
internal struct SubscriptionQueue<T> {
|
|||
|
|
|||
|
private LinkedList<T> _list;
|
|||
|
|
|||
|
public bool IsEmpty {
|
|||
|
get { return (_list == null || _list.Count == 0); }
|
|||
|
}
|
|||
|
|
|||
|
public ISubscriptionToken Enqueue(T value) {
|
|||
|
if (_list == null) {
|
|||
|
// lazily instantiate the list
|
|||
|
_list = new LinkedList<T>();
|
|||
|
}
|
|||
|
|
|||
|
LinkedListNode<T> node = _list.AddLast(value);
|
|||
|
return new SubscriptionToken(node);
|
|||
|
}
|
|||
|
|
|||
|
public void FireAndComplete(Action<T> action) {
|
|||
|
try {
|
|||
|
T value;
|
|||
|
// Use a while loop instead of a foreach since the list might be changing
|
|||
|
while (TryDequeue(out value)) {
|
|||
|
action(value);
|
|||
|
}
|
|||
|
}
|
|||
|
finally {
|
|||
|
_list = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool TryDequeue(out T result) {
|
|||
|
if (_list != null && _list.First != null) {
|
|||
|
LinkedListNode<T> theNode = _list.First;
|
|||
|
_list.RemoveFirst(); // also marks the SubscriptionToken as inactive
|
|||
|
result = theNode.Value;
|
|||
|
theNode.Value = default(T); // unroot the value in case it's large
|
|||
|
return true;
|
|||
|
}
|
|||
|
else {
|
|||
|
result = default(T); // unroot the value in case it's large
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private sealed class SubscriptionToken : ISubscriptionToken {
|
|||
|
private readonly LinkedListNode<T> _node;
|
|||
|
|
|||
|
public SubscriptionToken(LinkedListNode<T> node) {
|
|||
|
_node = node;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsActive {
|
|||
|
get { return (_node.List != null); }
|
|||
|
}
|
|||
|
|
|||
|
public void Unsubscribe() {
|
|||
|
if (IsActive) {
|
|||
|
_node.List.Remove(_node);
|
|||
|
_node.Value = default(T); // unroot the value in case it's large
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|