Click here to Skip to main content
15,895,746 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 182.4K   4.8K   140  
In-memory B-Tree sorted dictionary
/* 
 * Copyright(c) 2002 Gerardo Recinto/4A Technologies (http://www.4atech.net)
 */

#region History Log
/* DESCRIPTION       :                                           *
* This class provides the generic and extendible Collection      *
* class and its item base object. Collection is an extendible    *
* container type of class. It defines the overridable methods    *
* for managing contained objects. Benefit of this is that        *
* applications could easily switch Collection types whenever they*
* want to. For example, initially, an array Collection was used  *
* and later it was found that array searching is so slow and a   *
* need to use a Collection offering faster searches then, a      *
* Btree(look for Gerry's Btree Collection implementation)        *
* Collection might be introduced and could be easily swapped to  *
* the old array Collection. Only the code that instantiates the  *
* Collection object needs to be changed.                         */

// 06/02/2001   Gerardo
// - .NET migration work.

// 04/30/1999	Gerardo
// - Write operation request will no longer wait until all overlapping Read 
//	requests had been served. After serving the last Read operation and the
//	requested operation is Write, will prioritize the Write in that succeeding
//	Read requests while Write is waiting for its turn will wait until the Write
//	operation had been served.

// 04/24/1999	Gerardo
// - Decided to support Key & Data through inheritance. Descendant Collection
//	classes will be introduced to support it.

// 03/23/1999	Gerardo
// - Changed back return types from bool to 'short'. 'short' will
//	allow us to support multiple error return types.
// 06/18/1998	Gerardo
// - Added multi-thread support.
#endregion

namespace Sop.Collections.BTree
{
	using System;
	using System.Threading;
	/// <summary>
	/// ICollection defines the BTree "custom" Collection interface
	/// </summary>
	internal interface ICollection
	{
		/// <summary>
		/// Returns the count of items stored in the Collection
		/// </summary>
		int Count
		{
			get;
		}
		/// <summary>
		/// MoveNext makes the next entry the current one
		/// </summary>
		bool MoveNext();
		/// <summary>
		/// MovePrevious makes the previous entry the current one
		/// </summary>
		bool MovePrevious();
		/// <summary>
		/// MoveFirst makes the first entry in the Collection the current one
		/// </summary>
		bool MoveFirst();
		/// <summary>
		/// MoveLast makes the last entry in the Collection the current one
		/// </summary>
		bool MoveLast();
		/// <summary>
		/// Returns the Current entry
		/// </summary>
		object CurrentEntry
		{
			get;
		}
		/// <summary>
		/// Search the Collection for existence of ObjectToSearch
		/// </summary>
		bool Search(object ObjectToSearch);	// return true if found, else false
		/// <summary>
		/// Add 'ObjectToAdd' to the Collection
		/// </summary>
		void Add(object ObjectToAdd);
		/// <summary>
		/// Remove ObjectToRemove from the Collection if found, else throws an exception
		/// </summary>
		void Remove(object ObjectToRemove);	// return true if found & removed, else false
		/// <summary>
		/// Clear the Collection of all its items
		/// </summary>
		void Clear();
		/// <summary>
		/// Shallow copy the Collection and returns a duplicate Collection.
		/// </summary>
		object Clone();		// Do a shallow copy of the Collection
	}
	/// <summary>
	/// Extends the Collections.BTreeICollection interface and adds Dictionary related api
	/// </summary>
	internal interface IDictionary : Collections.BTree.ICollection
	{
		/// <summary>
		/// Add Key and Value as entry to the Dictionary/Collection
		/// </summary>
		void Add(object Key, object Value);
		/// <summary>
		/// Returns the Current entry's key
		/// </summary>
		object CurrentKey
		{
			get;
		}
		/// <summary>
		/// Returns the Current entry's Value
		/// </summary>
		object CurrentValue
		{
			get;
		}
	}
	
