/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2022, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */
#pragma once

#include <mrpt/math/math_frwds.h>  // forward declarations

namespace mrpt
{
namespace math
{
/** Internal classes not to be directly used by the user. */
// Forward declarations:
template <typename T, typename U, bool UIsObject>
class CBinaryRelation;
namespace detail
{
/**
 * This template is a trick to switch the type of a variable using a boolean
 * variable in the template. It's easy to extend its functionality to several
 * types, using a unsigned char instead of a bool.
 */
template <typename U, bool B>
class MatrixWrapper;

// partial specializations:
template <typename U>
class MatrixWrapper<U, true>
{
   public:
	using MatrixType = CMatrixTemplateObjects<U>;
};
template <typename U>
class MatrixWrapper<U, false>
{
   public:
	using MatrixType = CMatrixDynamic<U>;
};

template <typename T, typename U, bool UIsObject, typename FunctionType>
inline void applyFunction(
	CBinaryRelation<T, U, UIsObject>& o, FunctionType fun, size_t e1, size_t e2,
	const T& T1, const T& T2);
}  // namespace detail

namespace detail
{
/** Template class for matrix accessor's iterators.
 * \sa CMatrixRowAccessor,CMatrixColumnAccessor
 */
template <typename A, typename T>
class AccessorIterator
{
   protected:
	A* base;
	int pos;

   public:
	// typedefs for iterator_traits:
	using iterator_category = std::random_access_iterator_tag;
	using value_type = T;
	using difference_type = int;
	using pointer = T*;
	using reference = T&;

	inline AccessorIterator(A& obj, size_t N) : base(&obj), pos(N) {}
	inline T& operator*() const { return (*base)[pos]; }
	inline AccessorIterator<A, T>& operator++()
	{
		++pos;
		return *this;
	}
	inline AccessorIterator<A, T> operator++(int)
	{
		AccessorIterator<A, T> it = *this;
		++*this;
		return it;
	}
	inline AccessorIterator<A, T>& operator--()
	{
		--pos;
		return *this;
	}
	inline AccessorIterator<A, T> operator--(int)
	{
		AccessorIterator<A, T> it = *this;
		--*this;
		return it;
	}
	inline AccessorIterator<A, T>& operator+=(int off)
	{
		pos += off;
		return *this;
	}
	inline AccessorIterator<A, T> operator+(int off) const
	{
		AccessorIterator<A, T> it = *this;
		it += off;
		return it;
	}
	inline AccessorIterator<A, T>& operator-=(int off)
	{
		pos -= off;
		return *this;
	}
	inline AccessorIterator<A, T> operator-(int off) const
	{
		AccessorIterator<A, T> it = *this;
		it -= off;
		return it;
	}
	inline int operator-(const AccessorIterator<A, T>& it) const
	{
		return pos - it.pos;
	}
	inline T& operator[](int off) const { return (*base)[pos + off]; }
	inline bool operator==(const AccessorIterator<A, T>& it) const
	{
		return (pos == it.pos) && (base == it.base);
	}
	inline bool operator!=(const AccessorIterator<A, T>& it) const
	{
		return !(operator==(it));
	}
};

/** Template class for matrix accessor's iterators.
 * \sa CMatrixRowAccessor,CMatrixColumnAccessor
 */
template <typename A, typename T>
class ReverseAccessorIterator
{
   protected:
	A* base;
	int pos;

   public:
	// typedefs for iterator_traits:
	using iterator_category = std::random_access_iterator_tag;
	using value_type = T;
	using difference_type = int;
	using pointer = T*;
	using reference = T&;

