< Summary

Line coverage
36%
Covered lines: 39
Uncovered lines: 67
Coverable lines: 106
Total lines: 247
Line coverage: 36.7%
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

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
File 1: CountDigits(...)100%110%
File 1: CountDigits(...)100%11100%
File 1: CountHexDigits(...)100%11100%
File 1: CountDecimalTrailingZeros(...)0%440%
File 2: CountDigits(...)0%880%
File 2: CountHexDigits(...)100%110%
File 3: TryFormat(...)0%440%
File 3: GetSymbolOrDefault(...)0%440%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/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
 6167            ReadOnlySpan<long> table =
 6168            [
 6169                4294967296,
 6170                8589934582,
 6171                8589934582,
 6172                8589934582,
 6173                12884901788,
 6174                12884901788,
 6175                12884901788,
 6176                17179868184,
 6177                17179868184,
 6178                17179868184,
 6179                21474826480,
 6180                21474826480,
 6181                21474826480,
 6182                21474826480,
 6183                25769703776,
 6184                25769703776,
 6185                25769703776,
 6186                30063771072,
 6187                30063771072,
 6188                30063771072,
 6189                34349738368,
 6190                34349738368,
 6191                34349738368,
 6192                34349738368,
 6193                38554705664,
 6194                38554705664,
 6195                38554705664,
 6196                41949672960,
 6197                41949672960,
 6198                41949672960,
 6199                42949672960,
 61100                42949672960,
 61101            ];
 61102            Debug.Assert(table.Length == 32, "Every result of uint.Log2(value) needs a long entry in the table.");
 103
 61104            long tableValue = table[(int)uint.Log2(value)];
 61105            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
 53112            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}
 144

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/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}
 60

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/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 unsafe bool TryFormat<T>(T value, Span<byte> utf8Destination, out int bytesWritten, StandardFormat
 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}
 43