/* AvlDictionary.cs - C# implementation of an AVL tree based generic IDictionary interface. Copyright (C) 2009 Peter Graf This file is part of PBL - The Program Base Library. PBL is free software. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA For more information on the Program Base Library or Peter Graf, please see: http://www.mission-base.com/. $Log: AvlDictionary.cs,v $ */ using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Diagnostics; namespace Com.Mission_Base.Pbl { /// /// AvlDictionary<TKey,TValue> is an implementation of the generic IDictionary<TKey,TValue> interface based on an AVL-tree. /// The AvlDictionary<TKey,TValue> represents a collection of key/value pairs that are sorted on the key. /// /// /// The type of keys in the dictionary. /// /// /// The type of values in the dictionary. /// [Serializable] [ComVisible(false)] [DebuggerDisplay("Count = {Count}")] public class AvlDictionary : IDictionary, ICollection>, IEnumerable>, ICollection, IEnumerable where TKey : IComparable { /// /// Provides the common base functionality of all Enumerators used with an AvlDictionary<TKey,TValue>. /// public class AvlDictionaryBaseEnumerator { private AvlDictionary _AvlDictionary; private AvlTreeNode _Node; private bool _IsExhausted; private long _ChangeCounter; /// /// Creates a new enumerator of the AvlDictionary<TKey,TValue>. /// /// /// The AvlDictionary<TKey,TValue> the enumerator is created for. /// protected AvlDictionaryBaseEnumerator(AvlDictionary dictionary) { _AvlDictionary = dictionary; _ChangeCounter = dictionary._ChangeCounter; _Node = null; _IsExhausted = _AvlDictionary._RootNode == null; } /// /// Tests whether the enumerator is properly postioned. /// /// /// true if the enumerator is postioned; otherwise, false. /// protected bool IsPositioned { get { return !_IsExhausted && null != _Node; } } /// /// Gets the element at the current position of the enumerator. /// /// /// The KeyValuePair<TKey, TValue> in the AvlDictionary<TKey,TValue> at the current position of the enumerator. /// protected KeyValuePair CurrentPair { get { if (!_IsExhausted && null != _Node) { return _Node.item; } return new KeyValuePair(default(TKey), default(TValue)); } } /// /// Gets the key at the current position of the enumerator. /// /// /// The key in the AvlDictionary<TKey,TValue>.KeyCollection at the current position of the enumerator. /// protected TKey CurrentKey { get { if (!_IsExhausted && null != _Node) { return _Node.item.Key; } return default(TKey); } } /// /// Gets the value at the current position of the enumerator. /// /// /// The value in the AvlDictionary<TKey,TValue>.ValueCollection at the current position of the enumerator. /// protected TValue CurrentValue { get { if (!_IsExhausted && null != _Node) { return _Node.item.Value; } return default(TValue); } } /// /// Advances the enumerator to the next element of the AvlDictionary<TKey,TValue>. /// /// /// true if the enumerator was successfully advanced to the next element; false // if the enumerator has passed the end of the collection. /// /// /// The AvlDictionary was modified after the enumerator was created. /// public bool MoveNext() { if (_ChangeCounter != _AvlDictionary._ChangeCounter) { throw new System.InvalidOperationException("The AvlDictionary was modified after the enumerator was created."); } if (_IsExhausted) { return false; } if (null == _AvlDictionary._RootNode) { _IsExhausted = true; return false; } AvlTreeNode next; if (null == _Node) { next = _AvlDictionary._RootNode.pblTreeNodeFirst(); } else { next = _Node.pblTreeNodeNext(); } if (null == next) { _IsExhausted = true; return false; } _Node = next; return true; } /// /// Resets the enumerator of the AvlDictionary<TKey,TValue>. /// public void Reset() { _Node = null; _IsExhausted = _AvlDictionary._RootNode == null; } #region IDisposable Member /// /// Disposes the enumerator of the AvlDictionary<TKey,TValue>. /// public void Dispose() { } #endregion } /// /// Enumerates the elements of an AvlDictionary<TKey,TValue>. /// public sealed class Enumerator : AvlDictionaryBaseEnumerator, System.Collections.Generic.IEnumerator> { /// /// Creates a new enumerator of the AvlDictionary<TKey,TValue>. /// /// /// The AvlDictionary<TKey,TValue> the enumerator is created for. /// public Enumerator(AvlDictionary dictionary) : base(dictionary) { } #region IEnumerator> Member /// /// Gets the element at the current position of the enumerator. /// /// /// The KeyValuePair<TKey, TValue> in the AvlDictionary<TKey,TValue> at the current position of the enumerator. /// public KeyValuePair Current { get { return this.CurrentPair; } } #endregion #region IEnumerator Member /// /// Gets the element at the current position of the enumerator. /// /// /// The KeyValuePair<TKey, TValue> in the AvlDictionary<TKey,TValue> at the current position of the enumerator. /// /// /// The enumerator is not positioned. /// object IEnumerator.Current { get { if (!IsPositioned) { throw new System.InvalidOperationException("The enumerator is not positioned."); } return this.CurrentPair; } } #endregion } /// /// The actual AVL-tree code. It was lifted from the C implementation in pblSet.c. /// [Serializable] private sealed class AvlTreeNode { internal KeyValuePair item; internal AvlTreeNode prev; internal AvlTreeNode next; internal AvlTreeNode parent; private int balance; internal AvlTreeNode(KeyValuePair item) { this.item = item; this.prev = null; this.next = null; this.parent = null; this.balance = 0; } /* * Returns the first node in the tree defined by the node. * * @return AvlTreeNode node: The first node in the sub tree. */ internal AvlTreeNode pblTreeNodeFirst() { AvlTreeNode node = this; while (node.prev != null) { node = node.prev; } return node; } /* * Returns the next node after the node. * * @return AvlTreeNode node: The next node, may be null. */ internal AvlTreeNode pblTreeNodeNext() { AvlTreeNode node = this; if (node.next != null) { return node.next.pblTreeNodeFirst(); } else { AvlTreeNode child = node; while ((node = node.parent) != null) { if (child == node.prev) { return node; } child = node; } } return null; } /* * Returns the last node in the tree defined by the node. * * @return AvlTreeNode node: The last node in the sub tree. */ internal AvlTreeNode pblTreeNodeLast() { AvlTreeNode node = this; while (node.next != null) { node = node.next; } return node; } /* * Returns the previous node before the node. * * @return AvlTreeNode node: The previous node, may be null. */ internal AvlTreeNode pblTreeNodePrevious() { AvlTreeNode node = this; if (node.prev != null) { return node.prev.pblTreeNodeLast(); } else { AvlTreeNode child = node; while ((node = node.parent) != null) { if (child == node.next) { return node; } child = node; } } return null; } /* * Methods for setting node pointers and maintaining the parentNode pointer */ private void PBL_AVL_TREE_SET_LEFT(AvlTreeNode referenceNode) { if (this.prev != referenceNode) { if ((this.prev = referenceNode) != null) { this.prev.parent = this; } } } private void PBL_AVL_TREE_SET_RIGHT(AvlTreeNode referenceNode) { if (this.next != referenceNode) { if ((this.next = referenceNode) != null) { this.next.parent = this; } } } /* * Inserts a new tree node into a tree set * * @return AvlTreeNode retPtr != null: The subtree p after the insert. * @return AvlTreeNode retPtr == null: An error, see pbl_errno: * *
PBL_ERROR_OUT_OF_MEMORY - Out of memory. */ static internal AvlTreeNode pblTreeNodeInsert( AvlTreeNode parentNode, /** The parent node node to insert to */ TKey key, /** The key to insert */ TValue value, /** The value to insert */ out int heightChanged, /** Set if the tree height changed */ out AvlTreeNode node, /** For returning the node added */ out bool nodeAdded /** Flag showing whether node was added */ ) { AvlTreeNode p1; AvlTreeNode p2; int compareResult; if (null == parentNode) { /* * Element is not in the tree yet, insert it. */ heightChanged = 1; node = new AvlTreeNode(new KeyValuePair(key, value)); nodeAdded = true; return node; } heightChanged = 0; nodeAdded = false; compareResult = key.CompareTo(parentNode.item.Key); if (compareResult == 0) { /* * Element already in tree */ node = parentNode; return parentNode; } if (compareResult < 0) { /* * Insert into left sub tree */ p1 = pblTreeNodeInsert(parentNode.prev, key, value, out heightChanged, out node, out nodeAdded); parentNode.PBL_AVL_TREE_SET_LEFT(p1); if (0 == heightChanged) { return parentNode; } /* * Left sub tree increased in height */ if (parentNode.balance == 1) { parentNode.balance = 0; heightChanged = 0; return parentNode; } if (parentNode.balance == 0) { parentNode.balance = -1; return parentNode; } /* * Balancing needed */ p1 = parentNode.prev; if (p1.balance == -1) { /* * Simple LL rotation */ parentNode.PBL_AVL_TREE_SET_LEFT(p1.next); p1.PBL_AVL_TREE_SET_RIGHT(parentNode); parentNode.balance = 0; parentNode = p1; parentNode.balance = 0; heightChanged = 0; return parentNode; } /* * double LR rotation */ p2 = p1.next; p1.PBL_AVL_TREE_SET_RIGHT(p2.prev); p2.PBL_AVL_TREE_SET_LEFT(p1); parentNode.PBL_AVL_TREE_SET_LEFT(p2.next); p2.PBL_AVL_TREE_SET_RIGHT(parentNode); if (p2.balance == -1) { parentNode.balance = 1; } else { parentNode.balance = 0; } if (p2.balance == 1) { p1.balance = -1; } else { p1.balance = 0; } parentNode = p2; parentNode.balance = 0; heightChanged = 0; return parentNode; } /* * Insert into right sub tree */ p1 = pblTreeNodeInsert(parentNode.next, key, value, out heightChanged, out node, out nodeAdded); parentNode.PBL_AVL_TREE_SET_RIGHT(p1); if (0 == heightChanged) { return parentNode; } /* * Right sub tree increased in height */ if (parentNode.balance == -1) { parentNode.balance = 0; heightChanged = 0; return parentNode; } if (parentNode.balance == 0) { parentNode.balance = 1; return parentNode; } /* * Balancing needed */ p1 = parentNode.next; if (p1.balance == 1) { /* * Simple RR rotation */ parentNode.PBL_AVL_TREE_SET_RIGHT(p1.prev); p1.PBL_AVL_TREE_SET_LEFT(parentNode); parentNode.balance = 0; parentNode = p1; parentNode.balance = 0; heightChanged = 0; return parentNode; } /* * double RL rotation */ p2 = p1.prev; p1.PBL_AVL_TREE_SET_LEFT(p2.next); p2.PBL_AVL_TREE_SET_RIGHT(p1); parentNode.PBL_AVL_TREE_SET_RIGHT(p2.prev); p2.PBL_AVL_TREE_SET_LEFT(parentNode); if (p2.balance == 1) { parentNode.balance = -1; } else { parentNode.balance = 0; } if (p2.balance == -1) { p1.balance = 1; } else { p1.balance = 0; } parentNode = p2; parentNode.balance = 0; heightChanged = 0; return parentNode; } /* * Balances an AVL tree. * * Used if left sub tree decreased in size. * * @return PblTreeNode * retPtr: The subtree p after the balance. * */ private AvlTreeNode pblTreeNodeBalanceLeft( out int heightChanged /** Set if the tree height changed */ ) { AvlTreeNode p1; AvlTreeNode p2; int b1; int b2; heightChanged = 1; if (this.balance == -1) { this.balance = 0; return this; } if (this.balance == 0) { this.balance = 1; heightChanged = 0; return this; } /* * Balancing needed */ p1 = this.next; b1 = p1.balance; if (b1 >= 0) { /* * Simple RR rotation */ this.PBL_AVL_TREE_SET_RIGHT(p1.prev); p1.PBL_AVL_TREE_SET_LEFT(this); if (b1 == 0) { this.balance = 1; p1.balance = -1; heightChanged = 0; } else { this.balance = 0; p1.balance = 0; } return p1; } /* * double RL rotation */ p2 = p1.prev; b2 = p2.balance; p1.PBL_AVL_TREE_SET_LEFT(p2.next); p2.PBL_AVL_TREE_SET_RIGHT(p1); this.PBL_AVL_TREE_SET_RIGHT(p2.prev); p2.PBL_AVL_TREE_SET_LEFT(this); if (b2 == 1) { this.balance = -1; } else { this.balance = 0; } if (b2 == -1) { p1.balance = 1; } else { p1.balance = 0; } p2.balance = 0; return p2; } /* * Balances an AVL tree. * * Used if right sub tree decreased in size. * * @return PblTreeNode * retPtr: The subtree p after the balance. * */ private AvlTreeNode pblTreeNodeBalanceRight( out int heightChanged /** Set if the tree height changed */ ) { AvlTreeNode p1; AvlTreeNode p2; int b1; int b2; heightChanged = 1; if (this.balance == 1) { this.balance = 0; return this; } if (this.balance == 0) { this.balance = -1; heightChanged = 0; return this; } /* * Balancing needed */ p1 = this.prev; b1 = p1.balance; if (b1 <= 0) { /* * Simple LL rotation */ this.PBL_AVL_TREE_SET_LEFT(p1.next); p1.PBL_AVL_TREE_SET_RIGHT(this); if (b1 == 0) { this.balance = -1; p1.balance = 1; heightChanged = 0; } else { this.balance = 0; p1.balance = 0; } return p1; } /* * double LR rotation */ p2 = p1.next; b2 = p2.balance; p1.PBL_AVL_TREE_SET_RIGHT(p2.prev); p2.PBL_AVL_TREE_SET_LEFT(p1); this.PBL_AVL_TREE_SET_LEFT(p2.next); p2.PBL_AVL_TREE_SET_RIGHT(this); if (b2 == -1) { this.balance = 1; } else { this.balance = 0; } if (b2 == 1) { p1.balance = -1; } else { p1.balance = 0; } p2.balance = 0; return p2; } /* * Helper function for AVL tree remove. * * @return PblTreeNode * retPtr: The subtree p after the remove. */ private AvlTreeNode pblTreeNodeRemove2( AvlTreeNode q, out int heightChanged, out bool nodeRemoved ) { AvlTreeNode r = this; AvlTreeNode p; if (null != r.next) { p = r.next.pblTreeNodeRemove2(q, out heightChanged, out nodeRemoved); r.PBL_AVL_TREE_SET_RIGHT(p); if (0 != heightChanged) { r = r.pblTreeNodeBalanceRight(out heightChanged); } return r; } q.item = r.item; p = r.prev; heightChanged = 1; nodeRemoved = true; return p; } /* * Removes a tree node from a tree set * * @return PblTreeNode * retPtr: The subtree p after the remove. */ internal AvlTreeNode pblTreeNodeRemove( TKey key, /** The element to remove */ out int heightChanged, /** Set if the tree height changed */ out bool nodeRemoved /** Showing whether node was removed */ ) { AvlTreeNode p = this; AvlTreeNode q = null; AvlTreeNode p1; int compareResult; heightChanged = 0; nodeRemoved = false; compareResult = key.CompareTo(p.item.Key); if (compareResult < 0) { if (null != p.prev) { q = p.prev.pblTreeNodeRemove(key, out heightChanged, out nodeRemoved); } p.PBL_AVL_TREE_SET_LEFT(q); if (0 != heightChanged) { p = p.pblTreeNodeBalanceLeft(out heightChanged); } return p; } if (compareResult > 0) { if (null != p.next) { q = p.next.pblTreeNodeRemove(key, out heightChanged, out nodeRemoved); } p.PBL_AVL_TREE_SET_RIGHT(q); if (0 != heightChanged) { p = p.pblTreeNodeBalanceRight(out heightChanged); } return p; } /* * p is the node that needs to be removed! */ q = p; if (null == q.next) { p = q.prev; heightChanged = 1; nodeRemoved = true; } else if (null == q.prev) { p = q.next; heightChanged = 1; nodeRemoved = true; } else { /* * Replace q with is biggest predecessor and remove that */ p1 = q.prev.pblTreeNodeRemove2(q, out heightChanged, out nodeRemoved); q.PBL_AVL_TREE_SET_LEFT(p1); if (0 != heightChanged) { p = p.pblTreeNodeBalanceLeft(out heightChanged); } } return p; } } /// /// Represents the collection of keys in an AvlDictionary<TKey,TValue>. /// This class cannot be inherited. /// [Serializable] public sealed class KeyCollection : ICollection, ICollection { /// /// Enumerates the elements of an AvlDictionary<TKey,TValue>.KeyCollection. /// This class cannot be inherited. /// public sealed class Enumerator : AvlDictionaryBaseEnumerator, System.Collections.Generic.IEnumerator { /// /// Creates a new enumerator of the AvlDictionary<TKey,TValue>.KeyCollection. /// /// /// The AvlDictionary<TKey,TValue> the enumerator is created for. /// public Enumerator(AvlDictionary dictionary) : base(dictionary) { } #region IEnumerator Member /// /// Gets the key at the current position of the enumerator. /// /// /// The key in the AvlDictionary<TKey,TValue>.KeyCollection at the current position of the enumerator. /// public TKey Current { get { return this.CurrentKey; } } #endregion #region IEnumerator Member /// /// Gets the key at the current position of the enumerator. /// /// /// The key in the AvlDictionary<TKey,TValue>.KeyCollection at the current position of the enumerator. /// object IEnumerator.Current { get { return this.CurrentKey; } } #endregion } private AvlDictionary _AvlDictionary; internal KeyCollection(AvlDictionary avlDictionary) { _AvlDictionary = avlDictionary; } #region ICollection Member /// /// Because the KeyCollection is read only, this method always throws a System.NotSupportedException. /// /// /// The AvlDictionary.KeyCollection is read-only. /// public void Add(TKey item) { throw new NotSupportedException("The AvlDictionary.KeyCollection is read-only."); } /// /// Because the KeyCollection is read only, this method always throws a System.NotSupportedException. /// /// /// The AvlDictionary.KeyCollection is read-only. /// public void Clear() { throw new NotSupportedException("The AvlDictionary.KeyCollection is read-only."); } /// /// Determines whether the AvlDictionary.KeyCollection contains a specific item. /// /// /// The TKey to locate in the AvlDictionary.KeyCollection. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary.KeyCollection. /// /// /// true if item is found in the AvlDictionary.KeyCollection; otherwise, false. /// public bool Contains(TKey item) { return _AvlDictionary.ContainsKey(item); } /// /// Copies the elements of the AvlDictionary.KeyCollection to an existing /// one-dimensional TKey[], starting at the specified array index. /// /// /// The one-dimensional TKey[] that is the destination of the elements /// copied from AvlDictionary.KeyCollection. /// The array must have zero-based indexing. /// /// /// The zero-based index in array at which copying begins. /// /// /// array is null. /// /// /// arrayIndex is less than zero. /// /// /// arrayIndex is equal to or greater than the length of array. -or- The number of /// elements in the source AvlDictionary.KeyCollection /// is greater than the available space from arrayIndex to the end of the destination /// array. /// public void CopyTo(TKey[] array, int arrayIndex) { if (array == null) { throw new System.ArgumentNullException("array is null."); } if (arrayIndex < 0) { throw new System.ArgumentOutOfRangeException("arrayIndex is less than zero."); } if (arrayIndex >= array.Length) { throw new System.ArgumentException("arrayIndex is equal to or greater than the length of array."); } if (_AvlDictionary.Size == 0) { return; } if (arrayIndex + _AvlDictionary.Size > array.Length) { throw new System.ArgumentException("number of elements in the source AvlDictionary.KeyCollection is greater than the available space from arrayIndex to the end of the destination array."); } IEnumerator en = GetEnumerator(); for (int i = 0; en.MoveNext(); i++) { array[i + arrayIndex] = en.Current; } } /// /// Gets the number of elements contained in the AvlDictionary. /// /// /// The number of elements contained in the AvlDictionary. /// Retrieving the value of this property is an O(1) operation. /// public int Count { get { return _AvlDictionary.Count; } } /// /// Gets a value indicating whether the AvlDictionary.KeyCollection is read-only. /// /// /// true. /// public bool IsReadOnly { get { return true; } } /// /// Because the KeyCollection is read only, this method always throws a System.NotSupportedException. /// /// /// The AvlDictionary.KeyCollection is read-only. /// public bool Remove(TKey item) { throw new NotSupportedException("The AvlDictionary.KeyCollection is read-only."); } #endregion #region IEnumerable Member /// /// Returns an enumerator that iterates through the AvlDictionary.KeyCollection. /// /// /// An IEnumerator<TKey> enumerator for the AvlDictionary.KeyCollection. /// public IEnumerator GetEnumerator() { return new Enumerator(_AvlDictionary); } #endregion #region IEnumerable Member /// /// Returns an enumerator that iterates through the AvlDictionary.KeyCollection. /// /// /// An IEnumerator<TKey> enumerator for the AvlDictionary.KeyCollection. /// IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_AvlDictionary); } #endregion #region ICollection Member /// /// Copies the elements of the AvlDictionary.KeyCollection to an existing /// one-dimensional Array, starting at the specified array index. /// /// /// The one-dimensional Array that is the destination of the elements /// copied from AvlDictionary.KeyCollection. /// The array must have zero-based indexing. /// /// /// The zero-based index in array at which copying begins. /// /// /// array is null. /// /// /// index is less than zero. /// /// /// index is equal to or greater than the length of array. -or- The number of /// elements in the source AvlDictionary.KeyCollection /// is greater than the available space from index to the end of the destination /// array. /// public void CopyTo(Array array, int index) { if (array == null) { throw new System.ArgumentNullException("array is null."); } if (index < 0) { throw new System.ArgumentOutOfRangeException("index is less than zero."); } if (index >= array.Length) { throw new System.ArgumentException("index is equal to or greater than the length of array."); } if (Count == 0) { return; } if (index + Count > array.Length) { throw new System.ArgumentException("number of elements in the source AvlDictionary.KeyCollection is greater than the available space from index to the end of the destination array."); } IEnumerator en = GetEnumerator(); for (int i = 0; en.MoveNext(); i++) { array.SetValue(en.Current, i + index); } } /// /// Gets a value indicating whether access to the AvlDictionary.KeyCollection is synchronized (thread safe). /// /// /// false. /// public bool IsSynchronized { get { return false; } } /// /// Gets an object that can be used to synchronize access to the AvlDictionary. /// /// /// An object that can be used to synchronize access to the AvlDictionary. /// public object SyncRoot { get { return _AvlDictionary._Lock; } } #endregion } /// /// Represents the collection of values in an AvlDictionary<TKey,TValue>. /// This class cannot be inherited. /// [Serializable] public sealed class ValueCollection : ICollection, ICollection { /// /// Enumerates the elements of an AvlDictionary<TKey,TValue>.ValueCollection. /// This class cannot be inherited. /// public sealed class Enumerator : AvlDictionaryBaseEnumerator, System.Collections.Generic.IEnumerator { /// /// Creates a new enumerator of the AvlDictionary<TKey,TValue>.ValueCollection. /// /// /// The AvlDictionary<TKey,TValue> the enumerator is created for. /// public Enumerator(AvlDictionary dictionary) : base(dictionary) { } #region IEnumerator Member /// /// Gets the value at the current position of the enumerator. /// /// /// The value in the AvlDictionary<TKey,TValue>.ValueCollection at the current position of the enumerator. /// public TValue Current { get { return this.CurrentValue; } } #endregion #region IEnumerator Member /// /// Gets the value at the current position of the enumerator. /// /// /// The value in the AvlDictionary<TKey,TValue>.ValueCollection at the current position of the enumerator. /// object IEnumerator.Current { get { return this.CurrentValue; } } #endregion } private AvlDictionary _AvlDictionary; internal ValueCollection(AvlDictionary avlDictionary) { _AvlDictionary = avlDictionary; } #region ICollection Member /// /// Because the ValueCollection is read only, this method always throws a System.NotSupportedException. /// /// /// The AvlDictionary.ValueCollection is read-only. /// public void Add(TValue item) { throw new NotSupportedException("The AvlDictionary.ValueCollection is read-only."); } /// /// Because the ValueCollection is read only, this method always throws a System.NotSupportedException. /// /// /// The AvlDictionary.ValueCollection is read-only. /// public void Clear() { throw new NotSupportedException("The AvlDictionary.ValueCollection is read-only."); } /// /// Determines whether the AvlDictionary.ValueCollection contains a specific value. /// /// /// The TValue to locate in the AvlDictionary.ValueCollection. /// /// /// This method is an O(N) operation, where N is the number of elements in the AvlDictionary.ValueCollection. /// /// /// true if item is found in the AvlDictionary.ValueCollection; otherwise, false. /// public bool Contains(TValue item) { if (_AvlDictionary.Size == 0) { return false; } if (item == null) { for (IEnumerator en = GetEnumerator(); en.MoveNext(); ) { if (null == en.Current) { return true; } } } else { for (IEnumerator en = GetEnumerator(); en.MoveNext(); ) { if (item.Equals(en.Current)) { return true; } } } return false; } /// /// Copies the elements of the AvlDictionary.ValueCollection to an existing /// one-dimensional TValue[], starting at the specified array index. /// /// /// The one-dimensional TValue[] that is the destination of the elements /// copied from AvlDictionary.ValueCollection. /// The array must have zero-based indexing. /// /// /// The zero-based index in array at which copying begins. /// /// /// array is null. /// /// /// arrayIndex is less than zero. /// /// /// arrayIndex is equal to or greater than the length of array. -or- The number of /// elements in the source AvlDictionary.ValueCollection /// is greater than the available space from arrayIndex to the end of the destination /// array. /// public void CopyTo(TValue[] array, int arrayIndex) { if (array == null) { throw new System.ArgumentNullException("array is null."); } if (arrayIndex < 0) { throw new System.ArgumentOutOfRangeException("arrayIndex is less than zero."); } if (arrayIndex >= array.Length) { throw new System.ArgumentException("arrayIndex is equal to or greater than the length of array."); } if (_AvlDictionary.Size == 0) { return; } if (arrayIndex + _AvlDictionary.Size > array.Length) { throw new System.ArgumentException("number of elements in the source AvlDictionary.ValueCollection is greater than the available space from arrayIndex to the end of the destination array."); } IEnumerator en = GetEnumerator(); for (int i = 0; en.MoveNext(); i++) { array[i + arrayIndex] = en.Current; } } /// /// Gets the number of elements contained in the AvlDictionary. /// /// /// The number of elements contained in the AvlDictionary. /// Retrieving the value of this property is an O(1) operation. /// public int Count { get { return _AvlDictionary.Count; } } /// /// Gets a value indicating whether the AvlDictionary.ValueCollection is read-only. /// /// /// true. /// public bool IsReadOnly { get { return true; } } /// /// Because the ValueCollection is read only, this method always throws a System.NotSupportedException. /// /// /// The AvlDictionary.ValueCollection is read-only. /// public bool Remove(TValue item) { throw new NotSupportedException("The AvlDictionary.ValueCollection is read-only."); } #endregion #region IEnumerable Member /// /// Returns an enumerator that iterates through the AvlDictionary.ValueCollection. /// /// /// An IEnumerator<TValue> enumerator for the AvlDictionary.ValueCollection. /// public IEnumerator GetEnumerator() { return new Enumerator(_AvlDictionary); } #endregion #region IEnumerable Member /// /// Returns an enumerator that iterates through the AvlDictionary.ValueCollection. /// /// /// An IEnumerator<TValue> enumerator for the AvlDictionary.ValueCollection. /// IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_AvlDictionary); } #endregion #region ICollection Member /// /// Copies the elements of the AvlDictionary.ValueCollection to an existing /// one-dimensional Array, starting at the specified array index. /// /// /// The one-dimensional Array that is the destination of the elements /// copied from AvlDictionary.ValueCollection. /// The array must have zero-based indexing. /// /// /// The zero-based index in array at which copying begins. /// /// /// array is null. /// /// /// index is less than zero. /// /// /// index is equal to or greater than the length of array. -or- The number of /// elements in the source AvlDictionary.ValueCollection /// is greater than the available space from index to the end of the destination /// array. /// public void CopyTo(Array array, int index) { if (array == null) { throw new System.ArgumentNullException("array is null."); } if (index < 0) { throw new System.ArgumentOutOfRangeException("index is less than zero."); } if (index >= array.Length) { throw new System.ArgumentException("index is equal to or greater than the length of array."); } if (Count == 0) { return; } if (index + Count > array.Length) { throw new System.ArgumentException("number of elements in the source AvlDictionary.ValueCollection is greater than the available space from index to the end of the destination array."); } IEnumerator en = GetEnumerator(); for (int i = 0; en.MoveNext(); i++) { array.SetValue(en.Current, i + index); } } /// /// Gets a value indicating whether access to the AvlDictionary.ValueCollection is synchronized (thread safe). /// /// /// false. /// public bool IsSynchronized { get { return false; } } /// /// Gets an object that can be used to synchronize access to the AvlDictionary. /// /// /// An object that can be used to synchronize access to the AvlDictionary. /// public object SyncRoot { get { return _AvlDictionary._Lock; } } #endregion } private AvlTreeNode _RootNode; private long _ChangeCounter; private object _Lock; private int Size { get; set; } private KeyCollection _Keys; private ValueCollection _Values; private AvlTreeNode FindNode(TKey key) { if (Size == 0) { return null; } AvlTreeNode node = _RootNode; int compareResult; while (node != null) { compareResult = key.CompareTo(node.item.Key); if (compareResult == 0) { return node; } if (compareResult < 0) { node = node.prev; } else { node = node.next; } } return null; } private AvlTreeNode AddNode(TKey key, TValue value, out bool nodeAdded ) { if (key == null) { throw new ArgumentNullException("key is null."); } if (IsReadOnly) { throw new System.NotSupportedException("The AvlDictionary is read-only."); } int heightChanged; AvlTreeNode node; AvlTreeNode insertResult = AvlTreeNode.pblTreeNodeInsert(_RootNode, key, value, out heightChanged, out node, out nodeAdded); if (!nodeAdded) { return node; } Size += 1; _ChangeCounter++; /* * Remember the tree after the insert */ insertResult.parent = null; _RootNode = insertResult; return node; } /// /// Initializes a new instance of the AvlDictionary<TKey,TValue> class that is empty. /// public AvlDictionary() { _ChangeCounter = 0; _Lock = new object(); _Keys = new KeyCollection(this); _Values = new ValueCollection(this); } /// /// Initializes a new instance of the AvlDictionary<TKey,TValue> /// class that contains elements copied from the specified System.Collections.Generic.IDictionary<TKey,TValue>. /// /// /// The System.Collections.Generic.IDictionary<TKey,TValue> whose elements are /// copied to the new AvlDictionary<TKey,TValue>. /// /// /// This method is an O(N * log N) operation, where N is dictionary.Count. /// /// /// dictionary is null. /// /// /// dictionary contains one or more duplicate keys. /// public AvlDictionary(IDictionary dictionary) : this() { if (null == dictionary) { throw new System.ArgumentNullException("dictionary is null."); } for (IEnumerator> en = dictionary.GetEnumerator(); en.MoveNext(); ) { Add(en.Current); } } #region IDictionary Member /// /// Adds the specified key and value to the AvlDictionary. /// /// /// The key of the element to add. /// /// /// The value of the element to add. The value can be null for reference types. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// key is null. /// /// /// An element with the same key already exists in the AvlDictionary. /// public void Add(TKey key, TValue value) { bool nodeAdded; AddNode(key, value, out nodeAdded); if( !nodeAdded ) { throw new ArgumentException(string.Format("An element with the same key '{0}' already exists in the AvlDictionary.", key.ToString())); } } /// /// Determines whether the AvlDictionary contains the specified key. /// /// /// The key to locate in the AvlDictionary. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// true if the AvlDictionary contains an element with the specified key; otherwise, false. /// /// /// key is null. /// public bool ContainsKey(TKey key) { return FindNode(key) != null; } /// /// Gets a collection containing the keys in the AvlDictionary. /// /// /// An ICollection<TKey> containing the keys in the AvlDictionary. /// public ICollection Keys { get { return _Keys; } } /// /// Removes the value with the specified key from the AvlDictionary. /// /// /// The key of the element to remove. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// true if the element is successfully found and removed; otherwise, false. /// This method returns false if key is not found in the AvlDictionary. /// /// /// key is null. /// /// /// "The AvlDictionary is read-only." /// public bool Remove(TKey key) { if (key == null) { throw new ArgumentNullException("key is null."); } if (IsReadOnly) { throw new System.NotSupportedException("The AvlDictionary is read-only."); } if (null == _RootNode) { return false; } int heightChanged; bool nodeRemoved; AvlTreeNode removeResult = _RootNode.pblTreeNodeRemove(key, out heightChanged, out nodeRemoved); if (nodeRemoved) { Size -= 1; _ChangeCounter++; /* * Remember the tree after the removal */ if (removeResult != null) { removeResult.parent = null; } _RootNode = removeResult; } return nodeRemoved; } /// /// Gets the value associated with the specified key. /// /// /// The key of the value to get. /// /// /// When this method returns, contains the value associated with the specified /// key, if the key is found; otherwise, the default value for the type of the /// value parameter. This parameter is passed uninitialized. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// true if the AvlDictionary contains an /// element with the specified key; otherwise, false. /// /// /// key is null. /// public bool TryGetValue(TKey key, out TValue value) { if (key == null) { throw new ArgumentNullException("key is null."); } AvlTreeNode node = FindNode(key); if (node == null) { value = default(TValue); return false; } value = node.item.Value; return true; } /// /// Gets a collection containing the values in the AvlDictionary. /// /// /// An ICollection<TValue> containing the values in the AvlDictionary. /// public ICollection Values { get { return _Values; } } /// /// Gets or sets the value associated with the specified key. /// /// /// The key of the value to get or set. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// The value associated with the specified key. If the specified key is not /// found, a get operation throws a System.Collections.Generic.KeyNotFoundException, /// and a set operation creates a new element with the specified key. /// /// /// key is null. /// /// /// The property is retrieved and key does not exist in the collection. /// /// /// The property is set and the AvlDictionary is read-only. /// public TValue this[TKey key] { get { TValue value; if (TryGetValue(key, out value)) { return value; } throw new KeyNotFoundException("key does not exist in the collection."); } set { if (IsReadOnly) { throw new System.NotSupportedException("The AvlDictionary is read-only."); } bool nodeAdded; AvlTreeNode node = AddNode(key, value, out nodeAdded); if (!nodeAdded) { if (null == value) { if (null != node.item.Value) { node.item = new KeyValuePair(key, value); } } else { if (!value.Equals(node.item.Value)) { node.item = new KeyValuePair(key, value); } } } } } #endregion #region ICollection> Member /// /// Adds a KeyValuePair<TKey,TValue> to the AvlDictionary. /// /// /// The KeyValuePair<TKey,TValue> to add to the AvlDictionary. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// The AvlDictionary is read-only. /// /// /// An element with the same key already exists in the AvlDictionary. /// public void Add(KeyValuePair item) { bool nodeAdded; AvlTreeNode node = AddNode(item.Key, item.Value, out nodeAdded); if (!nodeAdded) { throw new ArgumentException(string.Format("An element with the same key '{0}' already exists in the AvlDictionary.", item.Key.ToString())); } node.item = item; } /// /// Removes all keys and values from the AvlDictionary. /// /// /// The AvlDictionary is read-only. /// public void Clear() { if (IsReadOnly) { throw new System.NotSupportedException("The AvlDictionary is read-only."); } _RootNode = null; Size = 0; } /// /// Determines whether the AvlDictionary contains a specific KeyValuePair<TKey,TValue>. /// /// /// The KeyValuePair<TKey,TValue> to locate in the AvlDictionary. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// true if item is found in the AvlDictionary; otherwise, false. /// public bool Contains(KeyValuePair item) { AvlTreeNode node = FindNode(item.Key); if (node == null) { return false; } return item.Equals(node.item); } /// /// Copies the elements of the AvlDictionary to an existing /// one-dimensional KeyValuePair<TKey,TValue>[], starting at the specified array index. /// /// /// The one-dimensional KeyValuePair<TKey,TValue>[] that is the destination of the elements /// copied from AvlDictionary. /// The array must have zero-based indexing. /// /// /// The zero-based index in array at which copying begins. /// /// /// array is null. /// /// /// arrayIndex is less than zero. /// /// /// arrayIndex is equal to or greater than the length of array. -or- The number of /// elements in the source AvlDictionary /// is greater than the available space from arrayIndex to the end of the destination /// array. /// public void CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) { throw new System.ArgumentNullException("array is null."); } if (arrayIndex < 0) { throw new System.ArgumentOutOfRangeException("index is less than zero."); } if (arrayIndex >= array.Length) { throw new System.ArgumentException("arrayIndex is equal to or greater than the length of array."); } if (Size == 0) { return; } if (arrayIndex + Size > array.Length) { throw new System.ArgumentException("number of elements in the source AvlDictionary is greater than the available space from arrayIndex to the end of the destination array."); } IEnumerator> en = GetEnumerator(); for (int i = 0; en.MoveNext(); i++) { array[i + arrayIndex] = en.Current; } } /// /// Gets the number of elements contained in the AvlDictionary. /// /// /// The number of elements contained in the AvlDictionary. /// Retrieving the value of this property is an O(1) operation. /// public int Count { get { return Size; } } /// /// Gets a value indicating whether the AvlDictionary is read-only. /// /// /// false. /// public bool IsReadOnly { get { return false; } } /// /// Removes the first occurrence of a specific KeyValuePair<TKey,TValue> from the AvlDictionary. /// /// /// The KeyValuePair<TKey,TValue> to remove from the AvlDictionary. /// /// /// This method is an O(log N) operation, where N is the number of elements in the AvlDictionary. /// /// /// true if item was successfully removed from the AvlDictionary; /// otherwise, false. This method also returns false if item is not found in /// the original AvlDictionary. /// /// /// The AvlDictionary is read-only. /// public bool Remove(KeyValuePair item) { if (IsReadOnly) { throw new System.NotSupportedException("The AvlDictionary is read-only."); } AvlTreeNode node = FindNode(item.Key); if (node == null) { return false; } if (item.Equals(node.item)) { Remove(item.Key); return true; } return false; } #endregion #region IEnumerable> Member /// /// Returns an enumerator that iterates through the AvlDictionary. /// /// /// An IEnumerator<KeyValuePair<TKey, TValue>> enumerator for the AvlDictionary. /// public IEnumerator> GetEnumerator() { return new Enumerator(this); } #endregion #region IEnumerable Member /// /// Returns an enumerator that iterates through the AvlDictionary. /// /// /// An IEnumerator enumerator for the AvlDictionary. /// IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } #endregion #region ICollection Member /// /// Copies the elements of the elements of the AvlDictionary to an System.Array, starting at a particular System.Array index. /// /// /// The one-dimensional System.Array that is the destination of the elements /// copied from AvlDictionary. The System.Array must have zero-based /// indexing. /// /// /// The zero-based index in array at which copying begins. /// /// /// array is null. /// /// /// index is less than zero. /// /// /// array is multidimensional. -or- index is equal to or greater than the length /// of array. -or- The number of elements in the source AvlDictionary /// is greater than the available space from index to the end of the destination /// array. /// public void CopyTo(Array array, int index) { if (array == null) { throw new System.ArgumentNullException("array is null."); } if (index < 0) { throw new System.ArgumentOutOfRangeException("index is less than zero."); } if (index >= array.Length) { throw new System.ArgumentException("index is equal to or greater than the length of array."); } if (Size == 0) { return; } if (index + Size > array.Length) { throw new System.ArgumentException("number of elements in the source AvlDictionary is greater than the available space from index to the end of the destination array."); } IEnumerator> en = GetEnumerator(); for (int i = 0; en.MoveNext(); i++) { array.SetValue(en.Current, i + index); } } /// /// Gets a value indicating whether access to the AvlDictionary is synchronized (thread safe). /// /// /// false. /// public bool IsSynchronized { get { return false; } } /// /// Gets an object that can be used to synchronize access to the AvlDictionary. /// /// /// An object that can be used to synchronize access to the AvlDictionary. /// public object SyncRoot { get { return _Lock; } } #endregion } }