	inline ReverseAccessorIterator(A& obj, size_t N) : base(&obj), pos(N) {}
	inline T& operator*() const { return (*base)[pos]; }
	inline ReverseAccessorIterator<A, T>& operator++()
	{
		--pos;
		return *this;
	}
	inline ReverseAccessorIterator<A, T> operator++(int)
	{
		ReverseAccessorIterator<A, T> it = *this;
		++*this;  // Yes, that's right.
		return it;
	}
	inline ReverseAccessorIterator<A, T>& operator--()
	{
		++pos;
		return *this;
	}
	inline ReverseAccessorIterator<A, T> operator--(int)
	{
		ReverseAccessorIterator<A, T> it = *this;
		--*this;  // Yes, that's right.
		return it;
	}
	inline ReverseAccessorIterator<A, T>& operator+=(int off)
	{
		pos -= off;
		return *this;
	}
	inline ReverseAccessorIterator<A, T> operator+(int off) const
	{
		ReverseAccessorIterator<A, T> it = *this;
		it += off;	// Yes, that's right.
		return it;
	}
	inline AccessorIterator<A, T>& operator-=(int off)
	{
		pos += off;
		return *this;
	}
	inline AccessorIterator<A, T> operator-(int off) const
	{
		ReverseAccessorIterator<A, T> it = *this;
		it -= off;	// Yes, that's right
		return it;
	}
	inline int operator-(const ReverseAccessorIterator<A, T>& it) const
	{
		return it.pos - pos;
	}
	inline T& operator[](int off) const { return (*base)[pos - off]; }
	inline bool operator==(const ReverseAccessorIterator<A, T>& it) const
	{
		return (pos == it.pos) && (&base == &it.base);
	}
	inline bool operator!=(const ReverseAccessorIterator<A, T>& it) const
	{
		return !(operator==(it));
	}
};
}  // namespace detail

/** A vector-like wrapper for a Matrix for accessing the elements of a given row
 * with a [] operator.
 *  For usage with MRPT's CMatrixDynamic only (for MRPT numeric matrices, use
 * Eigen methods)
 * \sa
 * CMatrixColumnAccessor,CMatrixRowAccessorExtended,CConstMatrixRowAccessor,CConstMatrixRowAccessorExtended
 */
template <typename MAT>
class CMatrixRowAccessor
{
   protected:
	MAT* m_mat;
	size_t m_rowInd;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CMatrixRowAccessor<MAT>;
	inline CMatrixRowAccessor(MAT& mat, size_t rowIdx)
		: m_mat(&mat), m_rowInd(rowIdx)
	{
		ASSERT_(rowIdx < mat.rows();
	}
	inline CMatrixRowAccessor() {}
	inline value_type& operator[](const size_t i)
	{
		return (*m_mat)(m_rowInd, i);
	}
	inline value_type operator[](const size_t i) const
	{
		return (*m_mat)(m_rowInd, i);
	}
	using iterator =
		detail::AccessorIterator<CMatrixRowAccessor<MAT>, value_type>;
	using const_iterator = detail::AccessorIterator<
		const CMatrixRowAccessor<MAT>, const value_type>;
	using reverse_iterator =
		detail::ReverseAccessorIterator<CMatrixRowAccessor<MAT>, value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CMatrixRowAccessor<MAT>, const value_type>;
	inline iterator begin() { return iterator(*this, 0); }
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline iterator end() { return iterator(*this, m_mat->cols()); }
	inline const_iterator end() const
	{
		return const_iterator(*this, m_mat->cols());
	}
	inline reverse_iterator rbegin()
	{
		return reverse_iterator(*this, m_mat->cols() - 1);
	}
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, m_mat->cols() - 1);
	}
	inline reverse_iterator rend() { return reverse_iterator(*this, -1); }
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return m_mat->cols(); }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CMatrixRowAccessor<MAT> getRowAccessor(MAT& m, size_t rowIdx)
{
	return CMatrixRowAccessor<MAT>(m, rowIdx);
}

/** A vector-like wrapper for a Matrix for accessing the elements of a given row
 * with a [] operator, with offset and custom spacing.
 *  For usage with MRPT's CMatrixDynamic only (for MRPT numeric matrices, use
 * Eigen methods)
 * \sa
 * CMatrixColumnAccessorExtended,CMatrixRowAccessor,CConstMatrixRowAccessor,CConstMatrixRowAccessorExtended
 */
template <class MAT>
class CMatrixRowAccessorExtended
{
   protected:
	MAT* m_mat;
	size_t m_rowInd;
	size_t m_colOffset;
	size_t m_elementsSpace;
	size_t howMany;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CMatrixRowAccessorExtended<MAT>;
	inline CMatrixRowAccessorExtended(
		MAT& mat, size_t row, size_t offset, size_t space)
		: m_mat(&mat),
		  m_rowInd(row),
		  m_colOffset(offset),
		  m_elementsSpace(space)
	{
		ASSERT_(row < mat.rows());
		howMany = (mat.cols() - m_colOffset) / m_elementsSpace;
	}
	inline CMatrixRowAccessorExtended() {}
	inline value_type& operator[](size_t i)
	{
		return (*m_mat)(m_rowInd, m_colOffset + (i * m_elementsSpace));
	}
	inline value_type operator[](size_t i) const
	{
		return (*m_mat)(m_rowInd, m_colOffset + (i * m_elementsSpace));
	}
	using iterator =
		detail::AccessorIterator<CMatrixRowAccessorExtended<MAT>, value_type>;
	using const_iterator = detail::AccessorIterator<
		const CMatrixRowAccessorExtended<MAT>, const value_type>;
	using reverse_iterator = detail::ReverseAccessorIterator<
		CMatrixRowAccessorExtended<MAT>, value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CMatrixRowAccessorExtended<MAT>, const value_type>;
	inline iterator begin() { return iterator(*this, 0); }
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline iterator end() { return iterator(*this, howMany); }
	inline const_iterator end() const { return const_iterator(*this, howMany); }
	inline reverse_iterator rbegin()
	{
		return reverse_iterator(*this, howMany - 1);
	}
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, howMany - 1);
	}
	inline reverse_iterator rend() { return reverse_iterator(*this, -1); }
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return howMany; }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CMatrixRowAccessorExtended<MAT> getRowAccessor(
	MAT& m, size_t rowIdx, size_t offset, size_t space = 1)
{
	return CMatrixRowAccessor<MAT>(m, rowIdx, offset, space);
}

