コード例 #1
0
        // Split long into three parts that can each fit in a uint - {1 digit}{9 digits}{9 digits}
        private static bool TryFormatInt64LessThanNegativeBillionMaxUInt(long value, Span <byte> destination, out int bytesWritten)
        {
            // value can still be negative if value == long.MinValue
            // Therefore, cast to ulong, since (ulong)value actually equals abs(long.MinValue)
            ulong overNineDigits     = (ulong)value / Utf8Constants.Billion;
            uint  lastNineDigits     = (uint)((ulong)value - (overNineDigits * Utf8Constants.Billion));
            uint  overEighteenDigits = (uint)(overNineDigits / Utf8Constants.Billion);
            uint  middleNineDigits   = (uint)(overNineDigits - (overEighteenDigits * Utf8Constants.Billion));

            int digitCountOverEighteenDigits = FormattingHelpers.CountDigits(overEighteenDigits);

            Debug.Assert(digitCountOverEighteenDigits == 1);
            int digitCount = digitCountOverEighteenDigits + 18;

            // WriteDigits does not do bounds checks
            if (digitCount >= destination.Length)
            {
                bytesWritten = 0;
                return(false);
            }
            destination[0] = Utf8Constants.Minus;
            bytesWritten   = digitCount + 1;
            FormattingHelpers.WriteDigits(overEighteenDigits, destination.Slice(1, digitCountOverEighteenDigits));
            FormattingHelpers.WriteDigits(middleNineDigits, destination.Slice(digitCountOverEighteenDigits + 1, 9));
            FormattingHelpers.WriteDigits(lastNineDigits, destination.Slice(digitCountOverEighteenDigits + 1 + 9, 9));
            return(true);
        }
