matrix.h
作者:互联网
/**
*
*
*
*
*
*
*
*/
#ifndef __IGS__matrix_H
#define __IGS__matrix_H
#include <iterator>
#include <iostream>
namespace IGS
{
namespace detail
{
namespace ns_matrix
{
template<typename _MatPtr>
struct _Matrix_data
{
typedef _MatPtr _Mat_pointer;
typedef std::size_t size_type;
size_type _M_row;
size_type _M_col;
_Mat_pointer _M_mat;
_Matrix_data()
: _M_row(), _M_col(), _M_mat()
{ }
_Matrix_data(_Matrix_data&& __t)
: _M_row(__t._M_row), _M_col(__t._M_col), _M_mat(__t._M_mat)
{
__t._M_row = __t._M_col = size_type();
__t._M_mat = _Mat_pointer();
}
void
_M_copy_data(const _Matrix_data& __t)
{
_M_row = __t._M_row;
_M_col = __t._M_col;
_M_mat = __t._M_mat;
}
void
_M_swap_data(_Matrix_data& __t)
{
_Matrix_data __tmp;
__tmp._M_copy_data(*this);
_M_copy_data(__t);
__t._M_copy_data(__tmp);
}
};
} // namespace ns_matrix
} // namespace details
template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class matrix
{
static_assert(std::is_same<typename std::remove_cv<_Tp>::type, _Tp>::value,
"IGS::matrix must have a non-const, non-volatile value_type");
static_assert(std::is_same<typename _Alloc::value_type, _Tp>::value,
"IGS::matrix must have the same value_type as its allocator");
protected:
typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
rebind<_Tp>::other _Tp_alloc_type;
typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits;
public:
typedef _Tp value_type;
typedef typename _Alloc_traits::reference reference;
typedef typename _Alloc_traits::const_reference const_reference;
typedef typename _Alloc_traits::pointer pointer;
typedef typename _Alloc_traits::const_pointer const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef _Alloc allocator_type;
typedef std::pair<size_type, size_type> shape_type;
/// Get a copy of the memory allocation object.
allocator_type
get_allocator() const noexcept
{ return allocator_type(this->_M_impl); }
protected:
_Tp_alloc_type&
_M_get_Tp_allocator() noexcept
{ return this->_M_impl; }
const _Tp_alloc_type&
_M_get_Tp_allocator() const noexcept
{ return this->_M_impl; }
protected:
struct _Matrix_impl
: public _Tp_alloc_type,
public detail::ns_matrix::_Matrix_data<pointer>
{
_Matrix_impl()
: _Tp_alloc_type()
{ }
_Matrix_impl(const _Tp_alloc_type& __a)
: _Tp_alloc_type(__a)
{ }
_Matrix_impl(_Matrix_impl&&) = default;
_Matrix_impl(_Tp_alloc_type&& __a) noexcept
: _Tp_alloc_type(std::move(__a))
{ }
_Matrix_impl(_Matrix_impl&& __m, _Tp_alloc_type&& __a)
: _Tp_alloc_type(std::move(__a)),
detail::ns_matrix::_Matrix_data<pointer>(std::move(__m))
{ }
};
_Matrix_impl _M_impl;
pointer
_M_allocate(size_type __n)
{ return _Alloc_traits::allocate(_M_get_Tp_allocator(), __n); }
void
_M_deallocate(pointer __p, size_type __n)
{ _Alloc_traits::deallocate(_M_get_Tp_allocator(), __p, __n); }
void
_M_construct(pointer __p, const_reference __x)
{ _Alloc_traits::construct(_M_get_Tp_allocator(), __p, __x); }
void
_M_construct(pointer __p, size_type __n, const_reference __x)
{ _M_construct(__p, __p + __n, __x); }
void
_M_construct(pointer __first, pointer __last, const_reference __x)
{
while (__first != __last)
{
_Alloc_traits::construct(_M_get_Tp_allocator(), __first, __x);
++__first;
}
}
void
_M_destroy(pointer __p, size_type __n)
{
for (pointer __end = __p + __n; __p != __end; ++__p)
_Alloc_traits::destroy(_M_get_Tp_allocator(), __p);
}
public:
matrix() = default;
matrix(const allocator_type& __a)
: _M_impl(__a)
{ }
matrix(matrix&&) noexcept = default;
matrix(const matrix& __t)
: _M_impl()
{ build(__t); }
matrix(size_type __row, size_type __col,
const_reference __x = value_type(0))
{ build(__row, __col, __x); }
~matrix() noexcept
{
clear();
_M_impl.~_Matrix_impl();
}
void
build(size_type __row, size_type __col,
const_reference __x = value_type(0))
{
clear();
size_type __tot = __row * __col;
this->_M_impl._M_row = __row;
this->_M_impl._M_col = __col;
this->_M_impl._M_mat = _M_allocate(__tot);
_M_construct(this->_M_impl._M_mat, __tot, __x);
}
void
build(const matrix& __t)
{
clear();
if (__t.empty()) return;
size_type __tot = __t._M_impl._M_row * __t._M_impl._M_col;
this->_M_impl._M_row = __t._M_impl._M_row;
this->_M_impl._M_col = __t._M_impl._M_col;
pointer& __self = this->_M_impl._M_mat;
const const_pointer& __other = __t._M_impl._M_mat;
__self = _M_allocate(__tot);
while (__tot--)
_M_construct(__self + __tot, *(__other + __tot) );
}
void
build(matrix&& __t)
{
clear();
if (__t.empty()) return;
_M_impl._M_copy_data(__t._M_impl);
}
void
build_square(size_type __n, const_reference __x = value_type(0))
{ build(__n, __n, __x); }
void
build_identity(size_type __n, const_reference __one = value_type(1),
const_reference __zero = value_type(0))
{ build_eye(__n, __n, __one, __zero); }
void
build_eye(size_type __row, size_type __col,
const_reference __one = value_type(1),
const_reference __zero = value_type(0))
{
clear();
const size_type __tot = __row * __col;
size_type __n = std::min(__row, __col) - 1;
pointer __p = this->_M_impl._M_mat = _M_allocate(__tot);
while (__n--)
{
_M_construct(__p, __one);
++__p;
_M_construct(__p, __p + __col, __zero);
__p += __col;
}
_M_construct(__p, __one);
_M_construct(__p + 1, this->_M_impl._M_mat + __tot, __zero);
this->_M_impl._M_row = __row;
this->_M_impl._M_col = __col;
}
/**
* Erases all the elements, and deallocates the storage.
*/
void
clear()
{
if (empty()) return;
size_type __tot = this->_M_impl._M_row * this->_M_impl._M_col;
_M_destroy(this->_M_impl._M_mat, __tot);
_M_deallocate(this->_M_impl._M_mat, __tot);
this->_M_impl._M_mat = nullptr;
this->_M_impl._M_row = 0;
this->_M_impl._M_col = 0;
}
/**
* @brief Swaps data with another %matrix.
* @param __t A %matrix of the same element and allocator types.
*
* This exchanges the elements between two matrices in constant time.
* Note that the global IGS::swap() function is specialized such that
* IGS::swap(m1,m2) will feed to this function.
*
* Whether the allocators are swapped depends on the allocator traits.
*/
void
swap(matrix& __t)
{
this->_M_impl._M_swap_data(__t);
_Alloc_traits::_S_on_swap(_M_get_Tp_allocator(),
__t._M_get_Tp_allocator());
}
/**
* Returns true if the %vector is empty.
*/
bool
empty() const
{ return this->_M_impl._M_mat == nullptr; }
protected:
/// Safety check used only from at().
void
_M_range_check(size_type __x, size_type __y) const
{
if (__x >= shape().first || __y >= shape().second)
std::__throw_out_of_range_fmt("matrix::_M_range_check: __x"
" (which is %zu) >= shape().first "
"(which is %zu) || __y (which is %zu) "
">= shape().second (which is %zu)",
__x, shape().first, __y, shape().second);
}
void
_M_matrix_multiplication_check(const matrix& __rhs) const
{
if (this->_M_impl._M_col != __rhs._M_impl._M_row)
std::__throw_invalid_argument("matrix::"
"_M_matrix_multiplication_check");
}
public:
// element access
/**
* @brief Subscript access to the data contained in the %matrix.
* @return Read/write reference to data.
*
* This operator allows for easy, 2D subscript index, data access.
* Note that data access with this operator is unchecked and
* out_of_range lookups are not defined. (For checked lookups
* see at().)
*/
reference
operator()(size_type __x, size_type __y)
{ return this->_M_impl._M_mat[__x * this->_M_impl._M_col + __y]; }
/**
* @brief Subscript access to the data contained in the %matrix.
* @return Read-only (constant) reference to data.
*
* This operator allows for easy, array-style, data access.
* Note that data access with this operator is unchecked and
* out_of_range lookups are not defined. (For checked lookups
* see at().)
*/
const_reference
operator()(size_type __x, size_type __y) const
{ return this->_M_impl._M_mat[__x * this->_M_impl._M_col + __y]; }
/**
* @brief Provides access to the data contained in the %matrix.
* @return Read/write reference to data.
* @throw std::out_of_range If @a __n is an invalid index.
*
* This function provides for safer data access. The parameter
* is first checked that it is in the range of the matrix. The
* function throws out_of_range if the check fails.
*/
reference
at(size_type __x, size_type __y)
{
_M_range_check(__x, __y);
return this->operator()(__x, __y);
}
/**
* @brief Provides access to the data contained in the %matrix.
* @return Read-only (constant) reference to data.
* @throw std::out_of_range If @a __n is an invalid index.
*
* This function provides for safer data access. The parameter
* is first checked that it is in the range of the matrix. The
* function throws out_of_range if the check fails.
*/
const_reference
at(size_type __x, size_type __y) const
{
_M_range_check(__x, __y);
return this->operator()(__x, __y);
}
shape_type
shape() const
{ return {_M_impl._M_row, _M_impl._M_col}; }
std::pair<size_type, size_type>
size() const
{ return shape(); }
std::string
to_string(std::string _btw_elt = " ", std::string _end_row = "\n") const
{
std::string __result;
if (empty()) return __result;
size_type __i = 0, __j;
while (__i < _M_impl._M_row)
{
__j = 0;
while (__j < _M_impl._M_col)
{
__result.append(std::to_string( (*this)(__i, __j) ));
__result.append(_btw_elt);
++__j;
}
__result.append(_end_row);
++__i;
}
return __result;
}
/**
* @brief Apply a function to the matrix.
* @param __func Function of value_type or
* reference or const_reference to apply.
*/
template<typename _Function>
typename std::enable_if<std::is_function<typename
std::remove_pointer<_Function>::type>::value, matrix&>::type
apply(_Function __func)
{
pointer __p = this->_M_impl._M_mat;
pointer __end = __p + _M_impl._M_row * _M_impl._M_col;
for (; __p != __end; ++__p) __func(*__p);
return *this;
}
matrix&
operator=(const matrix& __x)
{
build(__x);
return *this;
}
#define __IGS_FunctionDefinitionHelperFor_matrix_operators_00(_Op) \
matrix& \
operator _Op (const_reference __x) \
{ \
pointer __p = this->_M_impl._M_mat; \
pointer __end = __p + _M_impl._M_row * _M_impl._M_col; \
for (; __p != __end; ++__p) *__p _Op __x; \
return *this; \
}
__IGS_FunctionDefinitionHelperFor_matrix_operators_00(+=)
__IGS_FunctionDefinitionHelperFor_matrix_operators_00(-=)
__IGS_FunctionDefinitionHelperFor_matrix_operators_00(*=)
__IGS_FunctionDefinitionHelperFor_matrix_operators_00(/=)
__IGS_FunctionDefinitionHelperFor_matrix_operators_00(%=)
#define __IGS_FunctionDefinitionHelperFor_matrix_operators_10(_Op) \
template<typename _Up> \
matrix& \
operator _Op (const matrix<_Up>& __rhs) \
{ \
if (this->_M_impl._M_row != __rhs._M_impl._M_row \
|| this->_M_impl._M_col != __rhs._M_impl._M_col) \
std::__throw_invalid_argument("matrix::operator"#_Op); \
size_type __i = _M_impl._M_row * _M_impl._M_col; \
while (__i) \
{ \
--__i; \
this->_M_impl._M_mat[__i] _Op __rhs._M_impl._M_mat[__i]; \
} \
return *this; \
}
__IGS_FunctionDefinitionHelperFor_matrix_operators_10(+=)
__IGS_FunctionDefinitionHelperFor_matrix_operators_10(-=)
matrix&
operator*=(const matrix& __rhs)
{
/// Safaty check.
this->_M_matrix_multiplication_check(__rhs);
size_type __i = this->_M_impl._M_row, __j, __k;
while (__i--)
{
__k = __rhs._M_impl._M_row;
while (__k--)
{
__j = __rhs._M_impl._M_col;
const_reference _S = this->operator()(__i, __k);
while (__j--)
this->operator()(__i, __j) += _S * __rhs(__k, __j);
}
}
return *this;
}
matrix
operator+() const
{ return *this; }
matrix
operator-() const
{
size_type __i = _M_impl._M_row * _M_impl._M_col;
matrix __tmp(*this);
while (__i > 0)
{
--__i;
__tmp._M_impl._M_mat[__i] = -__tmp._M_impl._M_mat[__i];
}
return __tmp;
}
bool
operator==(const matrix& __rhs) const
{
if (this->_M_impl._M_mat == __rhs._M_impl._M_mat)
return true;
if (this->_M_impl._M_row != __rhs._M_impl._M_row)
return false;
if (this->_M_impl._M_col != __rhs._M_impl._M_col)
return false;
size_type __i = this->_M_impl._M_row * this->_M_impl._M_col;
while (__i--)
if (this->_M_impl._M_mat[__i] != __rhs._M_impl._M_mat[__i])
return false;
return true;
}
/// Based on operator==
bool
operator!=(const matrix& __rhs) const
{ return !(*this == __rhs); }
}; // class matrix
#define __IGS_FunctionDefinitionHelperFor_matrix_operators_01(_Op) \
template<typename T, typename A> \
matrix<T, A> \
operator _Op (const matrix<T, A>& __m, const T& __x) \
{ \
matrix<T, A> __tmp(__m); \
return __tmp _Op##= __x; \
} \
template<typename T, typename A> \
matrix<T, A> \
operator _Op (const T& __x, const matrix<T, A>& __m) \
{ \
matrix<T, A> __tmp(__m); \
return __tmp _Op##= __x; \
}
__IGS_FunctionDefinitionHelperFor_matrix_operators_01(+)
__IGS_FunctionDefinitionHelperFor_matrix_operators_01(-)
__IGS_FunctionDefinitionHelperFor_matrix_operators_01(*)
__IGS_FunctionDefinitionHelperFor_matrix_operators_01(/)
__IGS_FunctionDefinitionHelperFor_matrix_operators_01(%)
#define __IGS_FunctionDefinitionHelperFor_matrix_operators_11(_Op) \
template<typename T, typename A> \
matrix<T, A> \
operator _Op (const matrix<T, A>& __lhs, const matrix<T, A>& __rhs) \
{ \
matrix<T, A> __tmp(__lhs); \
return __tmp _Op##= __rhs; \
}
__IGS_FunctionDefinitionHelperFor_matrix_operators_11(+)
__IGS_FunctionDefinitionHelperFor_matrix_operators_11(-)
__IGS_FunctionDefinitionHelperFor_matrix_operators_11(*)
template<typename T, typename A>
inline std::string
to_string(const matrix<T, A>& __x, std::string _btw_elt = " ",
std::string _end_row = "\n")
{ return __x.to_string(_btw_elt, _end_row); }
//@{
/**
* @brief Global Output operator for matrices.
*
* Direct Output between streams and matrices is supported. Output is
* straightforward.
*/
template<typename _CharT, typename _Traits, typename T, typename A>
inline std::basic_ostream<_CharT, _Traits>&
operator<<(std::basic_ostream<_CharT, _Traits>& __os,
const matrix<T, A>& __x)
{
if (__x.empty()) return __os;
std::size_t __row = __x.shape().first;
std::size_t __col = __x.shape().second;
std::size_t __i = 0, __j;
while (__i < __row)
{
__j = 0;
while (__j < __col)
{
__os << __x(__i, __j);
__os << ' ';
++__j;
}
__os << '\n';
++__i;
}
return __os;
}
//@}
/// See IGS::matrix::swap().
template<typename T, typename A>
inline void
swap(matrix<T, A>& __lhs, matrix<T, A>& __rhs)
{ __lhs.swap(__rhs); }
} // namespace IGS
#endif // #ifndef __IGS__matrix_H
标签:__,const,matrix,._,type,impl 来源: https://www.cnblogs.com/gyan083/p/matrix_h.html