	/*
	/// <summary>
	/// Collection is an abstract class having Synchronized method that returns a Synchronized
	/// wrapper object to a Collection. All ICollection interface is still declared abstract 
	/// methods/properties in this class.
	/// </summary>
	public abstract class Collection : ICollection	//, System.Collections.ICollection
	{
		/// <summary>
		/// Returns synchronized collection wrapper 
		/// </summary>
		/// <param name="Collection"></param>
		/// <returns></returns>
		public static ICollection Synchronized(ICollection Collection)
		{
			return new Collections.BTreeSyncCollection(Collection, new SyncCollection.Synchronizer());
		}
		public abstract int Count
		{
			get;
		}
		public abstract bool MoveNext();
		public abstract bool MovePrevious();
		public abstract bool MoveFirst();
		public abstract bool MoveLast();
		public abstract object CurrentEntry
		{
			get;
			set;
		}
		public abstract bool Search(object ObjectToSearch);	// return true if found, else false
		public abstract void Add(object ObjectToAdd);
		public abstract void Remove(object ObjectToRemove);
		public abstract void Clear();
		public abstract object Clone();
	}
	/// <summary>
	/// Dictionary extends Collection by adding associated Kay/Value entry api
	/// and a method that returns Synchronize object wrapper to a Dictionary.
	/// </summary>
	public abstract class Dictionary : Collection
	{
		public static IDictionary Synchronized(IDictionary Collection)
		{
			return new SyncDictionary(Collection, new SyncCollection.Synchronizer());
		}
		private new void Add(object ObjectToAdd){}
		public abstract void Add(object Key, object Value);
		public abstract object CurrentKey
		{
			get;
		}
		public abstract object CurrentValue
		{
			get;
			set;
		}
	}
	*/


