Пример #1
0
        /// <summary>
        /// Integer
        /// Handles the 16,32bit signed and unsigned integers
        /// 64bit are handled separately
        /// </summary>
        private static void Integer(ref StackBuffer buffer, StackBuffer format, TypeCode type, long value, bool signed)
        {
            var negSign  = signed && value < 0;
            var fmt      = ParseFormatSpecifier(format, out var digits);
            var fmtUpper = (char)(fmt & 0xFFDF);  // ensure fmt is upper-cased for purposes of comparison

            if (fmtUpper == 'G' && digits < 1 || fmtUpper == 'D')
            {
                EvalInt(ref buffer, (ulong)Math.Abs(value), digits, 10, negSign);
            }
            else if (fmtUpper == 'X')
            {
                if (type == TypeCode.Int16)
                {
                    if (value < 0)
                    {
                        EvalInt(ref buffer, (uint)(value & 0x0000FFFF), digits, 16, false);
                        return;
                    }
                }

                if (type == TypeCode.Int32)
                {
                    if (value < 0)
                    {
                        EvalInt(ref buffer, (uint)(value & 0xFFFFFFFF), digits, 16, false);
                        return;
                    }
                }


                EvalInt(ref buffer, (ulong)Math.Abs(value), digits, 16, negSign);
            }
        }
Пример #2
0
        /// <summary>
        /// EvalArg
        /// Entry point for evaluating the generic arguments
        /// </summary>
        private static void EvalArg <T>(ref StackBuffer buffer, StackBuffer format, T arg)
            where T : IConvertible
        {
            switch (arg?.GetTypeCode())
            {
            case TypeCode.Int16:
            {
                Integer(ref buffer, format, arg.GetTypeCode(), arg.ToInt16(NumberFormatInfo.CurrentInfo), true);
                break;
            }

            case TypeCode.Int32:
            {
                Integer(ref buffer, format, arg.GetTypeCode(), arg.ToInt32(NumberFormatInfo.CurrentInfo), true);
                break;
            }

            case TypeCode.Int64:
            {
                Long(ref buffer, format, arg.GetTypeCode(), arg.ToInt64(NumberFormatInfo.CurrentInfo), true);
                break;
            }

            case TypeCode.UInt16:
            {
                Integer(ref buffer, format, arg.GetTypeCode(), arg.ToUInt16(NumberFormatInfo.CurrentInfo), false);
                break;
            }

            case TypeCode.UInt32:
            {
                Integer(ref buffer, format, arg.GetTypeCode(), arg.ToUInt32(NumberFormatInfo.CurrentInfo), false);
                break;
            }

            case TypeCode.UInt64:
            {
                ULong(ref buffer, format, arg.GetTypeCode(), arg.ToUInt64(NumberFormatInfo.CurrentInfo), false);
                break;
            }

            case TypeCode.Single:
            {
                FloatingPoint(ref buffer, format, arg.ToSingle(NumberFormatInfo.CurrentInfo));
                break;
            }

            case TypeCode.Double:
            {
                FloatingPoint(ref buffer, format, arg.ToDouble(NumberFormatInfo.CurrentInfo));
                break;
            }

            case TypeCode.String:
            {
                buffer.Append(arg.ToString());
                break;
            }
            }
        }
Пример #3
0
        /// <summary>
        /// EvalULong
        /// Converts 64bit signed and unsigned ints to ascii
        /// </summary>
        private static void EvalULong(ref StackBuffer buffer, ulong longVal, int digits, long baseVal, bool negSign)
        {
            // add the characters in reverse order
            do
            {
                // Lookup from static char array, to cover hex values too
                buffer.Append(asciiDigits[longVal % (ulong)baseVal]);
                longVal /= (ulong)baseVal;
                digits--;
            } while (longVal != 0);

            Pad(ref buffer, digits, negSign);
        }
Пример #4
0
        // Set the string using the contents of a StackBuffer
        public void SetStackBuffer(int destPos, StackBuffer buffer)
        {
            var newLength = destPos + buffer.Count;

            if (destPos + buffer.Count > Capacity)
            {
                throw new ArgumentOutOfRangeException();
            }
            SetLength(newLength);
            for (var i = destPos; i < newLength; i++)
            {
                this[i] = buffer[i];
            }
        }
Пример #5
0
 private static void Pad(ref StackBuffer buffer, int digits, bool negSign)
 {
     // add preceding zeros
     while (digits-- > 0)
     {
         buffer.Append('0');
     }
     // add sign
     if (negSign)
     {
         buffer.Append('-');
     }
     // reverse it into the correct order
     buffer.Reverse();
 }
Пример #6
0
        /// <summary>
        /// Unsigned 64bit ints
        /// </summary>
        private static void ULong(ref StackBuffer buffer, StackBuffer format, TypeCode type, ulong value, bool signed)
        {
            var negSign  = signed && value < 0;
            var fmt      = ParseFormatSpecifier(format, out var digits);
            var fmtUpper = (char)(fmt & 0xFFDF);  // ensure fmt is upper-cased for purposes of comparison

            if (fmtUpper == 'G' && digits < 1 || fmtUpper == 'D')
            {
                EvalULong(ref buffer, value, digits, 10, negSign);
            }
            else if (fmtUpper == 'X')
            {
                EvalULong(ref buffer, value, digits, 16, negSign);
            }
        }
