public static bool TryFormat(this DateTime value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (format.IsDefault)
            {
                format.Symbol = 'G';
            }
            Precondition.Require(format.Symbol == 'R' || format.Symbol == 'O' || format.Symbol == 'G');

            switch (format.Symbol)
            {
                case 'R':
                    var utc = value.ToUniversalTime();
                    if (formattingData.IsUtf16)
                    {
                        return TryFormatDateTimeRfc1123(utc, buffer, FormattingData.InvariantUtf16, out bytesWritten);
                    }
                    else
                    {
                        return TryFormatDateTimeRfc1123(utc, buffer, FormattingData.InvariantUtf8, out bytesWritten);
                    }
                case 'O':
                    if (formattingData.IsUtf16)
                    {
                        return TryFormatDateTimeFormatO(value, true, buffer, FormattingData.InvariantUtf16, out bytesWritten);
                    }
                    else
                    {
                        return TryFormatDateTimeFormatO(value, true, buffer, FormattingData.InvariantUtf8, out bytesWritten);
                    }
                case 'G':
                    return TryFormatDateTimeFormagG(value, buffer, formattingData, out bytesWritten);
                default:
                    throw new NotImplementedException();
            }
        }
示例#2
0
        internal static bool TryFormatUInt64(ulong value, byte numberOfBytes, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if(format.Symbol == 'g')
            {
                format.Symbol = 'G';
            }

            if (format.IsHexadecimal && formattingData.IsUtf16) {
                return TryFormatHexadecimalInvariantCultureUtf16(value, buffer, format, out bytesWritten);
            }

            if (format.IsHexadecimal && formattingData.IsUtf8) {
                return TryFormatHexadecimalInvariantCultureUtf8(value, buffer, format, out bytesWritten);
            }

            if ((formattingData.IsInvariantUtf16) && (format.Symbol == 'D' || format.Symbol == 'G')) {
                return TryFormatDecimalInvariantCultureUtf16(value, buffer, format, out bytesWritten);
            }

            if ((formattingData.IsInvariantUtf8) && (format.Symbol == 'D' || format.Symbol == 'G')) {
                return TryFormatDecimalInvariantCultureUtf8(value, buffer, format, out bytesWritten);
            }

            return TryFormatDecimal(value, buffer, format, formattingData, out bytesWritten);     
        }
