Browse Source

Merge remote-tracking branch 'origin/master' into cairo

pull/10/head
Steven Kirk 11 years ago
parent
commit
6906d24041
  1. 7
      Perspex.Application/Application.cs
  2. 26
      Perspex.Base/Perspex.Base.csproj
  3. 20
      Perspex.Base/Platform/IPlatformThreadingInterface.cs
  4. 89
      Perspex.Base/Threading/Dispatcher.cs
  5. 25
      Perspex.Base/Threading/DispatcherFrame.cs
  6. 159
      Perspex.Base/Threading/DispatcherOperation.cs
  7. 24
      Perspex.Base/Threading/DispatcherPriority.cs
  8. 18
      Perspex.Base/Threading/DispatcherTimer.cs
  9. 84
      Perspex.Base/Threading/MainLoop.cs
  10. 551
      Perspex.Base/Threading/NGenerics/BinarySearchTreeBase.cs
  11. 714
      Perspex.Base/Threading/NGenerics/BinaryTree.cs
  12. 78
      Perspex.Base/Threading/NGenerics/ComparisonComparer.cs
  13. 16
      Perspex.Base/Threading/NGenerics/Constants.cs
  14. 56
      Perspex.Base/Threading/NGenerics/Guard.cs
  15. 43
      Perspex.Base/Threading/NGenerics/IQueue.cs
  16. 65
      Perspex.Base/Threading/NGenerics/ISearchTree.cs
  17. 77
      Perspex.Base/Threading/NGenerics/ITree.cs
  18. 31
      Perspex.Base/Threading/NGenerics/IVisitor.cs
  19. 48
      Perspex.Base/Threading/NGenerics/InOrderVisitor.cs
  20. 74
      Perspex.Base/Threading/NGenerics/KeyTrackingVisitor.cs
  21. 86
      Perspex.Base/Threading/NGenerics/KeyValuePairComparer.cs
  22. 18
      Perspex.Base/Threading/NGenerics/NodeColor.cs
  23. 111
      Perspex.Base/Threading/NGenerics/OrderedVisitor.cs
  24. 557
      Perspex.Base/Threading/NGenerics/PriorityQueue.cs
  25. 27
      Perspex.Base/Threading/NGenerics/PriorityQueueType.cs
  26. 247
      Perspex.Base/Threading/NGenerics/RedBlackTree.cs
  27. 243
      Perspex.Base/Threading/NGenerics/RedBlackTreeDictionary.cs
  28. 225
      Perspex.Base/Threading/NGenerics/RedBlackTreeList.cs
  29. 90
      Perspex.Base/Threading/NGenerics/RedBlackTreeNode.cs
  30. 73
      Perspex.Base/Threading/NGenerics/TrackingVisitor.cs
  31. 75
      Perspex.Base/Threading/NGenerics/ValueTrackingVisitor.cs
  32. 1
      Perspex.sln
  33. 1
      TestApplication/Program.cs
  34. 5
      Windows/Perspex.Win32/Interop/UnmanagedMethods.cs
  35. 1
      Windows/Perspex.Win32/Perspex.Win32.csproj
  36. 371
      Windows/Perspex.Win32/Threading/WindowsDispatcher.cs
  37. 38
      Windows/Perspex.Win32/Win32Platform.cs
  38. 28
      Windows/Perspex.Win32/Window.cs

7
Perspex.Application/Application.cs

@ -7,6 +7,7 @@
namespace Perspex
{
using System;
using System.Threading;
using Perspex.Controls;
using Perspex.Input;
using Perspex.Styling;
@ -86,9 +87,9 @@ namespace Perspex
public void Run(ICloseable closable)
{
DispatcherFrame frame = new DispatcherFrame();
closable.Closed += (s, e) => frame.Continue = false;
Dispatcher.PushFrame(frame);
var source = new CancellationTokenSource();
closable.Closed += (s, e) => source.Cancel();
Dispatcher.UIThread.MainLoop(source.Token);
}
}
}

26
Perspex.Base/Perspex.Base.csproj

