namespace cloonel {
	template <typename Iterator>
	CircularBuffer<Iterator>::CircularBuffer (Iterator parFirst, Iterator parLast) :
		m_start(parFirst),
		m_end(parLast),
		m_curr(parFirst),
		m_used(0)
	{
	}

	template <typename Iterator>
	void CircularBuffer<Iterator>::push (value_type&& parObj) {
		*m_curr = std::move(parObj);
		++m_curr;
		++m_used;
		if (m_curr == m_end) {
			m_curr = m_start;
			m_used = capacity();
		}
	}

	template <typename Iterator>
	void CircularBuffer<Iterator>::reset() {
		m_used = 0;
		m_curr = m_start;
	}

	template <typename Iterator>
	void CircularBuffer<Iterator>::reset (Iterator parFirst, Iterator parLast) {
		m_start = parFirst;
		m_end = parLast;
		reset();
	}

	template <typename Iterator>
	typename CircularBuffer<Iterator>::reference CircularBuffer<Iterator>::front() {
		if (empty())
			throw std::out_of_range("The circular buffer is empty, but front() was called.");
		if (m_curr == m_start)
			return *(m_start + (capacity() - 1));
		else
			return *(m_curr - 1);
	}

	template <typename Iterator>
	typename CircularBuffer<Iterator>::reference CircularBuffer<Iterator>::back() {
		if (empty())
			throw std::out_of_range("The circular buffer is empty, but back() was called.");
		const auto cap = capacity();
		if (m_used != cap) {
			return *m_start;
		}
		else {
			const auto currPos = m_curr - m_start;
			const auto index = (currPos + cap - 1) % cap;
			return *(m_start + index);
		}
	}

	template <typename Iterator>
	typename CircularBuffer<Iterator>::reference CircularBuffer<Iterator>::operator[] (size_type parIndex) {
		if (parIndex < 0 or parIndex >= size())
			throw std::out_of_range("Index out of range in CircularBuffer");

		const auto index = (m_curr - m_start + parIndex) % capacity();
		return *(m_start + index);
	}
} //namespace cloonel
