// Copyright 2018-2022 David Robillard <d@drobilla.net>
// Copyright 2006-2007 Chris Hamilton <chamilton@cs.dal.ca>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CHILBERT_DETAIL_BITVECITERATOR_HPP
#define CHILBERT_DETAIL_BITVECITERATOR_HPP

#include "chilbert/detail/BitVecMask.hpp"

#include <cstddef>

namespace chilbert {
namespace detail {

template<class BitVec>
class BitVecIteratorBase
{
public:
  using Mask = typename BitVec::Mask;

  BitVecIteratorBase& operator++()
  {
    ++m_mask;
    return *this;
  }

  BitVecIteratorBase& operator--()
  {
    --m_mask;
    return *this;
  }

  bool operator==(const BitVecIteratorBase& rhs) const
  {
    return m_vec == rhs.m_vec && m_mask == rhs.m_mask;
  }

  bool operator!=(const BitVecIteratorBase& rhs) const
  {
    return !operator==(rhs);
  }

  bool operator*() const { return m_vec->test(m_mask); }

protected:
  BitVecIteratorBase(BitVec& vec, const size_t index)
    : m_vec{&vec}
    , m_mask{index}
  {}

  BitVec*                           m_vec;
  BitVecMask<typename BitVec::Rack> m_mask;
};

template<class BitVec>
class BitVecIterator : public BitVecIteratorBase<BitVec>
{
public:
  void set() { this->m_vec->set(this->m_mask); }
  void reset() { this->m_vec->reset(this->m_mask); }

private:
  friend BitVec;

  BitVecIterator(BitVec& vec, const size_t index)
    : BitVecIteratorBase<BitVec>{vec, index}
  {}
};

template<class BitVec>
class ConstBitVecIterator : public BitVecIteratorBase<const BitVec>
{
private:
  friend BitVec;

  ConstBitVecIterator(const BitVec& vec, const size_t index)
    : BitVecIteratorBase<const BitVec>{vec, index}
  {}
};

} // namespace detail
} // namespace chilbert

#endif