< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 106
Coverable lines: 106
Total lines: 244
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 20
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

C:\h\w\9FD50923\w\C0A20A61\e\runtime-utils\Runner\runtime\src\libraries\System.Private.CoreLib\src\System\Buffers\Text\FormattingHelpers.CountDigits.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Numerics;
 6using System.Runtime.CompilerServices;
 7using System.Runtime.InteropServices;
 8
 9namespace System.Buffers.Text
 10{
 11    internal static partial class FormattingHelpers
 12    {
 13        // Based on do_count_digits from https://github.com/fmtlib/fmt/blob/662adf4f33346ba9aba8b072194e319869ede54a/inc
 14        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 15        public static int CountDigits(ulong value)
 16        {
 17            // Map the log2(value) to a power of 10.
 018            ReadOnlySpan<byte> log2ToPow10 =
 019            [
 020                1,  1,  1,  2,  2,  2,  3,  3,  3,  4,  4,  4,  4,  5,  5,  5,
 021                6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  9,  9,  9,  10, 10, 10,
 022                10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
 023                15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20
 024            ];
 025            Debug.Assert(log2ToPow10.Length == 64);
 26
 027            nint elementOffset = log2ToPow10[(int)ulong.Log2(value)];
 28
 29            // Read the associated power of 10.
 030            ReadOnlySpan<ulong> powersOf10 =
 031            [
 032                0, // unused entry to avoid needing to subtract
 033                0,
 034                10,
 035                100,
 036                1000,
 037                10000,
 038                100000,
 039                1000000,
 040                10000000,
 041                100000000,
 042                1000000000,
 043                10000000000,
 044                100000000000,
 045                1000000000000,
 046                10000000000000,
 047                100000000000000,
 048                1000000000000000,
 049                10000000000000000,
 050                100000000000000000,
 051                1000000000000000000,
 052                10000000000000000000,
 053            ];
 054            Debug.Assert((elementOffset + 1) <= powersOf10.Length);
 055            ulong powerOf10 = Unsafe.Add(ref MemoryMarshal.GetReference(powersOf10), elementOffset);
 56
 57            // Return the number of digits based on the power of 10, shifted by 1
 58            // if it falls below the threshold.
 059            int index = (int)elementOffset;
 060            return index - (value < powerOf10 ? 1 : 0);
 61        }
 62
 63        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 64        public static int CountDigits(uint value)
 65        {
 66            // Algorithm based on https://lemire.me/blog/2021/06/03/computing-the-number-of-digits-of-an-integer-even-fa
 067            ReadOnlySpan<long> table =
 068            [
 069                4294967296,
 070                8589934582,
 071                8589934582,
 072                8589934582,
 073                12884901788,
 074                12884901788,
 075                12884901788,
 076                17179868184,
 077                17179868184,
 078                17179868184,
 079                21474826480,
 080                21474826480,
 081                21474826480,
 082                21474826480,
 083                25769703776,
 084                25769703776,
 085                25769703776,
 086                30063771072,
 087                30063771072,
 088                30063771072,
 089                34349738368,
 090                34349738368,
 091                34349738368,
 092                34349738368,
 093                38554705664,
 094                38554705664,
 095                38554705664,
 096                41949672960,
 097                41949672960,
 098                41949672960,
 099                42949672960,
 0100                42949672960,
 0101            ];
 0102            Debug.Assert(table.Length == 32, "Every result of uint.Log2(value) needs a long entry in the table.");
 103
 0104            long tableValue = table[(int)uint.Log2(value)];
 0105            return (int)((value + tableValue) >> 32);
 106        }
 107
 108        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 109        public static int CountHexDigits(ulong value)
 110        {
 111            // The number of hex digits is log16(value) + 1, or log2(value) / 4 + 1
 0112            return (BitOperations.Log2(value) >> 2) + 1;
 113        }
 114
 115        // Counts the number of trailing '0' digits in a decimal number.
 116        // e.g., value =      0 => retVal = 0, valueWithoutTrailingZeros = 0
 117        //       value =   1234 => retVal = 0, valueWithoutTrailingZeros = 1234
 118        //       value = 320900 => retVal = 2, valueWithoutTrailingZeros = 3209
 119        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 120        public static int CountDecimalTrailingZeros(uint value, out uint valueWithoutTrailingZeros)
 121        {
 0122            int zeroCount = 0;
 123
 0124            if (value != 0)
 125            {
 0126                while (true)
 127                {
 0128                    uint temp = value / 10;
 0129                    if (value != (temp * 10))
 130                    {
 131                        break;
 132                    }
 133
 0134                    value = temp;
 0135                    zeroCount++;
 136                }
 137            }
 138
 0139            valueWithoutTrailingZeros = value;
 0140            return zeroCount;
 141        }
 142    }
 143}