/** A vector-like wrapper for a const Matrix for accessing the elements of a
 * given row with a [] operator.
 *  For usage with MRPT's CMatrixDynamic only (for MRPT numeric matrices, use
 * Eigen methods)
 * \sa
 * CConstMatrixColumnAccessor,CMatrixRowAccessorExtended,CMatrixRowAccessor,CConstMatrixRowAccessorExtended
 */
template <class MAT>
class CConstMatrixRowAccessor
{
   protected:
	const MAT* m_mat;
	size_t m_rowInd;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CConstMatrixRowAccessor<MAT>;
	inline CConstMatrixRowAccessor(const MAT& mat, size_t row)
		: m_mat(&mat), m_rowInd(row)
	{
		ASSERT_(row < mat.rows());
	}
	inline CConstMatrixRowAccessor() {}
	inline value_type operator[](size_t i) const
	{
		return (*m_mat)(m_rowInd, i);
	}
	using const_iterator = detail::AccessorIterator<
		const CConstMatrixRowAccessor<MAT>, const value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CConstMatrixRowAccessor<MAT>, const value_type>;
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline const_iterator end() const
	{
		return const_iterator(*this, m_mat->cols());
	}
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, m_mat->cols() - 1);
	}
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return m_mat->cols(); }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CConstMatrixRowAccessor<MAT> getRowAccessor(const MAT& m, size_t rowIdx)
{
	return CMatrixRowAccessor<MAT>(m, rowIdx);
}

/** A vector-like wrapper for a const Matrix for accessing the elements of a
 * given row with a [] operator, with offset and custom spacing.
 *  For usage with MRPT's CMatrixDynamic only (for MRPT numeric matrices, use
 * Eigen methods)
 * \sa
 * CConstMatrixColumnAccessorExtended,CMatrixRowAccessor,CConstMatrixRowAccessor,CMatrixRowAccessorExtended
 */
template <class MAT>
class CConstMatrixRowAccessorExtended
{
   protected:
	const MAT* m_mat;
	size_t m_rowInd;
	size_t m_colOffset;
	size_t m_elementsSpace;
	size_t howMany;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CConstMatrixRowAccessorExtended<MAT>;
	inline CConstMatrixRowAccessorExtended(
		const MAT& mat, size_t row, size_t offset, size_t space)
		: m_mat(&mat),
		  m_rowInd(row),
		  m_colOffset(offset),
		  m_elementsSpace(space)
	{
		ASSERT_(row < mat.rows());
		howMany = (mat.cols() - m_colOffset) / m_elementsSpace;
	}
	inline CConstMatrixRowAccessorExtended() {}
	inline value_type operator[](size_t i) const
	{
		return (*m_mat)(m_rowInd, m_colOffset + (i * m_elementsSpace));
	}
	using const_iterator = detail::AccessorIterator<
		const CConstMatrixRowAccessorExtended<MAT>, const value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CConstMatrixRowAccessorExtended<MAT>, const value_type>;
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline const_iterator end() const { return const_iterator(*this, howMany); }
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, howMany - 1);
	}
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return howMany; }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CConstMatrixRowAccessorExtended<MAT> getRowAccessor(
	const MAT& m, size_t rowIdx, size_t offset, size_t space = 1)
{
	return CConstMatrixRowAccessorExtended<MAT>(m, rowIdx, offset, space);
}