示例#3
0
        internal static bool TryFormatInt64(long value, byte numberOfBytes, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            Precondition.Require(numberOfBytes <= sizeof(long));

            if (value >= 0)
            {
                return TryFormatUInt64(unchecked((ulong)value), numberOfBytes, buffer, format, formattingData, out bytesWritten);
            }
            else if (format.IsHexadecimal)
            {
                ulong bitMask = GetBitMask(numberOfBytes);
                return TryFormatUInt64(unchecked((ulong)value) & bitMask, numberOfBytes, buffer, format, formattingData, out bytesWritten);
            }
            else
            {
                int minusSignBytes = 0;
                if(!formattingData.TryWriteSymbol(FormattingData.Symbol.MinusSign, buffer, out minusSignBytes))
                {
                    bytesWritten = 0;
                    return false;
                }

                int digitBytes = 0;
                if(!TryFormatUInt64(unchecked((ulong)-value), numberOfBytes, buffer.Slice(minusSignBytes), format, formattingData, out digitBytes))
                {
                    bytesWritten = 0;
                    return false;
                }
                bytesWritten = digitBytes + minusSignBytes;
                return true;
            }
        }
 public static bool TryFormat(this float value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
 {
     if (format.IsDefault)
     {
         format.Symbol = 'G';
     }
     Precondition.Require(format.Symbol == 'G');
     return FloatFormatter.TryFormatNumber(value, true, buffer, format, formattingData, out bytesWritten);
 }
        public bool TryFormat(Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (!PrimitiveFormatters.TryFormat(_age, buffer, format, formattingData, out bytesWritten)) return false;

            char symbol = _inMonths ? 'm' : 'y';
            int symbolBytes;
            if (!PrimitiveFormatters.TryFormat(symbol, buffer.Slice(bytesWritten), format, formattingData, out symbolBytes)) return false;

            bytesWritten += symbolBytes;
            return true;
        }
        public static bool TryFormat(this char value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (formattingData.IsUtf16)
            {
                if (buffer.Length < 2)
                {
                    bytesWritten = 0;
                    return false;
                }
                buffer[0] = (byte)value;
                buffer[1] = (byte)(value >> 8);
                bytesWritten = 2;
                return true;
            }

            if (buffer.Length < 1)
            {
                bytesWritten = 0;
                return false;
            }

            // fast path for ASCII
            if (value <= 127)
            {
                buffer[0] = (byte)value;
                bytesWritten = 1;
                return true;
            }

            // TODO: This can be directly encoded to SpanByte. There is no conversion between spans yet
            var encoded = new Utf8EncodedCodePoint(value);
            bytesWritten = encoded.Length;
            if (buffer.Length < bytesWritten)
            {
                bytesWritten = 0;
                return false;
            }

            buffer[0] = encoded.Byte0;
            if(bytesWritten > 1)
            {
                buffer[1] = encoded.Byte1;
            }
            if(bytesWritten > 2)
            {
                buffer[2] = encoded.Byte2;
            }
            if(bytesWritten > 3)
            {
                buffer[3] = encoded.Byte3;
            }
            return true;
        }
示例#7
0
        public static bool TryFormat(this char value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (formattingData.IsUtf16)
            {
                if (buffer.Length < 2)
                {
                    bytesWritten = 0;
                    return false;
                }
                buffer[0] = (byte)value;
                buffer[1] = (byte)(value >> 8);
                bytesWritten = 2;
                return true;
            }

            if (buffer.Length < 1)
            {
                bytesWritten = 0;
                return false;
            }

            // fast path for ASCII
            if (value <= 127)
            {
                buffer[0] = (byte)value;
                bytesWritten = 1;
                return true;
            }

            var encoded = new FourBytes();
            bytesWritten = Utf8Encoder.CharToUtf8(value, ref encoded);
            if(buffer.Length < bytesWritten)
            {
                bytesWritten = 0;
                return false;
            }

            buffer[0] = encoded.B0;
            if(bytesWritten > 1)
            {
                buffer[1] = encoded.B1;
            }
            if(bytesWritten > 2)
            {
                buffer[2] = encoded.B2;
            }
            if(bytesWritten > 3)
            {
                buffer[3] = encoded.B3;
            }
            return true;
        }
示例#8
0
        private static bool TryFormatDecimalInvariantCultureUtf16(ulong value, Span<byte> buffer, Format.Parsed format, out int bytesWritten)
        {
            Precondition.Require(format.Symbol == 'D' || format.Symbol == 'G');

            // Count digits
            var valueToCountDigits = value;
            var digitsCount = 1;
            while (valueToCountDigits >= 10UL) {
                valueToCountDigits = valueToCountDigits / 10UL;
                digitsCount++;
            }

            var index = 0;
            var bytesCount = digitsCount * 2;

            // If format is D and precision is greater than digits count, append leading zeros
            if (format.Symbol == 'D' && format.HasPrecision) {
                var leadingZerosCount = format.Precision - digitsCount;
                if (leadingZerosCount > 0) {
                    bytesCount += leadingZerosCount * 2;
                }

                if (bytesCount > buffer.Length) {
                    bytesWritten = 0;
                    return false;
                }

                while (leadingZerosCount-- > 0) {
                    buffer[index++] = (byte)'0';
                    buffer[index++] = 0;
                }
            }
            else if (bytesCount > buffer.Length) {
                bytesWritten = 0;
                return false;
            }

            index = bytesCount;
            while (digitsCount-- > 0) {
                ulong digit = value % 10UL;
                value /= 10UL;
                buffer[--index] = 0;
                buffer[--index] = (byte)(digit + (ulong)'0'); 
            }

            bytesWritten = bytesCount;
            return true;
        }
示例#9
0
        public static bool TryFormatNumber(double value, bool isSingle, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            Precondition.Require(format.Symbol == 'G' || format.Symbol == 'E' || format.Symbol == 'F');

            bytesWritten = 0;
            int written;

            if (Double.IsNaN(value))
            {
                return formattingData.TryWriteSymbol(FormattingData.Symbol.NaN, buffer, out bytesWritten);
            }

            if (Double.IsInfinity(value))
            {
                if (Double.IsNegativeInfinity(value))
                {
                    if (!formattingData.TryWriteSymbol(FormattingData.Symbol.MinusSign, buffer, out written))
                    {
                        bytesWritten = 0;
                        return false;
                    }
                    bytesWritten += written;
                }
                if (!formattingData.TryWriteSymbol(FormattingData.Symbol.InfinitySign, buffer.Slice(bytesWritten), out written))
                {
                    bytesWritten = 0;
                    return false;
                }
                bytesWritten += written;
                return true;
            }

            // TODO: the lines below need to be replaced with properly implemented algorithm
            // the problem is the algorithm is complex, so I am commiting a stub for now
            var hack = value.ToString(format.Symbol.ToString());
            return hack.TryFormat(buffer, default(Format.Parsed), formattingData, out bytesWritten);
        }
 private static void Verify(Format.Parsed format, byte expectedPrecision, char expectedSymbol)
 {
     Assert.Equal(format.Precision, expectedPrecision);
     Assert.Equal(format.Symbol, expectedSymbol.ToString()[0]);
 }
        private static bool TryFormatTimeSpanG(TimeSpan value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            bytesWritten = 0;

            if (value.Ticks < 0)
            {
                if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; }
            }

            bool daysWritten = false;
            if (value.Days != 0 || format.Symbol == 'G')
            {
                if (!TryWriteInt32(Abs(value.Days), buffer, default(Format.Parsed), formattingData, ref bytesWritten)) { return false; }
                daysWritten = true;
                if (format.Symbol == 'c')
                {
                    if (!TryWriteChar('.', buffer, formattingData, ref bytesWritten)) { return false; }
                }
                else
                {
                    if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; }
                }
            }

            var hourFormat = default(Format.Parsed);
            if ((daysWritten || format.Symbol == 'c') && format.Symbol != 'g')
            {
                hourFormat = D2;
            }
            if (!TryWriteInt32(Abs(value.Hours), buffer, hourFormat, formattingData, ref bytesWritten)) { return false; }
            if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; }

            if (!TryWriteInt32(Abs(value.Minutes), buffer, D2, formattingData, ref bytesWritten)) { return false; }
            if (!TryWriteChar(':', buffer, formattingData, ref bytesWritten)) { return false; }

            if (!TryWriteInt32(Abs(value.Seconds), buffer, D2, formattingData, ref bytesWritten)) { return false; }

            long remainingTicks;
            if (value.Ticks != long.MinValue)
            {
                remainingTicks = Abs(value.Ticks) % TimeSpan.TicksPerSecond;
            }
            else
            {
                remainingTicks = long.MaxValue % TimeSpan.TicksPerSecond;
                remainingTicks = (remainingTicks + 1) % TimeSpan.TicksPerSecond;
            }

            var ticksFormat = D7;
            if (remainingTicks != 0)
            {
                if (!TryWriteChar('.', buffer, formattingData, ref bytesWritten)) { return false; }
                var fraction = remainingTicks * FractionalTimeScale / TimeSpan.TicksPerSecond;
                if (!TryWriteInt64(fraction, buffer, ticksFormat, formattingData, ref bytesWritten)) { return false; }
            }

            return true;
        }
 public static bool TryFormat(this DateTime value, Span <byte> buffer, ReadOnlySpan <char> format, FormattingData formattingData, out int bytesWritten)
 {
     Format.Parsed parsedFormat = Format.Parse(format);
     return(TryFormat(value, buffer, parsedFormat, formattingData, out bytesWritten));
 }
        public static bool TryFormat(this Guid value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (format.IsDefault)
            {
                format.Symbol = 'G';
            }
            Precondition.Require(format.Symbol == 'G' || format.Symbol == 'D' || format.Symbol == 'N' || format.Symbol == 'B' || format.Symbol == 'P');
            bool dash = true;
            char tail = '\0';
            bytesWritten = 0;

            switch (format.Symbol)
            {
                case 'D':
                case 'G':
                    break;

                case 'N':
                    dash = false;
                    break;

                case 'B':
                    if (!TryWriteChar('{', buffer, formattingData, ref bytesWritten)) { return false; }
                    tail = '}';
                    break;

                case 'P':
                    if (!TryWriteChar('(', buffer, formattingData, ref bytesWritten)) { return false; }
                    tail = ')';
                    break;

                default:
                    Precondition.Require(false); // how did we get here? 
                    break;
            }


            var byteFormat = new Format.Parsed('x', 2);
            unsafe
            {
                byte* bytes = (byte*)&value;

                if (!TryWriteByte(bytes[3], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[2], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[1], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[0], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }

                if (dash)
                {
                    if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; }
                }

                if (!TryWriteByte(bytes[5], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[4], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }

                if (dash)
                {
                    if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; }
                }

                if (!TryWriteByte(bytes[7], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[6], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }

                if (dash)
                {
                    if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; }
                }

                if (!TryWriteByte(bytes[8], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[9], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }

                if (dash)
                {
                    if (!TryWriteChar('-', buffer, formattingData, ref bytesWritten)) { return false; }
                }

                if (!TryWriteByte(bytes[10], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[11], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[12], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[13], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[14], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
                if (!TryWriteByte(bytes[15], buffer, byteFormat, formattingData, ref bytesWritten)) { return false; }
            }

            if (tail != '\0')
            {
                if (!TryWriteChar(tail, buffer, formattingData, ref bytesWritten)) { return false; }
            }

            return true;
        }
        public static bool TryFormat(this TimeSpan value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (format.IsDefault)
            {
                format.Symbol = 'c';
            }
            Precondition.Require(format.Symbol == 'G' || format.Symbol == 't' || format.Symbol == 'c' || format.Symbol == 'g');

            if (format.Symbol != 't')
            {
                return TryFormatTimeSpanG(value, buffer, format, formattingData, out bytesWritten);
            }

            // else it's format 't' (short time used to print time offsets)
            return TryFormatTimeSpanT(value, buffer, formattingData, out bytesWritten);
        }
示例#15
0
        public static bool TryFormat(this string value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (formattingData.IsUtf16)
            {
                var valueBytes = value.Length << 1;
                if (valueBytes > buffer.Length)
                {
                    bytesWritten = 0;
                    return false;
                }

                unsafe
                {
                    fixed (char* pCharacters = value)
                    {
                        byte* pBytes = (byte*)pCharacters;
                        buffer.Set(pBytes, valueBytes);
                    }
                }

                bytesWritten = valueBytes;
                return true;
            }

            GCHandle handle;
            var byteSpan = buffer.Pin(out handle);
            try {

                var avaliableBytes = byteSpan.Length;
                bytesWritten = 0;
                for (int i = 0; i < value.Length; i++)
                {
                    var c = value[i];

                    var codepoint = (ushort)c;
                    if (codepoint <= 0x7f) // this if block just optimizes for ascii
                    {
                        if (bytesWritten + 1 > avaliableBytes)
                        {
                            bytesWritten = 0;
                            return false;
                        }
                        byteSpan[bytesWritten++] = (byte)codepoint;
                    }
                    else
                    {
                        var encoded = new FourBytes();
                        var bytes = Utf8Encoder.CharToUtf8(c, ref encoded);

                        if (bytesWritten + bytes > avaliableBytes)
                        {
                            bytesWritten = 0;
                            return false;
                        }

                        byteSpan[bytesWritten] = encoded.B0;
                        if (bytes > 1)
                        {
                            byteSpan[bytesWritten + 1] = encoded.B1;

                            if (bytes > 2)
                            {
                                byteSpan[bytesWritten + 2] = encoded.B2;

                                if (bytes > 3)
                                {
                                    byteSpan[bytesWritten + 3] = encoded.B3;
                                }
                            }
                        }

                        bytesWritten += bytes;
                    }
                }
                return true;
            }
            finally
            {
                handle.Free();
            }
        }
 static bool TryWriteInt64(long i, Span<byte> buffer, Format.Parsed byteFormat, FormattingData formattingData, ref int bytesWritten)
 {
     int written;
     if (!i.TryFormat(buffer.Slice(bytesWritten), byteFormat, formattingData, out written))
     {
         bytesWritten = 0;
         return false;
     }
     bytesWritten += written;
     return true;
 }
示例#17
0
        public static bool TryFormat(this Utf8String value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (formattingData.IsUtf16) {
                throw new NotImplementedException();
            }

            if(buffer.Length < value.Length) {
                bytesWritten = 0;
                return false;
            }

            buffer.Set(value.Bytes);
            bytesWritten = value.Length;
            return true;
        }
示例#18
0
        // TODO: this whole routine is too slow. It does div and mod twice, which are both costly (especially that some JITs cannot optimize it).
        // It does it twice to avoid reversing the formatted buffer, which can be tricky given it should handle arbitrary cultures.
        // One optimization I thought we could do is to do div/mod once and store digits in a temp buffer (but that would allocate). Modification to the idea would be to store the digits in a local struct
        // Another idea possibly worth tying would be to special case cultures that have constant digit size, and go back to the format + reverse buffer approach.
        private static bool TryFormatDecimal(ulong value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if(format.IsDefault)
            {
                format.Symbol = 'G';
            }
            format.Symbol = Char.ToUpperInvariant(format.Symbol); // TODO: this is costly. I think the transformation should happen in Parse
            Precondition.Require(format.Symbol == 'D' || format.Symbol == 'G' || format.Symbol == 'N');

            // Reverse value on decimal basis, count digits and trailing zeros before the decimal separator
            ulong reversedValueExceptFirst = 0;
            var digitsCount = 1;
            var trailingZerosCount = 0;

            // We reverse the digits in numeric form because reversing encoded digits is hard and/or costly.
            // If value contains 20 digits, its reversed value will not fit into ulong size.
            // So reverse it till last digit (reversedValueExceptFirst will have all the digits except the first one).
            while (value >= 10)
            {
                var digit = value % 10UL;
                value = value / 10UL;

                if (reversedValueExceptFirst == 0 && digit == 0)
                {
                    trailingZerosCount++;
                }
                else
                {
                    reversedValueExceptFirst = reversedValueExceptFirst * 10UL + digit;
                    digitsCount++;
                }
            }

            bytesWritten = 0;
            int digitBytes;
            // If format is D and precision is greater than digitsCount + trailingZerosCount, append leading zeros
            if (format.Symbol == 'D' && format.HasPrecision)
            {
                var leadingZerosCount = format.Precision - digitsCount - trailingZerosCount;
                while (leadingZerosCount-- > 0)
                {
                    if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes))
                    {
                        bytesWritten = 0;
                        return false;
                    }
                    bytesWritten += digitBytes;
                }
            }

            // Append first digit
            if (!formattingData.TryWriteDigit(value, buffer.Slice(bytesWritten), out digitBytes))
            {
                bytesWritten = 0;
                return false;
            }
            bytesWritten += digitBytes;
            digitsCount--;

            if (format.Symbol == 'N')
            {
                const int GroupSize = 3;

                // Count amount of digits before first group separator. It will be reset to groupSize every time digitsLeftInGroup == zero
                var digitsLeftInGroup = (digitsCount + trailingZerosCount) % GroupSize;
                if (digitsLeftInGroup == 0)
                {
                    if (digitsCount + trailingZerosCount > 0)
                    {
                        // There is a new group immediately after the first digit
                        if (!formattingData.TryWriteSymbol(FormattingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes))
                        {
                            bytesWritten = 0;
                            return false;
                        }
                        bytesWritten += digitBytes;
                    }
                    digitsLeftInGroup = GroupSize;
                }

                // Append digits
                while (reversedValueExceptFirst > 0)
                {
                    if (digitsLeftInGroup == 0)
                    {
                        if (!formattingData.TryWriteSymbol(FormattingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes))
                        {
                            bytesWritten = 0;
                            return false;
                        }
                        bytesWritten += digitBytes;
                        digitsLeftInGroup = GroupSize;
                    }

                    var nextDigit = reversedValueExceptFirst % 10UL;
                    reversedValueExceptFirst = reversedValueExceptFirst / 10UL;

                    if (!formattingData.TryWriteDigit(nextDigit, buffer.Slice(bytesWritten), out digitBytes))
                    {
                        bytesWritten = 0;
                        return false;
                    }
                    bytesWritten += digitBytes;
                    digitsLeftInGroup--;
                }

                // Append trailing zeros if any
                while (trailingZerosCount-- > 0)
                {
                    if (digitsLeftInGroup == 0)
                    {
                        if (!formattingData.TryWriteSymbol(FormattingData.Symbol.GroupSeparator, buffer.Slice(bytesWritten), out digitBytes))
                        {
                            bytesWritten = 0;
                            return false;
                        }
                        bytesWritten += digitBytes;
                        digitsLeftInGroup = GroupSize;
                    }

                    if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes))
                    {
                        bytesWritten = 0;
                        return false;
                    }
                    bytesWritten += digitBytes;
                    digitsLeftInGroup--;
                }
            }
            else
            {
                while (reversedValueExceptFirst > 0)
                {
                    var bufferSlice = buffer.Slice(bytesWritten);
                    var nextDigit = reversedValueExceptFirst % 10UL;
                    reversedValueExceptFirst = reversedValueExceptFirst / 10UL;
                    if (!formattingData.TryWriteDigit(nextDigit, bufferSlice, out digitBytes))
                    {
                        bytesWritten = 0;
                        return false;
                    }
                    bytesWritten += digitBytes;
                }

                // Append trailing zeros if any
                while (trailingZerosCount-- > 0)
                {
                    if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes))
                    {
                        bytesWritten = 0;
                        return false;
                    }
                    bytesWritten += digitBytes;
                }
            }

            // If format is N and precision is not defined or is greater than zero, append trailing zeros after decimal point
            if (format.Symbol == 'N')
            {
                int trailingZerosAfterDecimalCount = format.HasPrecision ? format.Precision : 2;

                if (trailingZerosAfterDecimalCount > 0)
                {
                    if (!formattingData.TryWriteSymbol(FormattingData.Symbol.DecimalSeparator, buffer.Slice(bytesWritten), out digitBytes))
                    {
                        bytesWritten = 0;
                        return false;
                    }
                    bytesWritten += digitBytes;

                    while (trailingZerosAfterDecimalCount-- > 0)
                    {
                        if (!formattingData.TryWriteDigitOrSymbol(0, buffer.Slice(bytesWritten), out digitBytes))
                        {
                            bytesWritten = 0;
                            return false;
                        }
                        bytesWritten += digitBytes;
                    }
                }
            }

            return true;
        }