@ -49,9 +49,31 @@
<Compile Include="PriorityValue.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Threading\Dispatcher.cs" />
<Compile Include="Threading\DispatcherFrame.cs" />
<Compile Include="Threading\DispatcherOperation.cs" />
<Compile Include="Threading\DispatcherPriority.cs" />
<Compile Include="Threading\DispatcherTimer.cs" />
<Compile Include="Threading\MainLoop.cs" />
<Compile Include="Threading\NGenerics\BinarySearchTreeBase.cs" />
<Compile Include="Threading\NGenerics\BinaryTree.cs" />
<Compile Include="Threading\NGenerics\ComparisonComparer.cs" />
<Compile Include="Threading\NGenerics\Constants.cs" />
<Compile Include="Threading\NGenerics\Guard.cs" />
<Compile Include="Threading\NGenerics\InOrderVisitor.cs" />
<Compile Include="Threading\NGenerics\IQueue.cs" />
<Compile Include="Threading\NGenerics\ISearchTree.cs" />
<Compile Include="Threading\NGenerics\ITree.cs" />
<Compile Include="Threading\NGenerics\IVisitor.cs" />
<Compile Include="Threading\NGenerics\KeyTrackingVisitor.cs" />
<Compile Include="Threading\NGenerics\KeyValuePairComparer.cs" />
<Compile Include="Threading\NGenerics\NodeColor.cs" />
<Compile Include="Threading\NGenerics\OrderedVisitor.cs" />
<Compile Include="Threading\NGenerics\PriorityQueue.cs" />
<Compile Include="Threading\NGenerics\PriorityQueueType.cs" />
<Compile Include="Threading\NGenerics\RedBlackTree.cs" />
<Compile Include="Threading\NGenerics\RedBlackTreeDictionary.cs" />
<Compile Include="Threading\NGenerics\RedBlackTreeList.cs" />
<Compile Include="Threading\NGenerics\RedBlackTreeNode.cs" />
<Compile Include="Threading\NGenerics\TrackingVisitor.cs" />
<Compile Include="Threading\NGenerics\ValueTrackingVisitor.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Splat">

20
Perspex.Base/Platform/IPlatformThreadingInterface.cs

@ -7,14 +7,28 @@
namespace Perspex.Platform
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Perspex.Threading;
public interface IPlatformThreadingInterface
{
Dispatcher GetThreadDispatcher();
/// <summary>
/// Process a single message from the windowing system, blocking until one is available.
/// </summary>
void ProcessMessage();
void KillTimer(object timerHandle);
/// <summary>
/// Starts a timer.
/// </summary>
/// <param name="interval">The interval.</param>
/// <param name="internalTick">The action to call on each tick.</param>
/// <returns>An <see cref="IDisposable"/> used to stop the timer.</returns>
IDisposable StartTimer(TimeSpan interval, Action internalTick);
object StartTimer(TimeSpan interval, Action internalTick);
/// <summary>
/// Sends a message that causes <see cref="ProcessMessage"/> to exit.
/// </summary>
void Wake();
}
}

89
Perspex.Base/Threading/Dispatcher.cs

@ -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);
}
}

25
Perspex.Base/Threading/DispatcherFrame.cs

@ -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; }
}
}

159
Perspex.Base/Threading/DispatcherOperation.cs

@ -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);
}
}
}
}

24
Perspex.Base/Threading/DispatcherPriority.cs

@ -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,
}
}

18
Perspex.Base/Threading/DispatcherTimer.cs

@ -12,7 +12,7 @@ namespace Perspex.Threading
public class DispatcherTimer
{
private object timerHandle;
private IDisposable timer;
private DispatcherPriority priority;
@ -21,13 +21,13 @@ namespace Perspex.Threading
public DispatcherTimer()
{
this.priority = DispatcherPriority.Normal;
this.Dispatcher = Dispatcher.CurrentDispatcher;
this.Dispatcher = Dispatcher.UIThread;
}
public DispatcherTimer(DispatcherPriority priority)
{
this.priority = priority;
this.Dispatcher = Dispatcher.CurrentDispatcher;
this.Dispatcher = Dispatcher.UIThread;
}
public DispatcherTimer(DispatcherPriority priority, Dispatcher dispatcher)
@ -46,7 +46,7 @@ namespace Perspex.Threading
~DispatcherTimer()
{
if (this.timerHandle != null)
if (this.timer != null)
{
this.Stop();
}
@ -80,7 +80,7 @@ namespace Perspex.Threading
{
get
{
return this.timerHandle != null;
return this.timer != null;
}
set
@ -110,7 +110,7 @@ namespace Perspex.Threading
if (!this.IsEnabled)
{
IPlatformThreadingInterface threading = Locator.Current.GetService<IPlatformThreadingInterface>();
this.timerHandle = threading.StartTimer(this.Interval, this.InternalTick);
this.timer = threading.StartTimer(this.Interval, this.InternalTick);
}
}
@ -119,14 +119,14 @@ namespace Perspex.Threading
if (this.IsEnabled)
{
IPlatformThreadingInterface threading = Locator.Current.GetService<IPlatformThreadingInterface>();
threading.KillTimer(this.timerHandle);
this.timerHandle = null;
this.timer.Dispose();
this.timer = null;
}
}
private void InternalTick()
{
this.Dispatcher.BeginInvoke(this.priority, (Action)this.RaiseTick);
this.Dispatcher.InvokeAsync(this.RaiseTick, this.priority);
}
private void RaiseTick()

84
Perspex.Base/Threading/MainLoop.cs

@ -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; }
}
}
}

