|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
|
|
|
|
|
namespace Connected;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A universal T to double binding converter
|
|
|
|
|
///
|
|
|
|
|
/// Note: currently not in use. Should we ever use it, remove
|
|
|
|
|
/// the [ExcludeFromCodeCoverage] attribute
|
|
|
|
|
/// </summary>
|
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
|
|
|
public class NumericConverter<T> : Converter<T, double>
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
protected override double ConvertValue(T? value)
|
|
|
|
|
{
|
|
|
|
|
if (value is null)
|
|
|
|
|
{
|
|
|
|
|
return double.NaN;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Double
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(double))
|
|
|
|
|
{
|
|
|
|
|
return (double)(object)value;
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(double?))
|
|
|
|
|
{
|
|
|
|
|
return ((double?)(object)value).Value;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* String
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(string))
|
|
|
|
|
{
|
|
|
|
|
return double.Parse((string)(object)value, NumberStyles.Any, Culture);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* SByte
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(sbyte))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((sbyte)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(sbyte?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((sbyte?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Byte
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(byte))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((byte)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(byte?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((byte?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Short
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(short))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((short)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(short?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((short?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Ushort
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(ushort))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((ushort)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(ushort?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((ushort?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Int
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(int))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((int)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(int?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((int?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Uint
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(uint))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((uint)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(uint?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((uint?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Long
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(long))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((long)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(long?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((long?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Ulong
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(ulong))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((ulong)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(ulong?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((ulong?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Float
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(float))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((float)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(float?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((float?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Deimal
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(decimal))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble((decimal)(object)value);
|
|
|
|
|
}
|
|
|
|
|
else if (typeof(T) == typeof(decimal?))
|
|
|
|
|
{
|
|
|
|
|
return System.Convert.ToDouble(((decimal?)(object)value).Value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TriggerError("Unable to convert to double from type " + typeof(T).Name);
|
|
|
|
|
return double.NaN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override T? ConvertValueBack(double value)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Double
|
|
|
|
|
*/
|
|
|
|
|
if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)value;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* String
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(string))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)value.ToString(Culture);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Sbyte
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToSByte(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Byte
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToByte(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Short
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToInt16(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Ushort
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToUInt16(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Int
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToInt32(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Uint
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToUInt32(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Long
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToInt64(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Ulong
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToUInt64(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Float
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToSingle(value);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Decimal
|
|
|
|
|
*/
|
|
|
|
|
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
|
|
|
|
|
{
|
|
|
|
|
return (T)(object)System.Convert.ToDecimal(value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TriggerError($"Conversion to type {typeof(T)} not implemented");
|
|
|
|
|
return default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Floating Point comparison
|
|
|
|
|
|
|
|
|
|
private const double MinNormal = 2.2250738585072014E-308d;
|
|
|
|
|
|
|
|
|
|
public static bool AreEqual(double a, double b, double epsilon = MinNormal)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) Michael Borgwardt
|
|
|
|
|
*/
|
|
|
|
|
var absA = Math.Abs(a);
|
|
|
|
|
var absB = Math.Abs(b);
|
|
|
|
|
var diff = Math.Abs(a - b);
|
|
|
|
|
/*
|
|
|
|
|
* Shortcut, handles infinities
|
|
|
|
|
*/
|
|
|
|
|
if (a.Equals(b))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (a == 0 || b == 0 || absA + absB < MinNormal)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* a or b is zero or both are extremely close to it
|
|
|
|
|
* relative error is less meaningful here
|
|
|
|
|
*/
|
|
|
|
|
return diff < epsilon * MinNormal;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Use relative error
|
|
|
|
|
*/
|
|
|
|
|
return diff / (absA + absB) < epsilon;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[ExcludeFromCodeCoverage]
|
|
|
|
|
internal static class Number
|
|
|
|
|
{
|
|
|
|
|
public static T? To<T>(double d)
|
|
|
|
|
{
|
|
|
|
|
if (typeof(T) == typeof(sbyte) && d >= sbyte.MinValue && sbyte.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToSByte(d);
|
|
|
|
|
if (typeof(T) == typeof(byte) && d >= byte.MinValue && byte.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToByte(d);
|
|
|
|
|
if (typeof(T) == typeof(short) && d >= short.MinValue && short.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToInt16(d);
|
|
|
|
|
if (typeof(T) == typeof(ushort) && d >= ushort.MinValue && ushort.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToUInt16(d);
|
|
|
|
|
if (typeof(T) == typeof(int) && d >= int.MinValue && int.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToInt32(d);
|
|
|
|
|
if (typeof(T) == typeof(uint) && d >= uint.MinValue && uint.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToUInt32(d);
|
|
|
|
|
if (typeof(T) == typeof(long) && d >= long.MinValue && long.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToInt64(d);
|
|
|
|
|
if (typeof(T) == typeof(ulong) && d >= ulong.MinValue && ulong.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToUInt64(d);
|
|
|
|
|
if (typeof(T) == typeof(float) && d >= float.MinValue && float.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToSingle(d);
|
|
|
|
|
if (typeof(T) == typeof(double) && d >= double.MinValue && double.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToDouble(d);
|
|
|
|
|
if (typeof(T) == typeof(decimal) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d)
|
|
|
|
|
return (T)(object)Convert.ToDecimal(d);
|
|
|
|
|
if (typeof(T) == typeof(sbyte?) && d >= sbyte.MinValue && sbyte.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToSByte(d);
|
|
|
|
|
if (typeof(T) == typeof(byte?) && d >= byte.MinValue && byte.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToByte(d);
|
|
|
|
|
if (typeof(T) == typeof(short?) && d >= short.MinValue && short.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToInt16(d);
|
|
|
|
|
if (typeof(T) == typeof(ushort?) && d >= ushort.MinValue && ushort.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToUInt16(d);
|
|
|
|
|
if (typeof(T) == typeof(int?) && d >= int.MinValue && int.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToInt32(d);
|
|
|
|
|
if (typeof(T) == typeof(uint?) && d >= uint.MinValue && uint.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToUInt32(d);
|
|
|
|
|
if (typeof(T) == typeof(long?) && d >= long.MinValue && long.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToInt64(d);
|
|
|
|
|
if (typeof(T) == typeof(ulong?) && d >= ulong.MinValue && ulong.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToUInt64(d);
|
|
|
|
|
if (typeof(T) == typeof(float?) && d >= float.MinValue && float.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToSingle(d);
|
|
|
|
|
if (typeof(T) == typeof(double?) && d >= double.MinValue && double.MaxValue >= d)
|
|
|
|
|
return (T)(object)Convert.ToDouble(d);
|
|
|
|
|
if (typeof(T) == typeof(decimal?) && (decimal)d >= decimal.MinValue && decimal.MaxValue >= (decimal)d)
|
|
|
|
|
return (T)(object)Convert.ToDecimal(d);
|
|
|
|
|
|
|
|
|
|
return default;
|
|
|
|
|
}
|
|
|
|
|
public static double From<T>(T v)
|
|
|
|
|
{
|
|
|
|
|
if (typeof(T) == typeof(sbyte))
|
|
|
|
|
return Convert.ToDouble((sbyte)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(byte))
|
|
|
|
|
return Convert.ToDouble((byte)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(short))
|
|
|
|
|
return Convert.ToDouble((short)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(ushort))
|
|
|
|
|
return Convert.ToDouble((ushort)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(int))
|
|
|
|
|
return Convert.ToDouble((int)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(uint))
|
|
|
|
|
return Convert.ToDouble((uint)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(long))
|
|
|
|
|
return Convert.ToDouble((long)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(ulong))
|
|
|
|
|
return Convert.ToDouble((ulong)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(float))
|
|
|
|
|
return Convert.ToDouble((float)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(double))
|
|
|
|
|
return Convert.ToDouble((double)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(decimal))
|
|
|
|
|
return Convert.ToDouble((decimal)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(sbyte?))
|
|
|
|
|
return Convert.ToDouble((sbyte?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(byte?))
|
|
|
|
|
return Convert.ToDouble((byte?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(short?))
|
|
|
|
|
return Convert.ToDouble((short?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(ushort?))
|
|
|
|
|
return Convert.ToDouble((ushort?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(int?))
|
|
|
|
|
return Convert.ToDouble((int?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(uint?))
|
|
|
|
|
return Convert.ToDouble((uint?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(long?))
|
|
|
|
|
return Convert.ToDouble((long?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(ulong?))
|
|
|
|
|
return Convert.ToDouble((ulong?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(float?))
|
|
|
|
|
return Convert.ToDouble((float?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(double?))
|
|
|
|
|
return Convert.ToDouble((double?)(object)v);
|
|
|
|
|
if (typeof(T) == typeof(decimal?))
|
|
|
|
|
return Convert.ToDouble((decimal?)(object)v);
|
|
|
|
|
|
|
|
|
|
return default;
|
|
|
|
|
}
|
|
|
|
|
}
|