CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5

Threaded View

  1. #1
    Join Date
    Dec 2005
    Posts
    114

    Is this class efficient enough?

    I am working on a class library, and I have started with this one class called TextTraverser. It's purpose is to allow me to take either a StreamReader or StringReader and read through it back and forth, keeping track of things like the current offset, line number, and column. Is is also supposed to make it very easy for me to do lexing, but that potential has not yet been fully implemented. All I want to know is, is this code efficient enough? I am worried, with all the converting of StringBuilder to a string, and the counting new lines for each change in position, that the code might be very slow when applied to a large amount of text. I am basically keeping track of all the characters that have already been read, to make it possible to jump back and forth through the text, and I've also implemented a function that is like Substring, only it allows me to get a string that is spread across the read characters and the unread characters. Well, you guys are way smarter than me so I'll just let you look at the code yourself. Hopefully I can get some good feedback on this here code.

    Code:
    /*
     * Author: Guido Arbia
     * TextTraverser.cs
     */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    
    namespace Guido.Lexing
    {
        class TextTraverser
        {
            TextReader _textReader;
            int _currentChar;
            int _originChar;
            StringBuilder _pastChars = new StringBuilder();
            int _relativeIndex = 0;
            int _absoluteIndex = 0;
            TextTraverserRegion _region;
            Stack<int> _marks = new Stack<int>();
            bool _disableLineTracking = false;
            int _currentLine = 0;
            int _currentColumn = 0;
    
            public TextTraverser(TextReader textReader)
            {
                _textReader = textReader;
                _currentChar = _textReader.Peek();
    
                if (_currentChar > -1)
                    _region = TextTraverserRegion.Within;
            }
    
            public void Mark()
            {
                _marks.Push(CurrentOffset);
            }
    
            public void ReleaseMark()
            {
                _marks.Pop();
            }
    
            public string Sweep()
            {
                int lastOffset = _marks.Pop();
    
                int earlyOffset = Math.Min(lastOffset, CurrentOffset);
                int lateOffset = Math.Max(lastOffset, CurrentOffset) - earlyOffset;
    
                return ExtractRange(earlyOffset, lateOffset);
            }
    
            private string GetPastPartInRange(int start, int length)
            {
                if (start < _absoluteIndex)
                {
                    int pastStart = _pastChars.Length - (_absoluteIndex - start);
                    int remainingPastLength = _pastChars.Length - pastStart;
                    int desiredPastLength = Math.Min(remainingPastLength, length);
    
                    if (pastStart < 0 || pastStart + desiredPastLength > _pastChars.Length)
                        throw new ArgumentOutOfRangeException("start");
    
                    return _pastChars.ToString().Substring(pastStart, desiredPastLength);
                }
    
                return String.Empty;
            }
    
            private string GetFuturePartInRange(int start, int length)
            {
                int originalOffset = CurrentOffset;
                Seek(_absoluteIndex);
                if (start + length > _absoluteIndex)
                {
                    int futureStart = Math.Max(_absoluteIndex, start);
                    int remainingLength = (start + length) - futureStart;
    
                    Seek(futureStart);
                    Step(remainingLength - 1);
                    if (_currentChar == -1)
                        throw new ArgumentOutOfRangeException("length");
    
                    Step(1);
    
                    string futurePart = _pastChars.ToString().Substring(_pastChars.Length - remainingLength);
    
                    Seek(originalOffset);
    
                    return futurePart;
                }
    
                Seek(originalOffset);
                return String.Empty;
            }
    
            public string ExtractRange(int start, int length)
            {
                string pastPart = GetPastPartInRange(start, length);
                string futurePart = GetFuturePartInRange(start, length);
    
                return pastPart + futurePart;
            }
    
            public void Seek(int offset)
            {
                Step(offset - CurrentOffset);
            }
    
            public void Step(int count = 1)
            {
                Mark();
    
                if (_relativeIndex == 0)
                    _originChar = _currentChar;
               
                _relativeIndex = _relativeIndex + count;
    
                if (_relativeIndex < 0)
                {
                    if (Math.Abs(_relativeIndex) <= _pastChars.Length)
                    {
                        _currentChar = _pastChars[_pastChars.Length + _relativeIndex];
                        _region = TextTraverserRegion.Within;
                    }
                    else
                    {
                        _currentChar = -1;
                        _region = TextTraverserRegion.BeforeFirst;
                    }
                }
                else if (_relativeIndex > 0)
                {
                    ReadChars(_relativeIndex);
                    _relativeIndex = 0;
                }
                else if (_relativeIndex == 0)
                {
                    _currentChar = _originChar;
    
                    if (_currentChar != -1)
                        _region = TextTraverserRegion.Within;
                }
    
                if (!_disableLineTracking)
                    DoLineTracking();
                else
                    ReleaseMark();
    
            }
    
            private void WindBackToLastLineStart()
            {
                while (_currentChar != -1 && _currentChar != '\n')
                    Step(-1);
    
                Step(1);
            }
    
            private bool IsMarkAfter()
            {
                return (_marks.Peek() < CurrentOffset);
            }
    
            private void DoLineTracking()
            {
                bool oldMode = _disableLineTracking;
                _disableLineTracking = true;
    
                bool forward = IsMarkAfter();
                string sweptString = Sweep();
                int lineCount = 0;
    
                for (int i = 0; i < sweptString.Length; i++)
                {
                    char currChar = sweptString[i];
                    char nextChar = (i + 1 < sweptString.Length)
                        ? sweptString[i + 1]
                        : Convert.ToChar(0);
    
                    if ((currChar == '\r') && (nextChar == '\n'))
                    {
                        lineCount++;
                        i++;
                    }
                    else if ((currChar == '\n'))
                        lineCount++;
                }
    
                if (!forward)
                    lineCount = -lineCount;
    
                _currentLine += lineCount;
    
                int originalOffset = CurrentOffset;
                WindBackToLastLineStart();
    
                _currentColumn = originalOffset - CurrentOffset;
                Seek(originalOffset);
    
                _disableLineTracking = oldMode;
            }
    
            public int CurrentLine
            {
                get { return _currentLine; }
            }
    
            public int CurrentOffset
            {
                get { return _absoluteIndex + _relativeIndex; }
            }
    
            public int CurrentColumn
            {
                get { return _currentColumn; }
            }
    
            public TextTraverserRegion CurrentRegion
            {
                get { return _region; }
            }
    
            public char CurrentChar
            {
                get {return Convert.ToChar(_currentChar); }
            }
    
            private void ReadChars(int count)
            {
                char[] buffer = new char[count];
                int charsRead = _textReader.Read(buffer, 0, count);
    
                _pastChars.Append(buffer);
                _currentChar = _textReader.Peek();
    
                if (_currentChar == -1)
                    _region = TextTraverserRegion.AfterLast;
                else
                    _region = TextTraverserRegion.Within;
    
                _absoluteIndex += charsRead;
            }
        }
    }
    Last edited by Guidosoft; April 28th, 2012 at 07:39 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured