using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

#pragma warning disable 0420

public partial class LockFreeDictionary<K, V> : IDictionary<K, V>
	where K : IEquatable<K>
	where V : IEquatable<V>
{
	public partial class Config
	{
		/// <summary>
		/// Lock-free LIFO stack
		/// </summary>
		public partial struct Freelist
		{
			public Freelist(Config cfg)
			{
				this.cfg = cfg;
				this.m_head = unchecked((UInt32)FreeListTerminator);
			}

			internal const Int32 FreeListTerminator = unchecked((Int32)0xFFFFFFFE);
			const Int64 SequenceMask = unchecked((Int64)0xFFFFFFFF00000000);
			const Int64 SequenceIncrement = 0x0000000100000000;

			readonly Config cfg;
			Int64 m_head;

			/// <summary>
			/// Atomic (tear-free on x86) and volatile (cached-through on x86 and x64) access to m_head
			/// </summary>
			Int64 Head
			{
				get
				{
					if (IntPtr.Size == 4)
						return Interlocked.CompareExchange(ref m_head, 0, 0);
					Int64 h = m_head;
					Thread.MemoryBarrier();
					return h;
				}
			}

			/// <summary>
			/// Add an item to the free list
			/// </summary>
			public void AddIndexToFreeList(int gx_add)
			{
				Int64 new_head, head = Head;
				while (true)
				{
					cfg.SetEntryNext(gx_add, (Int32)head);

					new_head = ((head + SequenceIncrement) & SequenceMask) | (UInt32)gx_add;

					if ((new_head = Interlocked.CompareExchange(ref m_head, new_head, head)) == head)
						return;

					head = new_head;
				}
			}

			/// <summary>
			/// Pick the first item from the free list.
			/// </summary>
			/// <returns><value>true</value> if an free index is returned in <paramref name="gx_out"/>, 
			/// <value>false</value> otherwise.</returns>
			public bool TryGetFreeIndex(out int gx_out)
			{
				Int64 same_head, new_head, head = Head;
				while (true)
				{
					int gx_next;
					while (true)
					{
						gx_out = (Int32)head;
						gx_next = cfg.GetNextHot(gx_out);

						if (head == (same_head = Head))
							break;
						head = same_head;
					}

					if (gx_out == FreeListTerminator)
					{
						gx_out = -1;
						return false;
					}

					new_head = ((head + SequenceIncrement) & SequenceMask) | (UInt32)gx_next;

					if ((new_head = Interlocked.CompareExchange(ref m_head, new_head, head)) == head)
						return true;

					head = new_head;
				}
			}
		};
	};
};