// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.Decompiler.Util
{
///
/// Static helper method for converting between primitive types.
///
public static class CSharpPrimitiveCast
{
///
/// Performs a conversion between primitive types.
/// Unfortunately we cannot use Convert.ChangeType because it has different semantics
/// (e.g. rounding behavior for floats, overflow, etc.), so we write down every possible primitive C# cast
/// and let the compiler figure out the exact semantics.
/// And we have to do everything twice, once in a checked-block, once in an unchecked-block.
///
/// Overflow checking is enabled and an overflow occurred.
/// The cast is invalid, e.g. casting a boolean to an integer.
public static object Cast(TypeCode targetType, object input, bool checkForOverflow)
{
if (input == null)
return null;
if (checkForOverflow)
return CSharpPrimitiveCastChecked(targetType, input);
else
return CSharpPrimitiveCastUnchecked(targetType, input);
}
static object CSharpPrimitiveCastChecked(TypeCode targetType, object input)
{
checked
{
TypeCode sourceType = Type.GetTypeCode(input.GetType());
if (sourceType == targetType)
return input;
switch (targetType)
{
case TypeCode.Char:
switch (sourceType)
{
case TypeCode.SByte:
return (char)(sbyte)input;
case TypeCode.Byte:
return (char)(byte)input;
case TypeCode.Int16:
return (char)(short)input;
case TypeCode.UInt16:
return (char)(ushort)input;
case TypeCode.Int32:
return (char)(int)input;
case TypeCode.UInt32:
return (char)(uint)input;
case TypeCode.Int64:
return (char)(long)input;
case TypeCode.UInt64:
return (char)(ulong)input;
case TypeCode.Single:
return (char)(float)input;
case TypeCode.Double:
return (char)(double)input;
case TypeCode.Decimal:
return (char)(decimal)input;
case TypeCode.Boolean:
return (char)((bool)input ? 1 : 0);
}
break;
case TypeCode.SByte:
switch (sourceType)
{
case TypeCode.Char:
return (sbyte)(char)input;
case TypeCode.Byte:
return (sbyte)(byte)input;
case TypeCode.Int16:
return (sbyte)(short)input;
case TypeCode.UInt16:
return (sbyte)(ushort)input;
case TypeCode.Int32:
return (sbyte)(int)input;
case TypeCode.UInt32:
return (sbyte)(uint)input;
case TypeCode.Int64:
return (sbyte)(long)input;
case TypeCode.UInt64:
return (sbyte)(ulong)input;
case TypeCode.Single:
return (sbyte)(float)input;
case TypeCode.Double:
return (sbyte)(double)input;
case TypeCode.Decimal:
return (sbyte)(decimal)input;
case TypeCode.Boolean:
return (sbyte)((bool)input ? 1 : 0);
}
break;
case TypeCode.Byte:
switch (sourceType)
{
case TypeCode.Char:
return (byte)(char)input;
case TypeCode.SByte:
return (byte)(sbyte)input;
case TypeCode.Int16:
return (byte)(short)input;
case TypeCode.UInt16:
return (byte)(ushort)input;
case TypeCode.Int32:
return (byte)(int)input;
case TypeCode.UInt32:
return (byte)(uint)input;
case TypeCode.Int64:
return (byte)(long)input;
case TypeCode.UInt64:
return (byte)(ulong)input;
case TypeCode.Single:
return (byte)(float)input;
case TypeCode.Double:
return (byte)(double)input;
case TypeCode.Decimal:
return (byte)(decimal)input;
case TypeCode.Boolean:
return (byte)((bool)input ? 1 : 0);
}
break;
case TypeCode.Int16:
switch (sourceType)
{
case TypeCode.Char:
return (short)(char)input;
case TypeCode.SByte:
return (short)(sbyte)input;
case TypeCode.Byte:
return (short)(byte)input;
case TypeCode.UInt16:
return (short)(ushort)input;
case TypeCode.Int32:
return (short)(int)input;
case TypeCode.UInt32:
return (short)(uint)input;
case TypeCode.Int64:
return (short)(long)input;
case TypeCode.UInt64:
return (short)(ulong)input;
case TypeCode.Single:
return (short)(float)input;
case TypeCode.Double:
return (short)(double)input;
case TypeCode.Decimal:
return (short)(decimal)input;
case TypeCode.Boolean:
return (short)((bool)input ? 1 : 0);
}
break;
case TypeCode.UInt16:
switch (sourceType)
{
case TypeCode.Char:
return (ushort)(char)input;
case TypeCode.SByte:
return (ushort)(sbyte)input;
case TypeCode.Byte:
return (ushort)(byte)input;
case TypeCode.Int16:
return (ushort)(short)input;
case TypeCode.Int32:
return (ushort)(int)input;
case TypeCode.UInt32:
return (ushort)(uint)input;
case TypeCode.Int64:
return (ushort)(long)input;
case TypeCode.UInt64:
return (ushort)(ulong)input;
case TypeCode.Single:
return (ushort)(float)input;
case TypeCode.Double:
return (ushort)(double)input;
case TypeCode.Decimal:
return (ushort)(decimal)input;
case TypeCode.Boolean:
return (ushort)((bool)input ? 1 : 0);
}
break;
case TypeCode.Int32:
switch (sourceType)
{
case TypeCode.Char:
return (int)(char)input;
case TypeCode.SByte:
return (int)(sbyte)input;
case TypeCode.Byte:
return (int)(byte)input;
case TypeCode.Int16:
return (int)(short)input;
case TypeCode.UInt16:
return (int)(ushort)input;
case TypeCode.UInt32:
return (int)(uint)input;
case TypeCode.Int64:
return (int)(long)input;
case TypeCode.UInt64:
return (int)(ulong)input;
case TypeCode.Single:
return (int)(float)input;
case TypeCode.Double:
return (int)(double)input;
case TypeCode.Decimal:
return (int)(decimal)input;
case TypeCode.Boolean:
return (int)((bool)input ? 1 : 0);
}
break;
case TypeCode.UInt32:
switch (sourceType)
{
case TypeCode.Char:
return (uint)(char)input;
case TypeCode.SByte:
return (uint)(sbyte)input;
case TypeCode.Byte:
return (uint)(byte)input;
case TypeCode.Int16:
return (uint)(short)input;
case TypeCode.UInt16:
return (uint)(ushort)input;
case TypeCode.Int32:
return (uint)(int)input;
case TypeCode.Int64:
return (uint)(long)input;
case TypeCode.UInt64:
return (uint)(ulong)input;
case TypeCode.Single:
return (uint)(float)input;
case TypeCode.Double:
return (uint)(double)input;
case TypeCode.Decimal:
return (uint)(decimal)input;
case TypeCode.Boolean:
return (uint)((bool)input ? 1 : 0);
}
break;
case TypeCode.Int64:
switch (sourceType)
{
case TypeCode.Char:
return (long)(char)input;
case TypeCode.SByte:
return (long)(sbyte)input;
case TypeCode.Byte:
return (long)(byte)input;
case TypeCode.Int16:
return (long)(short)input;
case TypeCode.UInt16:
return (long)(ushort)input;
case TypeCode.Int32:
return (long)(int)input;
case TypeCode.UInt32:
return (long)(uint)input;
case TypeCode.UInt64:
return (long)(ulong)input;
case TypeCode.Single:
return (long)(float)input;
case TypeCode.Double:
return (long)(double)input;
case TypeCode.Decimal:
return (long)(decimal)input;
case TypeCode.Boolean:
return (long)((bool)input ? 1 : 0);
}
break;
case TypeCode.UInt64:
switch (sourceType)
{
case TypeCode.Char:
return (ulong)(char)input;
case TypeCode.SByte:
return (ulong)(sbyte)input;
case TypeCode.Byte:
return (ulong)(byte)input;
case TypeCode.Int16:
return (ulong)(short)input;
case TypeCode.UInt16:
return (ulong)(ushort)input;
case TypeCode.Int32:
return (ulong)(int)input;
case TypeCode.UInt32:
return (ulong)(uint)input;
case TypeCode.Int64:
return (ulong)(long)input;
case TypeCode.Single:
return (ulong)(float)input;
case TypeCode.Double:
return (ulong)(double)input;
case TypeCode.Decimal:
return (ulong)(decimal)input;
case TypeCode.Boolean:
return (ulong)((bool)input ? 1 : 0);
}
break;
case TypeCode.Single:
switch (sourceType)
{
case TypeCode.Char:
return (float)(char)input;
case TypeCode.SByte:
return (float)(sbyte)input;
case TypeCode.Byte:
return (float)(byte)input;
case TypeCode.Int16:
return (float)(short)input;
case TypeCode.UInt16:
return (float)(ushort)input;
case TypeCode.Int32:
return (float)(int)input;
case TypeCode.UInt32:
return (float)(uint)input;
case TypeCode.Int64:
return (float)(long)input;
case TypeCode.UInt64:
return (float)(ulong)input;
case TypeCode.Double:
return (float)(double)input;
case TypeCode.Decimal:
return (float)(decimal)input;
case TypeCode.Boolean:
return (float)((bool)input ? 1 : 0);
}
break;
case TypeCode.Double:
switch (sourceType)
{
case TypeCode.Char:
return (double)(char)input;
case TypeCode.SByte:
return (double)(sbyte)input;
case TypeCode.Byte:
return (double)(byte)input;
case TypeCode.Int16:
return (double)(short)input;
case TypeCode.UInt16:
return (double)(ushort)input;
case TypeCode.Int32:
return (double)(int)input;
case TypeCode.UInt32:
return (double)(uint)input;
case TypeCode.Int64:
return (double)(long)input;
case TypeCode.UInt64:
return (double)(ulong)input;
case TypeCode.Single:
return (double)(float)input;
case TypeCode.Decimal:
return (double)(decimal)input;
case TypeCode.Boolean:
return (double)((bool)input ? 1 : 0);
}
break;
case TypeCode.Decimal:
switch (sourceType)
{
case TypeCode.Char:
return (decimal)(char)input;
case TypeCode.SByte:
return (decimal)(sbyte)input;
case TypeCode.Byte:
return (decimal)(byte)input;
case TypeCode.Int16:
return (decimal)(short)input;
case TypeCode.UInt16:
return (decimal)(ushort)input;
case TypeCode.Int32:
return (decimal)(int)input;
case TypeCode.UInt32:
return (decimal)(uint)input;
case TypeCode.Int64:
return (decimal)(long)input;
case TypeCode.UInt64:
return (decimal)(ulong)input;
case TypeCode.Single:
return (decimal)(float)input;
case TypeCode.Double:
return (decimal)(double)input;
case TypeCode.Boolean:
return (decimal)((bool)input ? 1 : 0);
}
break;
}
throw new InvalidCastException("Cast from " + sourceType + " to " + targetType + "not supported.");
}
}
static object CSharpPrimitiveCastUnchecked(TypeCode targetType, object input)
{
unchecked
{
TypeCode sourceType = Type.GetTypeCode(input.GetType());
if (sourceType == targetType)
return input;
switch (targetType)
{
case TypeCode.Char:
switch (sourceType)
{
case TypeCode.SByte:
return (char)(sbyte)input;
case TypeCode.Byte:
return (char)(byte)input;
case TypeCode.Int16:
return (char)(short)input;
case TypeCode.UInt16:
return (char)(ushort)input;
case TypeCode.Int32:
return (char)(int)input;
case TypeCode.UInt32:
return (char)(uint)input;
case TypeCode.Int64:
return (char)(long)input;
case TypeCode.UInt64:
return (char)(ulong)input;
case TypeCode.Single:
return (char)(float)input;
case TypeCode.Double:
return (char)(double)input;
case TypeCode.Decimal:
return (char)(decimal)input;
case TypeCode.Boolean:
return (char)((bool)input ? 1 : 0);
}
break;
case TypeCode.SByte:
switch (sourceType)
{
case TypeCode.Char:
return (sbyte)(char)input;
case TypeCode.Byte:
return (sbyte)(byte)input;
case TypeCode.Int16:
return (sbyte)(short)input;
case TypeCode.UInt16:
return (sbyte)(ushort)input;
case TypeCode.Int32:
return (sbyte)(int)input;
case TypeCode.UInt32:
return (sbyte)(uint)input;
case TypeCode.Int64:
return (sbyte)(long)input;
case TypeCode.UInt64:
return (sbyte)(ulong)input;
case TypeCode.Single:
return (sbyte)(float)input;
case TypeCode.Double:
return (sbyte)(double)input;
case TypeCode.Decimal:
return (sbyte)(decimal)input;
case TypeCode.Boolean:
return (sbyte)((bool)input ? 1 : 0);
}
break;
case TypeCode.Byte:
switch (sourceType)
{
case TypeCode.Char:
return (byte)(char)input;
case TypeCode.SByte:
return (byte)(sbyte)input;
case TypeCode.Int16:
return (byte)(short)input;
case TypeCode.UInt16:
return (byte)(ushort)input;
case TypeCode.Int32:
return (byte)(int)input;
case TypeCode.UInt32:
return (byte)(uint)input;
case TypeCode.Int64:
return (byte)(long)input;
case TypeCode.UInt64:
return (byte)(ulong)input;
case TypeCode.Single:
return (byte)(float)input;
case TypeCode.Double:
return (byte)(double)input;
case TypeCode.Decimal:
return (byte)(decimal)input;
case TypeCode.Boolean:
return (byte)((bool)input ? 1 : 0);
}
break;
case TypeCode.Int16:
switch (sourceType)
{
case TypeCode.Char:
return (short)(char)input;
case TypeCode.SByte:
return (short)(sbyte)input;
case TypeCode.Byte:
return (short)(byte)input;
case TypeCode.UInt16:
return (short)(ushort)input;
case TypeCode.Int32:
return (short)(int)input;
case TypeCode.UInt32:
return (short)(uint)input;
case TypeCode.Int64:
return (short)(long)input;
case TypeCode.UInt64:
return (short)(ulong)input;
case TypeCode.Single:
return (short)(float)input;
case TypeCode.Double:
return (short)(double)input;
case TypeCode.Decimal:
return (short)(decimal)input;
case TypeCode.Boolean:
return (short)((bool)input ? 1 : 0);
}
break;
case TypeCode.UInt16:
switch (sourceType)
{
case TypeCode.Char:
return (ushort)(char)input;
case TypeCode.SByte:
return (ushort)(sbyte)input;
case TypeCode.Byte:
return (ushort)(byte)input;
case TypeCode.Int16:
return (ushort)(short)input;
case TypeCode.Int32:
return (ushort)(int)input;
case TypeCode.UInt32:
return (ushort)(uint)input;
case TypeCode.Int64:
return (ushort)(long)input;
case TypeCode.UInt64:
return (ushort)(ulong)input;
case TypeCode.Single:
return (ushort)(float)input;
case TypeCode.Double:
return (ushort)(double)input;
case TypeCode.Decimal:
return (ushort)(decimal)input;
case TypeCode.Boolean:
return (ushort)((bool)input ? 1 : 0);
}
break;
case TypeCode.Int32:
switch (sourceType)
{
case TypeCode.Char:
return (int)(char)input;
case TypeCode.SByte:
return (int)(sbyte)input;
case TypeCode.Byte:
return (int)(byte)input;
case TypeCode.Int16:
return (int)(short)input;
case TypeCode.UInt16:
return (int)(ushort)input;
case TypeCode.UInt32:
return (int)(uint)input;
case TypeCode.Int64:
return (int)(long)input;
case TypeCode.UInt64:
return (int)(ulong)input;
case TypeCode.Single:
return (int)(float)input;
case TypeCode.Double:
return (int)(double)input;
case TypeCode.Decimal:
return (int)(decimal)input;
case TypeCode.Boolean:
return (int)((bool)input ? 1 : 0);
}
break;
case TypeCode.UInt32:
switch (sourceType)
{
case TypeCode.Char:
return (uint)(char)input;
case TypeCode.SByte:
return (uint)(sbyte)input;
case TypeCode.Byte:
return (uint)(byte)input;
case TypeCode.Int16:
return (uint)(short)input;
case TypeCode.UInt16:
return (uint)(ushort)input;
case TypeCode.Int32:
return (uint)(int)input;
case TypeCode.Int64:
return (uint)(long)input;
case TypeCode.UInt64:
return (uint)(ulong)input;
case TypeCode.Single:
return (uint)(float)input;
case TypeCode.Double:
return (uint)(double)input;
case TypeCode.Decimal:
return (uint)(decimal)input;
case TypeCode.Boolean:
return (uint)((bool)input ? 1 : 0);
}
break;
case TypeCode.Int64:
switch (sourceType)
{
case TypeCode.Char:
return (long)(char)input;
case TypeCode.SByte:
return (long)(sbyte)input;
case TypeCode.Byte:
return (long)(byte)input;
case TypeCode.Int16:
return (long)(short)input;
case TypeCode.UInt16:
return (long)(ushort)input;
case TypeCode.Int32:
return (long)(int)input;
case TypeCode.UInt32:
return (long)(uint)input;
case TypeCode.UInt64:
return (long)(ulong)input;
case TypeCode.Single:
return (long)(float)input;
case TypeCode.Double:
return (long)(double)input;
case TypeCode.Decimal:
return (long)(decimal)input;
case TypeCode.Boolean:
return (long)((bool)input ? 1 : 0);
}
break;
case TypeCode.UInt64:
switch (sourceType)
{
case TypeCode.Char:
return (ulong)(char)input;
case TypeCode.SByte:
return (ulong)(sbyte)input;
case TypeCode.Byte:
return (ulong)(byte)input;
case TypeCode.Int16:
return (ulong)(short)input;
case TypeCode.UInt16:
return (ulong)(ushort)input;
case TypeCode.Int32:
return (ulong)(int)input;
case TypeCode.UInt32:
return (ulong)(uint)input;
case TypeCode.Int64:
return (ulong)(long)input;
case TypeCode.Single:
return (ulong)(float)input;
case TypeCode.Double:
return (ulong)(double)input;
case TypeCode.Decimal:
return (ulong)(decimal)input;
case TypeCode.Boolean:
return (ulong)((bool)input ? 1 : 0);
}
break;
case TypeCode.Single:
switch (sourceType)
{
case TypeCode.Char:
return (float)(char)input;
case TypeCode.SByte:
return (float)(sbyte)input;
case TypeCode.Byte:
return (float)(byte)input;
case TypeCode.Int16:
return (float)(short)input;
case TypeCode.UInt16:
return (float)(ushort)input;
case TypeCode.Int32:
return (float)(int)input;
case TypeCode.UInt32:
return (float)(uint)input;
case TypeCode.Int64:
return (float)(long)input;
case TypeCode.UInt64:
return (float)(ulong)input;
case TypeCode.Double:
return (float)(double)input;
case TypeCode.Decimal:
return (float)(decimal)input;
case TypeCode.Boolean:
return (float)((bool)input ? 1 : 0);
}
break;
case TypeCode.Double:
switch (sourceType)
{
case TypeCode.Char:
return (double)(char)input;
case TypeCode.SByte:
return (double)(sbyte)input;
case TypeCode.Byte:
return (double)(byte)input;
case TypeCode.Int16:
return (double)(short)input;
case TypeCode.UInt16:
return (double)(ushort)input;
case TypeCode.Int32:
return (double)(int)input;
case TypeCode.UInt32:
return (double)(uint)input;
case TypeCode.Int64:
return (double)(long)input;
case TypeCode.UInt64:
return (double)(ulong)input;
case TypeCode.Single:
return (double)(float)input;
case TypeCode.Decimal:
return (double)(decimal)input;
case TypeCode.Boolean:
return (double)((bool)input ? 1 : 0);
}
break;
case TypeCode.Decimal:
switch (sourceType)
{
case TypeCode.Char:
return (decimal)(char)input;
case TypeCode.SByte:
return (decimal)(sbyte)input;
case TypeCode.Byte:
return (decimal)(byte)input;
case TypeCode.Int16:
return (decimal)(short)input;
case TypeCode.UInt16:
return (decimal)(ushort)input;
case TypeCode.Int32:
return (decimal)(int)input;
case TypeCode.UInt32:
return (decimal)(uint)input;
case TypeCode.Int64:
return (decimal)(long)input;
case TypeCode.UInt64:
return (decimal)(ulong)input;
case TypeCode.Single:
return (decimal)(float)input;
case TypeCode.Double:
return (decimal)(double)input;
case TypeCode.Boolean:
return (decimal)((bool)input ? 1 : 0);
}
break;
}
throw new InvalidCastException("Cast from " + sourceType + " to " + targetType + " not supported.");
}
}
}
}