< Summary

Information
Class: System.IO.Compression.InputBuffer
Assembly: System.IO.Compression
File(s): D:\runner\runtime\src\libraries\System.IO.Compression\src\System\IO\Compression\DeflateManaged\InputBuffer.cs
Line coverage
93%
Covered lines: 107
Uncovered lines: 7
Coverable lines: 114
Total lines: 225
Line coverage: 93.8%
Branch coverage
84%
Covered branches: 27
Total branches: 32
Branch coverage: 84.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
EnsureBitsAvailable(...)90%1010100%
TryLoad16Bits()100%1010100%
GetBitMask(...)100%11100%
GetBits(...)75%44100%
CopyTo(...)66.66%6663.15%
CopyTo(...)100%11100%
NeedsInput()100%11100%
SetInput(...)50%22100%
SetInput(...)100%11100%
SkipBits(...)100%11100%
SkipToByteBoundary()100%11100%

File(s)

D:\runner\runtime\src\libraries\System.IO.Compression\src\System\IO\Compression\DeflateManaged\InputBuffer.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;
 5
 6namespace System.IO.Compression
 7{
 8    // This class can be used to read bits from an byte array quickly.
 9    // Normally we get bits from 'bitBuffer' field and bitsInBuffer stores
 10    // the number of bits available in 'BitBuffer'.
 11    // When we used up the bits in bitBuffer, we will try to get byte from
 12    // the byte array and copy the byte to appropriate position in bitBuffer.
 13    //
 14    // The byte array is not reused. We will go from 'start' to 'end'.
 15    // When we reach the end, most read operations will return -1,
 16    // which means we are running out of input.
 17
 18    internal sealed class InputBuffer
 19    {
 20        private Memory<byte> _buffer;     // memory to store input
 21        private uint _bitBuffer;      // store the bits here, we can quickly shift in this buffer
 22        private int _bitsInBuffer;    // number of bits available in bitBuffer
 23
 24        /// <summary>Total bits available in the input buffer.</summary>
 235588825        public int AvailableBits => _bitsInBuffer;
 26
 27        /// <summary>Total bytes available in the input buffer.</summary>
 168828        public int AvailableBytes => _buffer.Length + (_bitsInBuffer / 8);
 29
 30        /// <summary>Ensure that count bits are in the bit buffer.</summary>
 31        /// <param name="count">Can be up to 16.</param>
 32        /// <returns>Returns false if input is not sufficient to make this true.</returns>
 33        public bool EnsureBitsAvailable(int count)
 41673434        {
 41673435            Debug.Assert(0 < count && count <= 16, "count is invalid.");
 36
 37            // manual inlining to improve perf
 41673438            if (_bitsInBuffer < count)
 13227839            {
 13227840                if (NeedsInput())
 853841                {
 853842                    return false;
 43                }
 44
 45                // insert a byte to bitbuffer
 12374046                _bitBuffer |= (uint)_buffer.Span[0] << _bitsInBuffer;
 12374047                _buffer = _buffer.Slice(1);
 12374048                _bitsInBuffer += 8;
 49
 12374050                if (_bitsInBuffer < count)
 365051                {
 365052                    if (NeedsInput())
 2653                    {
 2654                        return false;
 55                    }
 56                    // insert a byte to bitbuffer
 362457                    _bitBuffer |= (uint)_buffer.Span[0] << _bitsInBuffer;
 362458                    _buffer = _buffer.Slice(1);
 362459                    _bitsInBuffer += 8;
 362460                }
 12371461            }
 62
 40817063            return true;
 41673464        }
 65
 66        /// <summary>
 67        /// This function will try to load 16 or more bits into bitBuffer.
 68        /// It returns whatever is contained in bitBuffer after loading.
 69        /// The main difference between this and GetBits is that this will
 70        /// never return -1. So the caller needs to check AvailableBits to
 71        /// see how many bits are available.
 72        /// </summary>
 73        public uint TryLoad16Bits()
 117839674        {
 117839675            if (_bitsInBuffer < 8)
 9006476            {
 9006477                if (_buffer.Length > 1)
 8450478                {
 8450479                    Span<byte> span = _buffer.Span;
 8450480                    _bitBuffer |= (uint)span[0] << _bitsInBuffer;
 8450481                    _bitBuffer |= (uint)span[1] << (_bitsInBuffer + 8);
 8450482                    _buffer = _buffer.Slice(2);
 8450483                    _bitsInBuffer += 16;
 8450484                }
 556085                else if (_buffer.Length != 0)
 47486                {
 47487                    _bitBuffer |= (uint)_buffer.Span[0] << _bitsInBuffer;
 47488                    _buffer = _buffer.Slice(1);
 47489                    _bitsInBuffer += 8;
 47490                }
 9006491            }
 108833292            else if (_bitsInBuffer < 16)
 69826093            {
 69826094                if (!_buffer.IsEmpty)
 69434895                {
 69434896                    _bitBuffer |= (uint)_buffer.Span[0] << _bitsInBuffer;
 69434897                    _buffer = _buffer.Slice(1);
 69434898                    _bitsInBuffer += 8;
 69434899                }
 698260100            }
 101
 1178396102            return _bitBuffer;
 1178396103        }
 104
 344918105        private static uint GetBitMask(int count) => ((uint)1 << count) - 1;
 106
 107        /// <summary>Gets count bits from the input buffer. Returns -1 if not enough bits available.</summary>
 108        public int GetBits(int count)
 346578109        {
 346578110            Debug.Assert(0 < count && count <= 16, "count is invalid.");
 111
 346578112            if (!EnsureBitsAvailable(count))
 1660113            {
 1660114                return -1;
 115            }
 116
 344918117            int result = (int)(_bitBuffer & GetBitMask(count));
 344918118            _bitBuffer >>= count;
 344918119            _bitsInBuffer -= count;
 344918120            return result;
 346578121        }
 122
 123        /// <summary>
 124        /// Copies bytes from input buffer to output buffer.
 125        /// You have to make sure, that the buffer is byte aligned. If not enough bytes are
 126        /// available, copies fewer bytes.
 127        /// </summary>
 128        /// <returns>Returns the number of bytes copied, 0 if no byte is available.</returns>
 129        public int CopyTo(Memory<byte> output)
 1688130        {
 1688131            Debug.Assert(_bitsInBuffer % 8 == 0);
 132
 133            // Copy the bytes in bitBuffer first.
 1688134            int bytesFromBitBuffer = 0;
 1688135            while (_bitsInBuffer > 0 && !output.IsEmpty)
 0136            {
 0137                output.Span[0] = (byte)_bitBuffer;
 0138                output = output.Slice(1);
 0139                _bitBuffer >>= 8;
 0140                _bitsInBuffer -= 8;
 0141                bytesFromBitBuffer++;
 0142            }
 143
 1688144            if (output.IsEmpty)
 1536145            {
 1536146                return bytesFromBitBuffer;
 147            }
 148
 152149            int length = Math.Min(output.Length, _buffer.Length);
 152150            _buffer.Slice(0, length).CopyTo(output);
 152151            _buffer = _buffer.Slice(length);
 152152            return bytesFromBitBuffer + length;
 1688153        }
 154
 155        /// <summary>
 156        /// Copies length bytes from input buffer to output buffer starting at output[offset].
 157        /// You have to make sure, that the buffer is byte aligned. If not enough bytes are
 158        /// available, copies fewer bytes.
 159        /// </summary>
 160        /// <returns>Returns the number of bytes copied, 0 if no byte is available.</returns>
 161        public int CopyTo(byte[] output, int offset, int length)
 1688162        {
 1688163            Debug.Assert(output != null);
 1688164            Debug.Assert(offset >= 0);
 1688165            Debug.Assert(length >= 0);
 1688166            Debug.Assert(offset <= output.Length - length);
 1688167            Debug.Assert((_bitsInBuffer % 8) == 0);
 168
 1688169            return CopyTo(output.AsMemory(offset, length));
 1688170        }
 171
 172        /// <summary>
 173        /// Return true is all input bytes are used.
 174        /// This means the caller can call SetInput to add more input.
 175        /// </summary>
 135928176        public bool NeedsInput() => _buffer.IsEmpty;
 177
 178        /// <summary>
 179        /// Set the byte buffer to be processed.
 180        /// All the bits remained in bitbuffer will be processed before the new bytes.
 181        /// We don't clone the byte buffer here since it is expensive.
 182        /// The caller should make sure after a buffer is passed in, that
 183        /// it will not be changed before calling this function again.
 184        /// </summary>
 185        public void SetInput(Memory<byte> buffer)
 6502186        {
 6502187            if (_buffer.IsEmpty)
 6502188            {
 6502189                _buffer = buffer;
 6502190            }
 6502191        }
 192
 193        /// <summary>
 194        /// Set the byte array to be processed.
 195        /// All the bits remained in bitBuffer will be processed before the new bytes.
 196        /// We don't clone the byte array here since it is expensive.
 197        /// The caller should make sure after a buffer is passed in.
 198        /// It will not be changed before calling this function again.
 199        /// </summary>
 200        public void SetInput(byte[] buffer, int offset, int length)
 6502201        {
 6502202            Debug.Assert(buffer != null);
 6502203            Debug.Assert(offset >= 0);
 6502204            Debug.Assert(length >= 0);
 6502205            Debug.Assert(offset <= buffer.Length - length);
 206
 6502207            SetInput(buffer.AsMemory(offset, length));
 6502208        }
 209
 210        /// <summary>Skip n bits in the buffer.</summary>
 211        public void SkipBits(int n)
 1174676212        {
 1174676213            Debug.Assert(_bitsInBuffer >= n, "No enough bits in the buffer, Did you call EnsureBitsAvailable?");
 1174676214            _bitBuffer >>= n;
 1174676215            _bitsInBuffer -= n;
 1174676216        }
 217
 218        /// <summary>Skips to the next byte boundary.</summary>
 219        public void SkipToByteBoundary()
 1846220        {
 1846221            _bitBuffer >>= (_bitsInBuffer % 8);
 1846222            _bitsInBuffer -= (_bitsInBuffer % 8);
 1846223        }
 224    }
 225}