Sample code -- TextFileIterator class (C++)


This code is the declaration and definition of the TextFileIterator class which is an indirect subclass of the Iterator class. Other than minor formatting for HTML presentation, this code is exactly as found in the production source code.


// Copyright (c) 1993..1996 by Michael Lee Finney.  All rights reserved.

#pragma pack(4)

/* TextFileIterator
 *
 *    Instances of TextFileIterator iterate over the characters in a
 * text file of 8-bit characters which are converted to Unicode by
 * the iterator.  The position of the iterator does not correspond
 * exactly (because of end of line translation) to a byte index into
 * the text file.  Therefore, the iterator cannot be positioned to
 * any location other than the start of the text file, the current
 * character and the next character.
 *
 * Note: Currently, it is assumed that the 8-bit characters are codepoints
 *       in the ISO 8859-1 which is a strict subset of 16-bit Unicode.
 */

class TextFileIterator isa UnicharIterator is
      SubClassMethods(TextFileIterator, UnicharIterator);
   private:
   protected:
      InputFileDoubleBufferIterator _buffers;  // Input FileBuffer iterator
      char *                        _ptr;      // Pointer to next character in file buffer
      char *                        _end;      // Pointer to end of data in file buffer
      unsigned4                     _position; // Position into file
      unsigned4                     _lines;    // Number of lines detected on look-ahead
      unichar                       _char;     // Current character
      bool                          _atEnd;    // End of file reached

      virtual void readNextBuffer();
   public:
      virtual bool                      isComparable(Order const & x) const;
      virtual signed4                   origin() const;
      virtual signed4                   position() const;
      virtual bool                      atLowerBound() const;
      virtual bool                      atUpperBound() const;
      virtual bool                      isAccessibleAt(signed4 aPosition) const;
      virtual void                      moveTo(signed4 aPosition);
      virtual bool                      isAccessible(signed4 i) const;
      virtual void                      move(signed4 i);
      virtual void                      advance();
      virtual bool                      isResettable() const;
      virtual void                      reset();
      virtual bool                      isValueAt(signed4 aPosition) const;
      virtual unichar const &           valueAt(signed4 aPosition) const;
      virtual bool                      isValue(signed4 i) const;
      virtual unichar const &           value(signed4 i) const;
      virtual bool                      isValue() const;
      virtual unichar const &           value() const;
      virtual Iterator<unichar> const & operator=(Iterator<unichar> const & anIterator);
                                        TextFileIterator(char const * fileName, unsigned4 bufferLength = 4096);
                                        TextFileIterator(TextFileIterator const & iterator);
      virtual                          ~TextFileIterator();
   global
      IteratorOperatorSignatures(TextFileIterator);

#pragma pack()


/* TextFileIterator::origin
 *
 *    Return r (the iterator origin).  This is the position the iterator
 * has immediately following creation or the reset() operation.
 */

inline signed4 TextFileIterator::origin() const is
   code
      nil;
   end (1)


/* TextFileIterator::position
 *
 *    Return p (the distinguished position).
 */

inline signed4 TextFileIterator::position() const is
   code
      nil;
   end (_position)


/* TextFileIterator::atLowerBound
 *
 *    Returns true iff p = L, i.e. the distinguished position is at
 * the greatest lower bound of the indexing set.
 */

inline bool TextFileIterator::atLowerBound() const is
   code
      nil;
   end (_position < 1)


/* TextFileIterator::atUpperBound
 *
 *    Returns true iff p == U, i.e. the distinguished position is at
 * the least upper bound of the indexing set.
 */

inline bool TextFileIterator::atUpperBound() const is
   code
      nil;
   end (_atEnd)


/* TextFileIterator::isAccessibleAt
 *
 *    Return true iff the specified position is accessible (i.e. in A).
 */

inline bool TextFileIterator::isAccessibleAt(
      signed4     aPosition) const is
   code
      nil;
   end ((not _atEnd and aPosition == _position + 1) or aPosition == 1 or _position == aPosition)


/* TextFileIterator::isAccessible
 *
 *    Return true iff the specified position is accessible (i.e. in A).
 */

inline bool TextFileIterator::isAccessible(
      signed4     i) const is
   code
      nil;
   end ((not _atEnd and i == 1) or _position + i == 1 or i == 0)


/* TextFileIterator::isResettable
 *
 *    Returns true iff the iterator can be reset so that it is
 * in the same state as existed immediately following creation.
 */

inline bool TextFileIterator::isResettable() const is
   code
      nil;
   end (true)


/* TextFileIterator::isValueAt
 *
 *    Returns true iff the specified position in M, i.e. is defined.
 */

inline bool TextFileIterator::isValueAt(
      signed4     aPosition) const is
   code
      nil;
   end (not _atEnd and aPosition == _position)


