Laden...

Bulk Queue-Klasse

Erstellt von kleines_eichhoernchen vor 16 Jahren Letzter Beitrag vor 16 Jahren 4.440 Views
kleines_eichhoernchen Themenstarter:in
3.971 Beiträge seit 2006
vor 16 Jahren
Bulk Queue-Klasse

Beschreibung:
Diese Klasse, hat den selben Aufbau wie System.Collections.Generic.Queue<T> und kann auch genauso verwendet werden. Sie bietet die Funktionen EnqueueBulk, DequeueBulk und PeekBulk, die jeweils die selben Funktionen haben, wie die Pendanten, mit dem Unterschied, das jeweils mehrere Daten mit einem Rutsch verarbeitet können.


using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace MySystem.Collections.Generic
{
	/// <summary>
	/// Stellt eine FIFO-Auflistung von Objekten da.
	/// </summary>
	/// <typeparam name="T">Der Datentyp</typeparam>
	public class MyQueue<T> : ICollection, IEnumerable<T>
	{
		#region Konstanten

		private const int DefaultCapacity = 4;

		#endregion

		#region Nesty

		/// <summary>
		/// Listet die Elemente aus der MyQueue-Klasse auf.
		/// </summary>
		public struct Enumerator : IEnumerator<T>, IDisposable
		{
			#region Felder

			private MyQueue<T> _queue;
			private int _index;
			private int _version;
			private T _currentElement;

			#endregion

			#region Eigenschaften

			#endregion

			#region Konstruktoren

			internal Enumerator(MyQueue<T> queue)
			{
				this._queue = queue;
				this._version = queue._version;
				this._index = -1;
				this._currentElement = default(T);
			}

			#endregion

			#region Funktionen

			#endregion

			#region IEnumerator<T> Member

			/// <summary>
			/// Gibt das aktuelle Element zurück.
			/// </summary>
			public T Current
			{
				get { return this._currentElement; }
			}

			#endregion

			#region IDisposable Member

			/// <summary>
			/// Gibt alle verwendeten Ressourcen wieder frei.
			/// </summary>
			public void Dispose()
			{
				this._index = -2;
				this._currentElement = default(T);
			}

			#endregion

			#region IEnumerator Member

			object IEnumerator.Current
			{
				get { return this._currentElement; }
			}

			/// <summary>
			/// Setzt den Zeiger auf das nächste Element in der Liste.
			/// </summary>
			/// <returns>Gibt true zurück, wenn der Enumerator erfolgreich auf das nächste Element setzen konnte, false wenn das Ende der Liste überschritten wurde.</returns>
			public bool MoveNext()
			{
				if (this._version != this._queue._version)
					throw new InvalidOperationException("Die Auflistung hat sich geändert.");
				else
				{
					if (this._index < -1)
						return false;
					else
					{
						this._index++;
						if (this._index >= this._queue.Count)
						{
							this.Dispose();
							return false;
						}
						else
						{
							this._currentElement = this._queue.GetElement(this._index);
							return true;
						}
					}
				}
			}

			/// <summary>
			/// Setzt den Enumerator auf die anfängliche Position zurück.
			/// </summary>
			public void Reset()
			{
				if (this._version != this._queue._version)
					throw new InvalidOperationException("Die Auflistung hat sich geändert.");
				else
				{
					this._index = -1;
					this._currentElement = default(T);
				}
			}

			#endregion
		}

		#endregion

		#region Felder

		protected T[] _data;
		protected int _head = 0;
		protected int _size;
		protected int _tail = 0;
		protected int _version = 0;

		#endregion

		#region Eigenschaften

		#endregion

		#region Konstruktoren

		/// <summary>
		/// Erstellt eine neue Instanz der MyQueue-Klasse und kopiert die Elemente aus der übergebenen Auflistung in diese Instanz.
		/// </summary>
		/// <param name="collection">Die Auflistung, derren Elemente in diese Queue-Instanz kopiert werden sollen.</param>
		public MyQueue(IEnumerable<T> collection)
		{
			if (collection == null) throw new ArgumentNullException("collection");

			this._data = new T[4];
			this._size = 0;

			foreach (T fValue in collection)
			{
				this.Enqueue(fValue);
			}
		}

		/// <summary>
		/// Erstellt eine neue leere Instanz der MyQueue-Klasse mit einer anfänglichen Kapazitätsgröße.
		/// </summary>
		/// <param name="capacity">Die anfängliche Anzahl an Elementen, die die MyQueue-Klasse enthalten kann.</param>
		public MyQueue(int capacity)
		{
			if (capacity < 0) throw new ArgumentOutOfRangeException("capacity");

			this._data = new T[capacity];
			this._size = 0;
		}

		/// <summary>
		/// Erstellt eine neue leere Instanz der MyQueue-Klasse.
		/// </summary>
		public MyQueue() : this (DefaultCapacity)
		{

		}

		#endregion

		#region Funktionen

		/// <summary>
		/// Fügt ein Element an das Ende der Queue-Klasse hinzu.
		/// </summary>
		/// <param name="value">Das Element das hinzugefügt werden soll.</param>
		public void Enqueue(T value)
		{
			if (this._size >= this._data.Length)
			{
				int capacity = this._data.Length * 2;
				if (capacity < this._data.Length + DefaultCapacity) capacity += DefaultCapacity;

				this.SetCapacity(capacity);
			}
			this._data[this._tail] = value;
			this._tail = (this._tail + 1) % this._data.Length;
			this._size++;
			this._version++;
		}

		/// <summary>
		/// Fügt ein Array von Elementen an das Ende der Queue-Klasse hinzu,
		/// </summary>
		/// <param name="value">Ein Array mit Elementen, die hinzugefügt werden sollen.</param>
		public void EnqueueBulk(T[] values)
		{
			this.EnqueueBulk(values, 0, values.Length);
		}

		/// <summary>
		/// Fügt ein Array von Elementen an das Ende der Queue-Klasse hinzu.
		/// </summary>
		/// <param name="values">Ein Array mit Elementen, die hinzugefügt werden sollen.</param>
		/// <param name="offset">Der Offset im values-Array, ab dem die Elemente hinzugefügt werden sollen.</param>
		/// <param name="length">Die Anzahl der Elemente, die hinzugefügt werden sollen.</param>
		public void EnqueueBulk(T[] values, int offset, int length)
		{
			if (values == null) throw new ArgumentNullException("values");
			if (offset < 0) throw new ArgumentOutOfRangeException("offset");
			if (length < 0) throw new ArgumentOutOfRangeException("length");
			if (offset + length > values.Length) throw new ArgumentOutOfRangeException("length");

			int size = this._size + length;
			if (size >= this._data.Length)
			{
				size = size * 2;
				if (size < this._data.Length + DefaultCapacity) size += DefaultCapacity;

				this.SetCapacity(size);
			}

			if (this._tail + length > this._data.Length)
			{
				int tmp = this._data.Length - this._tail;
				Array.Copy(values, offset, this._data, this._tail, tmp);
				this._tail = length - tmp;
				Array.Copy(values, offset + tmp, this._data, 0, this._tail - 1);
			}
			else
			{
				Array.Copy(values, offset, this._data, this._tail, length);
				this._tail = (this._tail + length) % this._data.Length;
			}
			this._size += length;
			this._version++;
		}

		/// <summary>
		/// Entfernt das Element am Anfang der Queue-Klasse und gibt dieses zurück.
		/// </summary>
		/// <returns>Das Element, dass vom Anfang der Queue-Klasse entfernt wurde.</returns>
		public T Dequeue()
		{
			if (this._size == 0) throw new InvalidOperationException("Es sind keine Elemente in der Liste vorhanden");

			T current = this._data[this._head];
			this._data[this._head] = default(T);
			this._head = (this._head + 1) % this._data.Length;
			this._size--;
			this._version++;

			return current;
		}

		/// <summary>
		/// Entfernt mehrere Elemente vom Anfang der Queue-Klasse und schreibt diese in das übergebene Array.
		/// </summary>
		/// <param name="buffer">Ein Array in das die Elemente geschrieben werden.</param>
		/// <param name="offset">Der Index im Array, ab den die Elemente geschrieben werden sollen.</param>
		/// <param name="length">Die Anzahl der Elemente, die aus der Queue-Liste entfernt werden sollen.</param>
		/// <returns>Gibt die Anzahl der entfernten Elemente zurück. Diese Zahl weicht von dem Argument length ab, sobald sich nicht mehr genügend Elemente in der Queue-Klasse befinden.</returns>
		public int DequeueBulk(T[] buffer, int offset, int length)
		{
			if (buffer == null) throw new ArgumentNullException("buffer");
			if (offset < 0) throw new ArgumentOutOfRangeException("offset");
			if (length < 0) throw new ArgumentOutOfRangeException("length");
			if (offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length");

			int count = Math.Min(length, this._size);
			int tHead = this._head;
			if (count == 0)
				return 0;
			else
			{
				for (int fi = 0; fi < count; fi++)
				{
					buffer[offset + fi] = this._data[tHead];
					tHead = (tHead + 1) % this._data.Length;
				}
				this._size -= count;
				this._head = tHead;
				this._version++;

				return count;
			}
		}

		/// <summary>
		/// Gibt das nächste Elemente zurück ohne es vom Stapel zu nehmen.
		/// </summary>
		/// <returns>Das nächste Element.</returns>
		public T Peek()
		{
			if (this._size == 0) throw new InvalidOperationException("Es sind keine Elemente in der Liste vorhanden");

			return this._data[this._head];
		}

		/// <summary>
		/// Gibt die nächsten Elemente zurück, ohne diese vom Stapel zu nehmen.
		/// </summary>
		/// <param name="buffer">Ein Array, in das die Elemente kopiert werden sollen.</param>
		/// <param name="offset">Der Offset im buffer-Array, an die die Elemente kopiert werden sollen.</param>
		/// <param name="length">Die Anzahl der Elemente die in das buffer-Array kopiert werden sollen.</param>
		/// <returns>Gibt die Anzahl der entfernten Elemente zurück. Diese Zahl weicht von dem Argument length ab, sobald sich nicht mehr genügend Elemente in der Queue-Klasse befinden.</returns>
		public int PeekBulk(T[] buffer, int offset, int length)
		{
			if (buffer == null) throw new ArgumentNullException("buffer");
			if (offset < 0) throw new ArgumentOutOfRangeException("offset");
			if (length < 0) throw new ArgumentOutOfRangeException("length");
			if (offset + length > buffer.Length) throw new ArgumentOutOfRangeException("length");

			int count = Math.Max(length, this._size);
			int tHead = this._head;
			if (count == 0)
				return 0;
			else
			{
				for (int fi = 0; fi < count; fi++)
				{
					buffer[offset + fi] = this._data[tHead];
					tHead = (tHead + 1) % this._data.Length;
				}
				this._size -= count;
				this._version++;

				return count;
			}
		}

		private void SetCapacity(int capacity)
		{
			T[] newData = new T[capacity];
			if (this._size > 0)
			{
				if (this._head < this._tail)
				{
					Array.Copy(this._data, this._head, newData, 0, this._size);
				}
				else
				{
					Array.Copy(this._data, this._head, newData, 0, this._data.Length - this._head);
					Array.Copy(this._data, 0, newData, this._data.Length - this._head, this._tail);
				}
				this._data = newData;
				this._head = 0;
				this._tail = this._size;
				this._version++;
			}
		}

		/// <summary>
		/// Kopiert alle Elemente der Queue-Klasse in ein Array und gibt dieses zurück.
		/// </summary>
		/// <returns>Ein Array mit den Elementen aus der Queue-Klasse.</returns>
		public T[] ToArray()
		{
			T[] destArray = new T[this._size];

			if (this._size > 0)
			{
				if (this._head < this._tail)
				{
					Array.Copy(this._data, this._head, destArray, 0, this._size);
				}
				else
				{
					Array.Copy(this._data, this._head, destArray, 0, this._data.Length - this._head);
					Array.Copy(this._data, 0, destArray, this._data.Length - this._head, this._tail);
				}
			}

			return destArray;
		}

		/// <summary>
		/// Legt die Kapazität auf die Anzahl der tatsächlich in der MyQueue-Klasse befindlichen Elemente fest, sofern diese Anzahl unter 90 Prozent der aktuellen Kapazität liegt.
		/// </summary>
		public void TrimExcess()
		{
			int newCapacity = (int)(this._data.Length * 0.9F);
			if (this._size < newCapacity)
				this.SetCapacity(this._size);
		}

		internal T GetElement(int index)
		{
			return this._data[(this._head + index) % this._data.Length];
		}

		/// <summary>
		/// Entfernt alle Elemente aus der Queue-Klasse.
		/// </summary>
		public void Clear()
		{
			if (this._size > 0)
			{
				if (this._head < this._tail)
				{
					for (int fi = this._head; fi < this._size; fi++)
					{
						this._data[fi] = default(T);
					}
				}
				else
				{
					for (int fi = this._head; fi < this._data.Length; fi++)
					{
						this._data[fi] = default(T);
					}
					for (int fi = 0; fi < this._tail; fi++)
					{
						this._data[fi] = default(T);
					}
				}
				this._size = 0;
				this._head = 0;
				this._tail = 0;
				this._version++;
			}
		}

		#endregion

		#region IEnumerable<T> Member

		/// <summary>
		/// Gibt einen Enumerator zurück, mit dem die Queue-Klasse durchlaufen kann, ohne die Elemente aus Queue zu entfernen.
		/// </summary>
		/// <returns></returns>
		public IEnumerator<T> GetEnumerator()
		{
			return new Enumerator(this);
		}

		#endregion

		#region IEnumerable Member

		IEnumerator IEnumerable.GetEnumerator()
		{
			return ((IEnumerable<T>)this).GetEnumerator();
		}

		#endregion
	
		#region ICollection Member

		/// <summary>
		/// Kopier alle Elemente in ein Array ohne diese aus der Queue zu entfernen.
		/// </summary>
		/// <param name="array">Das Array in den die Daten kopiert werden sollen.</param>
		/// <param name="index">Der Index im Array, an den die Daten kopiert werden sollen.</param>
		public void  CopyTo(Array array, int index)
		{
			if (array == null) throw new ArgumentNullException("array");
			if (index < 0) throw new ArgumentOutOfRangeException("index");
			if (array.Length + index < this._size) throw new ArgumentOutOfRangeException("array", "Die Länge des übergebenen Arrays ist zu kurz");

			if (this._size > 0)
			{
				if (this._head < this._tail)
				{
					Array.Copy(this._data, this._head, array, index, this._size);
				}
				else
				{
					Array.Copy(this._data, this._head, array, 0, this._data.Length - this._head);
					Array.Copy(this._data, 0, array, this._data.Length - this._head + index, this._tail);
				}
			}
		}

		/// <summary>
		/// Gibt die Anzahl der enthaltenen Elemente zurück.
		/// </summary>
		public int  Count
		{
			get { return this._size; }
		}

		/// <summary>
		/// Gibt true zurück, sobald die Queue-Klasse synchronisiert ist, andernfalls false.
		/// </summary>
		public bool  IsSynchronized
		{
			get { return false; }
		}

		/// <summary>
		/// Ruft ein Objekt ab, mit dem der Zugriff auf die MyQueue-Klasse synchronisiert werden kann.
		/// </summary>
		public object  SyncRoot
		{
			get { return null; }
		}

		#endregion
	}
}


Schlagwörter: Queue Bulk Generic

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...