diff --git a/BeefLibs/corlib/src/Int.bf b/BeefLibs/corlib/src/Int.bf index 722e85e3..1a782fce 100644 --- a/BeefLibs/corlib/src/Int.bf +++ b/BeefLibs/corlib/src/Int.bf @@ -9,11 +9,12 @@ namespace System { case Ok; case NoValue; + case Overflow; case InvalidChar(int partialResult); } - public const int MaxValue = (sizeof(uint) == 8) ? 0x7FFFFFFFFFFFFFFFL : 0x7FFFFFFF; - public const int MinValue = (sizeof(uint) == 8) ? -0x8000000000000000L : -0x80000000; + public const int MaxValue = (sizeof(int) == 8) ? 0x7FFFFFFFFFFFFFFFL : 0x7FFFFFFF; + public const int MinValue = (sizeof(int) == 8) ? -0x8000000000000000L : -0x80000000; public static int operator<=>(Self a, Self b) { diff --git a/BeefLibs/corlib/src/Int16.bf b/BeefLibs/corlib/src/Int16.bf index bf61bf4c..7dc7c352 100644 --- a/BeefLibs/corlib/src/Int16.bf +++ b/BeefLibs/corlib/src/Int16.bf @@ -1,10 +1,20 @@ +using System.Globalization; + namespace System { #unwarn struct Int16 : int16, IInteger, ISigned, IHashable, IFormattable, IIsNaN { - public const int32 MaxValue = 0x7FFF; - public const int32 MinValue = -0x8000; + public enum ParseError + { + case Ok; + case NoValue; + case Overflow; + case InvalidChar(int16 partialResult); + } + + public const int16 MaxValue = 0x7FFF; + public const int16 MinValue = -0x8000; public static int operator<=>(Self a, Self b) { @@ -66,5 +76,68 @@ namespace System NumberFormatter.NumberToString(format, (int32)this, formatProvider, outString); } } + + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) + { + if (val.IsEmpty) + return .Err(.NoValue); + + bool isNeg = false; + int16 result = 0; + + int16 radix = style.HasFlag(.AllowHexSpecifier) ? 0x10 : 10; + + for (int32 i = 0; i < val.Length; i++) + { + char8 c = val[i]; + + if ((i == 0) && (c == '-')) + { + isNeg = true; + continue; + } + + if ((c >= '0') && (c <= '9')) + { + result &*= radix; + result &+= (int16)(c - '0'); + } + else if ((c >= 'a') && (c <= 'f')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= c - 'a' + 10; + } + else if ((c >= 'A') && (c <= 'F')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= c - 'A' + 10; + } + else if ((c == 'X') || (c == 'x')) + { + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) + return .Err(.InvalidChar(result)); + radix = 0x10; + } + else if (c == '\'') + { + // Ignore + } + else if ((c == '+') && (i == 0)) + { + // Ignore + } + else + return .Err(.InvalidChar(result)); + + if (isNeg ? (uint16)result > (uint16)MinValue : (uint16)result > (uint16)MaxValue) + return .Err(.Overflow); + } + + return isNeg ? -result : result; + } } } diff --git a/BeefLibs/corlib/src/Int32.bf b/BeefLibs/corlib/src/Int32.bf index b036f7a2..2cb54301 100644 --- a/BeefLibs/corlib/src/Int32.bf +++ b/BeefLibs/corlib/src/Int32.bf @@ -9,6 +9,7 @@ namespace System { case Ok; case NoValue; + case Overflow; case InvalidChar(int32 partialResult); } @@ -125,7 +126,7 @@ namespace System } } - public static Result Parse(StringView val, NumberStyles style) + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) { if (val.IsEmpty) return .Err(.NoValue); @@ -147,26 +148,26 @@ namespace System if ((c >= '0') && (c <= '9')) { - result *= radix; - result += (int32)(c - '0'); + result &*= radix; + result &+= (int32)(c - '0'); } else if ((c >= 'a') && (c <= 'f')) { if (radix != 0x10) return .Err(.InvalidChar(result)); - result *= radix; - result += c - 'a' + 10; + result &*= radix; + result &+= c - 'a' + 10; } else if ((c >= 'A') && (c <= 'F')) { if (radix != 0x10) return .Err(.InvalidChar(result)); - result *= radix; - result += c - 'A' + 10; + result &*= radix; + result &+= c - 'A' + 10; } else if ((c == 'X') || (c == 'x')) { - if (result != 0) + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) return .Err(.InvalidChar(result)); radix = 0x10; } @@ -180,14 +181,12 @@ namespace System } else return .Err(.InvalidChar(result)); + + if (isNeg ? (uint32)result > (uint32)MinValue : (uint32)result > (uint32)MaxValue) + return .Err(.Overflow); } return isNeg ? -result : result; } - - public static Result Parse(StringView val) - { - return Parse(val, .Any); - } } } diff --git a/BeefLibs/corlib/src/Int64.bf b/BeefLibs/corlib/src/Int64.bf index 4ad00bf7..b40c75c2 100644 --- a/BeefLibs/corlib/src/Int64.bf +++ b/BeefLibs/corlib/src/Int64.bf @@ -9,6 +9,7 @@ namespace System { case Ok; case NoValue; + case Overflow; case InvalidChar(int64 partialResult); } @@ -104,7 +105,7 @@ namespace System strBuffer.Append(char8Ptr); } - public static Result Parse(StringView val, NumberStyles style) + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) { //TODO: Use Number.ParseNumber @@ -128,22 +129,26 @@ namespace System if ((c >= '0') && (c <= '9')) { - result *= radix; - result += (int32)(c - '0'); + result &*= radix; + result &+= (int64)(c - '0'); } else if ((c >= 'a') && (c <= 'f')) { - result *= radix; - result += c - 'a' + 10; + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= c - 'a' + 10; } else if ((c >= 'A') && (c <= 'F')) { - result *= radix; - result += c - 'A' + 10; + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= c - 'A' + 10; } else if ((c == 'X') || (c == 'x')) { - if (result != 0) + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) return .Err(.InvalidChar(result)); radix = 0x10; } @@ -157,14 +162,12 @@ namespace System } else return .Err(.InvalidChar(result)); + + if (isNeg ? (uint64)result > (uint64)MinValue : (uint64)result > (uint64)MaxValue) + return .Err(.Overflow); } return isNeg ? -result : result; } - - public static Result Parse(StringView val) - { - return Parse(val, .Any); - } } } diff --git a/BeefLibs/corlib/src/Int8.bf b/BeefLibs/corlib/src/Int8.bf index 5305b6bc..57f900ea 100644 --- a/BeefLibs/corlib/src/Int8.bf +++ b/BeefLibs/corlib/src/Int8.bf @@ -1,10 +1,20 @@ +using System.Globalization; + namespace System { #unwarn struct Int8 : int8, IInteger, ISigned, IHashable, IFormattable, IIsNaN { - public const int32 MaxValue = 0x7F; - public const int32 MinValue = -0x80; + public enum ParseError + { + case Ok; + case NoValue; + case Overflow; + case InvalidChar(int8 partialResult); + } + + public const int8 MaxValue = 0x7F; + public const int8 MinValue = -0x80; public static int operator<=>(Self a, Self b) { @@ -66,5 +76,68 @@ namespace System NumberFormatter.NumberToString(format, (int32)this, formatProvider, outString); } } + + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) + { + if (val.IsEmpty) + return .Err(.NoValue); + + bool isNeg = false; + int8 result = 0; + + int8 radix = style.HasFlag(.AllowHexSpecifier) ? 0x10 : 10; + + for (int32 i = 0; i < val.Length; i++) + { + char8 c = val[i]; + + if ((i == 0) && (c == '-')) + { + isNeg = true; + continue; + } + + if ((c >= '0') && (c <= '9')) + { + result &*= radix; + result &+= (int8)(c - '0'); + } + else if ((c >= 'a') && (c <= 'f')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (int8)(c - 'a' + 10); + } + else if ((c >= 'A') && (c <= 'F')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (int8)(c - 'A' + 10); + } + else if ((c == 'X') || (c == 'x')) + { + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) + return .Err(.InvalidChar(result)); + radix = 0x10; + } + else if (c == '\'') + { + // Ignore + } + else if ((c == '+') && (i == 0)) + { + // Ignore + } + else + return .Err(.InvalidChar(result)); + + if (isNeg ? (uint8)result > (uint8)MaxValue + 1 : (uint8)result > (uint8)MaxValue) + return .Err(.Overflow); + } + + return isNeg ? -result : result; + } } } diff --git a/BeefLibs/corlib/src/UInt.bf b/BeefLibs/corlib/src/UInt.bf index 4d9ac341..354ddb63 100644 --- a/BeefLibs/corlib/src/UInt.bf +++ b/BeefLibs/corlib/src/UInt.bf @@ -7,11 +7,12 @@ namespace System { case Ok; case NoValue; + case Overflow; case InvalidChar(uint partialResult); } - public const uint64 MaxValue = (sizeof(uint) == 8) ? 0xFFFFFFFFFFFFFFFFUL : 0xFFFFFFFFL; - public const uint64 MinValue = 0; + public const uint MaxValue = (sizeof(uint) == 8) ? 0xFFFFFFFFFFFFFFFFUL : 0xFFFFFFFFL; + public const uint MinValue = 0; public bool IsNull() { diff --git a/BeefLibs/corlib/src/UInt16.bf b/BeefLibs/corlib/src/UInt16.bf index 7167f4b0..44a708fe 100644 --- a/BeefLibs/corlib/src/UInt16.bf +++ b/BeefLibs/corlib/src/UInt16.bf @@ -1,9 +1,19 @@ +using System.Globalization; + namespace System { #unwarn struct UInt16 : uint16, IInteger, IUnsigned, IHashable, IFormattable, IIsNaN { - public const uint16 MaxValue = (uint16)0xFFFF; + public enum ParseError + { + case Ok; + case NoValue; + case Overflow; + case InvalidChar(uint16 partialResult); + } + + public const uint16 MaxValue = 0xFFFF; public const uint16 MinValue = 0; public static int operator<=>(Self a, Self b) @@ -66,5 +76,63 @@ namespace System NumberFormatter.NumberToString(format, (uint32)this, formatProvider, outString); } } + + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) + { + if (val.IsEmpty) + return .Err(.NoValue); + + uint16 result = 0; + uint16 prevResult = 0; + + uint16 radix = style.HasFlag(.AllowHexSpecifier) ? 0x10 : 10; + + for (int32 i = 0; i < val.Length; i++) + { + char8 c = val[i]; + + if ((c >= '0') && (c <= '9')) + { + result &*= radix; + result &+= (uint16)(c - '0'); + } + else if ((c >= 'a') && (c <= 'f')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint16)(c - 'a' + 10); + } + else if ((c >= 'A') && (c <= 'F')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint16)(c - 'A' + 10); + } + else if ((c == 'X') || (c == 'x')) + { + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) + return .Err(.InvalidChar(result)); + radix = 0x10; + } + else if (c == '\'') + { + // Ignore + } + else if ((c == '+') && (i == 0)) + { + // Ignore + } + else + return .Err(.InvalidChar(result)); + + if (result < prevResult) + return .Err(.Overflow); + prevResult = result; + } + + return result; + } } } diff --git a/BeefLibs/corlib/src/UInt32.bf b/BeefLibs/corlib/src/UInt32.bf index d5ba9318..780ef52d 100644 --- a/BeefLibs/corlib/src/UInt32.bf +++ b/BeefLibs/corlib/src/UInt32.bf @@ -1,3 +1,5 @@ +using System.Globalization; + namespace System { #unwarn @@ -7,11 +9,12 @@ namespace System { case Ok; case NoValue; + case Overflow; case InvalidChar(uint32 partialResult); } - public const uint MaxValue = 0xFFFFFFFFL; - public const uint MinValue = 0; + public const uint32 MaxValue = 0xFFFFFFFFL; + public const uint32 MinValue = 0; public static int operator<=>(Self a, Self b) { @@ -102,31 +105,62 @@ namespace System } } - public static Result Parse(StringView val) + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) { - if (val.Length == 0) + if (val.IsEmpty) return .Err(.NoValue); - uint32 result = 0; - //TODO: Use Number.ParseNumber + uint32 result = 0; + uint32 prevResult = 0; + + uint32 radix = style.HasFlag(.AllowHexSpecifier) ? 0x10 : 10; + for (int32 i = 0; i < val.Length; i++) { - char8 c = val.Ptr[i]; - - if ((i == 0) && (c == '-')) - { - return .Err(.InvalidChar(0)); - } + char8 c = val[i]; if ((c >= '0') && (c <= '9')) { - result *= 10; - result += (uint32)(c - '0'); + result &*= radix; + result &+= (uint32)(c - '0'); + } + else if ((c >= 'a') && (c <= 'f')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint32)(c - 'a' + 10); + } + else if ((c >= 'A') && (c <= 'F')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint32)(c - 'A' + 10); + } + else if ((c == 'X') || (c == 'x')) + { + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) + return .Err(.InvalidChar(result)); + radix = 0x10; + } + else if (c == '\'') + { + // Ignore + } + else if ((c == '+') && (i == 0)) + { + // Ignore } else return .Err(.InvalidChar(result)); + + if (result < prevResult) + return .Err(.Overflow); + prevResult = result; } - return .Ok(result); + + return result; } } } diff --git a/BeefLibs/corlib/src/UInt64.bf b/BeefLibs/corlib/src/UInt64.bf index e9f6b1de..645ae2a0 100644 --- a/BeefLibs/corlib/src/UInt64.bf +++ b/BeefLibs/corlib/src/UInt64.bf @@ -5,16 +5,17 @@ namespace System #unwarn struct UInt64 : uint64, IInteger, IUnsigned, IHashable, IIsNaN, IFormattable { - public const uint64 MaxValue = 0xFFFFFFFFFFFFFFFFUL; - public const uint64 MinValue = 0; - public enum ParseError { case Ok; case NoValue; + case Overflow; case InvalidChar(uint64 partialResult); } + public const uint64 MaxValue = 0xFFFFFFFFFFFFFFFFUL; + public const uint64 MinValue = 0; + public static int operator<=>(UInt64 a, UInt64 b) { return (SelfBase)a <=> (SelfBase)b; @@ -86,57 +87,64 @@ namespace System strBuffer.Append(char8Ptr); } - public static Result Parse(StringView val, NumberStyles numberStyles = .Number, CultureInfo cultureInfo = null) + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) { - if (val.Length == 0) + //TODO: Use Number.ParseNumber + + if (val.IsEmpty) return .Err(.NoValue); uint64 result = 0; - if (numberStyles.HasFlag(.AllowHexSpecifier)) - { - int numDigits = 0; + uint64 prevResult = 0; - for (int32 i = 0; i < val.Length; i++) - { - char8 c = val.Ptr[i]; + uint64 radix = style.HasFlag(.AllowHexSpecifier) ? 0x10 : 10; - if (c == '\'') - continue; - - if ((c == 'X') || (c == 'x')) - { - if ((numDigits == 1) && (result == 0)) - continue; - } - - numDigits++; - if ((c >= '0') && (c <= '9')) - result = result*0x10 + (uint64)(c - '0'); - else if ((c >= 'A') && (c <= 'F')) - result = result*0x10 + (uint64)(c - 'A') + 10; - else if ((c >= 'a') && (c <= 'f')) - result = result*0x10 + (uint64)(c - 'a') + 10; - else - return .Err(.InvalidChar(result)); - } - - return .Ok(result); - } - - //TODO: Use Number.ParseNumber for (int32 i = 0; i < val.Length; i++) { - char8 c = val.Ptr[i]; + char8 c = val[i]; if ((c >= '0') && (c <= '9')) { - result *= 10; - result += (uint64)(c - '0'); + result &*= radix; + result &+= (uint64)(c - '0'); + } + else if ((c >= 'a') && (c <= 'f')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint64)(c - 'a' + 10); + } + else if ((c >= 'A') && (c <= 'F')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint64)(c - 'A' + 10); + } + else if ((c == 'X') || (c == 'x')) + { + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) + return .Err(.InvalidChar(result)); + radix = 0x10; + } + else if (c == '\'') + { + // Ignore + } + else if ((c == '+') && (i == 0)) + { + // Ignore } else return .Err(.InvalidChar(result)); + + if (result < prevResult) + return .Err(.Overflow); + prevResult = result; } - return .Ok(result); + + return result; } } } diff --git a/BeefLibs/corlib/src/UInt8.bf b/BeefLibs/corlib/src/UInt8.bf index 67119af1..cee59e80 100644 --- a/BeefLibs/corlib/src/UInt8.bf +++ b/BeefLibs/corlib/src/UInt8.bf @@ -1,9 +1,19 @@ +using System.Globalization; + namespace System { #unwarn struct UInt8 : uint8, IInteger, IUnsigned, IHashable, IFormattable, IIsNaN { - public const uint8 MaxValue = (uint8)0xFF; + public enum ParseError + { + case Ok; + case NoValue; + case Overflow; + case InvalidChar(uint8 partialResult); + } + + public const uint8 MaxValue = 0xFF; public const uint8 MinValue = 0; public static int operator<=>(Self a, Self b) @@ -66,5 +76,63 @@ namespace System NumberFormatter.NumberToString(format, (uint32)this, formatProvider, outString); } } + + public static Result Parse(StringView val, NumberStyles style = .Number, CultureInfo cultureInfo = null) + { + if (val.IsEmpty) + return .Err(.NoValue); + + uint8 result = 0; + uint8 prevResult = 0; + + uint8 radix = style.HasFlag(.AllowHexSpecifier) ? 0x10 : 10; + + for (int32 i = 0; i < val.Length; i++) + { + char8 c = val[i]; + + if ((c >= '0') && (c <= '9')) + { + result &*= radix; + result &+= (uint8)(c - '0'); + } + else if ((c >= 'a') && (c <= 'f')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint8)(c - 'a' + 10); + } + else if ((c >= 'A') && (c <= 'F')) + { + if (radix != 0x10) + return .Err(.InvalidChar(result)); + result &*= radix; + result &+= (uint8)(c - 'A' + 10); + } + else if ((c == 'X') || (c == 'x')) + { + if ((!style.HasFlag(.AllowHexSpecifier)) || (i == 0) || (result != 0)) + return .Err(.InvalidChar(result)); + radix = 0x10; + } + else if (c == '\'') + { + // Ignore + } + else if ((c == '+') && (i == 0)) + { + // Ignore + } + else + return .Err(.InvalidChar(result)); + + if (result < prevResult) + return .Err(.Overflow); + prevResult = result; + } + + return result; + } } }