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

#pragma warning disable 0420

public partial class LockFreeDictionary<K, V> : IDictionary<K, V>
	where K : IEquatable<K>
	where V : IEquatable<V>
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public partial class EntryBlock
	{
		public EntryBlock(Config cfg, int block_no)
		{
			this.cfg = cfg;
			this.i_block = block_no;
			this.rg = new Entry[cfg.EntriesPerBlock];
		}
		readonly Config cfg;
		readonly int i_block;
		readonly Entry[] rg;
		volatile public EntryBlock next = null;

		internal int BlockIndex { get { return i_block; } }

		internal void GetEntryLoose(int offs, out Entry e)
		{
			e = rg[offs];
			Thread.MemoryBarrier();
		}

		internal void StoreEntryLoose(int offs, ref Entry e)
		{
			Thread.MemoryBarrier();
			rg[offs] = e;
		}

		internal void SetEntryNext(int offs, int gx_next)
		{
			rg[offs].gx_next = gx_next;	/// C# volatile
		}

		internal int GetEntryNext(int offs)
		{
			return rg[offs].gx_next;	/// C# volatile
		}

		internal void GetKeyReadback(int offs, out K key)
		{
			if (Entry.f_value_type_key)
			{
				//do
				{
					key = rg[offs].key;
					Thread.MemoryBarrier();
				}
				//while (!key.Equals(rg[offs].key));
			}
			else
			{
				key = rg[offs].key;
				Thread.MemoryBarrier();
			}
		}

		internal uint GetHashAndNext(int offs, out int gx_next)
		{
			gx_next = rg[offs].gx_next;		/// C# volatile
			return rg[offs].hash;			/// C# volatile
		}


		/// <summary>
		/// Note: still not atomic against torn reads matching as false positives
		/// </summary>
		internal void SetEntryValueReadback(int offs, ref V value)
		{
			if (Entry.f_value_type_value)
			{
				//do
				{
					Thread.MemoryBarrier();
					rg[offs].value = value;
					//Thread.MemoryBarrier();		/// read fence for external code 'Equals'
				}
				//while (!value.Equals(rg[offs].value));
			}
			else
			{
				Thread.MemoryBarrier();
				rg[offs].value = value;
			}
		}


		internal void SetEntryValueLoose(int offs, ref V value)
		{
			Thread.MemoryBarrier();
			rg[offs].value = value;
		}


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public partial struct Entry
		{
			static readonly int cb_ent;
			static internal int StructureSize { get { return cb_ent; } }
			static internal Type t_key;
			static internal Type t_value;
			static internal readonly bool f_value_type_key;
			static internal readonly bool f_value_type_value;
			static Entry()
			{
				t_key = typeof(K);
				t_value = typeof(V);
				f_value_type_key = t_key.IsValueType;
				f_value_type_value = t_value.IsValueType;

				cb_ent = sizeof(int) + sizeof(uint);
				cb_ent += f_value_type_key ? Marshal.SizeOf(default(K)) : IntPtr.Size;
				cb_ent += f_value_type_value ? Marshal.SizeOf(default(V)) : IntPtr.Size;
			}

			internal Entry(int gx_next, uint hash, K key, V value)
			{
				this.gx_next = gx_next;
				this.hash = hash;
				this.key = key;
				this.value = value;
			}
			volatile internal int gx_next;
			volatile internal uint hash;
			readonly internal K key;
			internal V value;
		};
	};
};