< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 55
Coverable lines: 55
Total lines: 209
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 36
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)0%660%
op_Implicit(...)100%110%
Parse(...)100%110%
Parse(...)0%220%
TryParse(...)100%110%
ParseHelper(...)0%14140%
Equals(...)0%220%
GetHashCode()100%110%
Equals(...)0%220%
ToString()100%110%
Format(...)0%880%
op_Equality(...)100%110%
op_Inequality(...)100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Buffers/StandardFormat.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.Diagnostics.CodeAnalysis;
 6
 7namespace System.Buffers
 8{
 9    /// <summary>
 10    /// Represents a standard formatting string without using an actual String. A StandardFormat consists of a character
 11    /// and an optional precision ranging from 0..99, or the special value NoPrecision.
 12    /// </summary>
 13    public readonly struct StandardFormat : IEquatable<StandardFormat>
 14    {
 15        /// <summary>
 16        /// Precision values for format that don't use a precision, or for when the precision is to be unspecified.
 17        /// </summary>
 18        public const byte NoPrecision = byte.MaxValue;
 19
 20        /// <summary>
 21        /// The maximum valid precision value.
 22        /// </summary>
 23        public const byte MaxPrecision = 99;
 24
 25        private readonly byte _format;
 26        private readonly byte _precision;
 27
 28        /// <summary>
 29        /// The character component of the format.
 30        /// </summary>
 031        public char Symbol => (char)_format;
 32
 33        /// <summary>
 34        /// The precision component of the format. Ranges from 0..9 or the special value NoPrecision.
 35        /// </summary>
 036        public byte Precision => _precision;
 37
 38        /// <summary>
 39        /// true if Precision is a value other than NoPrecision
 40        /// </summary>
 041        public bool HasPrecision => _precision != NoPrecision;
 42
 43        /// <summary>Gets the precision if one was specified; otherwise, 0.</summary>
 044        internal byte PrecisionOrZero => _precision != NoPrecision ? _precision : (byte)0;
 45
 46        /// <summary>
 47        /// true if the StandardFormat == default(StandardFormat)
 48        /// </summary>
 049        public bool IsDefault => (_format | _precision) == 0;
 50
 51        /// <summary>
 52        /// Create a StandardFormat.
 53        /// </summary>
 54        /// <param name="symbol">A type-specific formatting character such as 'G', 'D' or 'X'</param>
 55        /// <param name="precision">An optional precision ranging from 0..9 or the special value NoPrecision (the defaul
 56        public StandardFormat(char symbol, byte precision = NoPrecision)
 57        {
 058            if (precision != NoPrecision && precision > MaxPrecision)
 059                ThrowHelper.ThrowArgumentOutOfRangeException_PrecisionTooLarge();
 060            if (symbol != (byte)symbol)
 061                ThrowHelper.ThrowArgumentOutOfRangeException_SymbolDoesNotFit();
 62
 063            _format = (byte)symbol;
 064            _precision = precision;
 065        }
 66
 67        /// <summary>
 68        /// Converts a character to a StandardFormat using the NoPrecision precision.
 69        /// </summary>
 070        public static implicit operator StandardFormat(char symbol) => new StandardFormat(symbol);
 71
 72        /// <summary>
 73        /// Converts a <see cref="ReadOnlySpan{Char}"/> into a StandardFormat
 74        /// </summary>
 75        public static StandardFormat Parse([StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format
 76        {
 077            ParseHelper(format, out StandardFormat standardFormat, throws: true);
 78
 079            return standardFormat;
 80        }
 81
 82        /// <summary>
 83        /// Converts a classic .NET format string into a StandardFormat
 84        /// </summary>
 085        public static StandardFormat Parse([StringSyntax(StringSyntaxAttribute.NumericFormat)] string? format) => format
 86
 87        /// <summary>
 88        /// Tries to convert a <see cref="ReadOnlySpan{Char}"/> into a StandardFormat. A return value indicates whether 
 89        /// </summary>
 90        public static bool TryParse([StringSyntax(StringSyntaxAttribute.NumericFormat)] ReadOnlySpan<char> format, out S
 91        {
 092            return ParseHelper(format, out result);
 93        }
 94
 95        private static bool ParseHelper(ReadOnlySpan<char> format, out StandardFormat standardFormat, bool throws = fals
 96        {
 097            standardFormat = default;
 98
 099            if (format.Length == 0)
 0100                return true;
 101
 0102            char symbol = format[0];
 103            byte precision;
 0104            if (format.Length == 1)
 105            {
 0106                precision = NoPrecision;
 107            }
 108            else
 109            {
 0110                uint parsedPrecision = 0;
 0111                for (int srcIndex = 1; srcIndex < format.Length; srcIndex++)
 112                {
 0113                    uint digit = format[srcIndex] - 48u; // '0'
 0114                    if (digit > 9)
 115                    {
 0116                        return throws ? throw new FormatException(SR.Format(SR.Argument_CannotParsePrecision, MaxPrecisi
 117                    }
 0118                    parsedPrecision = parsedPrecision * 10 + digit;
 0119                    if (parsedPrecision > MaxPrecision)
 120                    {
 0121                        return throws ? throw new FormatException(SR.Format(SR.Argument_PrecisionTooLarge, MaxPrecision)
 122                    }
 123                }
 124
 0125                precision = (byte)parsedPrecision;
 126            }
 127
 0128            standardFormat = new StandardFormat(symbol, precision);
 0129            return true;
 130        }
 131
 132        /// <summary>
 133        /// Returns true if both the Symbol and Precision are equal.
 134        /// </summary>
 0135        public override bool Equals([NotNullWhen(true)] object? obj) => obj is StandardFormat other && Equals(other);
 136
 137        /// <summary>
 138        /// Compute a hash code.
 139        /// </summary>
 0140        public override int GetHashCode() => _format.GetHashCode() ^ _precision.GetHashCode();
 141
 142        /// <summary>
 143        /// Returns true if both the Symbol and Precision are equal.
 144        /// </summary>
 0145        public bool Equals(StandardFormat other) => _format == other._format && _precision == other._precision;
 146
 147        /// <summary>
 148        /// Returns the format in classic .NET format.
 149        /// </summary>
 0150        public override string ToString() => new string(Format(stackalloc char[FormatStringLength]));
 151
 152        /// <summary>The exact buffer length required by <see cref="Format"/>.</summary>
 153        internal const int FormatStringLength = 3;
 154
 155        /// <summary>
 156        /// Formats the format in classic .NET format.
 157        /// </summary>
 158        internal Span<char> Format(Span<char> destination)
 159        {
 0160            Debug.Assert(destination.Length == FormatStringLength);
 161
 0162            char symbol = Symbol;
 163
 0164            if (symbol != default && destination.Length == FormatStringLength)
 165            {
 0166                destination[0] = symbol;
 167
 0168                uint precision = Precision;
 0169                if (precision != NoPrecision)
 170                {
 171                    // Note that Precision is stored as a byte, so in theory it could contain
 172                    // values > MaxPrecision (99).  But all supported mechanisms for creating a
 173                    // StandardFormat limit values to being <= MaxPrecision, so the only way a value
 174                    // could be larger than that is if unsafe code or the equivalent were used
 175                    // to force a larger invalid value in, in which case we don't need to
 176                    // guarantee such an invalid value is properly roundtripped through here;
 177                    // we just need to make sure things aren't corrupted further.
 178
 0179                    if (precision >= 10)
 180                    {
 181                        uint div;
 0182                        (div, precision) = Math.DivRem(precision, 10);
 0183                        destination[1] = (char)('0' + div % 10);
 0184                        destination[2] = (char)('0' + precision);
 0185                        return destination;
 186                    }
 187
 0188                    destination[1] = (char)('0' + precision);
 0189                    return destination.Slice(0, 2);
 190                }
 191
 0192                return destination.Slice(0, 1);
 193            }
 194
 0195            return default;
 196        }
 197
 198        /// <summary>
 199        /// Returns true if both the Symbol and Precision are equal.
 200        /// </summary>
 0201        public static bool operator ==(StandardFormat left, StandardFormat right) => left.Equals(right);
 202
 203        /// <summary>
 204        /// Returns false if both the Symbol and Precision are equal.
 205        /// </summary>
 0206        public static bool operator !=(StandardFormat left, StandardFormat right) => !left.Equals(right);
 207    }
 208}
 209