private static bool TryFormatUInt64Default(ulong value, Span <byte> buffer, out int bytesWritten)
        {
            if (value < 10)
            {
                if (buffer.Length == 0)
                {
                    goto FalseExit;
                }
                buffer[0]    = (byte)('0' + value);
                bytesWritten = 1;
                return(true);
            }

            int digitCount = FormattingHelpers.CountDigits(value);

            if (digitCount > buffer.Length)
            {
                goto FalseExit;
            }
            bytesWritten = digitCount;
            // WriteDigits does not do bounds checks
            FormattingHelpers.WriteDigits(value, buffer.Slice(0, digitCount));
            return(true);

FalseExit:
            bytesWritten = 0;
            return(false);
        }
예제 #2
0
        /// <summary>
        /// Gets the total number of digits in the <see cref="Number"/>.
        /// </summary>
        /// <returns>The total number of digits in the <see cref="Number"/></returns>
        /// <exception cref="InvalidOperationException">The precision is greater than <see cref="int.MaxValue" />.</exception>
        public readonly int GetPrecision()
        {
            if (_isNull)
            {
                return(0);
            }

            int precision = FormattingHelpers.CountDigits(_unscaledNumber);
            int scale     = Scale;

            if (precision <= scale)
            {
                return(precision + (scale - precision) + 1);
            }
            return(precision);
        }
        private static bool TryFormatUInt64N(ulong value, byte precision, Span <byte> destination, bool insertNegationSign, out int bytesWritten)
        {
            // Calculate the actual digit count, number of group separators required, and the
            // number of trailing zeros requested. From all of this we can get the required
            // buffer length.

            int digitCount        = FormattingHelpers.CountDigits(value);
            int commaCount        = (digitCount - 1) / 3;
            int trailingZeroCount = (precision == StandardFormat.NoPrecision) ? 2 /* default for 'N' */ : precision;

            int requiredBufferLength = digitCount + commaCount;

            if (trailingZeroCount > 0)
            {
                requiredBufferLength += trailingZeroCount + 1;
            }

            if (insertNegationSign)
            {
                requiredBufferLength++;
            }

            if (requiredBufferLength > destination.Length)
            {
                bytesWritten = 0;
                return(false);
            }

            bytesWritten = requiredBufferLength;

            if (insertNegationSign)
            {
                destination[0] = Utf8Constants.Minus;
                destination    = destination.Slice(1);
            }

            FormattingHelpers.WriteDigitsWithGroupSeparator(value, destination.Slice(0, digitCount + commaCount));

            if (trailingZeroCount > 0)
            {
                destination[digitCount + commaCount] = Utf8Constants.Period;
                FormattingHelpers.FillWithAsciiZeros(destination.Slice(digitCount + commaCount + 1, trailingZeroCount));
            }

            return(true);
        }
        private static bool TryFormatInt64Default(long value, Span <byte> buffer, out int bytesWritten)
        {
            if ((ulong)value < 10)
            {
                if (buffer.Length == 0)
                {
                    goto FalseExit;
                }
                buffer[0]    = (byte)('0' + value);
                bytesWritten = 1;
                return(true);
            }

            if (value < 0)
            {
                value = -value;
                int digitCount = FormattingHelpers.CountDigits((ulong)value);
                if (digitCount >= buffer.Length)
                {
                    goto FalseExit;
                }
                bytesWritten = digitCount + 1;
                buffer[0]    = Utf8Constants.Minus;
                buffer       = buffer.Slice(1, digitCount);
            }
            else
            {
                int digitCount = FormattingHelpers.CountDigits((ulong)value);
                if (digitCount > buffer.Length)
                {
                    goto FalseExit;
                }
                bytesWritten = digitCount;
                buffer       = buffer.Slice(0, digitCount);
            }

            // WriteDigits does not do bounds checks
            FormattingHelpers.WriteDigits((ulong)value, buffer);
            return(true);

FalseExit:
            bytesWritten = 0;
            return(false);
        }
        private static bool TryFormatUInt64D(ulong value, byte precision, Span <byte> destination, bool insertNegationSign, out int bytesWritten)
        {
            // Calculate the actual digit count and the number of padding zeroes requested.
            // From all of this we can get the required buffer length.

            int digitCount       = FormattingHelpers.CountDigits(value);
            int leadingZeroCount = ((precision == StandardFormat.NoPrecision) ? 0 : (int)precision) - digitCount;

            if (leadingZeroCount < 0)
            {
                leadingZeroCount = 0;
            }

            int requiredBufferLength = digitCount + leadingZeroCount;

            if (insertNegationSign)
            {
                requiredBufferLength++;
            }

            if (requiredBufferLength > destination.Length)
            {
                bytesWritten = 0;
                return(false);
            }

            bytesWritten = requiredBufferLength;

            if (insertNegationSign)
            {
                destination[0] = Utf8Constants.Minus;
                destination    = destination.Slice(1);
            }

            if (leadingZeroCount > 0)
            {
                FormattingHelpers.FillWithAsciiZeros(destination.Slice(0, leadingZeroCount));
            }
            FormattingHelpers.WriteDigits(value, destination.Slice(leadingZeroCount, digitCount));

            return(true);
        }
예제 #6
0
        private static bool TryFormatStandard(TimeSpan value, StandardFormat format, string?decimalSeparator, Span <char> destination, out int charsWritten)
        {
            Debug.Assert(format == StandardFormat.C || format == StandardFormat.G || format == StandardFormat.g);

            // 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)
                {
                    requiredOutputLength = 9; // requiredOutputLength + 1 for the leading '-' sign
                    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)ticks, TimeSpan.TicksPerSecond);
                fraction = (uint)fraction64;
            }

