Click here to Skip to main content
15,888,527 members
Articles / General Programming / Performance

B-Tree Sorted Dictionary

Rate me:
Please Sign up or sign in to vote.
4.96/5 (48 votes)
26 Jan 2024MIT8 min read 181K   4.8K   140  
In-memory B-Tree sorted dictionary
/* 
 * Copyright(c) 2002 Gerardo Recinto/4A Technologies (http://www.4atech.net)
 */
using System;
using System.Collections;

namespace Sop.Collections.BTree
{
	/// <summary>
	/// Thread synchronized BTree. This is the object type returned by "BTree.Synchronized" property.
	/// </summary>
/*
#if !DEVICE
	[Serializable]
#endif
*/
	sealed public class ThreadSafeBTree : IBTree	//, System.ComponentModel.IListSource
	{
		/// <summary>
		/// Locks btree so that next operation is thread safe
		/// </summary>
		/// <param name="RequestedOperation">Lock btree for a specific operation</param>
		/// <paramref name="Synchronizer.OperationType"/>
		public void Lock(Collections.BTree.OperationType RequestedOperation)
		{
			Synchronizer.Lock(RequestedOperation);
		}
		/// <summary>
		/// Unlocks btree so that next operation is thread safe
		/// </summary>
		public void Unlock()
		{
			Synchronizer.Unlock();
		}
		/// <summary>
		/// Synchronized Add method. Add adds an entry with the provided key and value into the BTreeAlgorithm.
		/// </summary>
		/// <summary>
		/// Duplicate keys are allowed in BTree unlike in a Dictionary/HashTable
		/// where key is required to be unique.
		/// <param name="Key">key of item you want to add to the collection</param>
		/// <param name="Value">the item you want to be collected</param>
		/// </summary>
		public void Add(object Key, object Value)
		{
			Lock(Collections.BTree.OperationType.Write);
			try
			{
				BTree.Add(Key, Value);
			}
			finally
			{
				Unlock();
			}
		}
		/// <summary>
		/// Synchronized Clear method.
		/// </summary>
		/// <summary>
		/// Set to null all collected items and their internal buffers making collection empty
		/// </summary>
		public void Clear()
		{
			Lock(Collections.BTree.OperationType.Write);
			try
			{
				BTree.Clear();
			}
			finally
			{
				Unlock();
			}
		}
		/*
		/// <summary>
		/// Synchronized Clear method. Set to null all collected items and their internal buffers.
		/// If 'IsGarbageCollect' is true, forces Garbage Collection for better memory reclamation.
		/// </summary>
		/// <param name="IsGarbageCollect">true will call GC.Collect after clearing the tree, else will not</param>
		public void Clear(bool IsGarbageCollect)
		{
			Lock(Collections.BTree.OperationType.Write);
			try
			{
				BTree.Clear(IsGarbageCollect);
			}
			finally
			{
				Unlock();
			}
		}
		*/
		/// <summary>
		/// Synchronized Clone method.
		/// </summary>
		/// <summary>
		/// Shallow copy this collection and returns the copy as "object" type.
		/// </summary>
		public object Clone()
		{
			object o;
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				o = new ThreadSafeBTree((BTree)BTree.Clone());
			}
			finally
			{
				Unlock();
			}
			return o;
		}
		/// <summary>
		/// Checks whether the tree has collected an item having its key equals "key"
		/// </summary>
		/// <param name="key">key of item to check</param>
		/// <returns>true if key is found in the btree, false if not</returns>
		public bool Contains(object key)
		{
			return Search(key);
		}
		/// <summary>
		/// Copy into an array contents of the btree
		/// </summary>
		/// <param name="DestArray">Destination array that will contain the items.</param>
		/// <param name="StartIndex"></param>
		/// <exception cref="ArgumentNullException">array is a null reference (Nothing in Visual Basic).</exception>
		/// <exception cref="ArgumentOutOfRangeException">arrayIndex is less than zero.</exception>
		/// <exception cref="ArgumentException">array is multidimensional.</exception>
		/// <exception>-or-
		/// arrayIndex is equal to or greater than the length of array.
		/// </exception>
		/// <exception>-or-
		/// arrayIndex is equal to or greater than the length of array.
		/// </exception>
		/// <exception>-or-
		/// The number of elements in the source Hashtable is greater than the available space from arrayIndex to the end of the destination array.
		/// </exception>
		public void CopyTo(Array DestArray, int StartIndex)
		{
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				BTree.CopyTo(DestArray, StartIndex);
			}
			finally
			{
				Unlock();
			}
		}
		/// <summary>
		/// Returns ThreadSafeBTree's Enumerator or Iterator object
		/// </summary>
		/// <returns>System.Collections.IDictionaryEnumerator object</returns>
		public System.Collections.IDictionaryEnumerator GetEnumerator()
		{
			return new BTree.BTreeEnumerator((BTree)Clone());
		}
