a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
387 lines
8.6 KiB
C#
387 lines
8.6 KiB
C#
//
|
|
// System.Collections.Queue
|
|
//
|
|
// Author:
|
|
// Ricardo Fernández Pascual
|
|
//
|
|
// (C) 2001 Ricardo Fernández Pascual
|
|
//
|
|
|
|
//
|
|
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace System.Collections {
|
|
|
|
[ComVisible(true)]
|
|
[System.Diagnostics.DebuggerDisplay ("Count={Count}")]
|
|
[System.Diagnostics.DebuggerTypeProxy (typeof (CollectionDebuggerView))]
|
|
[Serializable]
|
|
#if INSIDE_CORLIB
|
|
public
|
|
#else
|
|
internal
|
|
#endif
|
|
class Queue : ICollection, IEnumerable, ICloneable {
|
|
|
|
private object[] _array;
|
|
private int _head = 0; // points to the first used slot
|
|
private int _size = 0;
|
|
private int _tail = 0;
|
|
private int _growFactor;
|
|
private int _version = 0;
|
|
|
|
public Queue () : this (32, 2.0F) {}
|
|
|
|
public Queue (int capacity) : this (capacity, 2.0F) {}
|
|
|
|
public Queue(ICollection col) : this (col == null ? 32 : col.Count)
|
|
{
|
|
if (col == null)
|
|
throw new ArgumentNullException ("col");
|
|
|
|
// We have to do this because msft seems to call the
|
|
// enumerator rather than CopyTo. This affects classes
|
|
// like bitarray.
|
|
foreach (object o in col)
|
|
Enqueue (o);
|
|
}
|
|
|
|
public Queue (int capacity, float growFactor) {
|
|
if (capacity < 0)
|
|
throw new ArgumentOutOfRangeException("capacity", "Needs a non-negative number");
|
|
if (!(growFactor >= 1.0F && growFactor <= 10.0F))
|
|
throw new ArgumentOutOfRangeException("growFactor", "Queue growth factor must be between 1.0 and 10.0, inclusive");
|
|
|
|
_array = new object[capacity];
|
|
|
|
this._growFactor = (int)(growFactor * 100);
|
|
}
|
|
|
|
// from ICollection
|
|
|
|
public virtual int Count {
|
|
get { return _size; }
|
|
}
|
|
|
|
public virtual bool IsSynchronized {
|
|
get { return false; }
|
|
}
|
|
|
|
public virtual object SyncRoot {
|
|
get { return this; }
|
|
}
|
|
|
|
public virtual void CopyTo (Array array, int index)
|
|
{
|
|
if (array == null)
|
|
throw new ArgumentNullException ("array");
|
|
|
|
if (index < 0)
|
|
throw new ArgumentOutOfRangeException ("index");
|
|
|
|
if (array.Rank > 1
|
|
|| (index != 0 && index >= array.Length)
|
|
|| _size > array.Length - index)
|
|
throw new ArgumentException ();
|
|
|
|
int contents_length = _array.Length;
|
|
int length_from_head = contents_length - _head;
|
|
// copy the _array of the circular array
|
|
Array.Copy (_array, _head, array, index,
|
|
Math.Min (_size, length_from_head));
|
|
if (_size > length_from_head)
|
|
Array.Copy (_array, 0, array,
|
|
index + length_from_head,
|
|
_size - length_from_head);
|
|
}
|
|
|
|
// from IEnumerable
|
|
|
|
public virtual IEnumerator GetEnumerator () {
|
|
return new QueueEnumerator (this);
|
|
}
|
|
|
|
// from ICloneable
|
|
|
|
public virtual object Clone () {
|
|
Queue newQueue;
|
|
|
|
newQueue = new Queue (this._array.Length);
|
|
newQueue._growFactor = _growFactor;
|
|
|
|
Array.Copy (this._array, 0, newQueue._array, 0,
|
|
this._array.Length);
|
|
newQueue._head = this._head;
|
|
newQueue._size = this._size;
|
|
newQueue._tail = this._tail;
|
|
|
|
return newQueue;
|
|
}
|
|
|
|
public virtual void Clear () {
|
|
_version++;
|
|
_head = 0;
|
|
_size = 0;
|
|
_tail = 0;
|
|
for (int length = _array.Length - 1; length >= 0; length--)
|
|
_array [length] = null;
|
|
}
|
|
|
|
public virtual bool Contains (object obj) {
|
|
int tail = _head + _size;
|
|
if (obj == null) {
|
|
for (int i = _head; i < tail; i++) {
|
|
if (_array[i % _array.Length] == null)
|
|
return true;
|
|
}
|
|
} else {
|
|
for (int i = _head; i < tail; i++) {
|
|
if (obj.Equals (_array[i % _array.Length]))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public virtual object Dequeue ()
|
|
{
|
|
_version++;
|
|
if (_size < 1)
|
|
throw new InvalidOperationException ();
|
|
object result = _array[_head];
|
|
_array [_head] = null;
|
|
_head = (_head + 1) % _array.Length;
|
|
_size--;
|
|
return result;
|
|
}
|
|
|
|
public virtual void Enqueue (object obj) {
|
|
_version++;
|
|
if (_size == _array.Length)
|
|
grow ();
|
|
_array[_tail] = obj;
|
|
_tail = (_tail+1) % _array.Length;
|
|
_size++;
|
|
|
|
}
|
|
|
|
public virtual object Peek () {
|
|
if (_size < 1)
|
|
throw new InvalidOperationException ();
|
|
return _array[_head];
|
|
}
|
|
|
|
public static Queue Synchronized (Queue queue) {
|
|
if (queue == null) {
|
|
throw new ArgumentNullException ("queue");
|
|
}
|
|
return new SyncQueue (queue);
|
|
}
|
|
|
|
public virtual object[] ToArray () {
|
|
object[] ret = new object[_size];
|
|
CopyTo (ret, 0);
|
|
return ret;
|
|
}
|
|
|
|
public virtual void TrimToSize() {
|
|
_version++;
|
|
object[] trimmed = new object [_size];
|
|
CopyTo (trimmed, 0);
|
|
_array = trimmed;
|
|
_head = 0;
|
|
_tail = 0;
|
|
}
|
|
|
|
// private methods
|
|
|
|
private void grow () {
|
|
int newCapacity = (_array.Length * _growFactor) / 100;
|
|
if (newCapacity < _array.Length + 1)
|
|
newCapacity = _array.Length + 1;
|
|
object[] newContents = new object[newCapacity];
|
|
CopyTo (newContents, 0);
|
|
_array = newContents;
|
|
_head = 0;
|
|
_tail = _head + _size;
|
|
}
|
|
|
|
// private classes
|
|
|
|
private class SyncQueue : Queue {
|
|
Queue queue;
|
|
|
|
internal SyncQueue (Queue queue) {
|
|
this.queue = queue;
|
|
}
|
|
|
|
public override int Count {
|
|
get {
|
|
lock (queue) {
|
|
return queue.Count;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool IsSynchronized {
|
|
get {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public override object SyncRoot {
|
|
get {
|
|
return queue.SyncRoot;
|
|
}
|
|
}
|
|
|
|
public override void CopyTo (Array array, int index) {
|
|
lock (queue) {
|
|
queue.CopyTo (array, index);
|
|
}
|
|
}
|
|
|
|
public override IEnumerator GetEnumerator () {
|
|
lock (queue) {
|
|
return queue.GetEnumerator ();
|
|
}
|
|
}
|
|
|
|
public override object Clone () {
|
|
lock (queue) {
|
|
return new SyncQueue((Queue) queue.Clone ());
|
|
}
|
|
}
|
|
|
|
/*
|
|
public override bool IsReadOnly {
|
|
get {
|
|
lock (queue) {
|
|
return queue.IsReadOnly;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
public override void Clear () {
|
|
lock (queue) {
|
|
queue.Clear ();
|
|
}
|
|
}
|
|
|
|
public override void TrimToSize () {
|
|
lock (queue) {
|
|
queue.TrimToSize ();
|
|
}
|
|
}
|
|
|
|
public override bool Contains (object obj) {
|
|
lock (queue) {
|
|
return queue.Contains (obj);
|
|
}
|
|
}
|
|
|
|
public override object Dequeue () {
|
|
lock (queue) {
|
|
return queue.Dequeue ();
|
|
}
|
|
}
|
|
|
|
public override void Enqueue (object obj) {
|
|
lock (queue) {
|
|
queue.Enqueue (obj);
|
|
}
|
|
}
|
|
|
|
public override object Peek () {
|
|
lock (queue) {
|
|
return queue.Peek ();
|
|
}
|
|
}
|
|
|
|
public override object[] ToArray () {
|
|
lock (queue) {
|
|
return queue.ToArray ();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
private class QueueEnumerator : IEnumerator, ICloneable {
|
|
Queue queue;
|
|
private int _version;
|
|
private int current;
|
|
|
|
internal QueueEnumerator (Queue q) {
|
|
queue = q;
|
|
_version = q._version;
|
|
current = -1; // one element before the _head
|
|
}
|
|
|
|
public object Clone ()
|
|
{
|
|
QueueEnumerator q = new QueueEnumerator (queue);
|
|
q._version = _version;
|
|
q.current = current;
|
|
return q;
|
|
}
|
|
|
|
public virtual object Current {
|
|
get {
|
|
if (_version != queue._version
|
|
|| current < 0
|
|
|| current >= queue._size)
|
|
throw new InvalidOperationException ();
|
|
return queue._array[(queue._head + current) % queue._array.Length];
|
|
}
|
|
}
|
|
|
|
public virtual bool MoveNext () {
|
|
if (_version != queue._version) {
|
|
throw new InvalidOperationException ();
|
|
}
|
|
|
|
if (current >= queue._size - 1) {
|
|
current = Int32.MaxValue; // to late!
|
|
return false;
|
|
} else {
|
|
current++;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public virtual void Reset () {
|
|
if (_version != queue._version) {
|
|
throw new InvalidOperationException();
|
|
}
|
|
current = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|