/** A vector-like wrapper for a Matrix for accessing the elements of a given
 * column with a [] operator.
 * \sa
 * CMatrixRowAccessor,CMatrixColumnAccessorExtended,CConstMatrixColumnAccessor,CConstMatrixColumnAccessorExtended
 */
template <typename MAT>
class CMatrixColumnAccessor
{
   protected:
	MAT* m_mat;
	size_t m_colInd;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CMatrixColumnAccessor<MAT>;
	inline CMatrixColumnAccessor(MAT& mat, size_t colIdx)
		: m_mat(&mat), m_colInd(colIdx)
	{
		ASSERT_(colIdx < mat.cols();
	}
	inline CMatrixColumnAccessor() {}
	inline value_type& operator[](const size_t i)
	{
		return (*m_mat)(i, m_colInd);
	}
	inline value_type operator[](const size_t i) const
	{
		return (*m_mat)(i, m_colInd);
	}
	using iterator =
		detail::AccessorIterator<CMatrixColumnAccessor<MAT>, value_type>;
	using const_iterator = detail::AccessorIterator<
		const CMatrixColumnAccessor<MAT>, const value_type>;
	using reverse_iterator =
		detail::ReverseAccessorIterator<CMatrixColumnAccessor<MAT>, value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CMatrixColumnAccessor<MAT>, const value_type>;
	inline iterator begin() { return iterator(*this, 0); }
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline iterator end() { return iterator(*this, m_mat->rows()); }
	inline const_iterator end() const
	{
		return const_iterator(*this, m_mat->rows());
	}
	inline reverse_iterator rbegin()
	{
		return reverse_iterator(*this, m_mat->rows() - 1);
	}
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, m_mat->rows() - 1);
	}
	inline reverse_iterator rend() { return reverse_iterator(*this, -1); }
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return m_mat->rows(); }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CMatrixColumnAccessor<MAT> getColumnAccessor(MAT& m, size_t colIdx)
{
	return CMatrixColumnAccessor<MAT>(m, colIdx);
}

/** A vector-like wrapper for a Matrix for accessing the elements of a given
 * column with a [] operator, with offset and custom spacing.
 * \sa
 * CMatrixRowAccessorExtended,CMatrixColumnAccessor,CConstMatrixColumnAccessor,CConstMatrixColumnAccessorExtended
 */
template <typename MAT>
class CMatrixColumnAccessorExtended
{
   protected:
	MAT* m_mat;
	size_t m_colInd;
	size_t m_rowOffset;
	size_t m_elementsSpace;
	size_t howMany;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CMatrixColumnAccessorExtended<MAT>;
	inline CMatrixColumnAccessorExtended(
		MAT& mat, size_t col, size_t offset, size_t space)
		: m_mat(&mat),
		  m_colInd(col),
		  m_rowOffset(offset),
		  m_elementsSpace(space)
	{
		ASSERT_(col < mat.cols());
		howMany = (mat.rows() - m_rowOffset) / m_elementsSpace;
	}
	inline CMatrixColumnAccessorExtended() {}
	inline value_type& operator[](size_t i)
	{
		return (*m_mat)(m_rowOffset + (i * m_elementsSpace), m_colInd);
	}
	inline value_type operator[](size_t i) const
	{
		return (*m_mat)(m_rowOffset + (i * m_elementsSpace), m_colInd);
	}
	using iterator = detail::AccessorIterator<
		CMatrixColumnAccessorExtended<MAT>, value_type>;
	using const_iterator = detail::AccessorIterator<
		const CMatrixColumnAccessorExtended<MAT>, const value_type>;
	using reverse_iterator = detail::ReverseAccessorIterator<
		CMatrixColumnAccessorExtended<MAT>, value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CMatrixColumnAccessorExtended<MAT>, const value_type>;
	inline iterator begin() { return iterator(*this, 0); }
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline iterator end() { return iterator(*this, howMany); }
	inline const_iterator end() const { return const_iterator(*this, howMany); }
	inline reverse_iterator rbegin()
	{
		return reverse_iterator(*this, howMany - 1);
	}
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, howMany - 1);
	}
	inline reverse_iterator rend() { return reverse_iterator(*this, -1); }
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return howMany; }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CMatrixColumnAccessorExtended<MAT> getColumnAccessor(
	MAT& m, size_t colIdx, size_t offset, size_t space = 1)
{
	return CMatrixColumnAccessorExtended<MAT>(m, colIdx, offset, space);
}

