public static ParseResult DecimalTryParse()

in src/Elastic.Apm/Libraries/Newtonsoft.Json/Utilities/ConvertUtils.cs [1218:1394]


		public static ParseResult DecimalTryParse(char[] chars, int start, int length, out decimal value)
		{
			value = 0M;
			const decimal decimalMaxValueHi28 = 7922816251426433759354395033M;
			const ulong decimalMaxValueHi19 = 7922816251426433759UL;
			const ulong decimalMaxValueLo9 = 354395033UL;
			const char decimalMaxValueLo1 = '5';

			if (length == 0) return ParseResult.Invalid;

			var isNegative = chars[start] == '-';
			if (isNegative)
			{
				// text just a negative sign
				if (length == 1) return ParseResult.Invalid;

				start++;
				length--;
			}

			var i = start;
			var end = start + length;
			var numDecimalStart = end;
			var numDecimalEnd = end;
			var exponent = 0;
			var hi19 = 0UL;
			var lo10 = 0UL;
			var mantissaDigits = 0;
			var exponentFromMantissa = 0;
			char? digit29 = null;
			bool? storeOnly28Digits = null;
			for (; i < end; i++)
			{
				var c = chars[i];
				switch (c)
				{
					case '.':
						if (i == start) return ParseResult.Invalid;

						if (i + 1 == end) return ParseResult.Invalid;

						if (numDecimalStart != end)
						{
							// multiple decimal points
							return ParseResult.Invalid;
						}

						numDecimalStart = i + 1;
						break;
					case 'e':
					case 'E':
						if (i == start) return ParseResult.Invalid;

						if (i == numDecimalStart)
						{
							// E follows decimal point
							return ParseResult.Invalid;
						}
						i++;
						if (i == end) return ParseResult.Invalid;

						if (numDecimalStart < end) numDecimalEnd = i - 1;

						c = chars[i];
						var exponentNegative = false;
						switch (c)
						{
							case '-':
								exponentNegative = true;
								i++;
								break;
							case '+':
								i++;
								break;
						}

						// parse 3 digit
						for (; i < end; i++)
						{
							c = chars[i];
							if (c < '0' || c > '9') return ParseResult.Invalid;

							var newExponent = 10 * exponent + (c - '0');
							// stops updating exponent when overflowing
							if (exponent < newExponent) exponent = newExponent;
						}

						if (exponentNegative) exponent = -exponent;
						break;
					default:
						if (c < '0' || c > '9') return ParseResult.Invalid;

						if (i == start && c == '0')
						{
							i++;
							if (i != end)
							{
								c = chars[i];
								if (c == '.') goto case '.';
								if (c == 'e' || c == 'E') goto case 'E';

								return ParseResult.Invalid;
							}
						}

						if (mantissaDigits < 29 && (mantissaDigits != 28 || !(storeOnly28Digits
							?? (storeOnly28Digits = hi19 > decimalMaxValueHi19 || hi19 == decimalMaxValueHi19
								&& (lo10 > decimalMaxValueLo9 || lo10 == decimalMaxValueLo9 && c > decimalMaxValueLo1)).GetValueOrDefault())))
						{
							if (mantissaDigits < 19)
								hi19 = hi19 * 10UL + (ulong)(c - '0');
							else
								lo10 = lo10 * 10UL + (ulong)(c - '0');
							++mantissaDigits;
						}
						else
						{
							if (!digit29.HasValue) digit29 = c;
							++exponentFromMantissa;
						}
						break;
				}
			}

			exponent += exponentFromMantissa;

			// correct the decimal point
			exponent -= numDecimalEnd - numDecimalStart;

			if (mantissaDigits <= 19)
				value = hi19;
			else
				value = hi19 / new decimal(1, 0, 0, false, (byte)(mantissaDigits - 19)) + lo10;

			if (exponent > 0)
			{
				mantissaDigits += exponent;
				if (mantissaDigits > 29) return ParseResult.Overflow;

				if (mantissaDigits == 29)
				{
					if (exponent > 1)
					{
						value /= new decimal(1, 0, 0, false, (byte)(exponent - 1));
						if (value > decimalMaxValueHi28) return ParseResult.Overflow;
					}
					else if (value == decimalMaxValueHi28 && digit29 > decimalMaxValueLo1) return ParseResult.Overflow;

					value *= 10M;
				}
				else
					value /= new decimal(1, 0, 0, false, (byte)exponent);
			}
			else
			{
				if (digit29 >= '5' && exponent >= -28) ++value;
				if (exponent < 0)
				{
					if (mantissaDigits + exponent + 28 <= 0)
					{
						value = isNegative ? -0M : 0M;
						return ParseResult.Success;
					}
					if (exponent >= -28)
						value *= new decimal(1, 0, 0, false, (byte)-exponent);
					else
					{
						value /= 1e28M;
						value *= new decimal(1, 0, 0, false, (byte)(-exponent - 28));
					}
				}
			}

			if (isNegative) value = -value;

			return ParseResult.Success;
		}