コード例 #2
0
        private static bool TryFormatInt64N(long value, byte precision, Span <byte> buffer, out int bytesWritten)
        {
            int digitCount      = FormattingHelpers.CountDigits(value);
            int groupSeparators = (int)FormattingHelpers.DivMod(digitCount, Utf8Constants.GroupSize, out long firstGroup);

            if (firstGroup == 0)
            {
                firstGroup = 3;
                groupSeparators--;
            }

            int trailingZeros = (precision == StandardFormat.NoPrecision) ? 2 : precision;
            int idx           = (int)((value >> 63) & 1) + digitCount + groupSeparators;

            bytesWritten = idx;
            if (trailingZeros > 0)
            {
                bytesWritten += trailingZeros + 1; // +1 for period.
            }
            if (buffer.Length < bytesWritten)
            {
                bytesWritten = 0;
                return(false);
            }

            ref byte utf8Bytes = ref MemoryMarshal.GetReference(buffer);
コード例 #3
0
        private static bool TryFormatDecimalInt64(long value, byte precision, Span <byte> buffer, out int bytesWritten)
        {
            int digitCount  = FormattingHelpers.CountDigits(value);
            int bytesNeeded = digitCount + (int)((value >> 63) & 1);

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

            ref byte utf8Bytes = ref buffer.DangerousGetPinnableReference();
コード例 #4
0
        private static bool TryFormatDecimalInt64(long value, byte precision, Span <byte> buffer, out int bytesWritten)
        {
            int         digitCount  = FormattingHelpers.CountDigits(value);
            int         charsNeeded = digitCount + (int)((value >> 63) & 1);
            Span <char> span        = buffer.NonPortableCast <byte, char>();

            if (span.Length < charsNeeded)
            {
                bytesWritten = 0;
                return(false);
            }

            ref char utf16Bytes = ref span.DangerousGetPinnableReference();
コード例 #5
0
        private static bool TryFormatDecimalInt64(long value, byte precision, Span <byte> buffer, out int bytesWritten)
        {
            int         digitCount  = FormattingHelpers.CountDigits(value);
            int         charsNeeded = digitCount + (int)((value >> 63) & 1);
            Span <char> span        = MemoryMarshal.Cast <byte, char>(buffer);

            if (span.Length < charsNeeded)
            {
                bytesWritten = 0;
                return(false);
            }

            ref char utf16Bytes = ref MemoryMarshal.GetReference(span);
コード例 #6
0
        private static bool TryFormatUInt64MultipleDigits(ulong value, Span <byte> destination, out int bytesWritten)
        {
            int digitCount = FormattingHelpers.CountDigits(value);

            // WriteDigits does not do bounds checks
            if (digitCount > destination.Length)
            {
                bytesWritten = 0;
                return(false);
            }
            bytesWritten = digitCount;
            FormattingHelpers.WriteDigits(value, destination.Slice(0, digitCount));
            return(true);
        }
コード例 #7
0
        private static bool TryFormatUInt32MultipleDigits(uint value, Span <byte> buffer, out int bytesWritten)
        {
            int digitCount = FormattingHelpers.CountDigits(value);

            // WriteDigits does not do bounds checks
            if (digitCount > buffer.Length)
            {
                bytesWritten = 0;
                return(false);
            }
            bytesWritten = digitCount;
            FormattingHelpers.WriteDigits(value, buffer.Slice(0, digitCount));
            return(true);
        }
コード例 #8
0
        private static bool TryFormatInt64D(long value, byte precision, Span <byte> buffer, out int bytesWritten)
        {
            int digitCount  = FormattingHelpers.CountDigits(value);
            int bytesNeeded = digitCount + (int)((value >> 63) & 1);

            if (precision != StandardFormat.NoPrecision && precision > digitCount)
            {
                bytesNeeded += (precision - digitCount);
            }

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

            ref byte utf8Bytes = ref MemoryMarshal.GetReference(buffer);
コード例 #9
0
        private static bool TryFormatUInt64LessThanBillionMaxUInt(ulong value, Span <byte> destination, out int bytesWritten)
        {
            uint overNineDigits = (uint)(value / Utf8Constants.Billion);
            uint lastNineDigits = (uint)(value - (overNineDigits * Utf8Constants.Billion));

            int digitCountOverNineDigits = FormattingHelpers.CountDigits(overNineDigits);

            Debug.Assert(digitCountOverNineDigits >= 1 && digitCountOverNineDigits <= 10);
            int digitCount = digitCountOverNineDigits + 9;

            // WriteDigits does not do bounds checks
            if (digitCount > destination.Length)
            {
                bytesWritten = 0;
                return(false);
            }
            bytesWritten = digitCount;
            FormattingHelpers.WriteDigits(overNineDigits, destination.Slice(0, digitCountOverNineDigits));
            FormattingHelpers.WriteDigits(lastNineDigits, destination.Slice(digitCountOverNineDigits, 9));
            return(true);
        }
コード例 #10
0
 private static bool TryFormatInt64MultipleDigits(long value, Span <byte> destination, out int bytesWritten)
 {
     if (value < 0)
     {
         value = -value;
         int digitCount = FormattingHelpers.CountDigits((ulong)value);
         // WriteDigits does not do bounds checks
         if (digitCount >= destination.Length)
         {
             bytesWritten = 0;
             return(false);
         }
         destination[0] = Utf8Constants.Minus;
         bytesWritten   = digitCount + 1;
         FormattingHelpers.WriteDigits((ulong)value, destination.Slice(1, digitCount));
         return(true);
     }
     else
     {
         return(TryFormatUInt64MultipleDigits((ulong)value, destination, out bytesWritten));
     }
 }
コード例 #11
0
 private static bool TryFormatInt32MultipleDigits(int value, Span <byte> buffer, out int bytesWritten)
 {
     if (value < 0)
     {
         value = -value;
         int digitCount = FormattingHelpers.CountDigits((uint)value);
         // WriteDigits does not do bounds checks
         if (digitCount >= buffer.Length)
         {
             bytesWritten = 0;
             return(false);
         }
         buffer[0]    = Utf8Constants.Minus;
         bytesWritten = digitCount + 1;
         FormattingHelpers.WriteDigits((uint)value, buffer.Slice(1, digitCount));
         return(true);
     }
     else
     {
         return(TryFormatUInt32MultipleDigits((uint)value, buffer, out bytesWritten));
     }
 }
コード例 #12
0
        // Split long into two parts that can each fit in a uint - {1-10 digits}{9 digits}
        private static bool TryFormatInt64MoreThanNegativeBillionMaxUInt(long value, Span <byte> buffer, out int bytesWritten)
        {
            uint overNineDigits = (uint)(value / Utf8Constants.Billion);
            uint lastNineDigits = (uint)(value - (overNineDigits * Utf8Constants.Billion));

            int digitCountOverNineDigits = FormattingHelpers.CountDigits(overNineDigits);

            Debug.Assert(digitCountOverNineDigits >= 1 && digitCountOverNineDigits <= 10);
            int digitCount = digitCountOverNineDigits + 9;

            // WriteDigits does not do bounds checks
            if (digitCount >= buffer.Length)
            {
                bytesWritten = 0;
                return(false);
            }
            buffer[0]    = Utf8Constants.Minus;
            bytesWritten = digitCount + 1;
            FormattingHelpers.WriteDigits(overNineDigits, buffer.Slice(1, digitCountOverNineDigits));
            FormattingHelpers.WriteDigits(lastNineDigits, buffer.Slice(digitCountOverNineDigits + 1, 9));
            return(true);
        }
コード例 #13
0
        // Split ulong into three parts that can each fit in a uint - {1-2 digits}{9 digits}{9 digits}
        private static bool TryFormatUInt64MoreThanBillionMaxUInt(ulong value, Span <byte> buffer, out int bytesWritten)
        {
            ulong overNineDigits     = value / Utf8Constants.Billion;
            uint  lastNineDigits     = (uint)(value - (overNineDigits * Utf8Constants.Billion));
            uint  overEighteenDigits = (uint)(overNineDigits / Utf8Constants.Billion);
            uint  middleNineDigits   = (uint)(overNineDigits - (overEighteenDigits * Utf8Constants.Billion));

            int digitCountOverEighteenDigits = FormattingHelpers.CountDigits(overEighteenDigits);

            Debug.Assert(digitCountOverEighteenDigits >= 1 && digitCountOverEighteenDigits <= 2);
            int digitCount = digitCountOverEighteenDigits + 18;

            // WriteDigits does not do bounds checks
            if (digitCount > buffer.Length)
            {
                bytesWritten = 0;
                return(false);
            }
            bytesWritten = digitCount;
            FormattingHelpers.WriteDigits(overEighteenDigits, buffer.Slice(0, digitCountOverEighteenDigits));
            FormattingHelpers.WriteDigits(middleNineDigits, buffer.Slice(digitCountOverEighteenDigits, 9));
            FormattingHelpers.WriteDigits(lastNineDigits, buffer.Slice(digitCountOverEighteenDigits + 9, 9));
            return(true);
        }
コード例 #14
0
        /// <summary>
        /// Formats a TimeSpan as a UTF8 string.
        /// </summary>
        /// <param name="value">Value to format</param>
        /// <param name="destination">Buffer to write the UTF8-formatted value to</param>
        /// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
        /// <param name="format">The standard format to use</param>
        /// <returns>
        /// true for success. "bytesWritten" contains the length of the formatted text in bytes.
        /// false if buffer was too short. Iteratively increase the size of the buffer and retry until it succeeds.
        /// </returns>
        /// <remarks>
        /// Formats supported:
        ///     c/t/T (default) [-][d.]hh:mm:ss[.fffffff]              (constant format)
        ///     G               [-]d:hh:mm:ss.fffffff                  (general long)
        ///     g               [-][d:][h]h:mm:ss[.f[f[f[f[f[f[f]]]]]] (general short)
        /// </remarks>
        /// <exceptions>
        /// <cref>System.FormatException</cref> if the format is not valid for this data type.
        /// </exceptions>
        public static bool TryFormat(TimeSpan value, Span <byte> destination, out int bytesWritten, StandardFormat format = default)
        {
            char symbol = FormattingHelpers.GetSymbolOrDefault(format, 'c');

            switch (symbol)
            {
            case 'c':
            case 'G':
            case 'g':
                break;

            case 't':
            case 'T':
                symbol = 'c';
                break;

            default:
                return(FormattingHelpers.TryFormatThrowFormatException(out bytesWritten));
            }

            // First, calculate how large an output buffer is needed to hold the entire output.

            int requiredOutputLength = 8; // start with "hh:mm:ss" and adjust as necessary

            uint  fraction;
            ulong totalSecondsRemaining;

            {
                // Turn this into a non-negative TimeSpan if possible.
                long ticks = value.Ticks;
                if (ticks < 0)
                {
                    ticks = -ticks;
                    if (ticks < 0)
                    {
                        Debug.Assert(ticks == long.MinValue /* -9223372036854775808 */);

                        // We computed these ahead of time; they're straight from the decimal representation of Int64.MinValue.
                        fraction = 4775808;
                        totalSecondsRemaining = 922337203685;
                        goto AfterComputeFraction;
                    }
                }

                ulong fraction64;
                (totalSecondsRemaining, fraction64) = Math.DivRem((ulong)Math.Abs(value.Ticks), TimeSpan.TicksPerSecond);
                fraction = (uint)fraction64;
            }

AfterComputeFraction:

            int fractionDigits = 0;

            if (symbol == 'c')
            {
                // Only write out the fraction if it's non-zero, and in that
                // case write out the entire fraction (all digits).
                if (fraction != 0)
                {
                    fractionDigits = Utf8Constants.DateTimeNumFractionDigits;
                }
            }
            else if (symbol == 'G')
            {
                // Always write out the fraction, even if it's zero.
                fractionDigits = Utf8Constants.DateTimeNumFractionDigits;
            }
            else
            {
                // Only write out the fraction if it's non-zero, and in that
                // case write out only the most significant digits.
                if (fraction != 0)
                {
                    fractionDigits = Utf8Constants.DateTimeNumFractionDigits - FormattingHelpers.CountDecimalTrailingZeros(fraction, out fraction);
                }
            }

            Debug.Assert(fraction < 10_000_000);

            // If we're going to write out a fraction, also need to write the leading decimal.
            if (fractionDigits != 0)
            {
                requiredOutputLength += fractionDigits + 1;
            }

            ulong totalMinutesRemaining = 0;
            ulong seconds = 0;

            if (totalSecondsRemaining > 0)
            {
                // Only compute minutes if the TimeSpan has an absolute value of >= 1 minute.
                (totalMinutesRemaining, seconds) = Math.DivRem(totalSecondsRemaining, 60 /* seconds per minute */);
            }

            Debug.Assert(seconds < 60);

            ulong totalHoursRemaining = 0;
            ulong minutes             = 0;

            if (totalMinutesRemaining > 0)
            {
                // Only compute hours if the TimeSpan has an absolute value of >= 1 hour.
                (totalHoursRemaining, minutes) = Math.DivRem(totalMinutesRemaining, 60 /* minutes per hour */);
            }

            Debug.Assert(minutes < 60);

            // At this point, we can switch over to 32-bit divmod since the data has shrunk far enough.
            Debug.Assert(totalHoursRemaining <= uint.MaxValue);

            uint days  = 0;
            uint hours = 0;

            if (totalHoursRemaining > 0)
            {
                // Only compute days if the TimeSpan has an absolute value of >= 1 day.
                (days, hours) = Math.DivRem((uint)totalHoursRemaining, 24 /* hours per day */);
            }

            Debug.Assert(hours < 24);

            int hourDigits = 2;

            if (hours < 10 && symbol == 'g')
            {
                // Only writing a one-digit hour, not a two-digit hour
                hourDigits--;
                requiredOutputLength--;
            }

            int dayDigits = 0;

            if (days == 0)
            {
                if (symbol == 'G')
                {
                    requiredOutputLength += 2; // for the leading "0:"
                    dayDigits             = 1;
                }
            }
            else
            {
                dayDigits             = FormattingHelpers.CountDigits(days);
                requiredOutputLength += dayDigits + 1; // for the leading "d:" (or "d.")
            }

            if (value.Ticks < 0)
            {
                requiredOutputLength++; // for the leading '-' sign
            }

            if (destination.Length < requiredOutputLength)
            {
                bytesWritten = 0;
                return(false);
            }

            bytesWritten = requiredOutputLength;

            int idx = 0;

            // Write leading '-' if necessary
            if (value.Ticks < 0)
            {
                destination[idx++] = Utf8Constants.Minus;
            }

            // Write day (and separator) if necessary
            if (dayDigits > 0)
            {
                FormattingHelpers.WriteDigits(days, destination.Slice(idx, dayDigits));
                idx += dayDigits;
                destination[idx++] = (symbol == 'c') ? Utf8Constants.Period : Utf8Constants.Colon;
            }

            // Write "[h]h:mm:ss"
            FormattingHelpers.WriteDigits(hours, destination.Slice(idx, hourDigits));
            idx += hourDigits;
            destination[idx++] = Utf8Constants.Colon;
            FormattingHelpers.WriteDigits((uint)minutes, destination.Slice(idx, 2));
            idx += 2;
            destination[idx++] = Utf8Constants.Colon;
            FormattingHelpers.WriteDigits((uint)seconds, destination.Slice(idx, 2));
            idx += 2;

            // Write fraction (and separator) if necessary
            if (fractionDigits > 0)
            {
                destination[idx++] = Utf8Constants.Period;
                FormattingHelpers.WriteDigits(fraction, destination.Slice(idx, fractionDigits));
                idx += fractionDigits;
            }

            // And we're done!

            Debug.Assert(idx == requiredOutputLength);
            return(true);
        }
コード例 #15
0
        /// <summary>
        /// Formats a TimeSpan as a UTF8 string.
        /// </summary>
        /// <param name="value">Value to format</param>
        /// <param name="buffer">Buffer to write the UTF8-formatted value to</param>
        /// <param name="bytesWritten">Receives the length of the formatted text in bytes</param>
        /// <param name="format">The standard format to use</param>
        /// <returns>
        /// true for success. "bytesWritten" contains the length of the formatted text in bytes.
        /// false if buffer was too short. Iteratively increase the size of the buffer and retry until it succeeds.
        /// </returns>
        /// <remarks>
        /// Formats supported:
        ///     c/t/T (default) [-][d.]hh:mm:ss[.fffffff]             (constant format)
        ///     G               [-]d:hh:mm:ss.fffffff                 (general long)
        ///     g               [-][d:]h:mm:ss[.f[f[f[f[f[f[f[]]]]]]] (general short)
        /// </remarks>
        /// <exceptions>
        /// <cref>System.FormatException</cref> if the format is not valid for this data type.
        /// </exceptions>
        public static bool TryFormat(TimeSpan value, Span <byte> buffer, out int bytesWritten, StandardFormat format = default)
        {
            char symbol = format.IsDefault ? 'c' : format.Symbol;

            switch (symbol)
            {
            case 'G':
            case 'g':
            case 'c':
            case 't':
            case 'T':
            {
                bool longForm = (symbol == 'G');
                bool constant = (symbol == 't' || symbol == 'T' || symbol == 'c');

                long ticks = value.Ticks;
                int  days  = (int)FormattingHelpers.DivMod(ticks, TimeSpan.TicksPerDay, out long timeLeft);

                bool showSign = false;
                if (ticks < 0)
                {
                    showSign = true;
                    days     = -days;
                    timeLeft = -timeLeft;
                }

                int hours   = (int)FormattingHelpers.DivMod(timeLeft, TimeSpan.TicksPerHour, out timeLeft);
                int minutes = (int)FormattingHelpers.DivMod(timeLeft, TimeSpan.TicksPerMinute, out timeLeft);
                int seconds = (int)FormattingHelpers.DivMod(timeLeft, TimeSpan.TicksPerSecond, out long fraction);

                int dayDigits      = 0;
                int hourDigits     = (constant || longForm || hours > 9) ? 2 : 1;
                int fractionDigits = 0;

                bytesWritten = hourDigits + 6;         // [h]h:mm:ss
                if (showSign)
                {
                    bytesWritten += 1;          // [-]
                }
                if (longForm || days > 0)
                {
                    dayDigits     = FormattingHelpers.CountDigits(days);
                    bytesWritten += dayDigits + 1;         // [d'.']
                }
                if (longForm || fraction > 0)
                {
                    fractionDigits = (longForm || constant) ? Utf8Constants.DateTimeNumFractionDigits : FormattingHelpers.CountFractionDigits(fraction);
                    bytesWritten  += fractionDigits + 1;        // ['.'fffffff] or ['.'FFFFFFF] for short-form
                }

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

                ref byte utf8Bytes = ref buffer.DangerousGetPinnableReference();
                int      idx       = 0;

                if (showSign)
                {
                    Unsafe.Add(ref utf8Bytes, idx++) = Utf8Constants.Minus;
                }

                if (dayDigits > 0)
                {
                    idx += FormattingHelpers.WriteDigits(days, dayDigits, ref utf8Bytes, idx);
                    Unsafe.Add(ref utf8Bytes, idx++) = constant ? Utf8Constants.Period : Utf8Constants.Colon;
                }

                idx += FormattingHelpers.WriteDigits(hours, hourDigits, ref utf8Bytes, idx);
                Unsafe.Add(ref utf8Bytes, idx++) = Utf8Constants.Colon;

                idx += FormattingHelpers.WriteDigits(minutes, 2, ref utf8Bytes, idx);
                Unsafe.Add(ref utf8Bytes, idx++) = Utf8Constants.Colon;

                idx += FormattingHelpers.WriteDigits(seconds, 2, ref utf8Bytes, idx);

                if (fractionDigits > 0)
                {
                    Unsafe.Add(ref utf8Bytes, idx++) = Utf8Constants.Period;
                    idx += FormattingHelpers.WriteFractionDigits(fraction, fractionDigits, ref utf8Bytes, idx);
                }

                return(true);
            }