AfterComputeFraction:
            // Only write out the fraction if it's non-zero, and in that
            // case write out the entire fraction (all digits).
            Debug.Assert(fraction < 10_000_000);
            int fractionDigits = 0;

            switch (format)
            {
            case StandardFormat.C:
                // "c": Write out a fraction only if it's non-zero, and write out all 7 digits of it.
                if (fraction != 0)
                {
                    fractionDigits        = DateTimeFormat.MaxSecondsFractionDigits;
                    requiredOutputLength += fractionDigits + 1;     // digits plus leading decimal separator
                }
                break;

            case StandardFormat.G:
                // "G": Write out a fraction regardless of whether it's 0, and write out all 7 digits of it.
                fractionDigits        = DateTimeFormat.MaxSecondsFractionDigits;
                requiredOutputLength += fractionDigits + 1;     // digits plus leading decimal separator
                break;

            default:
                // "g": Write out a fraction only if it's non-zero, and write out only the most significant digits.
                Debug.Assert(format == StandardFormat.g);
                if (fraction != 0)
                {
                    fractionDigits        = DateTimeFormat.MaxSecondsFractionDigits - FormattingHelpers.CountDecimalTrailingZeros(fraction, out fraction);
                    requiredOutputLength += fractionDigits + 1;     // digits plus leading decimal separator
                }
                break;
            }

            ulong totalMinutesRemaining = 0, 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, 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 DivRem since the data has shrunk far enough.
            Debug.Assert(totalHoursRemaining <= uint.MaxValue);

            uint days = 0, 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 (format == StandardFormat.g && hours < 10)
            {
                // "g": Only writing a one-digit hour, rather than expected two-digit hour
                hourDigits = 1;
                requiredOutputLength--;
            }

            int dayDigits = 0;

            if (days > 0)
            {
                dayDigits = FormattingHelpers.CountDigits(days);
                Debug.Assert(dayDigits <= 8);
                requiredOutputLength += dayDigits + 1; // for the leading "d."
            }
            else if (format == StandardFormat.G)
            {
                // "G": has a leading "0:" if days is 0
                requiredOutputLength += 2;
                dayDigits             = 1;
            }

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

            // Write leading '-' if necessary
            int idx = 0;

            if (value.Ticks < 0)
            {
                destination[idx++] = '-';
            }

            // Write day and separator, if necessary
            if (dayDigits != 0)
            {
                WriteDigits(days, destination.Slice(idx, dayDigits));
                idx += dayDigits;
                destination[idx++] = format == StandardFormat.C ? '.' : ':';
            }

            // Write "[h]h:mm:ss
            Debug.Assert(hourDigits == 1 || hourDigits == 2);
            if (hourDigits == 2)
            {
                WriteTwoDigits(hours, destination.Slice(idx));
                idx += 2;
            }
            else
            {
                destination[idx++] = (char)('0' + hours);
            }
            destination[idx++] = ':';
            WriteTwoDigits((uint)minutes, destination.Slice(idx));
            idx += 2;
            destination[idx++] = ':';
            WriteTwoDigits((uint)seconds, destination.Slice(idx));
            idx += 2;

            // Write fraction and separator, if necessary
            if (fractionDigits != 0)
            {
                Debug.Assert(format == StandardFormat.C || decimalSeparator != null);
                if (format == StandardFormat.C)
                {
                    destination[idx++] = '.';
                }
                else if (decimalSeparator !.Length == 1)
                {
                    destination[idx++] = decimalSeparator[0];
                }
                else
                {
                    decimalSeparator.AsSpan().CopyTo(destination);
                    idx += decimalSeparator.Length;
                }
                WriteDigits(fraction, destination.Slice(idx, fractionDigits));
                idx += fractionDigits;
            }
예제 #7
0
        private static bool TryFormatC(TimeSpan value, Span <char> destination, out int charsWritten)
        {
            // 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)
                {
                    requiredOutputLength = 9; // requiredOutputLength + 1 for the leading '-' sign
                    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;
                    }
                }

                totalSecondsRemaining = Math.DivRem((ulong)ticks, TimeSpan.TicksPerSecond, out ulong fraction64);
                fraction = (uint)fraction64;
            }

AfterComputeFraction:
            // Only write out the fraction if it's non-zero, and in that
            // case write out the entire fraction (all digits).
            int fractionDigits = 0;

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

            ulong totalMinutesRemaining = 0, seconds = 0;

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

            ulong totalHoursRemaining = 0, minutes = 0;

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

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

            uint days = 0, hours = 0;

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

            int dayDigits = 0;

            if (days > 0)
            {
                dayDigits = FormattingHelpers.CountDigits(days);
                Debug.Assert(dayDigits <= 8);
                requiredOutputLength += dayDigits + 1; // for the leading "d."
            }

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

            // Write leading '-' if necessary
            int idx = 0;

            if (value.Ticks < 0)
            {
                destination[idx++] = '-';
            }

            // Write day and separator, if necessary
            if (dayDigits != 0)
            {
                WriteDigits(days, destination.Slice(idx, dayDigits));
                idx += dayDigits;
                destination[idx++] = '.';
            }

            // Write "hh:mm:ss"
            WriteTwoDigits(hours, destination.Slice(idx));
            idx += 2;
            destination[idx++] = ':';
            WriteTwoDigits((uint)minutes, destination.Slice(idx));
            idx += 2;
            destination[idx++] = ':';
            WriteTwoDigits((uint)seconds, destination.Slice(idx));
            idx += 2;

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

            Debug.Assert(idx == requiredOutputLength);
            charsWritten = requiredOutputLength;
            return(true);
        }