C:\h\w\9FD50923\w\C0A20A61\e\runtime-utils\Runner\runtime\src\libraries\System.Private.CoreLib\src\System\Buffers\Text\FormattingHelpers.CountDigits.Int128.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Runtime.CompilerServices;
 6
 7namespace System.Buffers.Text
 8{
 9    internal static partial class FormattingHelpers
 10    {
 11        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 12        public static int CountDigits(UInt128 value)
 13        {
 014            ulong upper = value.Upper;
 15
 16            // 1e19 is    8AC7_2304_89E8_0000
 17            // 1e20 is  5_6BC7_5E2D_6310_0000
 18            // 1e21 is 36_35C9_ADC5_DEA0_0000
 19
 020            if (upper == 0)
 21            {
 22                // We have less than 64-bits, so just return the lower count
 023                return CountDigits(value.Lower);
 24            }
 25
 26            // We have more than 1e19, so we have at least 20 digits
 027            int digits = 20;
 28
 029            if (upper > 5)
 30            {
 31                // ((2^128) - 1) / 1e20 < 34_02_823_669_209_384_635 which
 32                // is 18.5318 digits, meaning the result definitely fits
 33                // into 64-bits and we only need to add the lower digit count
 34
 035                value /= new UInt128(0x5, 0x6BC7_5E2D_6310_0000); // value /= 1e20
 036                Debug.Assert(value.Upper == 0);
 37
 038                digits += CountDigits(value.Lower);
 39            }
 040            else if ((upper == 5) && (value.Lower >= 0x6BC75E2D63100000))
 41            {
 42                // We're greater than 1e20, but definitely less than 1e21
 43                // so we have exactly 21 digits
 44
 045                digits++;
 046                Debug.Assert(digits == 21);
 47            }
 48
 049            return digits;
 50        }
 51
 52        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 53        public static int CountHexDigits(UInt128 value)
 54        {
 55            // The number of hex digits is log16(value) + 1, or log2(value) / 4 + 1
 056            return ((int)UInt128.Log2(value) >> 2) + 1;
 57        }
 58    }
 59}

C:\h\w\9FD50923\w\C0A20A61\e\runtime-utils\Runner\runtime\src\libraries\System.Private.CoreLib\src\System\Buffers\Text\Utf8Formatter\FormattingHelpers.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Globalization;
 5using System.Runtime.CompilerServices;
 6
 7namespace System.Buffers.Text
 8{
 9    internal static partial class FormattingHelpers
 10    {
 11        public static bool TryFormat<T>(T value, Span<byte> utf8Destination, out int bytesWritten, StandardFormat format
 12        {
 013            scoped Span<char> formatText = default;
 014            if (!format.IsDefault)
 15            {
 016                formatText = format.Format(stackalloc char[StandardFormat.FormatStringLength]);
 17            }
 18
 019            return value.TryFormat(utf8Destination, out bytesWritten, formatText, CultureInfo.InvariantCulture);
 20        }
 21
 22        /// <summary>
 23        /// Returns the symbol contained within the standard format. If the standard format
 24        /// has not been initialized, returns the provided fallback symbol.
 25        /// </summary>
 26        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 27        public static char GetSymbolOrDefault(in StandardFormat format, char defaultSymbol)
 28        {
 29            // This is equivalent to the line below, but it is written in such a way
 30            // that the JIT is able to perform more optimizations.
 31            //
 32            // return (format.IsDefault) ? defaultSymbol : format.Symbol;
 33
 034            char symbol = format.Symbol;
 035            if (symbol == default && format.Precision == default)
 36            {
 037                symbol = defaultSymbol;
 38            }
 039            return symbol;
 40        }
 41    }
 42}