示例#19
0
        private static bool TryFormatHexadecimalInvariantCultureUtf8(ulong value, Span<byte> buffer, Format.Parsed format, out int bytesWritten)
        {
            Precondition.Require(format.Symbol == 'X' || format.Symbol == 'X');

            byte firstDigitOffset = (byte)'0';
            byte firstHexCharOffset = format.Symbol == 'X' ? (byte)'a' : (byte)'A';
            firstHexCharOffset -= 10;

            // Count amount of hex digits
            var hexDigitsCount = 1;
            ulong valueToCount = value;
            if (valueToCount > 0xFFFFFFFF)
            {
                hexDigitsCount += 8;
                valueToCount >>= 0x20;
            }
            if (valueToCount > 0xFFFF)
            {
                hexDigitsCount += 4;
                valueToCount >>= 0x10;
            }
            if (valueToCount > 0xFF)
            {
                hexDigitsCount += 2;
                valueToCount >>= 0x8;
            }
            if (valueToCount > 0xF)
            {
                hexDigitsCount++;
            }

            var bytesCount = hexDigitsCount;

            // Count leading zeros
            var leadingZerosCount = format.HasPrecision ? format.Precision - hexDigitsCount : 0;
            bytesCount += leadingZerosCount > 0 ? leadingZerosCount : 0;

            if (bytesCount > buffer.Length)
            {
                bytesWritten = 0;
                return false;
            }

            var index = bytesCount;
            while (hexDigitsCount-- > 0)
            {
                byte digit = (byte)(value & 0xF);
                value >>= 0x4;
                digit += digit < 10 ? firstDigitOffset : firstHexCharOffset;
                buffer[--index] = digit;
            }

            // Write leading zeros if any
            while (leadingZerosCount-- > 0)
            {
                buffer[--index] = firstDigitOffset;
            }

            bytesWritten = bytesCount;
            return true;
        }
        public static bool TryFormat(this string value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
        {
            if (formattingData.IsUtf16)
            {
                var valueBytes = value.Length << 1;
                if (valueBytes > buffer.Length)
                {
                    bytesWritten = 0;
                    return false;
                }

                unsafe
                {
                    fixed (char* pCharacters = value)
                    {
                        byte* pBytes = (byte*)pCharacters;
                        buffer.Set(pBytes, valueBytes);
                    }
                }

                bytesWritten = valueBytes;
                return true;
            }

            GCHandle handle;
            var byteSpan = buffer.Pin(out handle);
            try {

                var avaliableBytes = byteSpan.Length;
                bytesWritten = 0;
                for (int i = 0; i < value.Length; i++)
                {
                    var c = value[i];

                    var codepoint = (ushort)c;
                    if (codepoint <= 0x7f) // this if block just optimizes for ascii
                    {
                        if (bytesWritten + 1 > avaliableBytes)
                        {
                            bytesWritten = 0;
                            return false;
                        }
                        byteSpan[bytesWritten++] = (byte)codepoint;
                    }
                    else
                    {
                        Utf8EncodedCodePoint encoded;
                        if (!char.IsSurrogate(c))
                            encoded = new Utf8EncodedCodePoint(c);
                        else
                        {
                            if (++i >= value.Length)
                                throw new ArgumentException("value", "Invalid surrogate pair.");
                            char lowSurrogate = value[i];
                            encoded = new Utf8EncodedCodePoint(c, lowSurrogate);
                        }

                        if (bytesWritten + encoded.Length > avaliableBytes)
                        {
                            bytesWritten = 0;
                            return false;
                        }

                        byteSpan[bytesWritten] = encoded.Byte0;
                        if (encoded.Length > 1)
                        {
                            byteSpan[bytesWritten + 1] = encoded.Byte1;

                            if (encoded.Length > 2)
                            {
                                byteSpan[bytesWritten + 2] = encoded.Byte2;

                                if (encoded.Length > 3)
                                {
                                    byteSpan[bytesWritten + 3] = encoded.Byte3;
                                }
                            }
                        }

                        bytesWritten += encoded.Length;
                    }
                }
                return true;
            }
            finally
            {
                handle.Free();
            }
        }
 public static bool TryFormat(this long value, Span<byte> buffer, Format.Parsed format, FormattingData formattingData, out int bytesWritten)
 {
     return IntegerFormatter.TryFormatInt64(value, 8, buffer, format, formattingData, out bytesWritten);
 }