Пример #7
0
        /// <summary>
        /// EvalInt
        /// Converts 16,32bit signed and unsigned ints to ascii
        /// </summary>
        private static void EvalInt(ref StackBuffer buffer, ulong intVal, int digits, ulong baseVal, bool negSign)
        {
            // add the characters in reverse order
            do
            {
                // Lookup from static char array, to cover hex values too
                buffer.Append(asciiDigits[intVal % baseVal]);
                intVal /= baseVal;
                digits--;
            } while (intVal != 0);

            // add preceding zeros
            while (digits-- > 0)
            {
                buffer.Append('0');
            }
            // add sign
            if (negSign)
            {
                buffer.Append('-');
            }
            // reverse it into the correct order
            buffer.Reverse();
        }
Пример #8
0
        public static void Convert(ref StackBuffer buffer, double f, int precision)
        {
            if (f > ulong.MaxValue)
            {
                buffer.Append("Out-of-range");
                return;
            }

            ulong intPart;
            ulong baseVal = 10; // baseVal has to be the same type as the integer part

            // check precision bounds
            if (precision > MAX_PRECISION)
            {
                precision = MAX_PRECISION;
            }

            // sign stuff
            if (f < 0)
            {
                f = -f;
                buffer.Append('-');
            }

            if (precision < 0) // negative precision == automatic precision guess
            {
                if (f < 1.0)
                {
                    precision = 6;
                }
                else if (f < 10.0)
                {
                    precision = 5;
                }
                else if (f < 100.0)
                {
                    precision = 4;
                }
                else if (f < 1000.0)
                {
                    precision = 3;
                }
                else if (f < 10000.0)
                {
                    precision = 2;
                }
                else if (f < 100000.0)
                {
                    precision = 1;
                }
                else
                {
                    precision = 0;
                }
            }

            // round value according the precision
            if (precision > 0)
            {
                f += rounders[precision];
            }


            // integer part...
            intPart = (ulong)Math.Truncate(f);
            f      -= intPart;

            if (intPart == 0)
            {
                buffer.Append('0');
            }
            else
            {
                var tempBuffer = new StackBuffer(stackalloc char[MAX_PRECISION]);
                // convert (reverse order)
                while (intPart != 0)
                {
                    tempBuffer.Append((char)('0' + intPart % baseVal));
                    intPart /= baseVal;
                }

                tempBuffer.Reverse();
                for (var i = 0; i < tempBuffer.Count; i++)
                {
                    buffer.Append(tempBuffer[i]);
                }
            }

            // decimal part
            if (precision != 0)
            {
                // place decimal point
                buffer.Append('.');

                // convert
                while (precision-- != 0)
                {
                    f *= 10.0;
                    var c = (char)f;
                    buffer.Append((char)('0' + c));
                    f -= c;
                }
            }
        }
Пример #9
0
        /// <summary>
        /// ParseFormatSpecifier
        /// https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs
        /// </summary>
        /// <returns></returns>
        private static char ParseFormatSpecifier(StackBuffer format, out int digits)
        {
            char c = default;

            if (format.Length > 0)
            {
                // If the format begins with a symbol, see if it's a standard format
                // with or without a specified number of digits.
                c = format[0];
                if ((uint)(c - 'A') <= 'Z' - 'A' ||
                    (uint)(c - 'a') <= 'z' - 'a')
                {
                    // Fast path for sole symbol, e.g. "D"
                    if (format.Length == 1)
                    {
                        digits = -1;
                        return(c);
                    }

                    if (format.Length == 2)
                    {
                        // Fast path for symbol and single digit, e.g. "X4"
                        var d = format[1] - '0';
                        if ((uint)d < 10)
                        {
                            digits = d;
                            return(c);
                        }
                    }
                    else if (format.Length == 3)
                    {
                        // Fast path for symbol and double digit, e.g. "F12"
                        int d1 = format[1] - '0', d2 = format[2] - '0';
                        if ((uint)d1 < 10 && (uint)d2 < 10)
                        {
                            digits = d1 * 10 + d2;
                            return(c);
                        }
                    }

                    // Fallback for symbol and any length digits.  The digits value must be >= 0 && <= 99,
                    // but it can begin with any number of 0s, and thus we may need to check more than two
                    // digits.  Further, for compat, we need to stop when we hit a null char.
                    var n = 0;
                    var i = 1;
                    while (i < format.Length && (uint)format[i] - '0' < 10 && n < 10)
                    {
                        n = n * 10 + format[i++] - '0';
                    }

                    // If we're at the end of the digits rather than having stopped because we hit something
                    // other than a digit or overflowed, return the standard format info.
                    if (i == format.Length || format[i] == '\0')
                    {
                        digits = n;
                        return(c);
                    }
                }
            }

            // Default empty format to be "G"; custom format is signified with '\0'.
            digits = -1;
            return(format.Length == 0 || c == '\0'
                ? // For compat, treat '\0' as the end of the specifier, even if the specifier extends beyond it.
                   'G'
                : '\0');
        }
Пример #10
0
        /// <summary>
        /// FloatingPoint
        /// Handles single and double precision floating point values
        /// </summary>
        private static void FloatingPoint(ref StackBuffer buffer, StackBuffer format, double value)
        {
            var fmt = ParseFormatSpecifier(format, out var digits);

            ftoa.Convert(ref buffer, value, digits);
        }