/*
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
{
///
/// A RedBlack Tree list variant. Equivalent to where TValue is a .
///
/// The type of the key.
/// The type of the value.
//[Serializable]
internal class RedBlackTreeList : RedBlackTree>
{
#region Delegates
private delegate bool NodeAction(TKey key, LinkedList values);
#endregion
#region Construction
///
/// Initializes a new instance of the class.
///
///
public RedBlackTreeList() {
// Do nothing else.
}
///
public RedBlackTreeList(IComparer comparer)
: base(comparer) {
// Do nothing else.
}
///
public RedBlackTreeList(Comparison comparison)
: base(comparison) {
// Do nothing else.
}
#endregion
#region Public Members
///
/// Determines whether the specified value contains value.
///
/// The value.
///
/// true if the specified value contains value; otherwise, false.
///
public bool ContainsValue(TValue value)
{
return TraverseItems((key, list) => list.Contains(value));
}
///
/// Gets the value enumerator.
///
/// An enumerator to enumerate through the values contained in this instance.
public IEnumerator GetValueEnumerator()
{
var stack = new Stack>>>();
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);
}
}
}
///
/// Returns an enumerator that iterates through the collection.
///
///
/// A that can be used to iterate through the collection.
///
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
public IEnumerator> GetKeyEnumerator()
{
var stack = new Stack>>>();
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(currentNode.Data.Key, item);
}
if (currentNode.Left != null)
{
stack.Push(currentNode.Left);
}
if (currentNode.Right != null)
{
stack.Push(currentNode.Right);
}
}
}
///
/// Removes the specified value.
///
/// The value.
/// The key under which the item was found.
/// A value indicating whether the item was found or not.
public bool Remove(TValue value, out TKey key)
{
var foundKey = default(TKey);
var ret = TraverseItems(
delegate(TKey itemKey, LinkedList 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
///
/// Traverses the items.
///
/// A predicate that performs an action on the list, and indicates whether the enumeration of items should stop or not.
/// An indication of whether the enumeration was stopped prematurely.
private bool TraverseItems(NodeAction shouldStop)
{
#region Validation
Debug.Assert(shouldStop != null);
#endregion
var stack = new Stack>>>();
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
}
}