#if !DEVICE
		/// <summary>
		/// Implements the ISerializable interface and raises the deserialization event when the deserialization is complete.
		/// </summary>
		/// <param name="sender">Source of the deserialization event</param>
		public void OnDeserialization(object sender)
		{
			Lock(OperationType.Write);
			try
			{
				BTree.OnDeserialization(sender);
			}
			finally
			{
				Unlock();
			}
		}
		/// <summary>
		/// Used by serializer to get btree graph's serializable info
		/// </summary>
		/// <param name="info">The SerializationInfo to populate with data.</param>
		/// <param name="context">The destination (see StreamingContext) for this serialization.</param>
		public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
		{
			Lock(OperationType.Read);
			try
			{
				BTree.GetObjectData(info, context);
			}
			finally
			{
				Unlock();
			}
		}
#endif
		/// <summary>
		/// Synchronized Move to first item.
		/// </summary>
		/// <returns>Returns true if able to make 1st item current item or false if not</returns>
		public bool MoveFirst()
		{
			bool b;
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				b = BTree.MoveFirst();
			}
			finally
			{
				Unlock();
			}
			return b;
		}
		/// <summary>
		/// Synchronized Move to last item.
		/// </summary>
		/// <returns>Returns true if able to make last item current item or false if not</returns>
		public bool MoveLast()
		{
			bool b;
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				b = BTree.MoveLast();
			}
			finally
			{
				Unlock();
			}
			return b;
		}
		/// <summary>
		/// Synchronized Move to next item.
		/// </summary>
		/// <returns>Returns true if able to make next item current item or false if not</returns>
		public bool MoveNext()
		{
			bool b;
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				b = BTree.MoveNext();
			}
			finally
			{
				Unlock();
			}
			return b;
		}
		/// <summary>
		/// Synchronized Move to previous item.
		/// </summary>
		/// <returns>Returns true if able to make previous item current item or false if not</returns>
		public bool MovePrevious()
		{
			bool b;
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				b = BTree.MovePrevious();
			}
			finally
			{
				Unlock();
			}
			return b;
		}
		/// <summary>
		/// Synchronized remove item
		/// </summary>
		/// <param name="key">key of item to remove from btree</param>
		public void Remove(object key)
		{
			Lock(Collections.BTree.OperationType.Write);
			try
			{
				BTree.Remove(key);
			}
			finally
			{
				Unlock();
			}
		}
		/// <summary>
		/// Synchronized Search for an item
		/// </summary>
		/// <param name="Key">key of the item to search for in the btree</param>
		/// <returns></returns>
		public bool Search(object Key)
		{
			return Search(Key, false);
		}

		/// <summary>
		/// Synchronized Search for an item
		/// </summary>
		/// <param name="Key">key of the item to search for in the btree</param>
		/// <param name="GoToFirstInstance">true tells BTree to go to First Instance of Key, else any key instance matching will match</param>
		/// <returns></returns>
		public bool Search(object Key, bool GoToFirstInstance)
		{
			bool b;
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				b = BTree.Search(Key, GoToFirstInstance);
			}
			finally
			{
				Unlock();
			}
			return b;
		}
		/// <summary>
		/// Returns the number of items in the btree
		/// </summary>
		public int Count
		{
			get
			{
				Lock(OperationType.Read);
				try
				{
					// NOTE: we don't need to lock as returning a snapshot Count
					// value before or after lock/unlock is not guaranteed to be the same
					// as another thread might change the value again while we return the value where we are unlocked
					return BTree.Count;
				}
				finally
				{
					Unlock();
				}
			}
		}
		/// <summary>
		/// Returns/Sets the current item (key and value pair) (Synchronized)
		/// </summary>
		public DictionaryEntry CurrentEntry
		{
			get
			{
				DictionaryEntry o;
				Lock(Collections.BTree.OperationType.Read);
				try
				{
					o = BTree.CurrentEntry;
				}
				finally
				{
					Unlock();
				}
				return o;
			}
		}
		/// <summary>
		/// Returns true if current record pointer is beyond last item in tree.
		/// </summary>
		/// <returns></returns>
		public bool EndOfTree()
		{
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				return BTree.EndOfTree();
			}
			finally
			{
				Unlock();
			}
		}
		/// <summary>
		/// Returns the Current item's key. (Synchronized)
		/// </summary>
		public object CurrentKey
		{
			get
			{
				object o;
				Lock(Collections.BTree.OperationType.Read);
				try
				{
					o = BTree.CurrentKey;
				}
				finally
				{
					Unlock();
				}
				return o;
			}
		}
		/// <summary>
		/// Returns the current item's value. (Synchronized)
		/// </summary>
		public object CurrentValue
		{
			get
			{
				object o;
				Lock(Collections.BTree.OperationType.Read);
				try
				{
					o = BTree.CurrentValue;
				}
				finally
				{
					Unlock();
				}
				return o;
			}
			set
			{
				Lock(Collections.BTree.OperationType.Write);
				try
				{
					BTree.CurrentValue = value;
				}
				finally
				{
					Unlock();
				}
			}
		}
		/// <summary>
		/// IsFixedSize will always return false. BTree don't support fixed size collection
		/// </summary>
		public bool IsFixedSize
		{
			get
			{
				return false;
			}
		}
		/// <summary>
		/// IsReadOnly will always return false. This BTree implementation is always Read/Write.
		/// </summary>
		public bool IsReadOnly
		{
			get
			{
				return false;
			}
		}
		/// <summary>
		/// Returns true as this btree implementation is Synchronized.
		/// </summary>
		public bool IsSynchronized
		{
			get
			{
				return true;
			}
		}
		/// <summary>
		/// Returns collection (System.Collections.ICollection type) of all items' keys. (Synchronized)
		/// </summary>
		public System.Collections.ICollection Keys
		{
			get
			{
				System.Collections.ICollection o;
				Lock(Collections.BTree.OperationType.Read);
				try
				{
					o = new ThreadSafeBTree((BTree)BTree.Keys);
				}
				finally
				{
					Unlock();
				}
				return o;
			}
		}
		/// <summary>
		/// Returns the sort order type
		/// </summary>
		public SortOrderType SortOrder
		{
			get
			{
				Lock(OperationType.Read);
				try
				{
					return BTree.SortOrder;
				}
				finally
				{
					Unlock();
				}
			}
			set
			{
				Lock(OperationType.Write);
				try
				{
					BTree.SortOrder = value;
				}
				finally
				{
					Unlock();
				}
			}
		}
		/// <summary>
		/// Returns the synchronization object used to lock/unlock this btree resource.
		/// </summary>
		public object SyncRoot
		{
			get
			{
				return Synchronizer;
			}
		}
		/// <summary>
		/// Synchronized accessor. item's key is the parameter used to access the item
		/// </summary>
		public object this[object key]
		{
			get
			{
				object o;
				Lock(Collections.BTree.OperationType.Read);
				try
				{
					o = BTree[key];
				}
				finally
				{
					Unlock();
				}
				return o;
			}
			set
			{
				Lock(Collections.BTree.OperationType.Write);
				try
				{
					BTree[key] = value;
				}
				finally
				{
					Unlock();
				}
			}
		}
		/// <summary>
		/// Returns collection of values in the btree. (Synchronized)
		/// </summary>
		public System.Collections.ICollection Values
		{
			get
			{
				System.Collections.ICollection o;
				Lock(Collections.BTree.OperationType.Read);
				try
				{
					o = new ThreadSafeBTree((BTree)BTree.Values);
				}
				finally
				{
					Unlock();
				}
				return o;
			}
		}
		/// <summary>
		/// Returns the Synchronized version of BTree
		/// </summary>
		/// <returns>Synchronized BTree object</returns>
        public IBTree Synchronized()
		{
			return BTree.Synchronized(this.BTree);
		}
		/// <summary>
		/// Constructor for project internal use
		/// </summary>
		/// <param name="BTree"></param>
		internal ThreadSafeBTree(BTree BTree)
		{
			this.BTree = BTree;
			this.Synchronizer = (Synchronizer)BTree.SyncRoot;
		}
		/// <summary>
		/// IEnumerable Interface Implementation
		/// </summary>
		/// <returns></returns>
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return new BTree.BTreeEnumerator((BTree)Clone());
		}
		private BTree BTree;
		private Synchronizer Synchronizer;
		/*
		#region IListSource Members

		IList System.ComponentModel.IListSource.GetList()
		{
			Lock(Collections.BTree.OperationType.Read);
			try
			{
				return ((System.ComponentModel.IListSource)BTree).GetList();
			}
			finally
			{
				Unlock();
			}
		}
		/// <summary>
		/// Returns false as B-Tree can be irregularly shaped graph.
		/// </summary>
		bool System.ComponentModel.IListSource.ContainsListCollection
		{
			get
			{
				return false;
			}
		}

		#endregion
		*/
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
United States United States
Ex Google, ex Microsoft
I'm just fresh off from a software eng'g gig & is looking forward to my next.
Pls. do drop me a line @gerardorecinto@yahoo.com if interested or having any question/feedback on these Open Source projects.

I'm excited to help/volunteer my services.
Have a great day!

Comments and Discussions