using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Runtime.InteropServices;
using System.Management;
using System.Reflection;


class Program
{
	static void Main(string[] args) { new Program()._Main(args); }

	static Dictionary<Type, int[]> dicts = new Dictionary<Type, int[]>
	{
		{ typeof(LockFreeDictionary<,>), new int[] { 1, 4, 8 } },
//		{ typeof(ConcurrentDictionary<,>), new int[] { 1, 4, 8 } },
//		{ typeof(SpinLockDictionary<,>), new int[] { 1, 4, 8 } },
//		{ typeof(Dictionary<,>), new int[] { 1 } },
//		{ typeof(MonitorLockDictionary<,>), new int[] { 1, 4, 8 } },
	};

	static Dictionary<Type, Delegate> types = new Dictionary<Type, Delegate>
	{
		{ typeof(ObjectEq), (Func<int,Random,ObjectEq>)ObjectGetter },
		{ typeof(String), (Func<int,Random,String>)StringGetter },
		{ typeof(Guid), (Func<int,Random,Guid>)GuidGetter },
		{ typeof(Int32), (Func<int,Random,Int32>)Int32Getter },
		{ typeof(Int64), (Func<int,Random,Int64>)Int64Getter },
	};

	static Type[] tests = new Type[]
		{
			typeof(_RandomUsageTestTo1000<,>),
			typeof(_45Sec10000MaxUsageTest<,>),
			typeof(_45SecondRandomUsageTest<,>),
			typeof(Add10E6Test<,>),
			typeof(_60SecReadOnly1E5Test<,>),
		};

	void _Main(string[] args)
	{
#if DEBUG
		Console.WriteLine("DEBUG {0}", IntPtr.Size==4 ? "x86" : "x64");
#else
		Console.WriteLine("RELEASE {0}", IntPtr.Size == 4 ? "x86" : "x64");
#endif
		Console.WriteLine("{0} processors @{1}\n", Environment.ProcessorCount, Util.CPUSpeed());

		foreach (var ttype in tests)
		{
			foreach (var dtype in dicts)
			{
				foreach (int c_tasks in dtype.Value.Where(c => c <= Environment.ProcessorCount))
				{
					foreach (var ktype in types)
					{
						foreach (var vtype in types)
						{
							//if (c_tasks != 8)
								//continue;

							DoTest(c_tasks, dtype.Key, ktype, vtype, ttype);
						}
					}
				}
			}
		}
	}

	void DoTest(int c_tasks, Type dtype, KeyValuePair<Type, Delegate> ktype, KeyValuePair<Type, Delegate> vtype, Type ttype)
	{
		Type tester = ttype.MakeGenericType(new Type[] { ktype.Key, vtype.Key });
		using (dynamic otester = Activator.CreateInstance(tester, new Object[] { c_tasks, ktype.Value, vtype.Value, dtype }))
		{
			otester.StartTest();
		}
	}


	class ObjectEq : IEquatable<ObjectEq>
	{
		public bool Equals(ObjectEq other)
		{
			return Object.Equals(this, other);
		}
	}

	static ObjectEq ObjectGetter(int num, Random r)
	{
		return new ObjectEq();
	}

	static Guid GuidGetter(int num, Random r)
	{
		var rgb = Guid.NewGuid().ToByteArray();
		rgb[0] = (byte)num;
		return new Guid(rgb);
	}

	static String StringGetter(int num, Random r)
	{
		return GuidGetter(num, r).ToString();
	}

	static Int32 Int32Getter(int num, Random r)
	{
		return (r.Next(int.MaxValue) & ~(byte)0x0F) | num;
	}

	static Int64 Int64Getter(int num, Random r)
	{
		byte[] rgb = new byte[7];
		r.NextBytes(rgb);
		return (long)
			   (((ulong)rgb[0] << 56) | 
				((ulong)rgb[1] << 48) |
				((ulong)rgb[2] << 40) |
				((ulong)rgb[3] << 32) |
				((ulong)rgb[4] << 24) |
				((ulong)rgb[5] << 16) | 
				((ulong)rgb[6] << 8) |
				(uint)num);			
	}
};


struct Counts
{
	public long add;
	public long get;
	public long update;
	public long remove;
	public TimeSpan ts;
	public static Counts operator +(Counts a, Counts b)
	{
		Counts c = new Counts();
		c.add = a.add + b.add;
		c.get = a.get + b.get;
		c.update = a.update + b.update;
		c.remove = a.remove + b.remove;
		c.ts = a.ts + b.ts;
		return c;
	}
};


class Util
{
	public static uint CPUSpeed()
	{
		using (ManagementObject Mo = new ManagementObject("Win32_Processor.DeviceID='CPU0'"))
			return (uint)Mo["CurrentClockSpeed"];
	}
}