/* TextFileIterator::valueAt
 *
 *    Returns m(i), i.e. the value of the iterator at the specified
 * position.
 */

inline unichar const & TextFileIterator::valueAt(
      signed4     aPosition) const is
   require
      when (_atEnd or aPosition != _position)
         reject ("Attempted to access iterator at an undefined position");
   proc
      nil;
   end (_char)


/* TextFileIterator::isValue
 *
 *    Returns true iff p+i is defined, i.e. in M.
 */

inline bool TextFileIterator::isValue(
      signed4     i) const is
   code
      nil;
   end (not _atEnd and i == 0)


/* TextFileIterator::value
 *
 *    Returns m(p+i).
 */

inline unichar const & TextFileIterator::value(
      signed4     i) const is
   require
      when (_atEnd or i)
         reject ("Attempted to access iterator at an undefined position");
   proc
      nil;
   end (_char)


/* TextFileIterator::isValue
 *
 *    Returns true iff the distinguished position is defined, i.e. in M.
 * The distinguished position is always defined except when p = L or
 * p = U (which is only possible for finite iterators).
 */

inline bool TextFileIterator::isValue() const is
   code
      nil;
   end (not _atEnd)


/* TextFileIterator::value
 *
 *    Returns m(p), the value of the iterator at the distinguished
 * position.
 */

inline unichar const & TextFileIterator::value() const is
   code
      nil;
   end (_char)


/* TextFileIterator::readNextBuffer
 *
 *    Read data from the file into _buffer.
 */

void TextFileIterator::readNextBuffer() is
   code
      _buffers.advance();
      _ptr = (char *)_buffers.value().bufferStart();
      _end = (char *)_buffers.value().bufferEnd();
      if (_buffers.isAccessible(2))
            *_end = 0x01;
         else
            *_end = 0x1a;
   end (nil)


/* TextFileIterator::isComparable
 *
 *    This method returns true iff the left object and the right object
 * are comparable.
 */

bool TextFileIterator::isComparable(
      Order const &  x) const is
   local
      bool           result;
   code
      #if (_rttiEnabled)
            result = (typeId(x) == classId(TextFileIterator)) and
                     (_buffers.isComparable(((TextFileIterator const &)x)._buffers));
         #else
            result = true;
         #endif
   end (result)


/* TextFileIterator::moveTo
 *
 *    Move the distinguished position to the specified position.
 */

void TextFileIterator::moveTo(
      signed4     newPosition) is
   code
      if (newPosition == _position)
            nil;
         elif (newPosition == 1)
            reset();
         elif (not _atEnd and newPosition == _position + 1)
            advance();
         else
            reject ("Attempt to position iterator to inaccessible position");
   end (nil)


/* TextFileIterator::move
 *
 *    Move the distinguished position by the specified amount.
 */

void TextFileIterator::move(
      signed4     i) is
   code
      if (i == 0)
            nil;
         elif (_position + i == 1)
            reset();
         elif (not _atEnd and i == 1)
            advance();
         else
            reject ("Attempt to position iterator to inaccessible position");
   end (nil)


/* TextFileIterator::advance
 *
 *    Advances the distinguished position to the next position.
 */

void TextFileIterator::advance() is
   local
      char        c;
   require
      when (_atEnd)
         reject ("Attempt to position iterator to inaccessible position");
   proc
      if (_lines)
            {
            --_lines;
            if (_lines == 0 and *_ptr == 0x1a)
                  _atEnd = true;
               else
                  _char = uniLineSeparator;
            }
         else
            loop
               {
               c = *_ptr;
               ++_ptr;
               if (c >= ' ' or c == tab)
                     _char = c;  // Note: Convert to Unicode based on current code page.
                  elif (c == cr)
                     {
                     loop
                        {
                        when (*_ptr == 0x01 and _ptr == _end)
                           readNextBuffer();
                        if (*_ptr == cr)
                              ++_lines;
                           else
                              upon (*_ptr == nul);
                        ++_ptr;
                        }
                     when (*_ptr == lf)
                        {
                        ++_ptr;
                        when (*_ptr == 0x01 and _ptr == _end)
                           readNextBuffer();
                        _lines = 0;
                        }
                     while (*_ptr == ff or *_ptr == nul)
                        {
                        ++_ptr;
                        when (*_ptr == 0x01 and _ptr == _end)
                           readNextBuffer();
                        }
                     if (_lines == 0 and *_ptr == 0x1a)
                           _atEnd = true;
                        else
                           _char = uniLineSeparator;
                     }
                  elif (c == lf)
                     {
                     loop
                        {
                        when (*_ptr == 0x01 and _ptr == _end)
                           readNextBuffer();
                        upon (*_ptr == cr or *_ptr == nul);
                        ++_ptr;
                        }
                     while (*_ptr == ff or *_ptr == nul)
                        {
                        ++_ptr;
                        when (*_ptr == 0x01 and _ptr == _end)
                           readNextBuffer();
                        }
                     if (*_ptr == 0x1a)
                           _atEnd = true;
                        else
                           _char = uniLineSeparator;
                     }
                  elif (c == ff)
                     {
                     loop
                        {
                        when (*_ptr == 0x01 and _ptr == _end)
                           readNextBuffer();
                        upon (*_ptr == ff or *_ptr == nul);
                        ++_ptr;
                        }
                     if (*_ptr == cr or *_ptr == lf)
                           continue;
                        elif (*_ptr == 0x1a)
                           _atEnd = true;
                        else
                           _char = uniLineSeparator;
                     }
                  elif (c == nul)
                     {
                     loop
                        {
                        when (*_ptr == 0x01 and _ptr == _end)
                           readNextBuffer();
                        upon (*_ptr == nul);
                        ++_ptr;
                        }
                     continue;
                     }
                  elif (c == 0x1a)
                     _atEnd = true;
                  elif (c == 0x01 and _ptr > _end)
                     {
                     readNextBuffer();
                     continue;
                     }
                  else
                     _char = c;  // Note: Convert to Unicode based on current code page.
               break;
               }
      ++_position;
   end (nil)


