121 lines
3.5 KiB
Plaintext
121 lines
3.5 KiB
Plaintext
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: TQueue.sg
|
||
|
//
|
||
|
// Note: File is part of Sing# runtime files and copied into Singularity tree
|
||
|
// whenever a new version of Sing# is dropped.
|
||
|
//
|
||
|
|
||
|
using Microsoft.SingSharp;
|
||
|
|
||
|
namespace Microsoft.Singularity.Channels {
|
||
|
|
||
|
public class TQueue<T> : ITracked where T : ITracked {
|
||
|
|
||
|
private Node! listSentinel;
|
||
|
|
||
|
public TQueue() {
|
||
|
this.listSentinel = new Node();
|
||
|
base();
|
||
|
}
|
||
|
|
||
|
private class Node {
|
||
|
unsafe internal T data;
|
||
|
|
||
|
internal Node! next;
|
||
|
internal Node! prev;
|
||
|
|
||
|
internal Node() {
|
||
|
this.next = this;
|
||
|
this.prev = this;
|
||
|
}
|
||
|
|
||
|
internal Node([Claims] T! arg) {
|
||
|
this.next = this;
|
||
|
this.prev = this;
|
||
|
this.data = arg;
|
||
|
}
|
||
|
|
||
|
internal T Unlink() {
|
||
|
this.prev.next = this.next;
|
||
|
this.next.prev = this.prev;
|
||
|
this.next = this;
|
||
|
this.prev = this;
|
||
|
return this.data;
|
||
|
}
|
||
|
|
||
|
internal void LinkAsNext([Claims] T! data) {
|
||
|
Node next = new Node(data);
|
||
|
next.next = this.next;
|
||
|
this.next = next;
|
||
|
next.prev = this;
|
||
|
next.next.prev = next;
|
||
|
}
|
||
|
|
||
|
internal void LinkAsPrev([Claims] T! data) {
|
||
|
Node prev = new Node(data);
|
||
|
prev.prev = this.prev;
|
||
|
this.prev = prev;
|
||
|
prev.next = this;
|
||
|
prev.prev.next = prev;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#region ITracked members
|
||
|
|
||
|
void ITracked.Release() {}
|
||
|
void ITracked.Acquire() {}
|
||
|
public void Dispose()
|
||
|
{
|
||
|
Node current = this.listSentinel.next;
|
||
|
while (current != this.listSentinel) {
|
||
|
T! data = (!)current.data;
|
||
|
data.Dispose();
|
||
|
current = current.next;
|
||
|
}
|
||
|
this.listSentinel = new Node();
|
||
|
}
|
||
|
|
||
|
void ITracked.Expose() {}
|
||
|
void ITracked.UnExpose() {}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
public void AddHead([Claims] T! data) {
|
||
|
this.listSentinel.LinkAsNext(data);
|
||
|
}
|
||
|
|
||
|
public void AddTail([Claims] T! data) {
|
||
|
this.listSentinel.LinkAsPrev(data);
|
||
|
}
|
||
|
|
||
|
public bool Empty { get { return this.listSentinel.next == this.listSentinel; } }
|
||
|
|
||
|
public T ExtractHead() {
|
||
|
// Checking if list is empty
|
||
|
// and returning null causes the compiler to warn
|
||
|
// that return value can't be null (?).
|
||
|
//
|
||
|
// The following code works correctly whether the
|
||
|
// queue is empty or not.
|
||
|
Node candidate = this.listSentinel.next;
|
||
|
return candidate.Unlink();
|
||
|
}
|
||
|
|
||
|
public T ExtractTail() {
|
||
|
// Checking if list is empty
|
||
|
// and returning null causes the compiler to warn
|
||
|
// that return value can't be null (?).
|
||
|
//
|
||
|
// The following code works correctly whether the
|
||
|
// queue is empty or not.
|
||
|
Node candidate = this.listSentinel.prev;
|
||
|
return candidate.Unlink();
|
||
|
}
|
||
|
}
|
||
|
}
|