Cosmos/source/Cosmos.Common/StringHelper.cs
José Pedro f8e18e3fbc Fixed StringHelper.GetNumberString().
Changes in Conv*, Ld* and St* opcodes so that values with size < 4 bytes are extended to 4 bytes.
Implemented Not and Xor for values with size 8 bytes.
Added tests for bitwise operations, arithmetic operations and Conv* opcodes.
2017-01-24 20:54:07 +00:00

489 lines
16 KiB
C#

//#define COSMOSDEBUG
using System;
using Cosmos.Debug.Kernel;
namespace Cosmos.Common
{
public static class StringHelper
{
private static Debugger mDebugger = new Debugger("Common", "StringHelper");
internal enum StringComparisonResultEnum
{
Less = -1,
Equal = 0,
Greater = 1
}
public static string GetNumberString(uint aValue)
{
mDebugger.SendInternal("StringHelper.GetNumberString(uint)");
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
string xResult = string.Empty;
if (aValue == 0)
{
xResult = "0";
}
else
{
uint xValue = aValue;
while (xValue > 0)
{
uint xValue2 = xValue % 10;
xResult = string.Concat(xChars[xValue2], xResult);
xValue /= 10;
}
}
return xResult;
}
public static string GetNumberString(int aValue)
{
mDebugger.SendInternal("StringHelper.GetNumberString(int)");
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
string xResult = string.Empty;
if (aValue == 0)
{
xResult = "0";
}
else
{
int xValue = aValue;
while (xValue != 0)
{
int xValue2 = Math.Abs(xValue % 10);
xResult = string.Concat(xChars[xValue2], xResult);
xValue /= 10;
}
}
if (aValue < 0)
{
xResult = string.Concat("-", xResult);
}
return xResult;
}
public static string GetNumberString(ulong aValue)
{
mDebugger.SendInternal("StringHelper.GetNumberString(ulong)");
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
string xResult = string.Empty;
if (aValue == 0)
{
xResult = "0";
mDebugger.SendInternal("xResult =");
mDebugger.SendInternal(xResult);
}
else
{
ulong xValue = aValue;
mDebugger.SendInternal("xValue =");
mDebugger.SendInternal(xValue);
while (xValue > 0)
{
ulong xValue2 = xValue % 10;
mDebugger.SendInternal("xValue2 =");
mDebugger.SendInternal(xValue2);
xResult = string.Concat(xChars[xValue2], xResult);
mDebugger.SendInternal("xResult =");
mDebugger.SendInternal(xResult);
xValue /= 10;
mDebugger.SendInternal("xValue =");
mDebugger.SendInternal(xValue);
}
}
mDebugger.SendInternal("xResult =");
mDebugger.SendInternal(xResult);
return xResult;
}
public static string GetNumberString(long aValue)
{
mDebugger.SendInternal("StringHelper.GetNumberString(long)");
string[] xChars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
string xResult = string.Empty;
long xValue = aValue;
if (aValue == 0)
{
xResult = "0";
mDebugger.SendInternal("xResult =");
mDebugger.SendInternal(xResult);
}
else
{
if (aValue < 0)
{
xValue *= -1;
}
mDebugger.SendInternal("xValue =");
mDebugger.SendInternal(xValue);
while (xValue > 0)
{
long xValue2 = xValue % 10;
mDebugger.SendInternal("xValue2 =");
mDebugger.SendInternal(xValue2);
xResult = string.Concat(xChars[xValue2], xResult);
mDebugger.SendInternal("xResult =");
mDebugger.SendInternal(xResult);
xValue /= 10;
mDebugger.SendInternal("xValue =");
mDebugger.SendInternal(xValue);
}
}
if (aValue < 0)
{
xResult = string.Concat("-", xResult);
}
mDebugger.SendInternal("xResult =");
mDebugger.SendInternal(xResult);
return xResult;
}
/*
* This implementation could only print values which integer part is < ULONG_MAX, the only solution would have been to use BigInteger but then
* I'd have an analogous problem: to plug BigInteger.ToString() and I don't know how many other things.
* We will retain this code for now it is OK for debug purposes and big value should be printed in scientific notation to be readable anyway...
*/
public static string GetNumberString(float aValue)
{
mDebugger.SendInternal("StringHelper.GetNumberString(float)");
var singleBytes = BitConverter.GetBytes(aValue);
int hexVal = BitConverter.ToInt32(singleBytes, 0);
/* Let's extract the parts that compose our single: sign, exponent and mantissa */
bool isNeg = (hexVal >> 31) != 0;
int exp = ((hexVal >> 23) & 0xFF);
ulong mantissa = (ulong)(hexVal & 0x7FFFFF);
ulong intPart = 0, fracPart = 0;
/* First we handle the special cases INF, NaN, 0 and denormalized float */
switch (exp)
{
/*
* INF or NaN?
*/
case 0xFF:
if (mantissa == 0)
{
if (isNeg)
return "-∞";
else
return "∞";
}
else
/* It could exist -NaN but this is always printed as NaN */
return "NaN";
/* 0 or denormalized float? */
case 0x00:
if (mantissa == 0)
return "0";
/* Denormalized float have always exp -126 */
else
exp = -126;
break;
/* Normalized float the exponent is unbiased and the implicit leading one is placed in the mantissa */
default:
exp -= 127;
mantissa |= 0x800000;
break;
}
if (exp >= 23)
{
intPart = mantissa << (exp - 23);
}
else if (exp >= 0)
{
intPart = mantissa >> (23 - exp);
fracPart = (mantissa << (exp + 1)) & 0xFFFFFF;
}
else
{
fracPart = (mantissa & 0xFFFFFF) >> (-(exp + 1));
}
string result = "";
if (isNeg)
{
result += "-";
}
result += intPart.ToString();
int usedDigits = intPart.ToString().Length;
if (fracPart == 0)
{
return result;
}
result += ".";
if (usedDigits >= 7)
{
usedDigits = 6;
}
for (int m = usedDigits; m < 7; m++)
{
fracPart = (fracPart << 3) + (fracPart << 1);
char p = (char)((fracPart >> 24) + '0');
result += p;
fracPart &= 0xFFFFFF;
}
fracPart = (fracPart << 3) + (fracPart << 1);
char remain = (char)((fracPart >> 24) + '0');
if ((remain > '5') && (result[result.Length - 1] > '0'))
{
char[] answer = result.ToCharArray();
int digitPos = answer.Length - 1;
char digit = result[digitPos];
answer[digitPos] = (char)(digit + 1);
while (answer[digitPos] > '9')
{
answer[digitPos] = '0';
digitPos--;
digit = result[digitPos];
if (digit == '.')
{
digitPos--;
digit = result[digitPos];
}
answer[digitPos] = (char)(digit + 1);
}
result = new string(answer);
}
while (result[result.Length - 1] == '0')
{
result = result.Substring(0, result.Length - 1);
}
return result;
}
/*
* This implementation could only print values which integer part is < ULONG_MAX, the only solution would have been to use BigInteger but then
* I'd have an analogous problem: to plug BigInteger.ToString() and I don't know how many other things.
* We will retain this code for now it is OK for debug purposes and big value should be printed in scientific notation to be readable anyway...
*/
public static string GetNumberString(double aValue)
{
mDebugger.SendInternal("StringHelper.GetNumberString(double)");
mDebugger.SendInternal("aValue = ");
mDebugger.SendInternal(aValue);
long hexVal = BitConverter.DoubleToInt64Bits(aValue);
mDebugger.SendInternal("hexVal = ");
mDebugger.SendInternal(hexVal);
/* Let's extract the parts that compose our double: sign, exponent and mantissa */
bool isNeg = (hexVal >> 63) != 0;
int exp = (int)((hexVal >> 52) & 0x07FF);
ulong mantissa = (ulong)(hexVal & 0x0FFFFFFFFFFFFF);
mDebugger.SendInternal("isNeg = ");
mDebugger.SendInternal(isNeg.ToString());
mDebugger.SendInternal("exp = ");
mDebugger.SendInternal(exp);
mDebugger.SendInternal("mantissa = ");
mDebugger.SendInternal(mantissa);
ulong intPart = 0, fracPart = 0;
/* First we handle the special cases INF, NaN, 0 and denormalized float */
switch (exp)
{
case 0x07ff:
if (mantissa == 0)
{
if (isNeg)
return "-∞";
else
return "∞";
}
else
/* It could exist -NaN but this is always printed as NaN */
return "NaN";
/* 0 or denormalized double? */
case 0x0000:
if (mantissa == 0)
return "0";
/* Denormalized float have always exp -1022 */
else
exp = -1022;
break;
/* Normalized double the exponent is unbiased and the implicit leading one is placed in the mantissa */
default:
exp -= 1023;
mantissa |= 0x10000000000000;
break;
}
if (exp >= 52)
{
intPart = mantissa << (exp - 52);
}
else if (exp >= 0)
{
intPart = mantissa >> (52 - exp);
fracPart = (mantissa << (exp + 1)) & 0x1FFFFFFFFFFFFF;
}
else
{
fracPart = (mantissa & 0x1FFFFFFFFFFFFF) >> (-(exp + 1));
}
string result = "";
if (isNeg)
{
result += "-";
}
result += intPart.ToString();
int usedDigits = result.Length;
if (fracPart == 0)
{
return result;
}
result += ".";
if (usedDigits >= 15)
{
usedDigits = 14;
}
for (int m = usedDigits; m < 15; m++)
{
fracPart = (fracPart << 3) + (fracPart << 1);
char p = (char)(((fracPart >> 53) & 0xFF) + '0');
result += p;
fracPart &= 0x1FFFFFFFFFFFFF;
}
fracPart = (fracPart << 3) + (fracPart << 1);
char remain = (char)((fracPart >> 53) + '0');
if ((remain > '5') && (result[result.Length - 1] > '0'))
{
char[] answer = result.ToCharArray();
int digitPos = answer.Length - 1;
char digit = result[digitPos];
answer[digitPos] = (char)(digit + 1);
while (answer[digitPos] > '9')
{
answer[digitPos] = '0';
digitPos--;
digit = result[digitPos];
if (digit == '.')
{
digitPos--;
digit = result[digitPos];
}
answer[digitPos] = (char)(digit + 1);
}
result = new string(answer);
}
while (result[result.Length - 1] == '0')
{
result = result.Substring(0, result.Length - 1);
}
return result;
}
public static int GetStringToNumber(string aString)
{
bool xIsNegative = false;
int xNumber = 0;
if (!string.IsNullOrWhiteSpace(aString))
{
char[] xCharArray = aString.ToCharArray();
for (int i = 0; i < xCharArray.Length; i++)
{
if (char.IsDigit(xCharArray[i]))
{
int xValue = xCharArray[i] - '0';
int xMax = xCharArray.Length - 1;
for (int j = 0; j < xMax - i; i++)
{
xValue *= 10;
}
xNumber += xValue;
}
else if (xCharArray[i] == '-')
{
xIsNegative = true;
}
else if (xCharArray[i] == '.')
{
break;
}
else
{
throw new FormatException("The string parameter is not a number and is invalid.");
}
}
}
if (xIsNegative)
{
xNumber *= -1;
}
return xNumber;
}
public static int Compare(string aString1, int aIndex1, string aString2, int aIndex2, int aLength1, int aLength2)
{
if (aString1.Length < aString2.Length)
{
return (int)StringComparisonResultEnum.Less;
}
if (aString1.Length > aString2.Length)
{
return (int)StringComparisonResultEnum.Greater;
}
for (int i = aString1.Length; i < aString1.Length; i++)
{
if (aString1[i] < aString2[i])
{
return (int)StringComparisonResultEnum.Equal;
}
if (aString1[i] > aString2[i])
{
return (int)StringComparisonResultEnum.Greater;
}
}
return (int)StringComparisonResultEnum.Equal;
}
}
}