551
Perspex.Base/Threading/NGenerics/BinarySearchTreeBase.cs

@ -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&lt;TKey, TValue&gt;"/> 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
}
}

714
Perspex.Base/Threading/NGenerics/BinaryTree.cs

@ -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
}
}

78
Perspex.Base/Threading/NGenerics/ComparisonComparer.cs

@ -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
}
}

16
Perspex.Base/Threading/NGenerics/Constants.cs

@ -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.";
}
}

56
Perspex.Base/Threading/NGenerics/Guard.cs

@ -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
}
}

43
Perspex.Base/Threading/NGenerics/IQueue.cs

@ -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();
}
}

65
Perspex.Base/Threading/NGenerics/ISearchTree.cs

@ -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();
}
}

77
Perspex.Base/Threading/NGenerics/ITree.cs

@ -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;}
}
}

31
Perspex.Base/Threading/NGenerics/IVisitor.cs

@ -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);
}
}

48
Perspex.Base/Threading/NGenerics/InOrderVisitor.cs

@ -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
}
}

74
Perspex.Base/Threading/NGenerics/KeyTrackingVisitor.cs

@ -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
}
}

86
Perspex.Base/Threading/NGenerics/KeyValuePairComparer.cs

@ -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&lt;TKey, TValue&gt;"/> class.
/// </summary>
public KeyValuePairComparer() {
comparer = Comparer<TKey>.Default;
}
/// <summary>
/// Initializes a new instance of the <see cref="KeyValuePairComparer&lt;TKey, TValue&gt;"/> 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&lt;TKey, TValue&gt;"/> 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
}
}

18
Perspex.Base/Threading/NGenerics/NodeColor.cs

@ -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
}
}

111
Perspex.Base/Threading/NGenerics/OrderedVisitor.cs

@ -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
}
}

557
Perspex.Base/Threading/NGenerics/PriorityQueue.cs

@ -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&lt;TValue, TPriority&gt;"/> 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
}
}

27
Perspex.Base/Threading/NGenerics/PriorityQueueType.cs

@ -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
}
}

247
Perspex.Base/Threading/NGenerics/RedBlackTree.cs

@ -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
}
}

243
Perspex.Base/Threading/NGenerics/RedBlackTreeDictionary.cs

@ -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
}
}

225
Perspex.Base/Threading/NGenerics/RedBlackTreeList.cs

@ -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&lt;TKey, TValue&gt;"/> 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
}
}

90
Perspex.Base/Threading/NGenerics/RedBlackTreeNode.cs

@ -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&lt;T&gt;"/> 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&lt;T&gt;"/> 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
}
}

73
Perspex.Base/Threading/NGenerics/TrackingVisitor.cs

@ -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
}
}

75
Perspex.Base/Threading/NGenerics/ValueTrackingVisitor.cs

@ -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
Perspex.sln

@ -133,7 +133,6 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{811A76CF-1CF6-440F-963B-BBE31BD72A82} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{E3A1060B-50D0-44E8-88B6-F44EF2E5BD72} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{3E908F67-5543-4879-A1DC-08EACE79B3CD} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{FB05AC90-89BA-4F2F-A924-F37875FB547C} = {1D577B69-F23B-4C4F-8605-97704DAC75A9}

1
TestApplication/Program.cs

@ -101,6 +101,7 @@ namespace TestApplication
Window window = new Window
{
Title = "Perspex Test Application",
Content = new Grid
{
RowDefinitions = new RowDefinitions

5
Windows/Perspex.Win32/Interop/UnmanagedMethods.cs

@ -459,6 +459,9 @@ namespace Perspex.Win32.Interop
IntPtr hInstance,
IntPtr lpParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool SetWindowText(IntPtr hwnd, String lpString);
public struct MSG
{
public IntPtr hwnd;
@ -498,6 +501,6 @@ namespace Perspex.Win32.Interop
public string lpszMenuName;
public string lpszClassName;
public IntPtr hIconSm;
}
}
}
}

1
Windows/Perspex.Win32/Perspex.Win32.csproj

@ -64,7 +64,6 @@
<Compile Include="Input\KeyInterop.cs" />
<Compile Include="Input\WindowsKeyboardDevice.cs" />
<Compile Include="Input\WindowsMouseDevice.cs" />
<Compile Include="Threading\WindowsDispatcher.cs" />
<Compile Include="Interop\UnmanagedMethods.cs" />
<Compile Include="Window.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

371
Windows/Perspex.Win32/Threading/WindowsDispatcher.cs

@ -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;
}
}
}
}

38
Windows/Perspex.Win32/Win32Platform.cs

