File: System\Reflection\Metadata\PortablePdb\SequencePointCollection.cs
Web Access
Project: src\src\libraries\System.Reflection.Metadata\src\System.Reflection.Metadata.csproj (System.Reflection.Metadata)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Internal;
using System.Reflection.Metadata.Ecma335;
 
namespace System.Reflection.Metadata
{
    public readonly struct SequencePointCollection : IEnumerable<SequencePoint>
    {
        private readonly MemoryBlock _block;
        private readonly DocumentHandle _document;
 
        internal SequencePointCollection(MemoryBlock block, DocumentHandle document)
        {
            _block = block;
            _document = document;
        }
 
        public Enumerator GetEnumerator()
        {
            return new Enumerator(_block, _document);
        }
 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
 
        IEnumerator<SequencePoint> IEnumerable<SequencePoint>.GetEnumerator()
        {
            return GetEnumerator();
        }
 
        public struct Enumerator : IEnumerator<SequencePoint>
        {
            private BlobReader _reader;
            private SequencePoint _current;
            private int _previousNonHiddenStartLine;
            private ushort _previousNonHiddenStartColumn;
 
            internal Enumerator(MemoryBlock block, DocumentHandle document)
            {
                _reader = new BlobReader(block);
                _current = new SequencePoint(document, -1);
                _previousNonHiddenStartLine = -1;
                _previousNonHiddenStartColumn = 0;
            }
 
            public bool MoveNext()
            {
                if (_reader.RemainingBytes == 0)
                {
                    return false;
                }
 
                DocumentHandle document = _current.Document;
                int offset, deltaLines, deltaColumns, startLine;
                ushort startColumn;
 
                if (_reader.Offset == 0)
                {
                    // header (skip local signature rid):
                    _reader.ReadCompressedInteger();
 
                    if (document.IsNil)
                    {
                        document = ReadDocumentHandle();
                    }
                    // IL offset:
                    offset = _reader.ReadCompressedInteger();
                }
                else
                {
                    // skip all document records and update the current document accordingly:
                    int deltaOffset;
                    while ((deltaOffset = _reader.ReadCompressedInteger()) == 0)
                    {
                        document = ReadDocumentHandle();
                    }
 
                    // IL offset:
                    offset = AddOffsets(_current.Offset, deltaOffset);
                }
 
                ReadDeltaLinesAndColumns(out deltaLines, out deltaColumns);
 
                // hidden
                if (deltaLines == 0 && deltaColumns == 0)
                {
                    _current = new SequencePoint(document, offset);
                    return true;
                }
 
                // delta Start Line & Column:
                if (_previousNonHiddenStartLine < 0)
                {
                    Debug.Assert(_previousNonHiddenStartColumn == 0);
 
                    startLine = ReadLine();
                    startColumn = ReadColumn();
                }
                else
                {
                    startLine = AddLines(_previousNonHiddenStartLine, _reader.ReadCompressedSignedInteger());
                    startColumn = AddColumns(_previousNonHiddenStartColumn, _reader.ReadCompressedSignedInteger());
                }
 
                _previousNonHiddenStartLine = startLine;
                _previousNonHiddenStartColumn = startColumn;
 
                _current = new SequencePoint(
                    document,
                    offset,
                    startLine,
                    startColumn,
                    AddLines(startLine, deltaLines),
                    AddColumns(startColumn, deltaColumns));
 
                return true;
            }
 
            private void ReadDeltaLinesAndColumns(out int deltaLines, out int deltaColumns)
            {
                deltaLines = _reader.ReadCompressedInteger();
                deltaColumns = (deltaLines == 0) ? _reader.ReadCompressedInteger() : _reader.ReadCompressedSignedInteger();
            }
 
            private int ReadLine()
            {
                return _reader.ReadCompressedInteger();
            }
 
            private ushort ReadColumn()
            {
                int column = _reader.ReadCompressedInteger();
                if (column > ushort.MaxValue)
                {
                    Throw.SequencePointValueOutOfRange();
                }
 
                return (ushort)column;
            }
 
            private static int AddOffsets(int value, int delta)
            {
                int result = unchecked(value + delta);
                if (result < 0)
                {
                    Throw.SequencePointValueOutOfRange();
                }
 
                return result;
            }
 
            private static int AddLines(int value, int delta)
            {
                int result = unchecked(value + delta);
                if (result < 0 || result >= SequencePoint.HiddenLine)
                {
                    Throw.SequencePointValueOutOfRange();
                }
 
                return result;
            }
 
            private static ushort AddColumns(ushort value, int delta)
            {
                int result = unchecked(value + delta);
                if (result < 0 || result >= ushort.MaxValue)
                {
                    Throw.SequencePointValueOutOfRange();
                }
 
                return (ushort)result;
            }
 
            private DocumentHandle ReadDocumentHandle()
            {
                int rowId = _reader.ReadCompressedInteger();
                if (rowId == 0 || !TokenTypeIds.IsValidRowId(rowId))
                {
                    Throw.InvalidHandle();
                }
 
                return DocumentHandle.FromRowId(rowId);
            }
 
            public SequencePoint Current
            {
                get { return _current; }
            }
 
            object IEnumerator.Current
            {
                get { return _current; }
            }
 
            public void Reset()
            {
                _reader.Reset();
                _current = default(SequencePoint);
            }
 
            void IDisposable.Dispose()
            {
            }
        }
    }
}