	/*
	/// <summary>
	/// Synchronized Collection
	/// </summary>
	public abstract class SyncCollection : ICollection	//, System.Collections.ICollection
	{
		/// <summary>
		/// Collection operation types.
		/// </summary>
		public enum OperationType : byte
		{
			/// <summary>
			/// No operation
			/// </summary>
			Idle,
			/// <summary>
			/// In Move or get current object/key/value operation
			/// </summary>
			Read,
			/// <summary>
			/// In Search operation
			/// </summary>
			Search,
			/// <summary>
			/// In Add and Delete operation
			/// </summary>
			Write
		}
		/// <summary>
		/// Synchronizer wraps thread synchronization on Collection code.
		/// </summary>
		public class Synchronizer
		{
			private SingleThreadAccess ResCtrl = new SingleThreadAccess();
			/// <summary>
			/// ResControl returns a single thread access resource mngr
			/// </summary>
			internal SingleThreadAccess ResControl
			{
				get
				{
					return ResCtrl;
				}
			}
			/// <summary>
			/// Current operation being serviced by the Collection
			/// </summary>
			protected OperationType CurrentOperation;
			/// <summary>
			/// IsWriteRequested tells Collection if a request to update the Collection
			/// was received.
			/// </summary>
			protected bool IsWriteRequested;
			/// <summary>
			/// count of threads in read operation.
			/// </summary>
 			protected int ReadCount;
			//		Logic table:
			//Current Operation	: Requested Operation	: Result
			//Idle				: Read/Search or Write	: Allowed
			//Read/Search			: Read/Search			: Allowed
			//Read/Search			: Write					: Wait until Read/Search is done
			//Write				: Read/Search or Write	: Wait until Write is done
			//

			/// <summary>
			/// Locks this Synchronizer so that other threads won't be able to access this Synchronizer until this Synchronizer gets Unlocked. See Unlock function below.
			/// </summary>
			/// <param name="RequestedOperation">Lock resource for Read, Write or Search</param>
			public void Lock(OperationType RequestedOperation)
			{
				if (!IsWriteRequested && (CurrentOperation == OperationType.Read || CurrentOperation == OperationType.Search) 
						&& (RequestedOperation == OperationType.Read || RequestedOperation == OperationType.Search))
					// we don't need to lock since reading could be done by more than one thread. As result, multiple reads invoked by multiple threads will run in parallel!
					Interlocked.Increment(ref ReadCount);
				else
				{
					if (!IsWriteRequested)
						IsWriteRequested = (CurrentOperation == OperationType.Read || CurrentOperation == OperationType.Search) && RequestedOperation == OperationType.Write;
					ResControl.Lock();
					IsWriteRequested = false;
					CurrentOperation = RequestedOperation;
					if (RequestedOperation == OperationType.Read || RequestedOperation == OperationType.Search)
						ReadCount = 1;
				}
			}
			/// <summary>
			/// Unlock function. Removes Synchronizer lock so that pending operation waiting to get a lock on the Synchronizer, will be able to get one.
			/// </summary>
			public void Unlock()
			{
				if (((CurrentOperation == OperationType.Read || CurrentOperation == OperationType.Search) && Interlocked.Decrement(ref ReadCount) == 0) || 
					CurrentOperation == OperationType.Write)
				{
					CurrentOperation = OperationType.Idle;
					ResControl.Unlock();
					return;
				}
			}
			// Constructor
			public Synchronizer()
			{
				CurrentOperation = OperationType.Idle;
			}
		}	// End of Synchronizer class
		private Synchronizer oSynchronizer;
		private ushort nLockCtr;
		/// <summary>
		/// Collection is the Collection wrapped by the synchronize Collection wrapper
		/// </summary>
		protected ICollection Collection;		// the multi-thread shared Collection object!!
		/// <summary>
		/// Returns whether this Collection is synchronized. In this case, always returns true
		/// </summary>
		public bool IsSynchronized
		{
			get
			{
				return true;
			}
		}
		/// <summary>
		/// Returns the Synchronizer root
		/// </summary>
		public object SyncRoot
		{
			get
			{
				return this.oSynchronizer;
			}
		}
		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="Collection">Collection to be wrapped by synchronized Collection</param>
		/// <param name="oSync">synchronizer object used to do thread sync on Collection</param>
		public SyncCollection(ICollection Collection, Synchronizer oSync)
		{
			nLockCtr = 0;
			this.Collection = Collection;
			this.oSynchronizer = oSync;
		}
		// Locks this object if it is not locked by this thread yet. If it is then, just increment lock count. 
		// NOTE: not thread safe as this Synchronization object wrapper is designed for apartment thread.
		//		The multi-thread shared 'Collection' is the one having thread safety features.
		public void Lock(OperationType RequestedOperation)
		{
			if (nLockCtr == 0)
				((Synchronizer)SyncRoot).Lock(RequestedOperation);
			nLockCtr++;		// no need to synchronize as this lock ctr is for the current thread only
		}
		// Unlock function.
		// NOTE: not thread safe as this Synchronization object wrapper is designed for apartment thread.
		//		The multi-thread shared 'Collection' is the one having thread safety features.
		public void Unlock()
		{
			if (nLockCtr > 0 && --nLockCtr == 0)
				((Synchronizer)SyncRoot).Unlock();
		}
		// Removes lock. This ensures lock is removed.
		// NOTE: not thread safe as this Synchronization object wrapper is designed for apartment thread.
		//		The multi-thread shared 'Collection' is the one having thread safety features.
		public void ForceUnlock()
		{
			while (nLockCtr > 0)
			{
				if (--nLockCtr == 0)
					((Synchronizer)SyncRoot).Unlock();
			}
		}
		public int Count
		{
			get
			{
				return Collection.Count;
			}
		}
		public bool MoveNext()
		{
			bool r;
			Lock(OperationType.Read);
			r = Collection.MoveNext();
			Unlock();
			return r;
		}
		public bool MovePrevious()
		{
			bool r;
			Lock(OperationType.Read);
			r = Collection.MovePrevious();
			Unlock();
			return r;
		}
		public bool MoveFirst()
		{
			bool r;
			Lock(OperationType.Read);
			r = Collection.MoveFirst();
			Unlock();
			return r;
		}
		public bool MoveLast()
		{
			bool r;
			Lock(OperationType.Read);
			r = Collection.MoveFirst();
			Unlock();
			return r;
		}
		public object CurrentEntry
		{
			get
			{
				object o;
				Lock(OperationType.Read);
				o = Collection.CurrentEntry;
				Unlock();
				return o;
			}
		}
		public bool Search(object ObjectToSearch)	// return true if found, else false
		{
			bool r;
			Lock(OperationType.Read);
			r = Collection.Search(ObjectToSearch);
			Unlock();
			return r;
		}
		public void Add(object ObjectToAdd)
		{
			Lock(OperationType.Write);
			Collection.Add(ObjectToAdd);
			Unlock();
		}
		public void Remove(object ObjectToRemove)	// return true if found, else false
		{
			Lock(OperationType.Write);
			Collection.Remove(ObjectToRemove);
			Unlock();
		}
		public void Clear()
		{
			Lock(OperationType.Write);
			Collection.Clear();
			Unlock();
		}
		public object Clone()		// Do a shallow duplication of the Collection
		{
			object o;
			Lock(OperationType.Read);
			o = Collection.Clone();
			Unlock();
			return o;
		}
	}	// end of SyncCollection
*/


/*
	/// <summary>
	/// Synchronized Dictionary wrapper
	/// </summary>
	public class SyncDictionary :	SyncCollection, 
									IDictionary,
									System.Collections.IDictionary,
									System.Collections.ICollection, 
									System.Collections.IEnumerable,
									System.ICloneable
	{
		public SyncDictionary(IDictionary Collection, Synchronizer oSync) : base(Collection, oSync){}

		public static IDictionary Synchronized(IDictionary Collection)
		{
			return new SyncDictionary(Collection, new SyncCollection.Synchronizer());
		}

		public void Add(object Key, object Value)
		{
			Lock(OperationType.Read);
			((IDictionary)Collection).Add(Key, Value);
			Unlock();
		}
		public object CurrentKey
		{
			get
			{
				object o;
				Lock(OperationType.Read);
				o = ((IDictionary)Collection).CurrentKey;
				Unlock();
				return o;
			}
		}
		public object CurrentValue
		{
			get
			{
				object o;
				Lock(OperationType.Read);
				o = ((IDictionary)Collection).CurrentValue;
				Unlock();
				return o;
			}
		}
		//**** System.Collections.IDictionary API
		/// <summary>
		/// Contains determines whether this collection contains an entry with the specified key.
		/// </summary>
		/// <param name="key">key to look for</param>
		/// <returns></returns>
		public bool Contains(object key)
		{
			return true;
		}
		/// <summary>
		/// IsFixedSize returns "false" as this collection can hold variable number of items
		/// </summary>
		public bool IsFixedSize
		{
			get
			{
				return false;
			}
		}
		/// <summary>
		/// Returns "false", which means this collection is read/write
		/// </summary>
		public bool IsReadOnly 
		{
			get
			{
				return false;
			}
		}
		/// <summary>
		/// Copy To array all items from this BTree tree
		/// </summary>
		/// <param name="DestArray">DestArray is the destination array</param>
		/// <param name="StartIndex">StartIndex is the dest array index where copy starts</param>
		public void CopyTo(Array DestArray, int StartIndex)
		{
			foreach(object o in this)
			{
				DestArray.SetValue(o,StartIndex);
				StartIndex++;
			}
		}
		/// <summary>
		/// IDictionary GetEnumerator Implementation
		/// </summary>
		/// <returns>Returns a clone of this collection that can track its tree traversal state (per current record pointer)</returns>
		public System.Collections.IDictionaryEnumerator GetEnumerator()
		{
			return null;
		}
		/// <summary>
		/// IEnumerable Interface Implementation
		/// </summary>
		/// <returns></returns>
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return null;
		}
		/// <summary>
		/// BTree indexer. Given a key, will return its value.
		/// </summary>
		public object this[object key]
		{
			get
			{
				return null;
			}
			set
			{
				//Collection[key] = value;
			}
		}
		/// <summary>
		/// Returns a version of this BTree whose members are all Keys of the members
		/// </summary>
		public System.Collections.ICollection Keys
		{
			get
			{
				return null;
			}
		}
		/// <summary>
		/// Returns a version of this BTree whose members are all Values of the members
		/// </summary>
		public System.Collections.ICollection Values
		{
			get
			{
				return null;
			}
		}
	}
	*/
}

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