/** A vector-like wrapper for a const Matrix for accessing the elements of a
 * given column with a [] operator.
 * \sa
 * CConstMatrixRowAccessor,CMatrixColumnAccessorExtended,CMatrixColumnAccessor,CConstMatrixColumnAccessorExtended
 */
template <class MAT>
class CConstMatrixColumnAccessor
{
   protected:
	const MAT* m_mat;
	size_t m_colInd;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CConstMatrixColumnAccessor<MAT>;
	inline CConstMatrixColumnAccessor(const MAT& mat, size_t colIdx)
		: m_mat(&mat), m_colInd(colIdx)
	{
		ASSERT_(colIdx < mat.cols());
	}
	inline CConstMatrixColumnAccessor() {}
	inline value_type operator[](size_t i) const
	{
		return (*m_mat)(i, m_colInd);
	}
	using const_iterator = detail::AccessorIterator<
		const CConstMatrixColumnAccessor<MAT>, const value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CConstMatrixColumnAccessor<MAT>, const value_type>;
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline const_iterator end() const
	{
		return const_iterator(*this, m_mat->rows());
	}
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, m_mat->rows() - 1);
	}
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return m_mat->rows(); }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CConstMatrixColumnAccessor<MAT> getColumnAccessor(
	const MAT& m, size_t colIdx)
{
	return CConstMatrixColumnAccessor<MAT>(m, colIdx);
}

/** A vector-like wrapper for a const Matrix for accessing the elements of a
 * given column with a [] operator, with offset and custom spacing.
 * \sa
 * CConstMatrixRowAccessorExtended,CMatrixColumnAccessor,CConstMatrixColumnAccessor,CMatrixColumnAccessorExtended
 */
template <typename MAT>
class CConstMatrixColumnAccessorExtended
{
   protected:
	const MAT* m_mat;
	size_t m_colInd;
	size_t m_rowOffset;
	size_t m_elementsSpace;
	size_t howMany;

   public:
	using value_type = typename MAT::Scalar;
	using mrpt_autotype = CMatrixColumnAccessorExtended<MAT>;
	inline CConstMatrixColumnAccessorExtended(
		const MAT& mat, size_t col, size_t offset, size_t space)
		: m_mat(&mat),
		  m_colInd(col),
		  m_rowOffset(offset),
		  m_elementsSpace(space)
	{
		ASSERT_(col < mat.cols());
		howMany = (mat.rows() - m_rowOffset) / m_elementsSpace;
	}
	inline CConstMatrixColumnAccessorExtended() {}
	inline value_type operator[](size_t i) const
	{
		return (*m_mat)(m_rowOffset + (i * m_elementsSpace), m_colInd);
	}
	using const_iterator = detail::AccessorIterator<
		const CConstMatrixColumnAccessorExtended<MAT>, const value_type>;
	using const_reverse_iterator = detail::ReverseAccessorIterator<
		const CConstMatrixColumnAccessorExtended<MAT>, const value_type>;
	inline const_iterator begin() const { return const_iterator(*this, 0); }
	inline const_iterator end() const { return const_iterator(*this, howMany); }
	inline const_reverse_iterator rbegin() const
	{
		return const_reverse_iterator(*this, howMany - 1);
	}
	inline const_reverse_iterator rend() const
	{
		return const_reverse_iterator(*this, -1);
	}
	inline size_t size() const { return howMany; }
	inline void resize(size_t N)
	{
		if (N != size())
			throw std::logic_error("Tried to resize a fixed-size vector");
	}
};
template <typename MAT>
inline CConstMatrixColumnAccessorExtended<MAT> getColumnAccessor(
	const MAT& m, size_t colIdx, size_t offset, size_t space = 1)
{
	return CConstMatrixColumnAccessorExtended<MAT>(m, colIdx, offset, space);
}

}  // namespace math
}  // namespace mrpt
