DWC.Algorithms.NumberUtilities
/*
Copyright (c) 2004 DigiTec Web Consultants, LLC. All rights reserved.
The use of this software is for test and performance purposes only.
You may not use this software in any commercial applications without
the express permission of the copyright holder. You may add to or
modify the code contained here-in to cause it to run slower without
contacting the copyright holder, however, any attempts to make this
code run faster should be documented on:
http://weblogs.asp.net/justin_rogers/articles/104504.aspx
I reserve the right to change or modify the publicly available version
of this code at any time. I will not provide version protection, so
if you have reliance on a particular build of this software, then make
your own back-ups.
You must laugh, at least a little, when reading this licensing agreement,
unless of course you don't have a sense of humor. In all seriousness,
excluding the laughter, laughter in itself does not void this license
agreement, nor compromise it's ability to legally bind you.
You must not remove this notice, or any other, from this software.
*/
/*
I hate those things, but you have to have them. Here is the documentation:
DWC.Algorithms.NumberUtilities - This is where i'm hosting the best of the
best in terms of performance for parsing strings to integers.
DWC.Algorithms.NumberUtilitiesDeprecated - Everyone wants a piece of this
pie, so I'm including examination of as many algorithms as possible. These
are all algorithms that work, but don't make the cut.
Community - This is where I'll host code that I haven't reformated and have
copy/pasted directly from the community. This code can be sloppy, not work,
or kick the pants off of the currently accepted algorithm. They will
remain parked here until they can either replace an accepted algorithm and
have gone through a full sanity check pass, or they simply need to stay
for historical correctness of the testing and performance procedures.
ExecutableContent_TestClassRunner - When you compile this guy as an executable
you probably want some numbers. I'm including some of my test cases so you
can see what I'm using to get numbers. In general, as long as you don't change
methods between testing two methods you should get results that can easily be
compared. Issues with the GC can often compromise good test results, but I've
taken the liberty of trying to remove as many GC hiccups, burps, and coughs as
possible.
Test Builds:
csc /t:exe /unsafe /optimize+ {source}
Test Library:
csc /t:library /unsafe /optimize+ {source}
Release Builds:
// Remove the NumberUtilitiesDeprecated class
// Remove the Community class
csc /t:exe /optimize+ {source}
Release Library:
// Remove the NumberUtilitiesDeprecated class
// Remove the Community class
// Remove the ExecutableContent_TestClassRunner class
csc /t:library /optimize+ {source}
*/
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using DWC.Algorithms;
namespace DWC.Algorithms {
public sealed class NumberUtilities {
private const sbyte d1 = 1;
private const sbyte d2 = 10;
private const sbyte d3 = 100;
private const short d4 = 1000;
private const short d5 = 10000;
private const int d6 = 100000;
private const int d7 = 1000000;
private const int d8 = 10000000;
private const int d9 = 100000000;
private const int d10 = 1000000000;
private const long d11 = 10000000000;
private const long d12 = 100000000000;
private const long d13 = 1000000000000;
private const long d14 = 10000000000000;
private const long d15 = 100000000000000;
private const long d16 = 1000000000000000;
private const long d17 = 10000000000000000;
private const long d18 = 100000000000000000;
private const long d19 = 1000000000000000000;
public static readonly int SByteAllowableChars = (int) Math.Ceiling(Math.Log10(SByte.MaxValue));
public static readonly int ByteAllowableChars = (int) Math.Ceiling(Math.Log10(Byte.MaxValue));
public static readonly int Int16AllowableChars = (int) Math.Ceiling(Math.Log10(Int16.MaxValue));
public static readonly int UInt16AllowableChars = (int) Math.Ceiling(Math.Log10(UInt16.MaxValue));
public static readonly int Int32AllowableChars = (int) Math.Ceiling(Math.Log10(Int32.MaxValue));
public static readonly int UInt32AllowableChars = (int) Math.Ceiling(Math.Log10(UInt32.MaxValue));
#region Upgrade these to CLR types
public static readonly int longAllowableChars = (int) Math.Ceiling(Math.Log10(Int64.MaxValue));
#endregion
public static readonly int ByteLastChar = (int) Byte.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int SByteLastChar = (int) SByte.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int shortLastCharPos = (int) Int16.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int shortLastCharNeg = (int) Int16.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int intLastCharPos = (int) Int32.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int intLastCharNeg = (int) Int32.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int longLastCharPos = (int) Int64.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int longLastCharNeg = (int) Int64.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int maxAllowableChars = Int32AllowableChars;
public static readonly int maxLastCharPos = intLastCharPos;
public static readonly int maxLastCharNeg = intLastCharNeg;
private NumberUtilities() {
}
public static bool TryParseByte(string integer, out Byte value) {
int range = integer.Length;
int parseBegin = range - 1;
value = 0;
if ( range > ByteAllowableChars || range == 0 ) {
return false;
}
if ( parseBegin >= 0 ) {
ushort accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (Byte) (accumulator * d1);
if ( parseBegin >= 0 ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (Byte) (accumulator * d2);
if ( parseBegin >= 0 ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > ByteLastChar ) { return false; }
Byte preValue = value;
value += (Byte) (accumulator * d3);
if ( preValue > value ) {
return false;
}
}
}
}
return true;
}
public static bool TryParseSByte(string integer, bool allowneg, out SByte value) {
int range = integer.Length;
int parseEnd = 0;
int parseBegin = range - 1;
value = 0;
if ( range > 0 && integer[0] == '-' ) {
if ( !allowneg ) {
return false;
}
parseEnd++;
range--;
}
if ( range > SByteAllowableChars || range == 0 ) {
return false;
}
if ( parseBegin >= parseEnd ) {
ushort accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (SByte) (accumulator * d1);
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (SByte) (accumulator * d2);
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > SByteLastChar ) { return false; }
value += (SByte) (accumulator * d3);
}
}
}
if ( value == SByte.MinValue ) {
// Do nothing, we wrapped and this is a negative
// number anyway. This only happens when you
// specify a negative value of size MinValue
// within the string
} else if ( value < 0 ) {
// We overflowed! This'll happen if you specify
// an integer value too large that isn't actually
// a negative value of size MinValue
return false;
} else if (parseEnd == 1) {
value = (SByte) (-value); // invert to negative
}
return true;
}
public static bool TryParseInt16(string integer, bool allowneg, out Int16 value) {
int range = integer.Length;
int parseEnd = 0;
int parseBegin = range - 1;
value = 0;
if ( range > 0 && integer[0] == '-' ) {
if ( !allowneg ) {
return false;
}
parseEnd++;
range--;
}
if ( range > Int16AllowableChars || range == 0 ) {
return false;
}
if ( parseBegin >= parseEnd ) {
ushort accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) (accumulator * d1);
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) (accumulator * d2);
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) (accumulator * d3);
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) (accumulator * d4);
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > shortLastCharNeg ) { return false; }
value += (short) (accumulator * d5);
}
}
}
}
}
if ( value == Int16.MinValue ) {
// Do nothing, we wrapped and this is a negative
// number anyway. This only happens when you
// specify a negative value of size MinValue
// within the string
} else if ( value < 0 ) {
// We overflowed! This'll happen if you specify
// an integer value too large that isn't actually
// a negative value of size MinValue
return false;
} else if (parseEnd == 1) {
value = (short) -value; // invert to negative
}
return true;
}
public static bool TryParseInt32(string integer, bool allowneg, out Int32 value) {
int range = integer.Length;
int parseEnd = 0;
int parseBegin = range - 1;
value = 0;
if ( range > 0 && integer[0] == '-' ) {
if ( !allowneg ) {
return false;
}
parseEnd++;
range--;
}
if ( range > Int32AllowableChars || range == 0 ) {
return false;
}
/* METHOD 1... This is actually pretty good
ushort accumulator1 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator2 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator3 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator4 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator5 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator6 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator7 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator8 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator9 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
ushort accumulator10 = (parseBegin >= parseEnd) ? (ushort) (integer[parseBegin--] - '0') : (ushort) 0;
if (
accumulator1 > 9 ||
accumulator2 > 9 ||
accumulator3 > 9 ||
accumulator4 > 9 ||
accumulator5 > 9 ||
accumulator6 > 9 ||
accumulator7 > 9 ||
accumulator8 > 9 ||
accumulator9 > 9 ||
accumulator10 > 9 ){
return false;
}
*/
/* METHOD 2... This is faster than 1 so far
ushort accumulator1 = 0;
ushort accumulator2 = 0;
ushort accumulator3 = 0;
ushort accumulator4 = 0;
ushort accumulator5 = 0;
ushort accumulator6 = 0;
ushort accumulator7 = 0;
ushort accumulator8 = 0;
ushort accumulator9 = 0;
ushort accumulator10 = 0;
if ( parseBegin >= parseEnd ) {
accumulator1 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator1 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator2 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator2 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator3 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator3 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator4 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator4 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator5 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator5 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator6 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator6 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator7 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator7 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator8 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator8 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator9 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator9 > 9 ) { return false; }
if ( parseBegin >= parseEnd ) {
accumulator10 = (ushort) (integer[parseBegin--] - '0');
if ( accumulator10 > 9 ) { return false; }
}
}
}
}
}
}
}
}
}
}
// Process the last character with overflow protection
if ( range == maxAllowableChars ) {
if ( parseEnd == 1 && accumulator10 > maxLastCharNeg ) {
return false;
} else {
if ( accumulator10 > maxLastCharPos ) {
return false;
}
}
// A small perf increase to get rid of 1 of our
// mults
value = accumulator10 * d10;
}
value +=
accumulator1 * d1 +
accumulator2 * d2 +
accumulator3 * d3 +
accumulator4 * d4 +
accumulator5 * d5 +
accumulator6 * d6 +
accumulator7 * d7 +
accumulator8 * d8 +
accumulator9 * d9;
*/
/* METHOD 3... Probably the fastest, but oh so ugly */
if ( parseBegin >= parseEnd ) {
ushort accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d1;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d2;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d3;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d4;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d5;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d6;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d7;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d8;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += accumulator * d9;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > maxLastCharNeg ) { return false; }
value += accumulator * d10;
}
}
}
}
}
}
}
}
}
}
if ( value == Int32.MinValue ) {
// Do nothing, we wrapped and this is a negative
// number anyway. This only happens when you
// specify a negative value of size MinValue
// within the string
} else if ( value < 0 ) {
// We overflowed! This'll happen if you specify
// an integer value too large that isn't actually
// a negative value of size MinValue
return false;
} else if (parseEnd == 1) {
value = -value; // invert to negative
}
return true;
}
}
public unsafe sealed class NumberUtilitiesDeprecated {
private static readonly long[,] preMultiplied2D = new long[,]
{
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
{0, 10, 20, 30, 40, 50, 60, 70, 80, 90},
{0, 100, 200, 300, 400, 500, 600, 700, 800, 900},
{0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000},
{0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000}
};
private static readonly long[] preMultiplied1D = new long[]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 10, 20, 30, 40, 50, 60, 70, 80, 90,
0, 100, 200, 300, 400, 500, 600, 700, 800, 900,
0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000,
0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000
};
private static GCHandle preMultiplied1DGCHandle;
private static long* preMultiplied1DPointer;
private static readonly ushort[] Int16Max = new ushort[] { 9, 9, 9, 9, 3 };
private static GCHandle Int16MaxGCHandle;
private static ushort* Int16MaxPointer;
public static readonly int SByteAllowableChars = (int) Math.Ceiling(Math.Log10(SByte.MaxValue));
public static readonly int ByteAllowableChars = (int) Math.Ceiling(Math.Log10(Byte.MaxValue));
public static readonly int Int16AllowableChars = (int) Math.Ceiling(Math.Log10(Int16.MaxValue));
public static readonly int UInt16AllowableChars = (int) Math.Ceiling(Math.Log10(UInt16.MaxValue));
#region Upgrade these to CLR types
public static readonly int intAllowableChars = (int) Math.Ceiling(Math.Log10(Int32.MaxValue));
public static readonly int longAllowableChars = (int) Math.Ceiling(Math.Log10(Int64.MaxValue));
#endregion
public static readonly int ByteLastChar = (int) Byte.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int SByteLastChar = (int) SByte.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int shortLastCharPos = (int) Int16.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int shortLastCharNeg = (int) Int16.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int intLastCharPos = (int) Int32.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int intLastCharNeg = (int) Int32.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int longLastCharPos = (int) Int64.MaxValue.ToString(CultureInfo.InvariantCulture)[0] - '0';
public static readonly int longLastCharNeg = (int) Int64.MinValue.ToString(CultureInfo.InvariantCulture)[1] - '0';
public static readonly int maxAllowableChars = intAllowableChars;
public static readonly int maxLastCharPos = intLastCharPos;
public static readonly int maxLastCharNeg = intLastCharNeg;
static NumberUtilitiesDeprecated() {
/* Used by TryParseIn16_Elegance Method 1 */
preMultiplied1DGCHandle = GCHandle.Alloc(preMultiplied1D, GCHandleType.Pinned);
preMultiplied1DPointer = (long*) Marshal.UnsafeAddrOfPinnedArrayElement(preMultiplied1D, 0);
Int16MaxGCHandle = GCHandle.Alloc(Int16Max, GCHandleType.Pinned);
Int16MaxPointer = (ushort*) Marshal.UnsafeAddrOfPinnedArrayElement(Int16Max, 0);
}
public static bool TryParseInt(string integer, bool allowneg, out int value) {
int parseEnd = 0;
int parseBegin = integer.Length - 1;
int range = parseBegin - parseEnd + 1;
int mult = 1; value = 0;
if ( range > 0 && integer[0] == '-' ) {
if ( !allowneg ) {
return false;
}
parseEnd++;
range = parseBegin - parseEnd + 1;
}
if ( range > maxAllowableChars || range == 0 ) {
return false;
} else if ( range == maxAllowableChars ) {
parseEnd++;
}
for(int i = parseBegin; i >= parseEnd; i--) {
int val = (int) (integer[i] - '0');
switch(val) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
value += val * mult;
mult *= 10;
break;
default:
return false;
}
}
// Process the last character with overflow protection
if ( range == maxAllowableChars ) {
int val = (int) (integer[parseEnd-1] - '0');
// Pos testing
if ( parseEnd == 1 && val > maxLastCharPos ) {
return false;
} else {
// Neg testing
if ( parseEnd == 2 && val > maxLastCharNeg ) {
return false;
}
}
value += val * mult;
}
if ( value == Int32.MinValue ) {
// Do nothing, we wrapped and this is a negative
// number anyway. This only happens when you
// specify a negative value of size MinValue
// within the string
} else if ( value < 0 ) {
// We overflowed! This'll happen if you specify
// an integer value too large that isn't actually
// a negative value of size MinValue
return false;
} else if (parseEnd == 1 || (range == maxAllowableChars && parseEnd == 2)) {
value = -value; // invert to negative
}
return true;
}
public static unsafe bool TryParseInt16_Elegance(string integer, bool allowneg, out Int16 value) {
int range = integer.Length;
fixed(char* intString = integer) {
char* parseEnd = intString;
char* parseBegin = intString + range - 1;
value = 0;
if ( range > 0 && *parseEnd == '-' ) {
if ( !allowneg ) {
return false;
}
parseEnd++;
range--;;
}
if ( range > Int16AllowableChars || range == 0 ) {
return false;
}
long* basedvalue = preMultiplied1DPointer;
ushort* validator = Int16MaxPointer;
while(parseBegin >= parseEnd) {
ushort accumulator = (ushort) (*parseBegin-- - '0');
if ( accumulator > *validator++ ) { return false; }
value += (short) *(basedvalue+accumulator);
basedvalue+=10;
}
}
/* Method 2, note we don't use the preCalced GC Pins here
fixed(long* a = preMultiplied1D) {
fixed(ushort* b = Int16Max) {
long* basedvalue = a;
ushort* validator = b;
while(parseBegin >= parseEnd) {
ushort accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > *validator++ ) { return false; }
value += (short) *(basedvalue+accumulator);
basedvalue+=10;
}
}
}
*/
if ( value == Int16.MinValue ) {
// Do nothing, we wrapped and this is a negative
// number anyway. This only happens when you
// specify a negative value of size MinValue
// within the string
} else if ( value < 0 ) {
// We overflowed! This'll happen if you specify
// an integer value too large that isn't actually
// a negative value of size MinValue
return false;
} else if (range < integer.Length) {
value = (short) -value; // invert to negative
}
return true;
}
public static bool TryParseInt16_UseArray(string integer, bool allowneg, out Int16 value) {
int parseEnd = 0;
int parseBegin = integer.Length - 1;
int range = parseBegin - parseEnd + 1;
value = 0;
if ( range > 0 && integer[0] == '-' ) {
if ( !allowneg ) {
return false;
}
parseEnd++;
range = parseBegin - parseEnd + 1;
}
if ( range > Int16AllowableChars || range == 0 ) {
return false;
}
int x = 0;
if ( parseBegin >= parseEnd ) {
ushort accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) preMultiplied1D[x + accumulator];
x+= 10;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) preMultiplied1D[x + accumulator];
x+= 10;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) preMultiplied1D[x + accumulator];
x+= 10;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > 9 ) { return false; }
value += (short) preMultiplied1D[x + accumulator];
x+= 10;
if ( parseBegin >= parseEnd ) {
accumulator = (ushort) (integer[parseBegin--] - '0');
if ( accumulator > shortLastCharNeg ) { return false; }
value += (short) preMultiplied1D[x + accumulator];
}
}
}
}
}
if ( value == Int16.MinValue ) {
// Do nothing, we wrapped and this is a negative
// number anyway. This only happens when you
// specify a negative value of size MinValue
// within the string
} else if ( value < 0 ) {
// We overflowed! This'll happen if you specify
// an integer value too large that isn't actually
// a negative value of size MinValue
return false;
} else if (parseEnd == 1) {
value = (short) -value; // invert to negative
}
return true;
}
}
}
public class ExecutableContent_TestClassRunner {
private static void SanityCheck(bool fullCheckLight, bool fullCheckHeavy) {
Byte retValByte;
SByte retValSByte;
Int16 retValInt16;
UInt16 retValUInt16;
Int32 retValInt32;
UInt32 retValUInt32;
bool passFullCheck = true;
bool[] expectedOutputSigned = new bool[] {
false, false, false, /* Wrapping test */
true, true, true, true, /* Min/Max tests */
false, false, false, /* Extra large negatives */
true, true, true, true, true, true /* Within range negatives */
};
bool[] expectedOutputUnsigned = new bool[] {
false, false, false, /* Wrapping test */
true, true, true, true, /* Min/Max tests */
true, true, true, true, true, true /* Within range negatives */
};
Console.WriteLine("*** Community.TryParseInt32 ***");
Console.WriteLine(Community.TryParseInt("9999999999", out retValInt32));
Console.WriteLine(Community.TryParseInt("8888888888", out retValInt32));
Console.WriteLine(Community.TryParseInt("7777777777", out retValInt32));
Console.WriteLine(Community.TryParseInt(Int32.MaxValue.ToString(), out retValInt32));
Console.WriteLine(retValInt32 == Int32.MaxValue);
Console.WriteLine(Community.TryParseInt(Int32.MinValue.ToString(), out retValInt32));
Console.WriteLine(retValInt32 == Int32.MinValue);
Console.WriteLine(Community.TryParseInt("-7777777777", out retValInt32));
Console.WriteLine(Community.TryParseInt("-8888888888", out retValInt32));
Console.WriteLine(Community.TryParseInt("-9999999999", out retValInt32));
Console.WriteLine(Community.TryParseInt("-999999999", out retValInt32));
Console.WriteLine(retValInt32 == -999999999);
Console.WriteLine(Community.TryParseInt("-99999999", out retValInt32));
Console.WriteLine(retValInt32 == -99999999);
Console.WriteLine(Community.TryParseInt("-9999999", out retValInt32));
Console.WriteLine(retValInt32 == -9999999);
Console.WriteLine("*** TryParseByte ***");
Console.WriteLine(NumberUtilities.TryParseByte("999", out retValByte));
Console.WriteLine(NumberUtilities.TryParseByte("888", out retValByte));
Console.WriteLine(NumberUtilities.TryParseByte("777", out retValByte));
Console.WriteLine(NumberUtilities.TryParseByte(Byte.MaxValue.ToString(), out retValByte));
Console.WriteLine(retValByte == Byte.MaxValue);
Console.WriteLine(NumberUtilities.TryParseByte(Byte.MinValue.ToString(), out retValByte));
Console.WriteLine(retValByte == Byte.MinValue);
Console.WriteLine(NumberUtilities.TryParseByte("-777", out retValByte));
Console.WriteLine(NumberUtilities.TryParseByte("-888", out retValByte));
Console.WriteLine(NumberUtilities.TryParseByte("-999", out retValByte));
passFullCheck = true;
for(int i = Byte.MinValue; i <= Byte.MaxValue; i++) {
if ( !NumberUtilities.TryParseByte(i.ToString(), out retValByte) ) {
passFullCheck = false;
} else {
if ( i != retValByte ) {
passFullCheck = false;
}
}
}
Console.WriteLine("Pass Full Check: {0}", passFullCheck);
Console.WriteLine("*** TryParseSByte ***");
Console.WriteLine(NumberUtilities.TryParseSByte("999", true, out retValSByte));
Console.WriteLine(NumberUtilities.TryParseSByte("888", true, out retValSByte));
Console.WriteLine(NumberUtilities.TryParseSByte("777", true, out retValSByte));
Console.WriteLine(NumberUtilities.TryParseSByte(SByte.MaxValue.ToString(), true, out retValSByte));
Console.WriteLine(retValSByte == SByte.MaxValue);
Console.WriteLine(NumberUtilities.TryParseSByte(SByte.MinValue.ToString(), true, out retValSByte));
Console.WriteLine(retValSByte == SByte.MinValue);
Console.WriteLine(NumberUtilities.TryParseSByte("-777", true, out retValSByte));
Console.WriteLine(NumberUtilities.TryParseSByte("-888", true, out retValSByte));
Console.WriteLine(NumberUtilities.TryParseSByte("-999", true, out retValSByte));
Console.WriteLine(NumberUtilities.TryParseSByte("-99", true, out retValSByte));
Console.WriteLine(retValSByte == -99);
Console.WriteLine(NumberUtilities.TryParseSByte("-99", true, out retValSByte));
Console.WriteLine(retValSByte == -99);
Console.WriteLine(NumberUtilities.TryParseSByte("-9", true, out retValSByte));
Console.WriteLine(retValSByte == -9);
passFullCheck = true;
for(int i = SByte.MinValue; i <= SByte.MaxValue; i++) {
if ( !NumberUtilities.TryParseSByte(i.ToString(), true, out retValSByte) ) {
passFullCheck = false;
} else {
if ( i != retValSByte ) {
passFullCheck = false;
}
}
}
Console.WriteLine("Pass Full Check: {0}", passFullCheck);
Console.WriteLine("*** TryParseInt16 ***");
Console.WriteLine(NumberUtilities.TryParseInt16("99999", true, out retValInt16));
Console.WriteLine(NumberUtilities.TryParseInt16("88888", true, out retValInt16));
Console.WriteLine(NumberUtilities.TryParseInt16("77777", true, out retValInt16));
Console.WriteLine(NumberUtilities.TryParseInt16(Int16.MaxValue.ToString(), true, out retValInt16));
Console.WriteLine(retValInt16 == Int16.MaxValue);
Console.WriteLine(NumberUtilities.TryParseInt16(Int16.MinValue.ToString(), true, out retValInt16));
Console.WriteLine(retValInt16 == Int16.MinValue);
Console.WriteLine(NumberUtilities.TryParseInt16("-77777", true, out retValInt16));
Console.WriteLine(NumberUtilities.TryParseInt16("-88888", true, out retValInt16));
Console.WriteLine(NumberUtilities.TryParseInt16("-99999", true, out retValInt16));
Console.WriteLine(NumberUtilities.TryParseInt16("-9999", true, out retValInt16));
Console.WriteLine(retValInt16 == -9999);
Console.WriteLine(NumberUtilities.TryParseInt16("-999", true, out retValInt16));
Console.WriteLine(retValInt16 == -999);
Console.WriteLine(NumberUtilities.TryParseInt16("-99", true, out retValInt16));
Console.WriteLine(retValInt16 == -99);
Console.WriteLine("*** TryParseInt16_Elegance ***");
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("99999", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("88888", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("77777", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance(Int16.MaxValue.ToString(), true, out retValInt16));
Console.WriteLine(retValInt16 == Int16.MaxValue);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance(Int16.MinValue.ToString(), true, out retValInt16));
Console.WriteLine(retValInt16 == Int16.MinValue);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("-77777", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("-88888", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("-99999", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("-9999", true, out retValInt16));
Console.WriteLine(retValInt16 == -9999);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("-999", true, out retValInt16));
Console.WriteLine(retValInt16 == -999);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_Elegance("-99", true, out retValInt16));
Console.WriteLine(retValInt16 == -99);
Console.WriteLine("*** TryParseInt16_UseArray ***");
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("99999", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("88888", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("77777", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray(Int16.MaxValue.ToString(), true, out retValInt16));
Console.WriteLine(retValInt16 == Int16.MaxValue);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray(Int16.MinValue.ToString(), true, out retValInt16));
Console.WriteLine(retValInt16 == Int16.MinValue);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("-77777", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("-88888", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("-99999", true, out retValInt16));
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("-9999", true, out retValInt16));
Console.WriteLine(retValInt16 == -9999);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("-999", true, out retValInt16));
Console.WriteLine(retValInt16 == -999);
Console.WriteLine(NumberUtilitiesDeprecated.TryParseInt16_UseArray("-99", true, out retValInt16));
Console.WriteLine(retValInt16 == -99);
Console.WriteLine("*** TryParseInt32 ***");
Console.WriteLine(NumberUtilities.TryParseInt32("9999999999", true, out retValInt32));
Console.WriteLine(NumberUtilities.TryParseInt32("8888888888", true, out retValInt32));
Console.WriteLine(NumberUtilities.TryParseInt32("7777777777", true, out retValInt32));
Console.WriteLine(NumberUtilities.TryParseInt32(Int32.MaxValue.ToString(), true, out retValInt32));
Console.WriteLine(retValInt32 == Int32.MaxValue);
Console.WriteLine(NumberUtilities.TryParseInt32(Int32.MinValue.ToString(), true, out retValInt32));
Console.WriteLine(retValInt32 == Int32.MinValue);
Console.WriteLine(NumberUtilities.TryParseInt32("-7777777777", true, out retValInt32));
Console.WriteLine(NumberUtilities.TryParseInt32("-8888888888", true, out retValInt32));
Console.WriteLine(NumberUtilities.TryParseInt32("-9999999999", true, out retValInt32));
Console.WriteLine(NumberUtilities.TryParseInt32("-999999999", true, out retValInt32));
Console.WriteLine(retValInt32 == -999999999);
Console.WriteLine(NumberUtilities.TryParseInt32("-99999999", true, out retValInt32));
Console.WriteLine(retValInt32 == -99999999);
Console.WriteLine(NumberUtilities.TryParseInt32("-9999999", true, out retValInt32));
Console.WriteLine(retValInt32 == -9999999);
}
private static void Main(string[] args) {
SanityCheck(true, false);
SpeedCheckInt16();
SpeedCheckInt32();
}
private static void SpeedCheckInt16() {
short retVal;
int startRange = Int16.MinValue;
int endRange = Int16.MaxValue;
long range = endRange - startRange;
string[] strings = new string[range];
DateTime start, end;
Console.WriteLine("Preallocate strings");
for(int i = 0; i < range; i++) {
strings[i] = (i + startRange).ToString();
}
Console.WriteLine("Preallocation complete");
start = DateTime.Now;
for(int loop = 0; loop < 500; loop++) {
for(int i = 0; i < range; i++) {
string tryParse = strings[i];
if ( NumberUtilities.TryParseInt16(tryParse, true, out retVal) ) {
if ( (i+startRange) != retVal ) {
Console.WriteLine("Equality failure in TryParseInt16: {0}, {1}", i, retVal);
return;
}
} else {
Console.WriteLine("Processing failure {0}", i);
return;
}
}
}
end = DateTime.Now;
Console.WriteLine("TryParseInt16: {0}", end - start);
start = DateTime.Now;
for(int loop = 0; loop < 500; loop++) {
for(int i = 0; i < range; i++) {
string tryParse = strings[i];
if ( NumberUtilitiesDeprecated.TryParseInt16_Elegance(tryParse, true, out retVal) ) {
if ( (i+startRange) != retVal ) {
Console.WriteLine("Equality failure in TryParseInt16_Elegance: {0}, {1}", i, retVal);
return;
}
} else {
Console.WriteLine("Processing failure {0}", i);
return;
}
}
}
end = DateTime.Now;
Console.WriteLine("TryParseInt16_Elegance: {0}", end - start);
start = DateTime.Now;
for(int loop = 0; loop < 500; loop++) {
for(int i = 0; i < range; i++) {
string tryParse = strings[i];
if ( NumberUtilitiesDeprecated.TryParseInt16_UseArray(tryParse, true, out retVal) ) {
if ( (i+startRange) != retVal ) {
Console.WriteLine("Equality failure in TryParseInt16_UseArray: {0}, {1}", i, retVal);
return;
}
} else {
Console.WriteLine("Processing failure {0}", i);
return;
}
}
}
end = DateTime.Now;
Console.WriteLine("TryParseInt16_UseArray: {0}", end - start);
}
private static void SpeedCheckInt32() {<