File: Expression\CharCursor.cs
Web Access
Project: src\src\Microsoft.ML.Transforms\Microsoft.ML.Transforms.csproj (Microsoft.ML.Transforms)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using Microsoft.ML.Runtime;
 
namespace Microsoft.ML.Transforms
{
    internal sealed class CharCursor
    {
        private readonly char[] _buffer;
 
        // The base index for the beginning of the buffer.
        private int _ichBase;
 
        // Position within the buffer.
        private int _ichNext;
        private int _ichLim;
        private bool _fNoMore;
 
        public bool Eof { get; private set; }
 
        public int IchCur => _ichBase + _ichNext - 1;
 
        public char ChCur { get; private set; }
 
        public CharCursor(string text)
            : this(Contracts.CheckRef(text, nameof(text)).ToCharArray(), text.Length)
        {
        }
 
        public CharCursor(string text, int ichMin, int ichLim)
            : this(text.ToCharArray(ichMin, ichLim - ichMin), ichLim - ichMin)
        {
        }
 
        private CharCursor(char[] buffer, int ichLimInit)
        {
            Contracts.AssertValue(buffer);
            Contracts.Assert(0 <= ichLimInit && ichLimInit <= buffer.Length);
 
            _buffer = buffer;
            _ichBase = 0;
            _ichNext = 0;
            _ichLim = ichLimInit;
            _fNoMore = false;
            Eof = false;
            ChNext();
        }
 
        // Fetch the next character into _chCur and return it.
        public char ChNext()
        {
            if (Eof)
                return ChCur;
 
            if (_ichNext < _ichLim || EnsureMore())
            {
                Contracts.Assert(_ichNext < _ichLim);
                return ChCur = _buffer[_ichNext++];
            }
 
            Contracts.Assert(_fNoMore);
            Eof = true;
            _ichNext++; // This is so the final IchCur is reported correctly.
            return ChCur = '\x00';
        }
 
        public char ChPeek(int dich)
        {
            // If someone is peeking at ich, they should have peeked everything up to ich.
            Contracts.Assert(0 < dich && dich <= _ichLim - _ichNext + 1);
 
            int ich = dich + _ichNext - 1;
            if (ich < _ichLim)
                return _buffer[ich];
            if (EnsureMore())
            {
                ich = dich + _ichNext - 1;
                Contracts.Assert(ich < _ichLim);
                return _buffer[ich];
            }
 
            Contracts.Assert(_fNoMore);
            return '\x00';
        }
 
        private bool EnsureMore()
        {
            if (_fNoMore)
                return false;
 
            if (_ichNext > 0)
            {
                int ichDst = 0;
                int ichSrc = _ichNext;
                while (ichSrc < _ichLim)
                    _buffer[ichDst++] = _buffer[ichSrc++];
                _ichBase += _ichNext;
                _ichNext = 0;
                _ichLim = ichDst;
            }
 
            int ichLim = _ichLim;
 
            Contracts.Assert(ichLim == _ichLim);
            _fNoMore = true;
            return false;
        }
    }
}