context: #region Copyright & License Information
  /*
   * Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
   * This file is part of OpenRA, which is free software. It is made
   * available to you under the terms of the GNU General Public License
   * as published by the Free Software Foundation. For more information,
   * see COPYING.
   */
  #endregion
  
  using System;
  using System.Collections.Generic;
  using System.Drawing;
  using System.Globalization;
  using System.Linq;
  using System.Reflection;
  using OpenRA.Support;
  using OpenRA.Traits;
  
  namespace OpenRA
  {
  	public static class Exts
  	{
  		public static bool IsUppercase(this string str)
  		{
  			return string.Compare(str.ToUpperInvariant(), str, false) == 0;
  		}
  
  		public static string F(this string fmt, params object[] args)
  		{
  			return string.Format(fmt, args);
  		}
  
  		public static T WithDefault<T>(T def, Func<T> f)
  		{
  			try { return f(); }
  			catch { return def; }
  		}
  
  		public static void Do<T>(this IEnumerable<T> e, Action<T> fn)
  		{
  			foreach (var ee in e)
  				fn(ee);
  		}
  
  		public static Lazy<T> Lazy<T>(Func<T> p) { return new Lazy<T>(p); }
  
  		public static IEnumerable<string> GetNamespaces(this Assembly a)
  		{
  			return a.GetTypes().Select(t => t.Namespace).Distinct().Where(n => n != null);
  		}
  
  		public static bool HasAttribute<T>(this MemberInfo mi)
  		{
  			return mi.GetCustomAttributes(typeof(T), true).Length != 0;
  		}
  
  		public static T[] GetCustomAttributes<T>(this MemberInfo mi, bool inherit)
  			where T : class
  		{
  			return (T[])mi.GetCustomAttributes(typeof(T), inherit);
  		}
  
  		public static T[] GetCustomAttributes<T>(this ParameterInfo mi)
  			where T : class
  		{
  			return (T[])mi.GetCustomAttributes(typeof(T), true);
  		}
  
  		public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T>
  		{
  			if (val.CompareTo(min) < 0)
  				return min;
  			else if (val.CompareTo(max) > 0)
  				return max;
  			else
  				return val;
  		}
  
  		public static bool Contains(this Rectangle r, int2 p)
  		{
  			return r.Contains(p.ToPoint());
  		}
  
  		public static bool Contains(this RectangleF r, int2 p)
  		{
  			return r.Contains(p.ToPointF());
  		}
  
  		public static bool HasModifier(this Modifiers k, Modifiers mod)
  		{
  			return (k & mod) == mod;
  		}
  
  		public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k)
  			where V : new()
  		{
  			return d.GetOrAdd(k, _ => new V());
  		}
  
  		public static V GetOrAdd<K, V>(this Dictionary<K, V> d, K k, Func<K, V> createFn)
  		{
  			V ret;
  			if (!d.TryGetValue(k, out ret))
  				d.Add(k, ret = createFn(k));
  			return ret;
  		}
  
  		public static int IndexOf<T>(this T[] array, T value)
  		{
  			return Array.IndexOf(array, value);
  		}
  
  		public static T Random<T>(this IEnumerable<T> ts, MersenneTwister r)
  		{
  			var xs = ts as ICollection<T>;
  			if (xs != null)
  				return xs.ElementAt(r.Next(xs.Count));
  			var ys = ts.ToList();
  			return ys[r.Next(ys.Count)];
  		}
  
  		public static T RandomOrDefault<T>(this IEnumerable<T> ts, MersenneTwister r)
  		{
  			if (!ts.Any())
  				return default(T);
  
  			return ts.Random(r);
  		}
  
  		public static float Product(this IEnumerable<float> xs)
  		{
  			return xs.Aggregate(1f, (a, x) => a * x);
  		}
  
  		public static IEnumerable<T> SymmetricDifference<T>(this IEnumerable<T> xs, IEnumerable<T> ys)
  		{
  			// this is probably a shockingly-slow way to do this, but it's concise.
  			return xs.Except(ys).Concat(ys.Except(xs));
  		}
  
  		public static IEnumerable<T> Iterate<T>(this T t, Func<T, T> f)
  		{
  			for (;;) { yield return t; t = f(t); }
  		}
  
  		public static T MinBy<T, U>(this IEnumerable<T> ts, Func<T, U> selector)
  		{
  			return ts.CompareBy(selector, 1, true);
  		}
  
  		public static T MaxBy<T, U>(this IEnumerable<T> ts, Func<T, U> selector)
  		{
  			return ts.CompareBy(selector, -1, true);
  		}
  
  		public static T MinByOrDefault<T, U>(this IEnumerable<T> ts, Func<T, U> selector)
  		{
  			return ts.CompareBy(selector, 1, false);
  		}
  
  		public static T MaxByOrDefault<T, U>(this IEnumerable<T> ts, Func<T, U> selector)
  		{
  			return ts.CompareBy(selector, -1, false);
  		}
  
  		static T CompareBy<T, U>(this IEnumerable<T> ts, Func<T, U> selector, int modifier, bool throws)
  		{
  			var comparer = Comparer<U>.Default;
  			T t;
  			U u;
  			using (var e = ts.GetEnumerator())
  			{
  				if (!e.MoveNext())
  					if (throws)
  						throw new ArgumentException("Collection must not be empty.", "ts");
  					else
  						return default(T);
  				t = e.Current;
  				u = selector(t);
  				while (e.MoveNext())
  				{
  					var nextT = e.Current;
  					var nextU = selector(nextT);
  					if (comparer.Compare(nextU, u) * modifier < 0)
  					{
  						t = nextT;
  						u = nextU;
  					}
  				}
  
  				return t;
  			}
  		}
  
  		public static int NextPowerOf2(int v)
  		{
  			--v;
  			v |= v >> 1;
  			v |= v >> 2;
  			v |= v >> 4;
  			v |= v >> 8;
  			++v;
  			return v;
  		}
  
  		public static bool IsPowerOf2(int v)
  		{
  			return (v & (v - 1)) == 0;
  		}
  
  		public static Size NextPowerOf2(this Size s) { return new Size(NextPowerOf2(s.Width), NextPowerOf2(s.Height)); }
  
  		public enum ISqrtRoundMode { Floor, Nearest, Ceiling }
  		public static int ISqrt(int number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
  		{
  			if (number < 0)
  				throw new InvalidOperationException("Attempted to calculate the square root of a negative integer: {0}".F(number));
  
  			return (int)ISqrt((uint)number, round);
  		}
  
  		public static uint ISqrt(uint number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
  		{
  			var divisor = 1U << 30;
  
  			var root = 0U;
  			var remainder = number;
  
  			// Find the highest term in the divisor
  			while (divisor > number)
  				divisor >>= 2;
  
  			// Evaluate the root, two bits at a time
  			while (divisor != 0)
  			{
  				if (root + divisor <= remainder)
  				{
  					remainder -= root + divisor;
  					root += 2 * divisor;
  				}
  
  				root >>= 1;
  				divisor >>= 2;
  			}
  
  			// Adjust for other rounding modes
  			if (round == ISqrtRoundMode.Nearest && remainder > root)
  				root += 1;
  			else if (round == ISqrtRoundMode.Ceiling && root * root < number)
  				root += 1;
  
  			return root;
  		}
  
  		public static long ISqrt(long number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
  		{
  			if (number < 0)
  				throw new InvalidOperationException("Attempted to calculate the square root of a negative integer: {0}".F(number));
  
  			return (long)ISqrt((ulong)number, round);
  		}
  
  		public static ulong ISqrt(ulong number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
  		{
  			var divisor = 1UL << 62;
  
  			var root = 0UL;
  			var remainder = number;
  
  			// Find the highest term in the divisor
  
gt: 			while (divisor > number)