Merge pull request #2971 from BrzVlad/feature-cross-binprot
[mono.git] / mcs / class / referencesource / System.Web / Util / SubscriptionQueue.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SubscriptionQueue.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.Util {
8     using System;
9     using System.Collections.Generic;
10     using System.Web;
11
12     // Similar to a Queue<T>, but allows unsubscribing from the underlying queue.
13     //
14     // !! WARNING !!
15     // Mutable struct for performance reasons; optimized for case where Enqueue is never called.
16     // Be careful with usage, e.g. no readonly declarations of this type.
17     //
18     // Type is not thread safe.
19
20     internal struct SubscriptionQueue<T> {
21
22         private LinkedList<T> _list;
23
24         public bool IsEmpty {
25             get { return (_list == null || _list.Count == 0); }
26         }
27
28         public ISubscriptionToken Enqueue(T value) {
29             if (_list == null) {
30                 // lazily instantiate the list
31                 _list = new LinkedList<T>();
32             }
33
34             LinkedListNode<T> node = _list.AddLast(value);
35             return new SubscriptionToken(node);
36         }
37
38         public void FireAndComplete(Action<T> action) {
39             try {
40                 T value;
41                 // Use a while loop instead of a foreach since the list might be changing
42                 while (TryDequeue(out value)) {
43                     action(value);
44                 }
45             }
46             finally {
47                 _list = null;
48             }
49         }
50
51         private bool TryDequeue(out T result) {
52             if (_list != null && _list.First != null) {
53                 LinkedListNode<T> theNode = _list.First;
54                 _list.RemoveFirst(); // also marks the SubscriptionToken as inactive
55                 result = theNode.Value;
56                 theNode.Value = default(T); // unroot the value in case it's large
57                 return true;
58             }
59             else {
60                 result = default(T); // unroot the value in case it's large
61                 return false;
62             }
63         }
64
65         private sealed class SubscriptionToken : ISubscriptionToken {
66             private readonly LinkedListNode<T> _node;
67
68             public SubscriptionToken(LinkedListNode<T> node) {
69                 _node = node;
70             }
71
72             public bool IsActive {
73                 get { return (_node.List != null); }
74             }
75
76             public void Unsubscribe() {
77                 if (IsActive) {
78                     _node.List.Remove(_node);
79                     _node.Value = default(T); // unroot the value in case it's large
80                 }
81             }
82         }
83
84     }
85 }