< Summary

Line coverage
60%
Covered lines: 3
Uncovered lines: 2
Coverable lines: 5
Total lines: 174
Line coverage: 60%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
.ctor()100%11100%
CreateFallbackBuffer()100%110%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.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
 4//
 5// This is used internally to create best fit behavior as per the original windows best fit behavior.
 6//
 7
 8using System.Diagnostics;
 9using System.Globalization;
 10
 11namespace System.Text
 12{
 13    internal sealed class EncoderLatin1BestFitFallback : EncoderFallback
 14    {
 15        // Provides access to the singleton instance of this fallback mechanism
 116        internal static readonly EncoderLatin1BestFitFallback SingletonInstance = new EncoderLatin1BestFitFallback();
 17
 118        private EncoderLatin1BestFitFallback()
 19        {
 120        }
 21
 22        public override EncoderFallbackBuffer CreateFallbackBuffer() =>
 023            new EncoderLatin1BestFitFallbackBuffer();
 24
 25        // Maximum number of characters that this instance of this fallback could return
 026        public override int MaxCharCount => 1;
 27    }
 28
 29    internal sealed partial class EncoderLatin1BestFitFallbackBuffer : EncoderFallbackBuffer
 30    {
 31        // Our variables
 32        private char _cBestFit;
 33        private int _iCount = -1;
 34        private int _iSize;
 35
 36        // Fallback methods
 37        public override bool Fallback(char charUnknown, int index)
 38        {
 39            // If we had a buffer already we're being recursive, throw, it's probably at the suspect
 40            // character in our array.
 41            // Shouldn't be able to get here for all of our code pages, table would have to be messed up.
 42            Debug.Assert(_iCount < 1, $"[EncoderLatin1BestFitFallbackBuffer.Fallback(non surrogate)] Fallback char {(int
 43
 44            _iCount = _iSize = 1;
 45            _cBestFit = TryBestFit(charUnknown);
 46            if (_cBestFit == '\0')
 47                _cBestFit = '?';
 48
 49            return true;
 50        }
 51
 52        public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
 53        {
 54            // Double check input surrogate pair
 55            if (!char.IsHighSurrogate(charUnknownHigh))
 56                throw new ArgumentOutOfRangeException(nameof(charUnknownHigh),
 57                    SR.Format(SR.ArgumentOutOfRange_Range,
 58                    0xD800, 0xDBFF));
 59
 60            if (!char.IsLowSurrogate(charUnknownLow))
 61                throw new ArgumentOutOfRangeException(nameof(charUnknownLow),
 62                    SR.Format(SR.ArgumentOutOfRange_Range,
 63                    0xDC00, 0xDFFF));
 64
 65            // If we had a buffer already we're being recursive, throw, it's probably at the suspect
 66            // character in our array.  0 is processing last character, < 0 is not falling back
 67            // Shouldn't be able to get here, table would have to be messed up.
 68            Debug.Assert(_iCount < 1, $"[EncoderLatin1BestFitFallbackBuffer.Fallback(surrogate)] Fallback char {(int)_cB
 69
 70            // Go ahead and get our fallback, surrogates don't have best fit
 71            _cBestFit = '?';
 72            _iCount = _iSize = 2;
 73
 74            return true;
 75        }
 76
 77        // Default version is overridden in EncoderReplacementFallback.cs
 78        public override char GetNextChar()
 79        {
 80            // We want it to get < 0 because == 0 means that the current/last character is a fallback
 81            // and we need to detect recursion.  We could have a flag but we already have this counter.
 82            _iCount--;
 83
 84            // Do we have anything left? 0 is now last fallback char, negative is nothing left
 85            if (_iCount < 0)
 86                return '\0';
 87
 88            // Need to get it out of the buffer.
 89            // Make sure it didn't wrap from the fast count-- path
 90            if (_iCount == int.MaxValue)
 91            {
 92                _iCount = -1;
 93                return '\0';
 94            }
 95
 96            // Return the best fit character
 97            return _cBestFit;
 98        }
 99
 100        public override bool MovePrevious()
 101        {
 102            // Exception fallback doesn't have anywhere to back up to.
 103            if (_iCount >= 0)
 104                _iCount++;
 105
 106            // Return true if we could do it.
 107            return _iCount >= 0 && _iCount <= _iSize;
 108        }
 109
 110        // How many characters left to output?
 111        public override int Remaining => (_iCount > 0) ? _iCount : 0;
 112
 113        // Clear the buffer
 114        public override unsafe void Reset()
 115        {
 116            _iCount = -1;
 117            charStart = null;
 118            bFallingBack = false;
 119        }
 120
 121        // private helper methods
 122        private static char TryBestFit(char cUnknown)
 123        {
 124            // Need to figure out our best fit character, low is beginning of array, high is 1 AFTER end of array
 125            int lowBound = 0;
 126            int highBound = ArrayCharBestFit.Length;
 127            int index;
 128
 129            // Binary search the array
 130            int iDiff;
 131            while ((iDiff = (highBound - lowBound)) > 6)
 132            {
 133                // Look in the middle, which is complicated by the fact that we have 2 #s for each pair,
 134                // so we don't want index to be odd because we want to be on word boundaries.
 135                // Also note that index can never == highBound (because diff is rounded down)
 136                index = ((iDiff / 2) + lowBound) & 0xFFFE;
 137
 138                char cTest = ArrayCharBestFit[index];
 139                if (cTest == cUnknown)
 140                {
 141                    // We found it
 142                    Debug.Assert(index + 1 < ArrayCharBestFit.Length,
 143                        "[EncoderLatin1BestFitFallbackBuffer.TryBestFit]Expected replacement character at end of array")
 144                    return ArrayCharBestFit[index + 1];
 145                }
 146                else if (cTest < cUnknown)
 147                {
 148                    // We weren't high enough
 149                    lowBound = index;
 150                }
 151                else
 152                {
 153                    // We weren't low enough
 154                    highBound = index;
 155                }
 156            }
 157
 158            for (index = lowBound; index < highBound; index += 2)
 159            {
 160                if (ArrayCharBestFit[index] == cUnknown)
 161                {
 162                    // We found it
 163                    Debug.Assert(index + 1 < ArrayCharBestFit.Length,
 164                        "[EncoderLatin1BestFitFallbackBuffer.TryBestFit]Expected replacement character at end of array")
 165                    return ArrayCharBestFit[index + 1];
 166                }
 167            }
 168
 169            // Char wasn't in our table
 170            return '\0';
 171        }
 172    }
 173}
 174