/* TextFileIterator::reset
 *
 *    Resets the iterator so that it is in the same state as existed
 * immediately following creation.  Following reset(), the atOrigin()
 * method will be true and position() == origin().
 */

void TextFileIterator::reset() is
   code
      _buffers.reset();
      if (_buffers.atUpperBound())
            {
            _atEnd    = true;
            _position = 1;
            }
         else
            {
            _ptr      = (char *)_buffers.value().bufferStart();
            _end      = (char *)_buffers.value().bufferEnd();
            _atEnd    = false;
            _position = 0;
            if (_buffers.isAccessible(2))
                  *_end = 0x01;
               else
                  *_end = 0x1a;
            advance();
            }
   end (nil)


/* TextFileIterator::operator=
 *
 *    Assignment.
 */

Iterator<unichar> const & TextFileIterator::operator=(
      Iterator<unichar> const &  anIterator) is
   local
      TextFileIterator const &   iterator = (TextFileIterator const &)anIterator;
   code
      unless (self == &iterator)
         {
         _buffers  = iterator._buffers;
         _position = iterator._position;
         _lines    = iterator._lines;
         _char     = iterator._char;
         _atEnd    = iterator._atEnd;
         if (_atEnd)
               {
               _ptr = null;
               _end = null;
               }
            else
               {
               _ptr = (char *)_buffers.value().bufferStart() + (iterator._ptr - (char *)iterator._buffers.value().bufferStart());
               _end = (char *)_buffers.value().bufferEnd();
               }
         }
   end (*self)



/* TextFileIterator::TextFileIterator
 *
 *    Constructor.
 */

TextFileIterator::TextFileIterator(
      char const *   fileName,
      unsigned4      bufferLength)
   constructors
      _buffers(fileName, bufferLength, 1) is
   code
      _lines = 0;
      if (_buffers.atUpperBound())
            {
            _position = 1;
            _atEnd    = true;
            _ptr      = null;
            _end      = null;
            }
         else
            {
            _ptr = (char *)_buffers.value().bufferStart();
            _end = (char *)_buffers.value().bufferEnd();
            if (_buffers.isAccessible(2))
                  *_end = 0x01;
               else
                  *_end = 0x1a;
            _position = 0;
            _atEnd    = false;
            advance();
            }
   end (nil)


/* TextFileIterator::TextFileIterator
 *
 *    Copy constructor.
 */

TextFileIterator::TextFileIterator(
      TextFileIterator const &   iterator)
   constructors
      _buffers(iterator._buffers) is
   code
      _position = iterator._position;
      _lines    = iterator._lines;
      _char     = iterator._char;
      _atEnd    = iterator._atEnd;
      if (_atEnd)
            {
            _ptr = null;
            _end = null;
            }
         else
            {
            _ptr = (char *)_buffers.value().bufferStart() + (iterator._ptr - (char *)iterator._buffers.value().bufferStart());
            _end = (char *)_buffers.value().bufferEnd();
            }
   end (nil)


/* TextFileIterator::~TextFileIterator
 *
 *    Virtual destructor.
 */

TextFileIterator::~TextFileIterator() is
   code
      nil;
   end (nil)


/* IteratorOperatorSignatures
 *
 *    Define the operators for the TextFileIterator class.
 */

IteratorOperators(TextFileIterator)
         

[ Last | Overview ]