text: // Copyright (c) Microsoft Corporation.
  // Licensed under the MIT license.
  
  #include "precomp.h"
  
  #include "AttrRowIterator.hpp"
  #include "AttrRow.hpp"
  
  AttrRowIterator AttrRowIterator::CreateEndIterator(const ATTR_ROW* const attrRow) noexcept
  {
      AttrRowIterator it{ attrRow };
      it._setToEnd();
      return it;
  }
  
  AttrRowIterator::AttrRowIterator(const ATTR_ROW* const attrRow) noexcept :
      _pAttrRow{ attrRow },
      _run{ attrRow->_list.cbegin() },
      _currentAttributeIndex{ 0 },
      _exceeded{ false }
  {
  }
  
  AttrRowIterator::operator bool() const noexcept
  {
      return !_exceeded && _run < _pAttrRow->_list.cend();
  }
  
  bool AttrRowIterator::operator==(const AttrRowIterator& it) const noexcept
  {
      return (_pAttrRow == it._pAttrRow &&
              _run == it._run &&
              _currentAttributeIndex == it._currentAttributeIndex &&
              _exceeded == it._exceeded);
  }
  
  bool AttrRowIterator::operator!=(const AttrRowIterator& it) const noexcept
  {
      return !(*this == it);
  }
  
  AttrRowIterator& AttrRowIterator::operator+=(const ptrdiff_t& movement)
  {
      if (!_exceeded)
      {
          if (movement >= 0)
          {
              _increment(gsl::narrow<size_t>(movement));
          }
          else
          {
              _decrement(gsl::narrow<size_t>(-movement));
          }
      }
  
      return *this;
  }
  
  AttrRowIterator& AttrRowIterator::operator-=(const ptrdiff_t& movement)
  {
      return this->operator+=(-movement);
  }
  
  const TextAttribute* AttrRowIterator::operator->() const
  {
      THROW_HR_IF(E_BOUNDS, _exceeded);
      return &_run->GetAttributes();
  }
  
  const TextAttribute& AttrRowIterator::operator*() const
  {
      THROW_HR_IF(E_BOUNDS, _exceeded);
      return _run->GetAttributes();
  }
  
  // Routine Description:
  // - increments the index the iterator points to
  // Arguments:
  // - count - the amount to increment by
  void AttrRowIterator::_increment(size_t count) noexcept
  {
      while (count > 0)
      {
          const size_t runLength = _run->GetLength();
          if (count + _currentAttributeIndex < runLength)
          {
              _currentAttributeIndex += count;
              return;
          }
          else
          {
              count -= runLength - _currentAttributeIndex;
              ++_run;
              _currentAttributeIndex = 0;
          }
      }
  }
  
  // Routine Description:
  // - decrements the index the iterator points to
  // Arguments:
  // - count - the amount to decrement by
  void AttrRowIterator::_decrement(size_t count) noexcept
  {
      while (count > 0)
      {
          // If there's still space within this color attribute to move left, do so.
          if (count <= _currentAttributeIndex)
          {
              _currentAttributeIndex -= count;
              return;
          }
          // If there's not space, move to the previous attribute run
          // We'll walk through above on the if branch to move left further (if necessary)
          else
          {
              // make sure we don't go out of bounds
              if (_run == _pAttrRow->_list.cbegin())
              {
                  _exceeded = true;
                  return;
              }
              count -= _currentAttributeIndex + 1;
              --_run;
              _currentAttributeIndex = _run->GetLength() - 1;
          }
      }
  }
  
  // Routine Description:
  // - sets fields on the iterator to describe the end() state of the ATTR_ROW
  void AttrRowIterator::_setToEnd() noexcept
  {
      _run = _pAttrRow->_list.cend();
      _currentAttributeIndex = 0;
  }
  