@ -7,22 +7,20 @@
namespace Perspex.Win32
{
using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
using Perspex.Input;
using Perspex.Platform;
using Perspex.Threading;
using Perspex.Win32.Input;
using Perspex.Win32.Interop;
using Perspex.Win32.Threading;
using Splat;
public class Win32Platform : IPlatformThreadingInterface
{
private static Win32Platform instance = new Win32Platform();
private Dictionary<IntPtr, UnmanagedMethods.TimerProc> timerCallbacks =
new Dictionary<IntPtr, UnmanagedMethods.TimerProc>();
public static void Initialize()
{
var locator = Locator.CurrentMutable;
@ -30,19 +28,15 @@ namespace Perspex.Win32
locator.Register(() => instance, typeof(IPlatformThreadingInterface));
}
public Dispatcher GetThreadDispatcher()
{
return WindowsDispatcher.GetThreadDispatcher();
}
public void KillTimer(object handle)
public void ProcessMessage()
{
this.timerCallbacks.Remove((IntPtr)handle);
UnmanagedMethods.KillTimer(IntPtr.Zero, (IntPtr)handle);
UnmanagedMethods.MSG msg;
UnmanagedMethods.GetMessage(out msg, IntPtr.Zero, 0, 0);
UnmanagedMethods.TranslateMessage(ref msg);
UnmanagedMethods.DispatchMessage(ref msg);
}
public object StartTimer(TimeSpan interval, Action callback)
public IDisposable StartTimer(TimeSpan interval, Action callback)
{
UnmanagedMethods.TimerProc timerDelegate = (UnmanagedMethods.TimerProc)
((hWnd, uMsg, nIDEvent, dwTime) => callback());
@ -53,9 +47,19 @@ namespace Perspex.Win32
(uint)interval.TotalMilliseconds,
timerDelegate);
this.timerCallbacks.Add(handle, timerDelegate);
return Disposable.Create(() =>
{
UnmanagedMethods.KillTimer(IntPtr.Zero, handle);
});
}
return handle;
public void Wake()
{
UnmanagedMethods.PostMessage(
IntPtr.Zero,
(int)UnmanagedMethods.WindowsMessage.WM_DISPATCH_WORK_ITEM,
IntPtr.Zero,
IntPtr.Zero);
}
}
}

28
Windows/Perspex.Win32/Window.cs

@ -22,15 +22,18 @@ namespace Perspex.Win32
using Perspex.Threading;
using Perspex.Win32.Input;
using Perspex.Win32.Interop;
using Perspex.Win32.Threading;
using Splat;
public class Window : ContentControl, ILayoutRoot, IRenderRoot, ICloseable
{
public static readonly PerspexProperty<string> TitleProperty = PerspexProperty.Register<Window, string>("Title");
private UnmanagedMethods.WndProc wndProcDelegate;
private string className;
private Dispatcher dispatcher;
private IRenderer renderer;
private IInputManager inputManager;
@ -41,30 +44,32 @@ namespace Perspex.Win32
this.CreateWindow();
Size clientSize = this.ClientSize;
this.dispatcher = Dispatcher.UIThread;
this.LayoutManager = new LayoutManager(this);
this.RenderManager = new RenderManager();
this.renderer = factory.CreateRenderer(this.Handle, (int)clientSize.Width, (int)clientSize.Height);
this.inputManager = Locator.Current.GetService<IInputManager>();
this.Template = ControlTemplate.Create<Window>(this.DefaultTemplate);
this.LayoutManager.LayoutNeeded.Subscribe(x =>
this.LayoutManager.LayoutNeeded.Subscribe(x =>
{
WindowsDispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Render,
this.dispatcher.InvokeAsync(
() =>
{
this.LayoutManager.ExecuteLayoutPass();
this.renderer.Render(this);
this.RenderManager.RenderFinished();
});
},
DispatcherPriority.Render);
});
this.GetObservable(TitleProperty).Subscribe(s => UnmanagedMethods.SetWindowText(Handle, s));
this.RenderManager.RenderNeeded
.Where(_ => !this.LayoutManager.LayoutQueued)
.Subscribe(x =>
{
WindowsDispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Render,
this.dispatcher.InvokeAsync(
() =>
{
if (!this.LayoutManager.LayoutQueued)
@ -72,7 +77,8 @@ namespace Perspex.Win32
this.renderer.Render(this);
this.RenderManager.RenderFinished();
}
});
},
DispatcherPriority.Render);
});
}
@ -80,6 +86,12 @@ namespace Perspex.Win32
public event EventHandler Closed;
public string Title
{
get { return this.GetValue(TitleProperty); }
set { this.SetValue(TitleProperty, value); }
}
public Size ClientSize
{
get

Loading…
Cancel
Save