Browse Source
To make it easier to implement dispatchers on other platforms. Currently assuming a single dispatcher per application. Had to copy most of NGenerics locally just to get a PriorityQueue implementation as it has no PCL version.pull/10/head
35 changed files with 3711 additions and 674 deletions
@ -1,102 +1,39 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="Dispatcher.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Threading |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel; |
|||
using System.Security; |
|||
using System.Threading; |
|||
using Perspex.Platform; |
|||
using Splat; |
|||
using System.Threading.Tasks; |
|||
using Perspex.Win32.Threading; |
|||
|
|||
public enum DispatcherPriority |
|||
public class Dispatcher |
|||
{ |
|||
Invalid = -1, |
|||
Inactive = 0, |
|||
SystemIdle = 1, |
|||
ApplicationIdle = 2, |
|||
ContextIdle = 3, |
|||
Background = 4, |
|||
Input = 5, |
|||
Loaded = 6, |
|||
Render = 7, |
|||
DataBind = 8, |
|||
Normal = 9, |
|||
Send = 10, |
|||
} |
|||
private static Dispatcher instance = new Dispatcher(); |
|||
|
|||
[Flags] |
|||
internal enum Flags |
|||
{ |
|||
ShutdownStarted = 1, |
|||
Shutdown = 2, |
|||
Disabled = 4 |
|||
} |
|||
|
|||
public abstract class Dispatcher |
|||
{ |
|||
private static DispatcherFrame mainExecutionFrame = new DispatcherFrame(); |
|||
private MainLoop mainLoop = new MainLoop(); |
|||
|
|||
public static Dispatcher CurrentDispatcher |
|||
private Dispatcher() |
|||
{ |
|||
get { return Locator.Current.GetService<IPlatformThreadingInterface>().GetThreadDispatcher(); } |
|||
} |
|||
|
|||
public abstract bool HasShutdownFinished |
|||
public static Dispatcher UIThread |
|||
{ |
|||
get; |
|||
get { return instance; } |
|||
} |
|||
|
|||
public abstract DispatcherFrame CurrentFrame |
|||
public void MainLoop(CancellationToken cancellationToken) |
|||
{ |
|||
get; |
|||
set; |
|||
this.mainLoop.Run(cancellationToken); |
|||
} |
|||
|
|||
public static void PushFrame(DispatcherFrame frame) |
|||
public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) |
|||
{ |
|||
if (frame == null) |
|||
{ |
|||
throw new ArgumentNullException("frame"); |
|||
} |
|||
|
|||
Dispatcher dis = CurrentDispatcher; |
|||
|
|||
if (dis.HasShutdownFinished) |
|||
{ |
|||
throw new InvalidOperationException("The Dispatcher has shut down"); |
|||
} |
|||
|
|||
if (frame.Running != null) |
|||
{ |
|||
throw new InvalidOperationException("Frame is already running on a different dispatcher"); |
|||
} |
|||
|
|||
frame.ParentFrame = dis.CurrentFrame; |
|||
dis.CurrentFrame = frame; |
|||
|
|||
frame.Running = dis; |
|||
|
|||
dis.RunFrame(frame); |
|||
} |
|||
|
|||
|
|||
public static void Run() |
|||
{ |
|||
PushFrame(mainExecutionFrame); |
|||
return this.mainLoop.InvokeAsync(action, priority); |
|||
} |
|||
|
|||
public abstract DispatcherOperation BeginInvoke(Action method); |
|||
|
|||
public abstract DispatcherOperation BeginInvoke(DispatcherPriority priority, Action method); |
|||
|
|||
protected internal abstract void Reprioritize(DispatcherOperation op, DispatcherPriority oldpriority); |
|||
|
|||
protected abstract void RunFrame(DispatcherFrame frame); |
|||
} |
|||
} |
|||
@ -1,25 +0,0 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="DispatcherFrame.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Threading |
|||
{ |
|||
public class DispatcherFrame |
|||
{ |
|||
public DispatcherFrame() |
|||
{ |
|||
this.Continue = true; |
|||
this.ExitOnRequest = true; |
|||
} |
|||
|
|||
public bool Continue { get; set; } |
|||
|
|||
public bool ExitOnRequest { get; set; } |
|||
|
|||
public Dispatcher Running { get; set; } |
|||
|
|||
public DispatcherFrame ParentFrame { get; set; } |
|||
} |
|||
} |
|||
@ -1,159 +0,0 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="DispatcherOperation.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Threading |
|||
{ |
|||
using System; |
|||
using System.Security; |
|||
|
|||
public enum DispatcherOperationStatus |
|||
{ |
|||
Pending = 0, |
|||
Aborted = 1, |
|||
Completed = 2, |
|||
Executing = 3 |
|||
} |
|||
|
|||
public sealed class DispatcherOperation |
|||
{ |
|||
private DispatcherOperationStatus status; |
|||
private DispatcherPriority priority; |
|||
private Dispatcher dispatcher; |
|||
private object result; |
|||
private Delegate delegateMethod; |
|||
private object[] delegateArgs; |
|||
|
|||
public DispatcherOperation(Dispatcher dis, DispatcherPriority prio) |
|||
{ |
|||
this.dispatcher = dis; |
|||
this.priority = prio; |
|||
if (this.Dispatcher.HasShutdownFinished) |
|||
{ |
|||
this.status = DispatcherOperationStatus.Aborted; |
|||
} |
|||
else |
|||
{ |
|||
this.status = DispatcherOperationStatus.Pending; |
|||
} |
|||
} |
|||
|
|||
public DispatcherOperation(Dispatcher dis, DispatcherPriority prio, Delegate d) |
|||
: this(dis, prio) |
|||
{ |
|||
this.delegateMethod = d; |
|||
} |
|||
|
|||
public DispatcherOperation(Dispatcher dis, DispatcherPriority prio, Delegate d, object arg) |
|||
: this(dis, prio) |
|||
{ |
|||
this.delegateMethod = d; |
|||
this.delegateArgs = new object[1]; |
|||
this.delegateArgs[0] = arg; |
|||
} |
|||
|
|||
public DispatcherOperation(Dispatcher dis, DispatcherPriority prio, Delegate d, object arg, object[] args) |
|||
: this(dis, prio) |
|||
{ |
|||
this.delegateMethod = d; |
|||
this.delegateArgs = new object[args.Length + 1]; |
|||
this.delegateArgs[0] = arg; |
|||
Array.Copy(args, 1, this.delegateArgs, 0, args.Length); |
|||
} |
|||
|
|||
public event EventHandler Completed; |
|||
|
|||
public DispatcherOperationStatus Status |
|||
{ |
|||
get |
|||
{ |
|||
return this.status; |
|||
} |
|||
|
|||
internal set |
|||
{ |
|||
this.status = value; |
|||
} |
|||
} |
|||
|
|||
public Dispatcher Dispatcher |
|||
{ |
|||
get |
|||
{ |
|||
return this.dispatcher; |
|||
} |
|||
} |
|||
|
|||
public DispatcherPriority Priority |
|||
{ |
|||
get |
|||
{ |
|||
return this.priority; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
if (this.priority != value) |
|||
{ |
|||
DispatcherPriority old = this.priority; |
|||
this.priority = value; |
|||
this.dispatcher.Reprioritize(this, old); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public object Result |
|||
{ |
|||
get |
|||
{ |
|||
return this.result; |
|||
} |
|||
} |
|||
|
|||
public bool Abort() |
|||
{ |
|||
this.status = DispatcherOperationStatus.Aborted; |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public DispatcherOperationStatus Wait() |
|||
{ |
|||
if (this.status == DispatcherOperationStatus.Executing) |
|||
{ |
|||
throw new InvalidOperationException("Already executing"); |
|||
} |
|||
|
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
[SecurityCritical] |
|||
public DispatcherOperationStatus Wait(TimeSpan timeout) |
|||
{ |
|||
if (this.status == DispatcherOperationStatus.Executing) |
|||
{ |
|||
throw new InvalidOperationException("Already executing"); |
|||
} |
|||
|
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public void Invoke() |
|||
{ |
|||
this.status = DispatcherOperationStatus.Executing; |
|||
|
|||
if (this.delegateMethod != null) |
|||
{ |
|||
this.result = this.delegateMethod.DynamicInvoke(this.delegateArgs); |
|||
} |
|||
|
|||
this.status = DispatcherOperationStatus.Completed; |
|||
|
|||
if (this.Completed != null) |
|||
{ |
|||
this.Completed(this, EventArgs.Empty); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="DispatcherPriority.cs" company="Steven Kirk">
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Threading |
|||
{ |
|||
public enum DispatcherPriority |
|||
{ |
|||
Invalid = -1, |
|||
Inactive = 0, |
|||
SystemIdle = 1, |
|||
ApplicationIdle = 2, |
|||
ContextIdle = 3, |
|||
Background = 4, |
|||
Input = 5, |
|||
Loaded = 6, |
|||
Render = 7, |
|||
DataBind = 8, |
|||
Normal = 9, |
|||
Send = 10, |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="Application.cs" company="Steven Kirk">
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Win32.Threading |
|||
{ |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using NGenerics.DataStructures.Queues; |
|||
using Perspex.Platform; |
|||
using Perspex.Threading; |
|||
using Splat; |
|||
|
|||
internal class MainLoop |
|||
{ |
|||
private static IPlatformThreadingInterface platform; |
|||
|
|||
private PriorityQueue<Job, DispatcherPriority> queue = |
|||
new PriorityQueue<Job, DispatcherPriority>(PriorityQueueType.Maximum); |
|||
|
|||
static MainLoop() |
|||
{ |
|||
platform = Locator.Current.GetService<IPlatformThreadingInterface>(); |
|||
} |
|||
|
|||
public void Run(CancellationToken cancellationToken) |
|||
{ |
|||
while (!cancellationToken.IsCancellationRequested) |
|||
{ |
|||
Job job; |
|||
|
|||
// TODO: Dispatch windows messages in preference to lower priority jobs.
|
|||
while (queue.Count > 0) |
|||
{ |
|||
lock (this.queue) |
|||
{ |
|||
job = queue.Dequeue(); |
|||
} |
|||
|
|||
try |
|||
{ |
|||
job.Action(); |
|||
job.TaskCompletionSource.SetResult(null); |
|||
} |
|||
catch (Exception e) |
|||
{ |
|||
job.TaskCompletionSource.SetException(e); |
|||
} |
|||
} |
|||
|
|||
platform.ProcessMessage(); |
|||
} |
|||
} |
|||
|
|||
public Task InvokeAsync(Action action, DispatcherPriority priority) |
|||
{ |
|||
var job = new Job(action); |
|||
|
|||
lock (queue) |
|||
{ |
|||
this.queue.Add(job, priority); |
|||
} |
|||
|
|||
platform.Wake(); |
|||
return job.TaskCompletionSource.Task; |
|||
} |
|||
|
|||
private class Job |
|||
{ |
|||
public Job(Action action) |
|||
{ |
|||
this.Action = action; |
|||
this.TaskCompletionSource = new TaskCompletionSource<object>(); |
|||
} |
|||
|
|||
public Action Action { get; private set; } |
|||
|
|||
public TaskCompletionSource<object> TaskCompletionSource { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,551 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using NGenerics.Comparers; |
|||
using NGenerics.Patterns.Visitor; |
|||
using NGenerics.Util; |
|||
|
|||
namespace NGenerics.DataStructures.Trees |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// A base class for Binary Search Trees that store a single value in each node.
|
|||
/// </summary>
|
|||
/// <typeparam name="T"></typeparam>
|
|||
//[Serializable]
|
|||
internal abstract class BinarySearchTreeBase<T> : ISearchTree<T> |
|||
{ |
|||
|
|||
#region Globals
|
|||
|
|||
internal const string alreadyContainedInTheTree = "The item is already contained in the tree."; |
|||
private BinaryTree<T> tree; |
|||
private readonly IComparer<T> comparer; |
|||
|
|||
#endregion
|
|||
|
|||
#region Delegates
|
|||
|
|||
/// <summary>
|
|||
/// A custom comparison between some search value and the type of item that is kept in the tree.
|
|||
/// </summary>
|
|||
/// <typeparam name="TSearch">The type of the search.</typeparam>
|
|||
protected delegate int CustomComparison<TSearch>(TSearch value, T item); |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BinarySearchTreeBase{T}"/> class.
|
|||
/// </summary>
|
|||
protected BinarySearchTreeBase() |
|||
{ |
|||
comparer = Comparer<T>.Default; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BinarySearchTreeBase{T}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="comparer">The comparer to use when comparing items.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
protected BinarySearchTreeBase(IComparer<T> comparer) |
|||
{ |
|||
Guard.ArgumentNotNull(comparer, "comparer"); |
|||
this.comparer = comparer; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BinarySearchTreeBase<TKey, TValue>"/> class.
|
|||
/// </summary>
|
|||
/// <param name="comparison">The comparison.</param>
|
|||
protected BinarySearchTreeBase(Comparison<T> comparison) |
|||
{ |
|||
Guard.ArgumentNotNull(comparison, "comparison"); |
|||
comparer = new ComparisonComparer<T>(comparison); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Gets the comparer.
|
|||
/// </summary>
|
|||
/// <value>The comparer.</value>
|
|||
public IComparer<T> Comparer |
|||
{ |
|||
get |
|||
{ |
|||
return comparer; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Protected Members
|
|||
|
|||
/// <summary>
|
|||
/// Finds the node containing the specified data key.
|
|||
/// </summary>
|
|||
/// <param name="item">The item.</param>
|
|||
/// <returns>
|
|||
/// The node with the specified key if found. If the key is not in the tree, this method returns null.
|
|||
/// </returns>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
protected virtual BinaryTree<T> FindNode(T item) |
|||
{ |
|||
if (tree == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var currentNode = tree; |
|||
|
|||
while (currentNode != null) |
|||
{ |
|||
var nodeResult = comparer.Compare(item, currentNode.Data); |
|||
|
|||
if (nodeResult == 0) |
|||
{ |
|||
return currentNode; |
|||
} |
|||
|
|||
currentNode = nodeResult < 0 ? currentNode.Left : currentNode.Right; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Finds the node that matches the custom delegate.
|
|||
/// </summary>
|
|||
/// <typeparam name="TSearch">The type of the search.</typeparam>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <param name="customComparison">The custom comparison.</param>
|
|||
/// <returns>The item if found, else null.</returns>
|
|||
protected virtual BinaryTree<T> FindNode<TSearch>(TSearch value, CustomComparison<TSearch> customComparison) |
|||
{ |
|||
if (tree == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
var currentNode = tree; |
|||
|
|||
while (currentNode != null) |
|||
{ |
|||
var nodeResult = customComparison(value, currentNode.Data); |
|||
|
|||
if (nodeResult == 0) |
|||
{ |
|||
return currentNode; |
|||
} |
|||
|
|||
currentNode = nodeResult < 0 ? currentNode.Left : currentNode.Right; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the item from the tree.
|
|||
/// </summary>
|
|||
/// <param name="item">The item to remove.</param>
|
|||
/// <returns>An indication of whether the item has been removed from the tree.</returns>
|
|||
protected abstract bool RemoveItem(T item); |
|||
|
|||
/// <summary>
|
|||
/// Adds the item.
|
|||
/// </summary>
|
|||
/// <param name="item">The item.</param>
|
|||
protected abstract void AddItem(T item); |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Find the maximum node.
|
|||
/// </summary>
|
|||
/// <returns>The maximum node.</returns>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
protected BinaryTree<T> FindMaximumNode() |
|||
{ |
|||
#region Debug
|
|||
|
|||
Debug.Assert(tree != null); |
|||
|
|||
#endregion
|
|||
|
|||
return FindMaximumNode(tree); |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Find the minimum node.
|
|||
/// </summary>
|
|||
/// <returns>The minimum node.</returns>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
protected BinaryTree<T> FindMinimumNode() |
|||
{ |
|||
#region Debug
|
|||
|
|||
Debug.Assert(tree != null); |
|||
|
|||
#endregion
|
|||
|
|||
return FindMinimumNode(tree); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Finds the maximum node.
|
|||
/// </summary>
|
|||
/// <param name="startNode">The start node.</param>
|
|||
/// <returns>The maximum node below this node.</returns>
|
|||
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] |
|||
protected static BinaryTree<T> FindMaximumNode(BinaryTree<T> startNode) |
|||
{ |
|||
#region Asserts
|
|||
|
|||
Debug.Assert(startNode != null); |
|||
|
|||
#endregion
|
|||
|
|||
var searchNode = startNode; |
|||
|
|||
while (searchNode.Right != null) |
|||
{ |
|||
searchNode = searchNode.Right; |
|||
} |
|||
|
|||
return searchNode; |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Finds the minimum node.
|
|||
/// </summary>
|
|||
/// <param name="startNode">The start node.</param>
|
|||
/// <returns>The minimum node below this node.</returns>
|
|||
[SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] |
|||
protected static BinaryTree<T> FindMinimumNode(BinaryTree<T> startNode) |
|||
{ |
|||
#region Asserts
|
|||
|
|||
Debug.Assert(startNode != null); |
|||
|
|||
#endregion
|
|||
|
|||
var searchNode = startNode; |
|||
|
|||
while (searchNode.Left != null) |
|||
{ |
|||
searchNode = searchNode.Left; |
|||
} |
|||
|
|||
return searchNode; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="BinaryTree{T}"/> for this <see cref="BinarySearchTreeBase{TKey,TValue}"/>.
|
|||
/// </summary>
|
|||
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] |
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
protected BinaryTree<T> Tree |
|||
{ |
|||
get |
|||
{ |
|||
return tree; |
|||
} |
|||
set |
|||
{ |
|||
tree = value; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Private Members
|
|||
|
|||
/// <summary>
|
|||
/// Visits the node in an in-order fashion.
|
|||
/// </summary>
|
|||
/// <param name="node">The node.</param>
|
|||
/// <param name="visitor">The visitor.</param>
|
|||
private static void VisitNode(BinaryTree<T> node, OrderedVisitor<T> visitor) |
|||
{ |
|||
if (node != null) |
|||
{ |
|||
var pair = node.Data; |
|||
|
|||
visitor.VisitPreOrder(pair); |
|||
|
|||
VisitNode(node.Left, visitor); |
|||
|
|||
visitor.VisitInOrder(pair); |
|||
|
|||
VisitNode(node.Right, visitor); |
|||
|
|||
visitor.VisitPostOrder(pair); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ISearchTree<TKey,TValue> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Minimum" lang="cs" title="The following example shows how to use the Minimum property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Minimum" lang="vbnet" title="The following example shows how to use the Minimum property."/>
|
|||
/// </example>
|
|||
public virtual T Minimum |
|||
{ |
|||
get |
|||
{ |
|||
#region Validation
|
|||
|
|||
ValidateEmpty(); |
|||
|
|||
#endregion
|
|||
|
|||
return FindMinimumNode().Data; |
|||
} |
|||
} |
|||
|
|||
private void ValidateEmpty() |
|||
{ |
|||
if (Count == 0) |
|||
{ |
|||
throw new InvalidOperationException("The search tree is empty."); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Maximum" lang="cs" title="The following example shows how to use the Maximum property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Maximum" lang="vbnet" title="The following example shows how to use the Maximum property."/>
|
|||
/// </example>
|
|||
public virtual T Maximum |
|||
{ |
|||
get |
|||
{ |
|||
ValidateEmpty(); |
|||
|
|||
return FindMaximumNode().Data; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
/// <inheritdoc/>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
public void DepthFirstTraversal(OrderedVisitor<T> visitor) |
|||
{ |
|||
Guard.ArgumentNotNull(visitor, "visitor"); |
|||
|
|||
VisitNode(tree, visitor); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] |
|||
public IEnumerator<T> GetOrderedEnumerator() |
|||
{ |
|||
if (tree != null) |
|||
{ |
|||
var trackingVisitor = new TrackingVisitor<T>(); |
|||
var inOrderVisitor = new InOrderVisitor<T>(trackingVisitor); |
|||
|
|||
tree.DepthFirstTraversal(inOrderVisitor); |
|||
|
|||
var trackingList = trackingVisitor.TrackingList; |
|||
|
|||
for (var i = 0; i < trackingList.Count; i++) |
|||
{ |
|||
yield return trackingList[i]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="IsEmpty" lang="cs" title="The following example shows how to use the IsEmpty property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="IsEmpty" lang="vbnet" title="The following example shows how to use the IsEmpty property."/>
|
|||
/// </example>
|
|||
public bool IsEmpty |
|||
{ |
|||
get |
|||
{ |
|||
return Count == 0; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Remove(T item) |
|||
{ |
|||
var itemRemoved = RemoveItem(item); |
|||
|
|||
if (itemRemoved) |
|||
{ |
|||
Count--; |
|||
} |
|||
|
|||
return itemRemoved; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Clear" lang="cs" title="The following example shows how to use the Clear method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Clear" lang="vbnet" title="The following example shows how to use the Clear method."/>
|
|||
/// </example>
|
|||
public void Clear() |
|||
{ |
|||
ClearItems(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clears all the objects in this instance.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <b>Notes to Inheritors: </b>
|
|||
/// Derived classes can override this method to change the behavior of the <see cref="Clear"/> method.
|
|||
/// </remarks>
|
|||
protected virtual void ClearItems() |
|||
{ |
|||
tree = null; |
|||
Count = 0; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Count" lang="cs" title="The following example shows how to use the Count property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Count" lang="vbnet" title="The following example shows how to use the Count property."/>
|
|||
/// </example>
|
|||
public int Count { get; private set; } |
|||
|
|||
#endregion
|
|||
|
|||
#region IEnumerable Members
|
|||
|
|||
/// <inheritdoc />
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return GetEnumerator(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through the collection.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
|
|||
/// </returns>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="GetEnumerator" lang="cs" title="The following example shows how to use the GetEnumerator method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="GetEnumerator" lang="vbnet" title="The following example shows how to use the GetEnumerator method."/>
|
|||
/// </example>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
public IEnumerator<T> GetEnumerator() |
|||
{ |
|||
if (tree != null) |
|||
{ |
|||
var stack = new Stack<BinaryTree<T>>(); |
|||
|
|||
stack.Push(tree); |
|||
|
|||
while (stack.Count > 0) |
|||
{ |
|||
var binaryTree = stack.Pop(); |
|||
|
|||
yield return binaryTree.Data; |
|||
|
|||
if (binaryTree.Left != null) |
|||
{ |
|||
stack.Push(binaryTree.Left); |
|||
} |
|||
|
|||
if (binaryTree.Right != null) |
|||
{ |
|||
stack.Push(binaryTree.Right); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
|
|||
#region ICollection<T> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="AddKeyValuePair" lang="cs" title="The following example shows how to use the AddKeyValuePair method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="AddKeyValuePair" lang="vbnet" title="The following example shows how to use the AddKeyValuePair method."/>
|
|||
/// </example>
|
|||
public void Add(T item) |
|||
{ |
|||
AddItem(item); |
|||
Count++; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Contains" lang="cs" title="The following example shows how to use the Contains method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Contains" lang="vbnet" title="The following example shows how to use the Contains method."/>
|
|||
/// </example>
|
|||
public virtual bool Contains(T item) |
|||
{ |
|||
var node = FindNode(item); |
|||
return node != null; |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="CopyTo" lang="cs" title="The following example shows how to use the CopyTo method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="CopyTo" lang="vbnet" title="The following example shows how to use the CopyTo method."/>
|
|||
/// </example>
|
|||
public void CopyTo(T[] array, int arrayIndex) |
|||
{ |
|||
#region Validation
|
|||
|
|||
Guard.ArgumentNotNull(array, "array"); |
|||
|
|||
if ((array.Length - arrayIndex) < Count) |
|||
{ |
|||
throw new ArgumentException(Constants.NotEnoughSpaceInTheTargetArray, "array"); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
foreach (var association in tree) |
|||
{ |
|||
array[arrayIndex++] = association; |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="IsReadOnly" lang="cs" title="The following example shows how to use the IsReadOnly property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="IsReadOnly" lang="vbnet" title="The following example shows how to use the IsReadOnly property."/>
|
|||
/// </example>
|
|||
public bool IsReadOnly |
|||
{ |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,714 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using NGenerics.Patterns.Visitor; |
|||
using NGenerics.Util; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
|
|||
namespace NGenerics.DataStructures.Trees |
|||
{ |
|||
/// <summary>
|
|||
/// An implementation of a Binary Tree data structure.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of elements in the <see cref="BinaryTree{T}"/>.</typeparam>
|
|||
//[Serializable]
|
|||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] |
|||
internal class BinaryTree<T> : ICollection<T>, ITree<T> |
|||
{ |
|||
#region Globals
|
|||
|
|||
private BinaryTree<T> leftSubtree; |
|||
private BinaryTree<T> rightSubtree; |
|||
private T data; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
/// <param name="data">The data contained in this node.</param>
|
|||
public BinaryTree(T data) : this(data, null, null) { } |
|||
|
|||
/// <param name="data">The data.</param>
|
|||
/// <param name="left">The data of the left subtree.</param>
|
|||
/// <param name="right">The data of the right subtree.</param>
|
|||
public BinaryTree(T data, T left, T right) : this(data, new BinaryTree<T>(left), new BinaryTree<T>(right)) { } |
|||
|
|||
/// <param name="data">The data contained in this node.</param>
|
|||
/// <param name="left">The left subtree.</param>
|
|||
/// <param name="right">The right subtree.</param>
|
|||
public BinaryTree(T data, BinaryTree<T> left, BinaryTree<T> right) |
|||
: this(data, left, right, true) |
|||
{ |
|||
} |
|||
|
|||
|
|||
|
|||
/// <param name="data">The data contained in this node.</param>
|
|||
/// <param name="left">The left subtree.</param>
|
|||
/// <param name="right">The right subtree.</param>
|
|||
/// <param name="validateData"><see langword="true"/> to validate <paramref name="data"/>; otherwise <see langword="false"/>.</param>
|
|||
internal BinaryTree(T data, BinaryTree<T> left, BinaryTree<T> right, bool validateData) |
|||
{ |
|||
#region Validation
|
|||
|
|||
//TODO: probably not the most efficient way of doing this but SplayTree needs to use a BinaryTree with null data.
|
|||
if (validateData) |
|||
{ |
|||
Guard.ArgumentNotNull(data, "data"); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
leftSubtree = left; |
|||
|
|||
if (left != null) |
|||
{ |
|||
left.Parent = this; |
|||
} |
|||
|
|||
rightSubtree = right; |
|||
|
|||
if (right != null) |
|||
{ |
|||
right.Parent = this; |
|||
} |
|||
|
|||
this.data = data; |
|||
} |
|||
|
|||
|
|||
|
|||
#endregion
|
|||
|
|||
#region ICollection<T> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
public bool IsEmpty |
|||
{ |
|||
get |
|||
{ |
|||
return Count == 0; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool IsFull |
|||
{ |
|||
get |
|||
{ |
|||
return (leftSubtree != null) && (rightSubtree != null); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Contains(T item) |
|||
{ |
|||
foreach (var thisItem in this) |
|||
{ |
|||
if (item.Equals(thisItem)) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void CopyTo(T[] array, int arrayIndex) |
|||
{ |
|||
Guard.ArgumentNotNull(array, "array"); |
|||
|
|||
foreach (var item in this) |
|||
{ |
|||
#region Validation
|
|||
|
|||
if (arrayIndex >= array.Length) |
|||
{ |
|||
throw new ArgumentException(Constants.NotEnoughSpaceInTheTargetArray, "array"); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
array[arrayIndex++] = item; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public int Count |
|||
{ |
|||
get |
|||
{ |
|||
var count = 0; |
|||
|
|||
if (leftSubtree != null) |
|||
{ |
|||
count++; |
|||
} |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
count++; |
|||
} |
|||
|
|||
return count; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public void Add(T item) |
|||
{ |
|||
AddItem(new BinaryTree<T>(item)); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Remove(T item) |
|||
{ |
|||
if (leftSubtree != null) |
|||
{ |
|||
if (leftSubtree.data.Equals(item)) |
|||
{ |
|||
RemoveLeft(); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
if (rightSubtree.data.Equals(item)) |
|||
{ |
|||
RemoveRight(); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the specified child.
|
|||
/// </summary>
|
|||
/// <param name="child">The child.</param>
|
|||
/// <returns>A value indicating whether the child was found (and removed) from this tree.</returns>
|
|||
public bool Remove(BinaryTree<T> child) |
|||
{ |
|||
if (leftSubtree != null) |
|||
{ |
|||
if (leftSubtree == child) |
|||
{ |
|||
RemoveLeft(); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
if (rightSubtree == child) |
|||
{ |
|||
RemoveRight(); |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through the collection.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
|||
/// </returns>
|
|||
public IEnumerator<T> GetEnumerator() |
|||
{ |
|||
var stack = new Stack<BinaryTree<T>>(); |
|||
|
|||
stack.Push(this); |
|||
|
|||
while (stack.Count > 0) |
|||
{ |
|||
var tree = stack.Pop(); |
|||
|
|||
yield return tree.Data; |
|||
|
|||
if (tree.leftSubtree != null) |
|||
{ |
|||
stack.Push(tree.leftSubtree); |
|||
} |
|||
|
|||
if (tree.rightSubtree != null) |
|||
{ |
|||
stack.Push(tree.rightSubtree); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public virtual void Clear() |
|||
{ |
|||
if (leftSubtree != null) |
|||
{ |
|||
leftSubtree.Parent = null; |
|||
leftSubtree = null; |
|||
} |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
rightSubtree.Parent = null; |
|||
rightSubtree = null; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ITree<T> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
void ITree<T>.Add(ITree<T> child) |
|||
{ |
|||
AddItem((BinaryTree<T>)child); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
ITree<T> ITree<T>.GetChild(int index) |
|||
{ |
|||
return GetChild(index); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
bool ITree<T>.Remove(ITree<T> child) |
|||
{ |
|||
return Remove((BinaryTree<T>)child); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
ITree<T> ITree<T>.FindNode(Predicate<T> condition) |
|||
{ |
|||
return FindNode(condition); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
ITree<T> ITree<T>.Parent |
|||
{ |
|||
get |
|||
{ |
|||
return Parent; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Gets the parent of the current node..
|
|||
/// </summary>
|
|||
/// <value>The parent of the current node.</value>
|
|||
public BinaryTree<T> Parent { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Finds the node with the specified condition. If a node is not found matching
|
|||
/// the specified condition, null is returned.
|
|||
/// </summary>
|
|||
/// <param name="condition">The condition to test.</param>
|
|||
/// <returns>The first node that matches the condition supplied. If a node is not found, null is returned.</returns>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="condition"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
public BinaryTree<T> FindNode(Predicate<T> condition) |
|||
{ |
|||
Guard.ArgumentNotNull(condition, "condition"); |
|||
|
|||
if (condition(Data)) |
|||
{ |
|||
return this; |
|||
} |
|||
|
|||
if (leftSubtree != null) |
|||
{ |
|||
var ret = leftSubtree.FindNode(condition); |
|||
|
|||
if (ret != null) |
|||
{ |
|||
return ret; |
|||
} |
|||
} |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
var ret = rightSubtree.FindNode(condition); |
|||
|
|||
if (ret != null) |
|||
{ |
|||
return ret; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the left subtree.
|
|||
/// </summary>
|
|||
/// <value>The left subtree.</value>
|
|||
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] |
|||
public virtual BinaryTree<T> Left |
|||
{ |
|||
get |
|||
{ |
|||
return leftSubtree; |
|||
} |
|||
set |
|||
{ |
|||
if (leftSubtree != null) |
|||
{ |
|||
RemoveLeft(); |
|||
} |
|||
|
|||
if (value != null) |
|||
{ |
|||
if (value.Parent != null) |
|||
{ |
|||
value.Parent.Remove(value); |
|||
} |
|||
|
|||
value.Parent = this; |
|||
} |
|||
|
|||
leftSubtree = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the right subtree.
|
|||
/// </summary>
|
|||
/// <value>The right subtree.</value>
|
|||
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] |
|||
public virtual BinaryTree<T> Right |
|||
{ |
|||
get |
|||
{ |
|||
return rightSubtree; |
|||
} |
|||
set |
|||
{ |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
RemoveRight(); |
|||
} |
|||
|
|||
if (value != null) |
|||
{ |
|||
if (value.Parent != null) |
|||
{ |
|||
value.Parent.Remove(value); |
|||
} |
|||
|
|||
value.Parent = this; |
|||
} |
|||
|
|||
rightSubtree = value; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public virtual T Data |
|||
{ |
|||
get |
|||
{ |
|||
return data; |
|||
} |
|||
set |
|||
{ |
|||
#region Validation
|
|||
|
|||
Guard.ArgumentNotNull(value, "data"); |
|||
|
|||
#endregion
|
|||
|
|||
data = value; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public int Degree |
|||
{ |
|||
get |
|||
{ |
|||
return Count; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the child at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="index">The index of the child in question.</param>
|
|||
/// <returns>The child at the specified index.</returns>
|
|||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> does not equal 0 or 1.</exception>
|
|||
public BinaryTree<T> GetChild(int index) |
|||
{ |
|||
switch (index) |
|||
{ |
|||
case 0: |
|||
return leftSubtree; |
|||
case 1: |
|||
return rightSubtree; |
|||
default: |
|||
throw new ArgumentOutOfRangeException("index"); |
|||
} |
|||
} |
|||
/// <inheritdoc />
|
|||
public virtual int Height |
|||
{ |
|||
get |
|||
{ |
|||
if (Degree == 0) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
return 1 + FindMaximumChildHeight(); |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Performs a depth first traversal on this tree with the specified visitor.
|
|||
/// </summary>
|
|||
/// <param name="orderedVisitor">The ordered visitor.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="orderedVisitor"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
public virtual void DepthFirstTraversal(OrderedVisitor<T> orderedVisitor) |
|||
{ |
|||
Guard.ArgumentNotNull(orderedVisitor, "orderedVisitor"); |
|||
|
|||
if (orderedVisitor.HasCompleted) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// Preorder visit
|
|||
orderedVisitor.VisitPreOrder(Data); |
|||
|
|||
if (leftSubtree != null) |
|||
{ |
|||
leftSubtree.DepthFirstTraversal(orderedVisitor); |
|||
} |
|||
|
|||
// In-order visit
|
|||
orderedVisitor.VisitInOrder(data); |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
rightSubtree.DepthFirstTraversal(orderedVisitor); |
|||
} |
|||
|
|||
// PostOrder visit
|
|||
orderedVisitor.VisitPostOrder(Data); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Performs a breadth first traversal on this tree with the specified visitor.
|
|||
/// </summary>
|
|||
/// <param name="visitor">The visitor.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="visitor"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
public virtual void BreadthFirstTraversal(IVisitor<T> visitor) |
|||
{ |
|||
Guard.ArgumentNotNull(visitor, "visitor"); |
|||
|
|||
var queue = new Queue<BinaryTree<T>>(); |
|||
|
|||
queue.Enqueue(this); |
|||
|
|||
while (queue.Count > 0) |
|||
{ |
|||
if (visitor.HasCompleted) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
var binaryTree = queue.Dequeue(); |
|||
visitor.Visit(binaryTree.Data); |
|||
|
|||
for (var i = 0; i < binaryTree.Degree; i++) |
|||
{ |
|||
var child = binaryTree.GetChild(i); |
|||
|
|||
if (child != null) |
|||
{ |
|||
queue.Enqueue(child); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
public virtual bool IsLeafNode |
|||
{ |
|||
get |
|||
{ |
|||
return Degree == 0; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the left child.
|
|||
/// </summary>
|
|||
public virtual void RemoveLeft() |
|||
{ |
|||
if (leftSubtree != null) |
|||
{ |
|||
leftSubtree.Parent = null; |
|||
leftSubtree = null; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the left child.
|
|||
/// </summary>
|
|||
public virtual void RemoveRight() |
|||
{ |
|||
if (rightSubtree != null) |
|||
{ |
|||
rightSubtree.Parent = null; |
|||
rightSubtree = null; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds an item to the <see cref="ICollection{T}"/>.
|
|||
/// </summary>
|
|||
/// <param name="subtree">The subtree.</param>
|
|||
/// <exception cref="NotSupportedException">The <see cref="ICollection{T}"/> is read-only.</exception>
|
|||
/// <exception cref="InvalidOperationException">The <see cref="BinaryTree{T}"/> is full.</exception>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="subtree"/> is null (Nothing in Visual Basic).</exception>
|
|||
public void Add(BinaryTree<T> subtree) |
|||
{ |
|||
Guard.ArgumentNotNull(subtree, "subtree"); |
|||
|
|||
AddItem(subtree); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds an item to the <see cref="ICollection{T}"/>.
|
|||
/// </summary>
|
|||
/// <param name="subtree">The subtree.</param>
|
|||
/// <remarks>
|
|||
/// <b>Notes to Inheritors: </b>
|
|||
/// Derived classes can override this method to change the behavior of the <see cref="Clear"/> method.
|
|||
/// </remarks>
|
|||
protected virtual void AddItem(BinaryTree<T> subtree) |
|||
{ |
|||
if (leftSubtree == null) |
|||
{ |
|||
if (subtree.Parent != null) |
|||
{ |
|||
subtree.Parent.Remove(subtree); |
|||
} |
|||
|
|||
leftSubtree = subtree; |
|||
subtree.Parent = this; |
|||
} |
|||
else if (rightSubtree == null) |
|||
{ |
|||
if (subtree.Parent != null) |
|||
{ |
|||
subtree.Parent.Remove(subtree); |
|||
} |
|||
|
|||
rightSubtree = subtree; |
|||
subtree.Parent = this; |
|||
} |
|||
else |
|||
{ |
|||
throw new InvalidOperationException("This binary tree is full."); |
|||
} |
|||
} |
|||
|
|||
|
|||
#endregion
|
|||
|
|||
#region Private Members
|
|||
|
|||
/// <summary>
|
|||
/// Finds the maximum height between the child nodes.
|
|||
/// </summary>
|
|||
/// <returns>The maximum height of the tree between all paths from this node and all leaf nodes.</returns>
|
|||
protected virtual int FindMaximumChildHeight() |
|||
{ |
|||
var leftHeight = 0; |
|||
var rightHeight = 0; |
|||
|
|||
if (leftSubtree != null) |
|||
{ |
|||
leftHeight = leftSubtree.Height; |
|||
} |
|||
|
|||
if (rightSubtree != null) |
|||
{ |
|||
rightHeight = rightSubtree.Height; |
|||
} |
|||
|
|||
return leftHeight > rightHeight ? leftHeight : rightHeight; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Operator Overloads
|
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="BinaryTree{T}"/> at the specified index.
|
|||
/// </summary>
|
|||
public BinaryTree<T> this[int index] |
|||
{ |
|||
get |
|||
{ |
|||
return GetChild(index); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ICollection<T> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
public bool IsReadOnly |
|||
{ |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IEnumerable Members
|
|||
|
|||
/// <inheritdoc />
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return GetEnumerator(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Object Members
|
|||
|
|||
/// <inheritdoc />
|
|||
public override string ToString() |
|||
{ |
|||
return data.ToString(); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using NGenerics.Util; |
|||
|
|||
namespace NGenerics.Comparers |
|||
{ |
|||
/// <summary>
|
|||
/// A Comparer using a Comparison delegate for comparisons between items.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the objects to compare.</typeparam>
|
|||
//[Serializable]
|
|||
internal sealed class ComparisonComparer<T> : IComparer<T> |
|||
{ |
|||
#region Globals
|
|||
|
|||
private Comparison<T> comparison; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
|
|||
/// <param name="comparison">The comparison.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="comparison"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
public ComparisonComparer(Comparison<T> comparison) |
|||
{ |
|||
Guard.ArgumentNotNull(comparison, "comparison"); |
|||
|
|||
this.comparison = comparison; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the comparison used in this comparer.
|
|||
/// </summary>
|
|||
/// <value>The comparison used in this comparer.</value>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="value"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
public Comparison<T> Comparison |
|||
{ |
|||
get |
|||
{ |
|||
return comparison; |
|||
} |
|||
set |
|||
{ |
|||
|
|||
Guard.ArgumentNotNull(value, "value"); |
|||
|
|||
comparison = value; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IComparer<T> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
public int Compare(T x, T y) |
|||
{ |
|||
return comparison(x, y); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
namespace NGenerics |
|||
{ |
|||
static class Constants |
|||
{ |
|||
public const string NotEnoughSpaceInTheTargetArray = "Not enough space in the target array."; |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
|
|||
namespace NGenerics.Util |
|||
{ |
|||
/// <summary>
|
|||
/// Performs common argument validation.
|
|||
/// </summary>
|
|||
internal static class Guard |
|||
{ |
|||
#region Methods
|
|||
|
|||
/// <summary>
|
|||
/// Checks a string argument to ensure it isn't null or empty.
|
|||
/// </summary>
|
|||
/// <param name="argumentValue">The argument value to check.</param>
|
|||
/// <param name="argumentName">The name of the argument.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="argumentValue"/> is a null reference.</exception>
|
|||
/// <exception cref="ArgumentException"><paramref name="argumentValue"/> is <see cref="string.Empty"/>.</exception>
|
|||
public static void ArgumentNotNullOrEmptyString(string argumentValue, string argumentName) |
|||
{ |
|||
ArgumentNotNull(argumentValue, argumentName); |
|||
|
|||
if (argumentValue.Length == 0) |
|||
{ |
|||
throw new ArgumentException("String cannot be empty.", argumentName); |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Checks an argument to ensure it isn't null.
|
|||
/// </summary>
|
|||
/// <param name="argumentValue">The argument value to check.</param>
|
|||
/// <param name="argumentName">The name of the argument.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="argumentValue"/> is a null reference.</exception>
|
|||
public static void ArgumentNotNull(object argumentValue, string argumentName) |
|||
{ |
|||
if (argumentValue == null) |
|||
{ |
|||
throw new ArgumentNullException(argumentName); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
|
|||
namespace NGenerics.DataStructures.Queues |
|||
{ |
|||
/// <summary>
|
|||
/// A queue interface.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the elements in the queue.</typeparam>
|
|||
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] |
|||
internal interface IQueue<T> |
|||
{ |
|||
/// <summary>
|
|||
/// Enqueues the item at the back of the queue.
|
|||
/// </summary>
|
|||
/// <param name="item">The item.</param>
|
|||
void Enqueue(T item); |
|||
|
|||
/// <summary>
|
|||
/// Dequeues the item at the front of the queue.
|
|||
/// </summary>
|
|||
/// <returns>The item at the front of the queue.</returns>
|
|||
/// <exception cref="InvalidOperationException">The <see cref="Deque{T}"/> is empty.</exception>
|
|||
T Dequeue(); |
|||
|
|||
/// <summary>
|
|||
/// Peeks at the item in the front of the queue, without removing it.
|
|||
/// </summary>
|
|||
/// <returns>The item at the front of the queue.</returns>
|
|||
/// <exception cref="InvalidOperationException">The <see cref="Deque{T}"/> is empty.</exception>
|
|||
T Peek(); |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using NGenerics.Patterns.Visitor; |
|||
|
|||
namespace NGenerics.DataStructures.Trees |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// An interface for Search Trees that mimic a dictionary.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of element to hold in the tree.</typeparam>
|
|||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] |
|||
internal interface ISearchTree<T> : ICollection<T> { |
|||
/// <summary>
|
|||
/// Gets the largest item in the tree.
|
|||
/// </summary>
|
|||
/// <value>The largest item in the tree.</value>
|
|||
/// <exception cref="InvalidOperationException">The <see cref="ISearchTree{T}"/> is empty.</exception>
|
|||
T Maximum { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the smallest item in the tree.
|
|||
/// </summary>
|
|||
/// <value>The smallest item in the tree.</value>
|
|||
/// <exception cref="InvalidOperationException">The <see cref="ISearchTree{T}"/> is empty.</exception>
|
|||
T Minimum { get; } |
|||
|
|||
/// <summary>
|
|||
/// Performs a depth first traversal on the search tree.
|
|||
/// </summary>
|
|||
/// <param name="visitor">The visitor to use.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="visitor"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="DepthFirstTraversal" lang="cs" title="The following example shows how to use the DepthFirstTraversal method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="DepthFirstTraversal" lang="vbnet" title="The following example shows how to use the DepthFirstTraversal method."/>
|
|||
/// </example>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
void DepthFirstTraversal(OrderedVisitor<T> visitor); |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through the collection.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
|
|||
/// </returns>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="GetOrderedEnumerator" lang="cs" title="The following example shows how to use the GetOrderedEnumerator method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="GetOrderedEnumerator" lang="vbnet" title="The following example shows how to use the GetOrderedEnumerator method."/>
|
|||
/// </example>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] |
|||
IEnumerator<T> GetOrderedEnumerator(); |
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
using System; |
|||
|
|||
namespace NGenerics.DataStructures.Trees { |
|||
/// <summary>
|
|||
/// An interface for the tree data structure
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of elements in the tree.</typeparam>
|
|||
internal interface ITree<T> { |
|||
/// <summary>
|
|||
/// Adds the specified child to the tree.
|
|||
/// </summary>
|
|||
/// <param name="child">The child to add..</param>
|
|||
void Add(ITree<T> child); |
|||
|
|||
/// <summary>
|
|||
/// Gets the data held in this node.
|
|||
/// </summary>
|
|||
/// <value>The data.</value>
|
|||
T Data { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the degree of this node.
|
|||
/// </summary>
|
|||
/// <value>The degree of this node.</value>
|
|||
int Degree { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the child at the specified index.
|
|||
/// </summary>
|
|||
/// <param name="index">The index.</param>
|
|||
/// <returns>The child at the specified index.</returns>
|
|||
ITree<T> GetChild(int index); |
|||
|
|||
/// <summary>
|
|||
/// Gets the height of this tree.
|
|||
/// </summary>
|
|||
/// <value>The height of this tree.</value>
|
|||
int Height { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is leaf node.
|
|||
/// </summary>
|
|||
/// <value>
|
|||
/// <c>true</c> if this instance is leaf node; otherwise, <c>false</c>.
|
|||
/// </value>
|
|||
bool IsLeafNode { get; } |
|||
|
|||
/// <summary>
|
|||
/// Removes the specified child.
|
|||
/// </summary>
|
|||
/// <param name="child">The child.</param>
|
|||
/// <returns>An indication of whether the child was found (and removed) from this tree.</returns>
|
|||
bool Remove(ITree<T> child); |
|||
|
|||
/// <summary>
|
|||
/// Finds the node for which the given predicate holds true.
|
|||
/// </summary>
|
|||
/// <param name="condition">The condition to test on the data item.</param>
|
|||
/// <returns>The fist node that matches the condition if found, otherwise null.</returns>
|
|||
ITree<T> FindNode(Predicate<T> condition); |
|||
|
|||
/// <summary>
|
|||
/// Gets the parent of the current node.
|
|||
/// </summary>
|
|||
/// <value>The parent of the current node.</value>
|
|||
ITree<T> Parent { get;} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
namespace NGenerics.Patterns.Visitor |
|||
{ |
|||
/// <summary>
|
|||
/// Provides an interface for visitors.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of objects to be visited.</typeparam>
|
|||
internal interface IVisitor<T> |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a value indicating whether this instance is done performing it's work..
|
|||
/// </summary>
|
|||
/// <value><c>true</c> if this instance is done; otherwise, <c>false</c>.</value>
|
|||
bool HasCompleted { get; } |
|||
|
|||
/// <summary>
|
|||
/// Visits the specified object.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to visit.</param>
|
|||
void Visit(T obj); |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
namespace NGenerics.Patterns.Visitor |
|||
{ |
|||
/// <summary>
|
|||
/// An in order implementation of the <see cref="OrderedVisitor{T}"/> class.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of objects to be visited.</typeparam>
|
|||
internal sealed class InOrderVisitor<T> : OrderedVisitor<T> |
|||
{ |
|||
#region Construction
|
|||
|
|||
/// <param name="visitor">The visitor.</param>
|
|||
public InOrderVisitor(IVisitor<T> visitor) : base(visitor) { } |
|||
|
|||
#endregion
|
|||
|
|||
#region OrderedVisitor<T> Members
|
|||
|
|||
/// <summary>
|
|||
/// Visits the object in post order.
|
|||
/// </summary>
|
|||
/// <param name="obj">The obj.</param>
|
|||
public override void VisitPostOrder(T obj) |
|||
{ |
|||
// Do nothing.
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Visits the object in pre order.
|
|||
/// </summary>
|
|||
/// <param name="obj">The obj.</param>
|
|||
public override void VisitPreOrder(T obj) |
|||
{ |
|||
// Do nothing.
|
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System.Collections.Generic; |
|||
|
|||
namespace NGenerics.Patterns.Visitor |
|||
{ |
|||
/// <summary>
|
|||
/// A visitor that tracks (stores) keys from KeyValuePAirs in the order they were visited.
|
|||
/// </summary>
|
|||
/// <typeparam name="TKey">The type of the keys for the items to be visited.</typeparam>
|
|||
/// <typeparam name="TValue">The type of the values for the items to be visited.</typeparam>
|
|||
internal sealed class KeyTrackingVisitor<TKey, TValue> : IVisitor<KeyValuePair<TKey, TValue>> |
|||
{ |
|||
#region Globals
|
|||
|
|||
private readonly List<TKey> tracks; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
/// <inheritdoc/>
|
|||
public KeyTrackingVisitor() |
|||
{ |
|||
tracks = new List<TKey>(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Gets the tracking list.
|
|||
/// </summary>
|
|||
/// <value>The tracking list.</value>
|
|||
public IList<TKey> TrackingList |
|||
{ |
|||
get |
|||
{ |
|||
return tracks; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IVisitor<KeyValuePair<TKey,TValue>> Members
|
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
public void Visit(KeyValuePair<TKey, TValue> obj) |
|||
{ |
|||
tracks.Add(obj.Key); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool HasCompleted |
|||
{ |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,86 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace NGenerics.Comparers { |
|||
/// <summary>
|
|||
/// A comparer for comparing keys for the KeyValuePair class.
|
|||
/// </summary>
|
|||
/// <typeparam name="TKey">The key type.</typeparam>
|
|||
/// <typeparam name="TValue">The value type.</typeparam>
|
|||
//[Serializable]
|
|||
internal class KeyValuePairComparer<TKey, TValue> : IComparer<KeyValuePair<TKey, TValue>> { |
|||
|
|||
#region Globals
|
|||
|
|||
private readonly IComparer<TKey> comparer; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="KeyValuePairComparer<TKey, TValue>"/> class.
|
|||
/// </summary>
|
|||
public KeyValuePairComparer() { |
|||
comparer = Comparer<TKey>.Default; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="KeyValuePairComparer<TKey, TValue>"/> class.
|
|||
/// </summary>
|
|||
/// <param name="comparer">The comparer.</param>
|
|||
public KeyValuePairComparer(IComparer<TKey> comparer) { |
|||
|
|||
if (comparer == null) |
|||
{ |
|||
throw new ArgumentNullException("comparer"); |
|||
} |
|||
|
|||
this.comparer = comparer; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="KeyValuePairComparer<TKey, TValue>"/> class.
|
|||
/// </summary>
|
|||
/// <param name="comparison">The comparison.</param>
|
|||
public KeyValuePairComparer(Comparison<TKey> comparison) |
|||
{ |
|||
if (comparison == null) { |
|||
throw new ArgumentNullException("comparison"); |
|||
} |
|||
|
|||
comparer = new ComparisonComparer<TKey>(comparison); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IComparer<KeyValuePairComparer<TKey,TValue>> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
public int Compare(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y) { |
|||
return comparer.Compare(x.Key, y.Key); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IComparer<TKey> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
public int Compare(TKey x, TKey y) { |
|||
return comparer.Compare(x, y); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
namespace NGenerics.DataStructures.Trees |
|||
{ |
|||
internal enum NodeColor |
|||
{ |
|||
Red = 0, |
|||
Black = 1 |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using NGenerics.Util; |
|||
|
|||
namespace NGenerics.Patterns.Visitor |
|||
{ |
|||
/// <summary>
|
|||
/// A visitor that visits objects in order (PreOrder, PostOrder, or InOrder).
|
|||
/// Used primarily as a base class for Visitors specializing in a specific order type.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of objects to be visited.</typeparam>
|
|||
internal class OrderedVisitor<T> : IVisitor<T> |
|||
{ |
|||
#region Globals
|
|||
|
|||
private readonly IVisitor<T> visitorToUse; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
/// <param name="visitorToUse">The visitor to use when visiting the object.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="visitorToUse"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
public OrderedVisitor(IVisitor<T> visitorToUse) |
|||
{ |
|||
Guard.ArgumentNotNull(visitorToUse, "visitorToUse"); |
|||
|
|||
this.visitorToUse = visitorToUse; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IOrderedVisitor<T> Members
|
|||
|
|||
/// <summary>
|
|||
/// Determines whether this visitor is done.
|
|||
/// </summary>
|
|||
/// <value></value>
|
|||
/// <returns>
|
|||
/// <c>true</c> if this visitor is done; otherwise, <c>false</c>.
|
|||
/// </returns>
|
|||
public bool HasCompleted |
|||
{ |
|||
get |
|||
{ |
|||
return visitorToUse.HasCompleted; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Visits the object in pre order.
|
|||
/// </summary>
|
|||
/// <param name="obj">The obj.</param>
|
|||
[SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "PreOrder")] |
|||
public virtual void VisitPreOrder(T obj) |
|||
{ |
|||
visitorToUse.Visit(obj); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Visits the object in post order.
|
|||
/// </summary>
|
|||
/// <param name="obj">The obj.</param>
|
|||
public virtual void VisitPostOrder(T obj) |
|||
{ |
|||
visitorToUse.Visit(obj); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Visits the object in order.
|
|||
/// </summary>
|
|||
/// <param name="obj">The obj.</param>
|
|||
public virtual void VisitInOrder(T obj) |
|||
{ |
|||
visitorToUse.Visit(obj); |
|||
} |
|||
/// <inheritdoc />
|
|||
public void Visit(T obj) |
|||
{ |
|||
visitorToUse.Visit(obj); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Gets the visitor to use.
|
|||
/// </summary>
|
|||
/// <value>The visitor to use.</value>
|
|||
public IVisitor<T> VisitorToUse |
|||
{ |
|||
get |
|||
{ |
|||
return visitorToUse; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,557 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
|
|||
Community contributions : |
|||
- TKey Peek(out TPriority) contributed by Karl Shulze (http://www.karlschulze.com/).</remarks>
|
|||
*/ |
|||
|
|||
|
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using NGenerics.Comparers; |
|||
using NGenerics.DataStructures.Trees; |
|||
using NGenerics.Util; |
|||
|
|||
namespace NGenerics.DataStructures.Queues |
|||
{ |
|||
/// <summary>
|
|||
/// An implementation of a Priority Queue (can be <see cref="PriorityQueueType.Minimum"/> or <see cref="PriorityQueueType.Maximum"/>).
|
|||
/// </summary>
|
|||
/// <typeparam name="TPriority">The type of the priority in the <see cref="PriorityQueue{TPriority, TValue}"/>.</typeparam>
|
|||
/// <typeparam name="TValue">The type of the elements in the <see cref="PriorityQueue{TPriority, TValue}"/>.</typeparam>
|
|||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] |
|||
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] |
|||
//[Serializable]
|
|||
internal class PriorityQueue<TValue, TPriority> : ICollection<TValue>, IQueue<TValue> |
|||
{ |
|||
#region Globals
|
|||
|
|||
private readonly RedBlackTreeList<TPriority, TValue> tree; |
|||
private TPriority defaultPriority; |
|||
private readonly PriorityQueueType queueType; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
/// <param name="queueType">Type of the queue.</param>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Constructor" lang="cs" title="The following example shows how to use the default constructor."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Constructor" lang="vbnet" title="The following example shows how to use the default constructor."/>
|
|||
/// </example>
|
|||
public PriorityQueue(PriorityQueueType queueType) : |
|||
this(queueType, Comparer<TPriority>.Default) { |
|||
|
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public PriorityQueue(PriorityQueueType queueType, IComparer<TPriority> comparer) { |
|||
if ((queueType != PriorityQueueType.Minimum) && (queueType != PriorityQueueType.Maximum)) { |
|||
throw new ArgumentOutOfRangeException("queueType"); |
|||
} |
|||
this.queueType = queueType; |
|||
tree = new RedBlackTreeList<TPriority, TValue>(comparer); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PriorityQueue<TValue, TPriority>"/> class.
|
|||
/// </summary>
|
|||
/// <param name="queueType">Type of the queue.</param>
|
|||
/// <param name="comparison">The comparison.</param>
|
|||
/// <inheritdoc/>
|
|||
public PriorityQueue(PriorityQueueType queueType, Comparison<TPriority> comparison) : |
|||
this(queueType, new ComparisonComparer<TPriority>(comparison)) { |
|||
|
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IQueue<T> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Enqueue" lang="cs" title="The following example shows how to use the Enqueue method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Enqueue" lang="vbnet" title="The following example shows how to use the Enqueue method."/>
|
|||
/// </example>
|
|||
public void Enqueue(TValue item) |
|||
{ |
|||
Add(item); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Enqueues the specified item.
|
|||
/// </summary>
|
|||
/// <param name="item">The item.</param>
|
|||
/// <param name="priority">The priority.</param>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="EnqueuePriority" lang="cs" title="The following example shows how to use the Enqueue method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="EnqueuePriority" lang="vbnet" title="The following example shows how to use the Enqueue method."/>
|
|||
/// </example>
|
|||
public void Enqueue(TValue item, TPriority priority) |
|||
{ |
|||
Add(item, priority); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Dequeues the item at the front of the queue.
|
|||
/// </summary>
|
|||
/// <returns>The item at the front of the queue.</returns>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Dequeue" lang="cs" title="The following example shows how to use the Dequeue method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Dequeue" lang="vbnet" title="The following example shows how to use the Dequeue method."/>
|
|||
/// </example>
|
|||
public TValue Dequeue() |
|||
{ |
|||
TPriority priority; |
|||
return Dequeue(out priority); |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Peeks at the item in the front of the queue, without removing it.
|
|||
/// </summary>
|
|||
/// <returns>The item at the front of the queue.</returns>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Peek" lang="cs" title="The following example shows how to use the Peek method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Peek" lang="vbnet" title="The following example shows how to use the Peek method."/>
|
|||
/// </example>
|
|||
public TValue Peek() |
|||
{ |
|||
var association = GetNextItem(); |
|||
|
|||
// Always dequeue in FIFO manner
|
|||
return association.Value.First.Value; |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Peeks at the item in the front of the queue, without removing it.
|
|||
/// </summary>
|
|||
/// <param name="priority">The priority of the item.</param>
|
|||
/// <returns>The item at the front of the queue.</returns>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="PeekPriority" lang="cs" title="The following example shows how to use the Peek method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="PeekPriority" lang="vbnet" title="The following example shows how to use the Peek method."/>
|
|||
/// </example>
|
|||
public TValue Peek(out TPriority priority) |
|||
{ |
|||
var association = GetNextItem(); |
|||
var item = association.Value.First.Value; |
|||
priority = association.Key; |
|||
return item; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ICollection<T> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="IsReadOnly" lang="cs" title="The following example shows how to use the IsReadOnly property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="IsReadOnly" lang="vbnet" title="The following example shows how to use the IsReadOnly property."/>
|
|||
/// </example>
|
|||
public bool IsReadOnly |
|||
{ |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IEnumerable Members
|
|||
|
|||
/// <inheritdoc />
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return GetEnumerator(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through the collection.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
|||
/// </returns>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="GetEnumerator" lang="cs" title="The following example shows how to use the GetEnumerator method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="GetEnumerator" lang="vbnet" title="The following example shows how to use the GetEnumerator method."/>
|
|||
/// </example>
|
|||
public IEnumerator<TValue> GetEnumerator() |
|||
{ |
|||
return tree.GetValueEnumerator(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Count" lang="cs" title="The following example shows how to use the Count property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Count" lang="vbnet" title="The following example shows how to use the Count property."/>
|
|||
/// </example>
|
|||
public int Count { get; private set; } |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Contains" lang="cs" title="The following example shows how to use the Contains method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Contains" lang="vbnet" title="The following example shows how to use the Contains method."/>
|
|||
/// </example>
|
|||
public bool Contains(TValue item) |
|||
{ |
|||
return tree.ContainsValue(item); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="CopyTo" lang="cs" title="The following example shows how to use the CopyTo method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="CopyTo" lang="vbnet" title="The following example shows how to use the CopyTo method."/>
|
|||
/// </example>
|
|||
public void CopyTo(TValue[] array, int arrayIndex) |
|||
{ |
|||
#region Validation
|
|||
|
|||
Guard.ArgumentNotNull(array, "array"); |
|||
|
|||
if ((array.Length - arrayIndex) < Count) |
|||
{ |
|||
throw new ArgumentException(Constants.NotEnoughSpaceInTheTargetArray, "array"); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
|
|||
foreach (var association in tree) |
|||
{ |
|||
var items = association.Value; |
|||
|
|||
foreach (var item in items) |
|||
{ |
|||
array.SetValue(item, arrayIndex++); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Add" lang="cs" title="The following example shows how to use the Add method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Add" lang="vbnet" title="The following example shows how to use the Add method."/>
|
|||
/// </example>
|
|||
public void Add(TValue item) |
|||
{ |
|||
Add(item, defaultPriority); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds an item to the <see cref="ICollection{T}"/>.
|
|||
/// </summary>
|
|||
/// <param name="item">The object to add to the <see cref="ICollection{T}"/>.</param>
|
|||
/// <param name="priority">The priority of the item.</param>
|
|||
/// <exception cref="NotSupportedException">The <see cref="ICollection{T}"/> is read-only.</exception>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="AddPriority" lang="cs" title="The following example shows how to use the Add method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="AddPriority" lang="vbnet" title="The following example shows how to use the Add method."/>
|
|||
/// </example>
|
|||
public void Add(TValue item, TPriority priority) |
|||
{ |
|||
AddItem(item, priority); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool Remove(TValue item) |
|||
{ |
|||
TPriority priority; |
|||
return Remove(item, out priority); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through the keys in the collection.
|
|||
/// </summary>
|
|||
/// <returns>A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the keys in the collection.</returns>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="GetKeyEnumerator" lang="cs" title="The following example shows how to use the GetKeyEnumerator method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="GetKeyEnumerator" lang="vbnet" title="The following example shows how to use the GetKeyEnumerator method."/>
|
|||
/// </example>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] |
|||
public IEnumerator<KeyValuePair<TPriority, TValue>> GetKeyEnumerator() |
|||
{ |
|||
return tree.GetKeyEnumerator(); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="Clear" lang="cs" title="The following example shows how to use the Clear method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="Clear" lang="vbnet" title="The following example shows how to use the Clear method."/>
|
|||
/// </example>
|
|||
public void Clear() |
|||
{ |
|||
ClearItems(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Dequeues the item from the head of the queue.
|
|||
/// </summary>
|
|||
/// <param name="priority">The priority of the item to dequeue.</param>
|
|||
/// <returns>The item at the head of the queue.</returns>
|
|||
/// <exception cref="InvalidOperationException">The <see cref="PriorityQueue{TValue, TPriority}"/> is empty.</exception>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Queues\PriorityQueueExamples.cs" region="DequeueWithPriority" lang="cs" title="The following example shows how to use the Dequeue method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Queues\PriorityQueueExamples.vb" region="DequeueWithPriority" lang="vbnet" title="The following example shows how to use the Dequeue method."/>
|
|||
/// </example>
|
|||
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] |
|||
public TValue Dequeue(out TPriority priority) |
|||
{ |
|||
return DequeueItem(out priority); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Dequeues the item at the front of the queue.
|
|||
/// </summary>
|
|||
/// <returns>The item at the front of the queue.</returns>
|
|||
/// <remarks>
|
|||
/// <b>Notes to Inheritors: </b>
|
|||
/// Derived classes can override this method to change the behavior of the <see cref="Dequeue()"/> or <see cref="Dequeue(out TPriority)"/> methods.
|
|||
/// </remarks>
|
|||
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] |
|||
protected virtual TValue DequeueItem(out TPriority priority) |
|||
{ |
|||
var association = GetNextItem(); |
|||
|
|||
var item = association.Value.First.Value; |
|||
association.Value.RemoveFirst(); |
|||
|
|||
var key = association.Key; |
|||
|
|||
if (association.Value.Count == 0) |
|||
{ |
|||
tree.Remove(association.Key); |
|||
} |
|||
|
|||
Count--; |
|||
|
|||
priority = key; |
|||
return item; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the default priority.
|
|||
/// </summary>
|
|||
/// <value>The default priority.</value>
|
|||
public TPriority DefaultPriority |
|||
{ |
|||
get |
|||
{ |
|||
return defaultPriority; |
|||
} |
|||
set |
|||
{ |
|||
defaultPriority = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the first occurrence of the specified item from the property queue.
|
|||
/// </summary>
|
|||
/// <param name="item">The item to remove.</param>
|
|||
/// <param name="priority">The priority associated with the item.</param>
|
|||
/// <returns><c>true</c> if the item exists in the <see cref="PriorityQueue{TValue, TPriority}"/> and has been removed; otherwise <c>false</c>.</returns>
|
|||
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")] |
|||
public bool Remove(TValue item, out TPriority priority) |
|||
{ |
|||
return RemoveItem(item, out priority); |
|||
} |
|||
/// <summary>
|
|||
/// Removes the item.
|
|||
/// </summary>
|
|||
/// <param name="item">The item to remove</param>
|
|||
/// <param name="priority">The priority of the item that was removed.</param>
|
|||
/// <returns>An indication of whether the item was found, and removed.</returns>
|
|||
/// <remarks>
|
|||
/// <b>Notes to Inheritors: </b>
|
|||
/// Derived classes can override this method to change the behavior of the <see cref="Remove(TValue,out TPriority)"/> method.
|
|||
/// </remarks>
|
|||
[SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")] |
|||
protected virtual bool RemoveItem(TValue item, out TPriority priority) |
|||
{ |
|||
var removed = tree.Remove(item, out priority); |
|||
|
|||
if (removed) |
|||
{ |
|||
Count--; |
|||
} |
|||
|
|||
return removed; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the items with the specified priority.
|
|||
/// </summary>
|
|||
/// <param name="priority">The priority.</param>
|
|||
/// <returns><c>true</c> if the priority exists in the <see cref="PriorityQueue{TValue, TPriority}"/> and has been removed; otherwise <c>false</c>.</returns>
|
|||
public bool RemovePriorityGroup(TPriority priority) |
|||
{ |
|||
return RemoveItems(priority); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the items from the collection with the specified priority.
|
|||
/// </summary>
|
|||
/// <param name="priority">The priority to search for.</param>
|
|||
/// <returns>An indication of whether items were found having the specified priority.</returns>
|
|||
protected virtual bool RemoveItems(TPriority priority) |
|||
{ |
|||
LinkedList<TValue> items; |
|||
|
|||
if (tree.TryGetValue(priority, out items)) |
|||
{ |
|||
tree.Remove(priority); |
|||
Count -= items.Count; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the items with the specified priority.
|
|||
/// </summary>
|
|||
/// <param name="priority">The priority.</param>
|
|||
/// <returns>The items with the specified priority.</returns>
|
|||
public IList<TValue> GetPriorityGroup(TPriority priority) |
|||
{ |
|||
LinkedList<TValue> items; |
|||
|
|||
return tree.TryGetValue(priority, out items) ? new List<TValue>(items) : new List<TValue>(); |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Adds the specified items to the priority queue with the specified priority.
|
|||
/// </summary>
|
|||
/// <param name="items">The items.</param>
|
|||
/// <param name="priority">The priority.</param>
|
|||
/// <exception cref="ArgumentNullException"><paramref name="items"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
|
|||
public void AddPriorityGroup(IList<TValue> items, TPriority priority) |
|||
{ |
|||
#region Validation
|
|||
|
|||
Guard.ArgumentNotNull(items, "items"); |
|||
|
|||
#endregion
|
|||
|
|||
AddPriorityGroupItem(items, priority); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds the specified items to the priority queue with the specified priority.
|
|||
/// </summary>
|
|||
/// <param name="items">The items.</param>
|
|||
/// <param name="priority">The priority.</param>
|
|||
/// <remarks>
|
|||
/// <b>Notes to Inheritors: </b>
|
|||
/// Derived classes can override this method to change the behavior of the <see cref="AddPriorityGroup"/> method.
|
|||
/// </remarks>
|
|||
protected virtual void AddPriorityGroupItem(IList<TValue> items, TPriority priority) |
|||
{ |
|||
LinkedList<TValue> currentValues; |
|||
|
|||
if (tree.TryGetValue(priority, out currentValues)) |
|||
{ |
|||
for (var i = 0; i < items.Count; i++) |
|||
{ |
|||
currentValues.AddLast(items[i]); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
currentValues = new LinkedList<TValue>(items); |
|||
tree.Add(priority, currentValues); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Protected Members
|
|||
|
|||
/// <summary>
|
|||
/// Adds the item to the queue.
|
|||
/// </summary>
|
|||
/// <param name="item">The item to add.</param>
|
|||
/// <param name="priority">The priority of the item.</param>
|
|||
/// <remarks>
|
|||
/// <b>Notes to Inheritors: </b>
|
|||
/// Derived classes can override this method to change the behavior of the <see cref="Add(TValue,TPriority)"/> method.
|
|||
/// </remarks>
|
|||
protected virtual void AddItem(TValue item, TPriority priority) |
|||
{ |
|||
LinkedList<TValue> list; |
|||
|
|||
if (tree.TryGetValue(priority, out list)) |
|||
{ |
|||
list.AddLast(item); |
|||
} |
|||
else |
|||
{ |
|||
list = new LinkedList<TValue>(); |
|||
list.AddLast(item); |
|||
tree.Add(priority, list); |
|||
} |
|||
|
|||
Count++; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Clears all the objects in this instance.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <b>Notes to Inheritors: </b>
|
|||
/// Derived classes can override this method to change the behavior of the <see cref="Clear"/> method.
|
|||
/// </remarks>
|
|||
protected virtual void ClearItems() |
|||
{ |
|||
tree.Clear(); |
|||
Count = 0; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Private Members
|
|||
|
|||
/// <summary>
|
|||
/// Checks if the list is not empty, and if it is, throw an exception.
|
|||
/// </summary>
|
|||
private void CheckTreeNotEmpty() |
|||
{ |
|||
if (tree.Count == 0) |
|||
{ |
|||
throw new InvalidOperationException("The Priority Queue is empty."); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the next item.
|
|||
/// </summary>
|
|||
private KeyValuePair<TPriority, LinkedList<TValue>> GetNextItem() |
|||
{ |
|||
#region Validation
|
|||
|
|||
CheckTreeNotEmpty(); |
|||
|
|||
#endregion
|
|||
|
|||
return queueType == PriorityQueueType.Maximum ? tree.Maximum : tree.Minimum; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
namespace NGenerics.DataStructures.Queues |
|||
{ |
|||
/// <summary>
|
|||
/// Specifies the Priority Queue type (min or max).
|
|||
/// </summary>
|
|||
internal enum PriorityQueueType |
|||
{ |
|||
/// <summary>
|
|||
/// Specify a Minimum <see cref="PriorityQueue{TValue, TPriority}"/>.
|
|||
/// </summary>
|
|||
Minimum = 0, |
|||
|
|||
/// <summary>
|
|||
/// Specify a Maximum <see cref="PriorityQueue{TValue, TPriority}"/>.
|
|||
/// </summary>
|
|||
Maximum = 1 |
|||
} |
|||
} |
|||
@ -0,0 +1,247 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
/* |
|||
* The insertion and deletion code is based on the code found at http://eternallyconfuzzled.com/tuts/redblack.htm.
|
|||
* It's an excellent tutorial - if you want to understand Red Black trees, look there first. |
|||
*/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
|
|||
namespace NGenerics.DataStructures.Trees { |
|||
/// <summary>
|
|||
/// An implementation of a Red-Black tree.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of element to keep in the tree.</typeparam>
|
|||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] |
|||
//[Serializable]
|
|||
internal class RedBlackTree<T> : BinarySearchTreeBase<T> { |
|||
|
|||
#region Construction
|
|||
|
|||
/// <inheritdoc />
|
|||
public RedBlackTree() { |
|||
// Do nothing - the default Comparer will be used by the base class.
|
|||
} |
|||
|
|||
|
|||
/// <inheritdoc/>
|
|||
public RedBlackTree(IComparer<T> comparer) |
|||
: base(comparer) { |
|||
// Do nothing else.
|
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public RedBlackTree(Comparison<T> comparison) |
|||
: base(comparison) { |
|||
// Do nothing else.
|
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Adds an element with the provided key and value to the <see cref="IDictionary{TKey,TValue}"/>.
|
|||
/// </summary>
|
|||
/// <param name="item">The item.</param>
|
|||
protected override void AddItem(T item) { |
|||
#region Validation
|
|||
|
|||
if (Equals(item, null)) { |
|||
throw new ArgumentNullException("item"); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
var root = (RedBlackTreeNode<T>)Tree; |
|||
|
|||
var newRoot = InsertNode(root, item); |
|||
newRoot.Color = NodeColor.Black; |
|||
Tree = newRoot; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the element with the specified key from the <see cref="IDictionary{TKey,TValue}"/>.
|
|||
/// </summary>
|
|||
/// <param name="item">The item to remove.</param>
|
|||
/// <returns>
|
|||
/// <c>true</c> if the element is successfully removed; otherwise, <c>false</c>. This method also returns false if key was not found in the original <see cref="IDictionary{TKey,TValue}"/>.
|
|||
/// </returns>
|
|||
/// <inheritdoc/>
|
|||
protected override bool RemoveItem(T item) { |
|||
if (Tree != null) { |
|||
var startNode = new RedBlackTreeNode<T>(default(T)); |
|||
|
|||
var childNode = startNode; |
|||
startNode.Right = (RedBlackTreeNode<T>)Tree; |
|||
|
|||
RedBlackTreeNode<T> parent = null; |
|||
RedBlackTreeNode<T> foundNode = null; |
|||
|
|||
var direction = true; |
|||
|
|||
while (childNode[direction] != null) { |
|||
var lastDirection = direction; |
|||
|
|||
var grandParent = parent; |
|||
parent = childNode; |
|||
childNode = childNode[direction]; |
|||
|
|||
var comparisonValue = Comparer.Compare(childNode.Data, item); |
|||
|
|||
if (comparisonValue == 0) { |
|||
foundNode = childNode; |
|||
} |
|||
|
|||
direction = comparisonValue < 0; |
|||
|
|||
if ((IsBlack(childNode)) && (IsBlack(childNode[direction]))) { |
|||
if (IsRed(childNode[!direction])) { |
|||
parent = parent[lastDirection] = SingleRotation(childNode, direction); |
|||
} else if (IsBlack(childNode[direction])) { |
|||
var sibling = parent[!lastDirection]; |
|||
|
|||
if (sibling != null) { |
|||
if ((IsBlack(sibling.Left)) && (IsBlack(sibling.Right))) { |
|||
parent.Color = NodeColor.Black; |
|||
sibling.Color = NodeColor.Red; |
|||
childNode.Color = NodeColor.Red; |
|||
} else { |
|||
var parentDirection = grandParent.Right == parent; |
|||
|
|||
if (IsRed(sibling[lastDirection])) { |
|||
grandParent[parentDirection] = DoubleRotation(parent, lastDirection); |
|||
} else if (IsRed(sibling[!lastDirection])) { |
|||
grandParent[parentDirection] = SingleRotation(parent, lastDirection); |
|||
} |
|||
|
|||
childNode.Color = grandParent[parentDirection].Color = NodeColor.Red; |
|||
grandParent[parentDirection].Left.Color = NodeColor.Black; |
|||
grandParent[parentDirection].Right.Color = NodeColor.Black; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (foundNode != null) { |
|||
foundNode.Data = childNode.Data; |
|||
parent[parent.Right == childNode] = childNode[childNode.Left == null]; |
|||
} |
|||
|
|||
Tree = startNode.Right; |
|||
|
|||
if (Tree != null) { |
|||
((RedBlackTreeNode<T>)Tree).Color = NodeColor.Black; |
|||
} |
|||
|
|||
if (foundNode != null) { |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Private Members
|
|||
|
|||
/// <summary>
|
|||
/// Determines whether the specified node is red.
|
|||
/// </summary>
|
|||
/// <param name="node">The node.</param>
|
|||
/// <returns>
|
|||
/// <c>true</c> if the specified node is red; otherwise, <c>false</c>.
|
|||
/// </returns>
|
|||
private static bool IsRed(RedBlackTreeNode<T> node) { |
|||
return (node != null) && (node.Color == NodeColor.Red); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines whether the specified node is black.
|
|||
/// </summary>
|
|||
/// <param name="node">The node.</param>
|
|||
/// <returns>
|
|||
/// <c>true</c> if the specified node is black; otherwise, <c>false</c>.
|
|||
/// </returns>
|
|||
private static bool IsBlack(RedBlackTreeNode<T> node) { |
|||
return (node == null) || (node.Color == NodeColor.Black); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A recursive implementation of insertion of a node into the tree.
|
|||
/// </summary>
|
|||
/// <param name="node">The start node.</param>
|
|||
/// <param name="item">The item.</param>
|
|||
/// <returns>The node created in the insertion.</returns>
|
|||
private RedBlackTreeNode<T> InsertNode(RedBlackTreeNode<T> node, T item) { |
|||
if (node == null) { |
|||
node = new RedBlackTreeNode<T>(item); |
|||
} else if (Comparer.Compare(item, node.Data) != 0) { |
|||
var direction = Comparer.Compare(node.Data, item) < 0; |
|||
|
|||
node[direction] = InsertNode(node[direction], item); |
|||
|
|||
if (IsRed(node[direction])) { |
|||
if (IsRed(node[!direction])) { |
|||
node.Color = NodeColor.Red; |
|||
node.Left.Color = NodeColor.Black; |
|||
node.Right.Color = NodeColor.Black; |
|||
} else { |
|||
if (IsRed(node[direction][direction])) { |
|||
node = SingleRotation(node, !direction); |
|||
} else if (IsRed(node[direction][!direction])) { |
|||
node = DoubleRotation(node, !direction); |
|||
} |
|||
} |
|||
} |
|||
} else { |
|||
throw new ArgumentException(alreadyContainedInTheTree); |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Perform a single rotation on the node provided..
|
|||
/// </summary>
|
|||
/// <param name="node">The node on which to focus the rotation.</param>
|
|||
/// <param name="direction">The direction of the rotation. If direction is equal to true, a right rotation is performed. Other wise, a left rotation.</param>
|
|||
/// <returns>The new root of the cluster.</returns>
|
|||
private static RedBlackTreeNode<T> SingleRotation(RedBlackTreeNode<T> node, bool direction) { |
|||
var childSibling = node[!direction]; |
|||
|
|||
node[!direction] = childSibling[direction]; |
|||
childSibling[direction] = node; |
|||
|
|||
node.Color = NodeColor.Red; |
|||
childSibling.Color = NodeColor.Black; |
|||
|
|||
return childSibling; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Perform a double rotation on the node provided..
|
|||
/// </summary>
|
|||
/// <param name="node">The node on which to focus the rotation.</param>
|
|||
/// <param name="direction">The direction of the rotation. If direction is equal to true, a right rotation is performed. Other wise, a left rotation.</param>
|
|||
/// <returns>The new root of the cluster.</returns>
|
|||
private static RedBlackTreeNode<T> DoubleRotation(RedBlackTreeNode<T> node, bool direction) { |
|||
node[!direction] = SingleRotation(node[!direction], !direction); |
|||
return SingleRotation(node, direction); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,243 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
/* |
|||
* The insertion and deletion code is based on the code found at http://eternallyconfuzzled.com/tuts/redblack.htm.
|
|||
* It's an excellent tutorial - if you want to understand Red Black trees, look there first. |
|||
*/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.ObjectModel; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using NGenerics.Comparers; |
|||
using NGenerics.Patterns.Visitor; |
|||
|
|||
namespace NGenerics.DataStructures.Trees |
|||
{ |
|||
/// <summary>
|
|||
/// An implementation of a Red-Black tree.
|
|||
/// </summary>
|
|||
/// <typeparam name="TKey">The type of the keys in the <see cref="RedBlackTree{TKey,TValue}"/>.</typeparam>
|
|||
/// <typeparam name="TValue">The type of the values in the <see cref="RedBlackTree{TKey,TValue}"/>.</typeparam>
|
|||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] |
|||
#if (!SILVERLIGHT && !WINDOWSPHONE)
|
|||
//[Serializable]
|
|||
#endif
|
|||
internal class RedBlackTree<TKey, TValue> : RedBlackTree<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue> // BinarySearchTreeBase<TKey, TValue>
|
|||
{ |
|||
#region Construction
|
|||
/// <inheritdoc />
|
|||
public RedBlackTree() : base(new KeyValuePairComparer<TKey, TValue>()) |
|||
{ |
|||
// Do nothing - the default Comparer will be used by the base class.
|
|||
} |
|||
|
|||
|
|||
/// <inheritdoc/>
|
|||
public RedBlackTree(IComparer<TKey> comparer) |
|||
: base(new KeyValuePairComparer<TKey, TValue>(comparer)) |
|||
{ |
|||
// Do nothing else.
|
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public RedBlackTree(Comparison<TKey> comparison) |
|||
: base(new KeyValuePairComparer<TKey, TValue>(comparison)) |
|||
{ |
|||
// Do nothing else.
|
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Private Members
|
|||
|
|||
private RedBlackTreeNode<KeyValuePair<TKey, TValue>> FindNode(TKey key) |
|||
{ |
|||
return base.FindNode(new KeyValuePair<TKey, TValue>(key, default(TValue))) as RedBlackTreeNode<KeyValuePair<TKey, TValue>>; |
|||
} |
|||
|
|||
private bool Contains(KeyValuePair<TKey, TValue> item, bool checkValue) { |
|||
var node = FindNode(item); |
|||
|
|||
if ((node != null) && !checkValue) { |
|||
return true; |
|||
} |
|||
|
|||
return node != null && Equals(item.Value, node.Data.Value); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IDictionary<TKey,TValue> Members
|
|||
|
|||
/// <summary>
|
|||
/// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
|
|||
/// </summary>
|
|||
/// <param name="key">The key of the element to remove.</param>
|
|||
/// <returns>
|
|||
/// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not found in the original <see cref="T:System.Collections.Generic.IDictionary`2"/>.
|
|||
/// </returns>
|
|||
/// <exception cref="T:System.ArgumentNullException">
|
|||
/// <paramref name="key"/> is null.
|
|||
/// </exception>
|
|||
/// <exception cref="T:System.NotSupportedException">
|
|||
/// The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.
|
|||
/// </exception>
|
|||
public bool Remove(TKey key) { |
|||
return Remove(new KeyValuePair<TKey, TValue>(key, default(TValue))); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
|
|||
/// </summary>
|
|||
/// <param name="key">The object to use as the key of the element to add.</param>
|
|||
/// <param name="value">The object to use as the value of the element to add.</param>
|
|||
/// <exception cref="T:System.ArgumentNullException">
|
|||
/// <paramref name="key"/> is null.
|
|||
/// </exception>
|
|||
/// <exception cref="T:System.ArgumentException">
|
|||
/// An element with the same key already exists in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
|
|||
/// </exception>
|
|||
/// <exception cref="T:System.NotSupportedException">
|
|||
/// The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.
|
|||
/// </exception>
|
|||
public void Add(TKey key, TValue value) { |
|||
|
|||
if (Equals(key, null)) |
|||
{ |
|||
throw new ArgumentNullException("key"); |
|||
} |
|||
|
|||
Add(new KeyValuePair<TKey,TValue>(key, value)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines whether the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the specified key.
|
|||
/// </summary>
|
|||
/// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</param>
|
|||
/// <returns>
|
|||
/// true if the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the key; otherwise, false.
|
|||
/// </returns>
|
|||
/// <exception cref="T:System.ArgumentNullException">
|
|||
/// <paramref name="key"/> is null.
|
|||
/// </exception>
|
|||
public bool ContainsKey(TKey key) { |
|||
return Contains(new KeyValuePair<TKey, TValue>(key, default(TValue)), false); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
|
|||
/// </summary>
|
|||
/// <value></value>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Keys" lang="cs" title="The following example shows how to use the Keys property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Keys" lang="vbnet" title="The following example shows how to use the Keys property."/>
|
|||
/// </example>
|
|||
public ICollection<TKey> Keys |
|||
{ |
|||
get |
|||
{ |
|||
// Get the keys in sorted order
|
|||
var visitor = new KeyTrackingVisitor<TKey, TValue>(); |
|||
var inOrderVisitor = new InOrderVisitor<KeyValuePair<TKey, TValue>>(visitor); |
|||
DepthFirstTraversal(inOrderVisitor); |
|||
return new ReadOnlyCollection<TKey>(visitor.TrackingList); |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="TryGetValue" lang="cs" title="The following example shows how to use the TryGetValue method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="TryGetValue" lang="vbnet" title="The following example shows how to use the TryGetValue method."/>
|
|||
/// </example>
|
|||
public bool TryGetValue(TKey key, out TValue value) |
|||
{ |
|||
var node = FindNode(new KeyValuePair<TKey, TValue>(key, default(TValue))); |
|||
|
|||
if (node == null) |
|||
{ |
|||
value = default(TValue); |
|||
return false; |
|||
} |
|||
|
|||
value = node.Data.Value; |
|||
return true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the values in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.
|
|||
/// </summary>
|
|||
/// <value></value>
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Values" lang="cs" title="The following example shows how to use the Values property."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Values" lang="vbnet" title="The following example shows how to use the Values property."/>
|
|||
/// </example>
|
|||
public ICollection<TValue> Values |
|||
{ |
|||
get |
|||
{ |
|||
var visitor = new ValueTrackingVisitor<TKey, TValue>(); |
|||
var inOrderVisitor = new InOrderVisitor<KeyValuePair<TKey, TValue>>(visitor); |
|||
|
|||
DepthFirstTraversal(inOrderVisitor); |
|||
|
|||
return new ReadOnlyCollection<TValue>(visitor.TrackingList); |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the value with the specified key.
|
|||
/// </summary>
|
|||
/// <value>The key of the item to set or get.</value>
|
|||
public TValue this[TKey key] |
|||
{ |
|||
get |
|||
{ |
|||
var node = FindNode(key); |
|||
|
|||
if (node == null) |
|||
{ |
|||
throw new KeyNotFoundException("key"); |
|||
} |
|||
|
|||
return node.Data.Value; |
|||
} |
|||
set |
|||
{ |
|||
var node = FindNode(key); |
|||
|
|||
if (node == null) |
|||
{ |
|||
throw new KeyNotFoundException("key"); |
|||
} |
|||
|
|||
node.Data = new KeyValuePair<TKey,TValue>(key, value); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region ICollection<KeyValuePair<TKey,TValue>> Members
|
|||
|
|||
/// <inheritdoc />
|
|||
/// <example>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\Trees\BinarySearchTreeBaseExamples.cs" region="Contains" lang="cs" title="The following example shows how to use the Contains method."/>
|
|||
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\Trees\BinarySearchTreeBaseExamples.vb" region="Contains" lang="vbnet" title="The following example shows how to use the Contains method."/>
|
|||
/// </example>
|
|||
public override bool Contains(KeyValuePair<TKey, TValue> item) { |
|||
return Contains(item, true); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,225 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
|
|||
namespace NGenerics.DataStructures.Trees |
|||
{ |
|||
/// <summary>
|
|||
/// A RedBlack Tree list variant. Equivalent to <see cref="RedBlackTree{TKey,TValue}"/> where TValue is a <see cref="LinkedList{T}"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TKey">The type of the key.</typeparam>
|
|||
/// <typeparam name="TValue">The type of the value.</typeparam>
|
|||
//[Serializable]
|
|||
internal class RedBlackTreeList<TKey, TValue> : RedBlackTree<TKey, LinkedList<TValue>> |
|||
{ |
|||
#region Delegates
|
|||
|
|||
private delegate bool NodeAction(TKey key, LinkedList<TValue> values); |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RedBlackTreeList<TKey, TValue>"/> class.
|
|||
/// </summary>
|
|||
/// <inheritdoc/>
|
|||
public RedBlackTreeList() { |
|||
// Do nothing else.
|
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public RedBlackTreeList(IComparer<TKey> comparer) |
|||
: base(comparer) { |
|||
// Do nothing else.
|
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public RedBlackTreeList(Comparison<TKey> comparison) |
|||
: base(comparison) { |
|||
// Do nothing else.
|
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Determines whether the specified value contains value.
|
|||
/// </summary>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <returns>
|
|||
/// <c>true</c> if the specified value contains value; otherwise, <c>false</c>.
|
|||
/// </returns>
|
|||
public bool ContainsValue(TValue value) |
|||
{ |
|||
return TraverseItems((key, list) => list.Contains(value)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value enumerator.
|
|||
/// </summary>
|
|||
/// <returns>An enumerator to enumerate through the values contained in this instance.</returns>
|
|||
public IEnumerator<TValue> GetValueEnumerator() |
|||
{ |
|||
var stack = new Stack<BinaryTree<KeyValuePair<TKey, LinkedList<TValue>>>>(); |
|||
|
|||
if (Tree != null) |
|||
{ |
|||
stack.Push(Tree); |
|||
} |
|||
|
|||
while (stack.Count > 0) |
|||
{ |
|||
var currentNode = stack.Pop(); |
|||
|
|||
var list = currentNode.Data.Value; |
|||
|
|||
foreach (var item in list) |
|||
{ |
|||
yield return item; |
|||
} |
|||
|
|||
if (currentNode.Left != null) |
|||
{ |
|||
stack.Push(currentNode.Left); |
|||
} |
|||
|
|||
if (currentNode.Right != null) |
|||
{ |
|||
stack.Push(currentNode.Right); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns an enumerator that iterates through the collection.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
|
|||
/// </returns>
|
|||
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")] |
|||
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] |
|||
public IEnumerator<KeyValuePair<TKey, TValue>> GetKeyEnumerator() |
|||
{ |
|||
var stack = new Stack<BinaryTree<KeyValuePair<TKey, LinkedList<TValue>>>>(); |
|||
|
|||
if (Tree != null) |
|||
{ |
|||
stack.Push(Tree); |
|||
} |
|||
|
|||
while (stack.Count > 0) |
|||
{ |
|||
var currentNode = stack.Pop(); |
|||
|
|||
var list = currentNode.Data.Value; |
|||
|
|||
foreach (var item in list) |
|||
{ |
|||
yield return new KeyValuePair<TKey, TValue>(currentNode.Data.Key, item); |
|||
} |
|||
|
|||
if (currentNode.Left != null) |
|||
{ |
|||
stack.Push(currentNode.Left); |
|||
} |
|||
|
|||
if (currentNode.Right != null) |
|||
{ |
|||
stack.Push(currentNode.Right); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Removes the specified value.
|
|||
/// </summary>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <param name="key">The key under which the item was found.</param>
|
|||
/// <returns>A value indicating whether the item was found or not.</returns>
|
|||
public bool Remove(TValue value, out TKey key) |
|||
{ |
|||
var foundKey = default(TKey); |
|||
|
|||
var ret = TraverseItems( |
|||
delegate(TKey itemKey, LinkedList<TValue> list) { |
|||
if (list.Remove(value)) |
|||
{ |
|||
if (list.Count == 0) |
|||
{ |
|||
Remove(itemKey); |
|||
} |
|||
|
|||
foundKey = itemKey; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
); |
|||
|
|||
key = foundKey; |
|||
return ret; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Private Members
|
|||
|
|||
/// <summary>
|
|||
/// Traverses the items.
|
|||
/// </summary>
|
|||
/// <param name="shouldStop">A predicate that performs an action on the list, and indicates whether the enumeration of items should stop or not.</param>
|
|||
/// <returns>An indication of whether the enumeration was stopped prematurely.</returns>
|
|||
private bool TraverseItems(NodeAction shouldStop) |
|||
{ |
|||
#region Validation
|
|||
|
|||
Debug.Assert(shouldStop != null); |
|||
|
|||
#endregion
|
|||
|
|||
var stack = new Stack<BinaryTree<KeyValuePair<TKey, LinkedList<TValue>>>>(); |
|||
|
|||
if (Tree != null) |
|||
{ |
|||
stack.Push(Tree); |
|||
} |
|||
|
|||
while (stack.Count > 0) |
|||
{ |
|||
var currentNode = stack.Pop(); |
|||
|
|||
if (shouldStop(currentNode.Data.Key, currentNode.Data.Value)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
if (currentNode.Left != null) |
|||
{ |
|||
stack.Push(currentNode.Left); |
|||
} |
|||
|
|||
if (currentNode.Right != null) |
|||
{ |
|||
stack.Push(currentNode.Right); |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,90 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
|
|||
using System;using System.Diagnostics.CodeAnalysis; |
|||
|
|||
namespace NGenerics.DataStructures.Trees { |
|||
/// <summary>
|
|||
/// A container class, used for the RedBlackTree.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of element.</typeparam>
|
|||
//[Serializable]
|
|||
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] |
|||
internal class RedBlackTreeNode<T> : BinaryTree<T> { |
|||
|
|||
#region Construction
|
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RedBlackTreeNode<T>"/> class.
|
|||
/// </summary>
|
|||
/// <param name="data">The data contained in this node.</param>
|
|||
internal RedBlackTreeNode(T data) |
|||
: base(data) { |
|||
Color = NodeColor.Red; |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Properties
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the color of the current node.
|
|||
/// </summary>
|
|||
/// <value>The color of the node.</value>
|
|||
internal NodeColor Color { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="NGenerics.DataStructures.Trees.BinaryTree<T>"/> with the specified direction.
|
|||
/// </summary>
|
|||
/// <value></value>
|
|||
internal RedBlackTreeNode<T> this[bool direction] { |
|||
get { |
|||
return direction ? Right : Left; |
|||
} |
|||
set { |
|||
if (direction) { |
|||
Right = value; |
|||
} else { |
|||
Left = value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the left subtree.
|
|||
/// </summary>
|
|||
/// <value>The left subtree.</value>
|
|||
internal new RedBlackTreeNode<T> Left { |
|||
get { |
|||
return (RedBlackTreeNode<T>)base.Left; |
|||
} |
|||
set { |
|||
base.Left = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the right subtree.
|
|||
/// </summary>
|
|||
/// <value>The right subtree.</value>
|
|||
internal new RedBlackTreeNode<T> Right { |
|||
get { |
|||
return (RedBlackTreeNode<T>)base.Right; |
|||
} |
|||
set { |
|||
base.Right = value; |
|||
} |
|||
} |
|||
|
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System.Collections.Generic; |
|||
|
|||
namespace NGenerics.Patterns.Visitor |
|||
{ |
|||
/// <summary>
|
|||
/// A visitor that tracks (stores) objects in the order they were visited.
|
|||
/// Handy for demonstrating and testing different ordered visits implementations on
|
|||
/// data structures.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of objects to be visited.</typeparam>
|
|||
internal sealed class TrackingVisitor<T> : IVisitor<T> |
|||
{ |
|||
#region Globals
|
|||
|
|||
private readonly List<T> tracks; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
|
|||
/// <inheritdoc/>
|
|||
public TrackingVisitor() |
|||
{ |
|||
tracks = new List<T>(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IVisitor<T> Members
|
|||
/// <inheritdoc />
|
|||
public void Visit(T obj) |
|||
{ |
|||
tracks.Add(obj); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool HasCompleted { |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Gets the tracking list.
|
|||
/// </summary>
|
|||
/// <value>The tracking list.</value>
|
|||
public IList<T> TrackingList |
|||
{ |
|||
get |
|||
{ |
|||
return tracks; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/* |
|||
Copyright 2007-2013 The NGenerics Team |
|||
(https://github.com/ngenerics/ngenerics/wiki/Team)
|
|||
|
|||
This program is licensed under the GNU Lesser General Public License (LGPL). You should |
|||
have received a copy of the license along with the source code. If not, an online copy |
|||
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
|
|||
*/ |
|||
|
|||
|
|||
using System.Collections.Generic; |
|||
|
|||
namespace NGenerics.Patterns.Visitor |
|||
{ |
|||
/// <summary>
|
|||
/// A visitor that tracks (stores) keys from KeyValuePairs in the order they were visited.
|
|||
/// </summary>
|
|||
/// <typeparam name="TKey">The type of key of the KeyValuePair.</typeparam>
|
|||
/// <typeparam name="TValue">The type of value of the KeyValuePair.</typeparam>
|
|||
internal sealed class ValueTrackingVisitor<TKey, TValue> : IVisitor<KeyValuePair<TKey, TValue>> |
|||
{ |
|||
#region Globals
|
|||
|
|||
private readonly List<TValue> tracks; |
|||
|
|||
#endregion
|
|||
|
|||
#region Construction
|
|||
|
|||
|
|||
/// <inheritdoc/>
|
|||
public ValueTrackingVisitor() |
|||
{ |
|||
tracks = new List<TValue>(); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Public Members
|
|||
|
|||
/// <summary>
|
|||
/// Gets the tracking list.
|
|||
/// </summary>
|
|||
/// <value>The tracking list.</value>
|
|||
public IList<TValue> TrackingList |
|||
{ |
|||
get |
|||
{ |
|||
return tracks; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IVisitor<KeyValuePair<TKey,TValue>> Members
|
|||
|
|||
|
|||
/// <inheritdoc />
|
|||
public void Visit(KeyValuePair<TKey, TValue> obj) |
|||
{ |
|||
tracks.Add(obj.Value); |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public bool HasCompleted |
|||
{ |
|||
get |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -1,371 +0,0 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="WindowsDispatcher.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Win32.Threading |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel; |
|||
using System.Security; |
|||
using System.Threading; |
|||
using Perspex.Threading; |
|||
using Perspex.Win32.Interop; |
|||
|
|||
[Flags] |
|||
internal enum Flags |
|||
{ |
|||
ShutdownStarted = 1, |
|||
Shutdown = 2, |
|||
Disabled = 4 |
|||
} |
|||
|
|||
public sealed class WindowsDispatcher : Dispatcher |
|||
{ |
|||
private const int TopPriority = (int)DispatcherPriority.Send; |
|||
|
|||
private static Dictionary<Thread, WindowsDispatcher> dispatchers = new Dictionary<Thread, WindowsDispatcher>(); |
|||
|
|||
private static object olock = new object(); |
|||
|
|||
private Thread baseThread; |
|||
|
|||
private PokableQueue[] priorityQueues = new PokableQueue[TopPriority + 1]; |
|||
|
|||
private Flags flags; |
|||
|
|||
private int queueBits; |
|||
|
|||
private WindowsDispatcher(Thread t) |
|||
{ |
|||
this.baseThread = t; |
|||
|
|||
for (int i = 1; i <= (int)DispatcherPriority.Send; i++) |
|||
{ |
|||
this.priorityQueues[i] = new PokableQueue(); |
|||
} |
|||
} |
|||
|
|||
public event EventHandler ShutdownStarted; |
|||
|
|||
public event EventHandler ShutdownFinished; |
|||
|
|||
public override DispatcherFrame CurrentFrame |
|||
{ |
|||
get; |
|||
set; |
|||
} |
|||
|
|||
public Thread Thread |
|||
{ |
|||
get { return this.baseThread; } |
|||
} |
|||
|
|||
public bool HasShutdownStarted |
|||
{ |
|||
get { return (this.flags & Flags.ShutdownStarted) != 0; } |
|||
} |
|||
|
|||
public override bool HasShutdownFinished |
|||
{ |
|||
get { return (this.flags & Flags.Shutdown) != 0; } |
|||
} |
|||
|
|||
[SecurityCritical] |
|||
public static void ExitAllFrames() |
|||
{ |
|||
Dispatcher dis = CurrentDispatcher; |
|||
|
|||
for (DispatcherFrame frame = dis.CurrentFrame; frame != null; frame = frame.ParentFrame) |
|||
{ |
|||
if (frame.ExitOnRequest) |
|||
{ |
|||
frame.Continue = false; |
|||
} |
|||
else |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public static WindowsDispatcher FromThread(Thread thread) |
|||
{ |
|||
WindowsDispatcher dis; |
|||
|
|||
if (dispatchers.TryGetValue(thread, out dis)) |
|||
{ |
|||
return dis; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public static WindowsDispatcher GetThreadDispatcher() |
|||
{ |
|||
lock (olock) |
|||
{ |
|||
Thread t = Thread.CurrentThread; |
|||
WindowsDispatcher dis = FromThread(t); |
|||
|
|||
if (dis != null) |
|||
{ |
|||
return dis; |
|||
} |
|||
|
|||
dis = new WindowsDispatcher(t); |
|||
dispatchers[t] = dis; |
|||
return dis; |
|||
} |
|||
} |
|||
|
|||
public override DispatcherOperation BeginInvoke(Action method) |
|||
{ |
|||
return this.BeginInvoke(DispatcherPriority.Normal, method); |
|||
} |
|||
|
|||
public override DispatcherOperation BeginInvoke(DispatcherPriority priority, Action method) |
|||
{ |
|||
if (priority < DispatcherPriority.Inactive || priority > DispatcherPriority.Send) |
|||
{ |
|||
throw new InvalidEnumArgumentException("priority"); |
|||
} |
|||
|
|||
if (priority == DispatcherPriority.Inactive) |
|||
{ |
|||
throw new ArgumentException("priority can not be inactive", "priority"); |
|||
} |
|||
|
|||
if (method == null) |
|||
{ |
|||
throw new ArgumentNullException("method"); |
|||
} |
|||
|
|||
DispatcherOperation op = new DispatcherOperation(this, priority, method); |
|||
this.Queue(priority, op); |
|||
return op; |
|||
} |
|||
|
|||
[SecurityCritical] |
|||
public void InvokeShutdown() |
|||
{ |
|||
this.flags |= Flags.ShutdownStarted; |
|||
|
|||
UnmanagedMethods.PostMessage( |
|||
IntPtr.Zero, |
|||
(int)UnmanagedMethods.WindowsMessage.WM_DISPATCH_WORK_ITEM, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero); |
|||
} |
|||
|
|||
protected override void Reprioritize(DispatcherOperation op, DispatcherPriority oldpriority) |
|||
{ |
|||
int oldp = (int)oldpriority; |
|||
PokableQueue q = this.priorityQueues[oldp]; |
|||
|
|||
lock (q) |
|||
{ |
|||
q.Remove(op); |
|||
} |
|||
|
|||
this.Queue(op.Priority, op); |
|||
} |
|||
|
|||
private void Queue(DispatcherPriority priority, DispatcherOperation x) |
|||
{ |
|||
int p = (int)priority; |
|||
PokableQueue q = this.priorityQueues[p]; |
|||
|
|||
lock (q) |
|||
{ |
|||
int flag = 1 << p; |
|||
q.Enqueue(x); |
|||
this.queueBits |= flag; |
|||
} |
|||
|
|||
if (Thread.CurrentThread != this.baseThread) |
|||
{ |
|||
UnmanagedMethods.PostMessage( |
|||
IntPtr.Zero, |
|||
(int)UnmanagedMethods.WindowsMessage.WM_DISPATCH_WORK_ITEM, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero); |
|||
} |
|||
} |
|||
|
|||
private void PerformShutdown() |
|||
{ |
|||
EventHandler h; |
|||
|
|||
h = this.ShutdownStarted; |
|||
if (h != null) |
|||
{ |
|||
h(this, new EventArgs()); |
|||
} |
|||
|
|||
this.flags |= Flags.Shutdown; |
|||
|
|||
h = this.ShutdownFinished; |
|||
if (h != null) |
|||
{ |
|||
h(this, new EventArgs()); |
|||
} |
|||
|
|||
this.priorityQueues = null; |
|||
} |
|||
|
|||
protected override void RunFrame(DispatcherFrame frame) |
|||
{ |
|||
do |
|||
{ |
|||
while (this.queueBits != 0) |
|||
{ |
|||
for (int i = TopPriority; i > 0 && this.queueBits != 0; i--) |
|||
{ |
|||
int currentBit = this.queueBits & (1 << i); |
|||
if (currentBit != 0) |
|||
{ |
|||
PokableQueue q = this.priorityQueues[i]; |
|||
|
|||
do |
|||
{ |
|||
DispatcherOperation task; |
|||
|
|||
lock (q) |
|||
{ |
|||
task = (DispatcherOperation)q.Dequeue(); |
|||
} |
|||
|
|||
task.Invoke(); |
|||
|
|||
if (!frame.Continue) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (this.HasShutdownStarted) |
|||
{ |
|||
this.PerformShutdown(); |
|||
return; |
|||
} |
|||
|
|||
lock (q) |
|||
{ |
|||
if (q.Count == 0) |
|||
{ |
|||
this.queueBits &= ~(1 << i); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (currentBit < (this.queueBits & ~currentBit)) |
|||
{ |
|||
break; |
|||
} |
|||
} |
|||
while (true); |
|||
} |
|||
} |
|||
} |
|||
|
|||
UnmanagedMethods.MSG msg; |
|||
UnmanagedMethods.GetMessage(out msg, IntPtr.Zero, 0, 0); |
|||
UnmanagedMethods.TranslateMessage(ref msg); |
|||
UnmanagedMethods.DispatchMessage(ref msg); |
|||
|
|||
if (this.HasShutdownStarted) |
|||
{ |
|||
this.PerformShutdown(); |
|||
return; |
|||
} |
|||
} |
|||
while (frame.Continue); |
|||
} |
|||
|
|||
private class PokableQueue |
|||
{ |
|||
private const int InitialCapacity = 32; |
|||
|
|||
private int size, head, tail; |
|||
private object[] array; |
|||
|
|||
internal PokableQueue(int capacity) |
|||
{ |
|||
this.array = new object[capacity]; |
|||
} |
|||
|
|||
internal PokableQueue() |
|||
: this(InitialCapacity) |
|||
{ |
|||
} |
|||
|
|||
public int Count |
|||
{ |
|||
get |
|||
{ |
|||
return this.size; |
|||
} |
|||
} |
|||
|
|||
public void Enqueue(object obj) |
|||
{ |
|||
if (this.size == this.array.Length) |
|||
{ |
|||
this.Grow(); |
|||
} |
|||
|
|||
this.array[this.tail] = obj; |
|||
this.tail = (this.tail + 1) % this.array.Length; |
|||
this.size++; |
|||
} |
|||
|
|||
public object Dequeue() |
|||
{ |
|||
if (this.size < 1) |
|||
{ |
|||
throw new InvalidOperationException(); |
|||
} |
|||
|
|||
object result = this.array[this.head]; |
|||
this.array[this.head] = null; |
|||
this.head = (this.head + 1) % this.array.Length; |
|||
this.size--; |
|||
return result; |
|||
} |
|||
|
|||
public void Remove(object obj) |
|||
{ |
|||
for (int i = 0; i < this.size; i++) |
|||
{ |
|||
if (this.array[(this.head + i) % this.array.Length] == obj) |
|||
{ |
|||
for (int j = i; j < this.size - i; j++) |
|||
{ |
|||
this.array[(this.head + j) % this.array.Length] = this.array[(this.head + j + 1) % this.array.Length]; |
|||
} |
|||
|
|||
this.size--; |
|||
if (this.size < 0) |
|||
{ |
|||
this.size = this.array.Length - 1; |
|||
} |
|||
|
|||
this.tail--; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void Grow() |
|||
{ |
|||
int newc = this.array.Length * 2; |
|||
object[] newContents = new object[newc]; |
|||
this.array.CopyTo(newContents, 0); |
|||
this.array = newContents; |
|||
this.head = 0; |
|||
this.tail = this.head + this.size; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue