/* 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 } }