#ifndef _mitrax_mitrax_proxy_hpp_INCLUDED_
#define _mitrax_mitrax_proxy_hpp_INCLUDED_
/// \file proxy.hpp
///
/// \brief Proxyklassen für Zeilen und Spalten eines Matrixobjekts
///
/// In dieser Datei werden die vier Proxyklassen definiert, welche jeweils ein Zeile oder Spalte
/// einer konstante oder nicht-konstanten Matrix repräsentieren. Weiterhin steht hier die Funktion
/// <code>element_swap()</code> welche alle Elemente zweier Zeilen oder Spalten miteinander
/// vertauscht.
#include "detail/proxy_iterator.hpp"
#include "exception.hpp"
namespace mitrax{
// Forward-Deklarationen
template < typename Matrix > class row_proxy;
template < typename Matrix > class column_proxy;
namespace detail{
/// \brief Private Basisklasse für alle Proxys
///
/// Diese Klasse enthält die Datenmember der Proxyklassen. Alle vier Proxyklassen werden direkt
/// oder indirekt private von dieser Klasse angeleitet. Es ist nicht möglich Objekte von dieser
/// Klasse zu erzeugen. Die Klasse ist eine Helferklasse mit der ein Benutzer keinen direkten
/// Kontakt haben sollte.
///
/// Compilergenrierte Methoden:
/// - Kopierkonstruktor
/// - Kopierzuweisung
/// - Destruktor
template < typename Matrix >
class line_const_proxy{
protected:
/// \brief Die Klasseninstanz des Klassentemplats matrix zu der der Proxy gehört
typedef Matrix matrix_type;
/// \brief Typ der Elemente der Matrix
typedef typename Matrix::value_type value_type;
/// \brief Typ der Dimensionselemente der Matrix
typedef typename Matrix::size_type size_type;
/// \brief Konstruktor zur Objekterzeugung aus einem Verweis auf ein konstantes
/// <code>matrix</code>-Objekt und einer Zeilen-/Spaltennummer
line_const_proxy(matrix_type const& matrix, size_type const& pos):
matrix_(&matrix), pos_(pos){}
/// \brief Lesezugriff auf die verwaltete Zeilen-/Spaltennummer
size_type const pos()const{ return pos_; }
/// \brief Lesezugriff auf die referenzierte Matrix
matrix_type const& matrix_const()const{ return *matrix_; }
private:
/// \brief Die referenzierte Matrix
matrix_type const* matrix_;
/// \brief Die verwaltete Zeile/Spalte aus der Matrix
size_type pos_;
};
/// \brief Private Basisklasse für alle Proxys für nicht-konstante Matrizen
///
/// Diese Klasse stellt das Matrixobjekt als nicht-konstante Referenz zu Verfügung. Alle
/// Proxyklassen für nicht-konstante Matrizen werden private von dieser Klasse angeleitet. Es ist
/// nicht möglich Objekte von dieser Klasse zu erzeugen. Die Klasse ist eine Helferklasse mit der
/// ein Benutzer keinen direkten Kontakt haben sollte.
///
/// Compilergenerierte Methoden:
/// - Kopierkonstruktor
/// - Kopierzuweisung
/// - Destruktor
template < typename Matrix >
class line_proxy: protected line_const_proxy< Matrix >{
protected:
/// \brief Die Klasseninstanz des Klassentemplats matrix zu der der Proxy gehört
typedef Matrix matrix_type;
/// \brief Typ der Elemente der Matrix
typedef typename Matrix::value_type value_type;
/// \brief Typ der Dimensionselemente der Matrix
typedef typename Matrix::size_type size_type;
/// \brief Konstruktor zur Objekterzeugung aus einem Verweis auf <code>matrix</code>-Objekt und
/// einer Zeilen-/Spaltennummer
line_proxy(matrix_type& matrix, size_type const& pos):
detail::line_const_proxy< matrix_type >(matrix, pos){}
/// \brief Schreibzugriff auf die referenzierte Matrix
matrix_type& matrix()const{ return const_cast< matrix_type& >(this->matrix_const()); }
};
/// \brief Helfer zu Iteratorerzeugung in Zeilenproxys (<code>begin()</code>)
template < typename Matrix, typename Iterator >
inline
Iterator const
create_begin_row_iterator(
Matrix& matrix,
typename Matrix::size_type const& row
){
return Iterator(
matrix.begin() + (matrix.columns() * row)
);
}
/// \brief Helfer zu Iteratorerzeugung in Zeilenproxys (<code>end()</code>)
template < typename Matrix, typename Iterator >
inline
Iterator const
create_end_row_iterator(
Matrix& matrix,
typename Matrix::size_type const& row
){
return Iterator(
matrix.begin() + (matrix.columns() * (row + 1))
);
}
/// \brief Helfer zu Iteratorerzeugung in Spaltenproxys (<code>begin()</code>)
template < typename Matrix, typename Iterator >
inline
Iterator const
create_begin_column_iterator(
Matrix& matrix,
typename Matrix::size_type const& column
){
return Iterator(
matrix,
column
);
}
/// \brief Helfer zu Iteratorerzeugung in Spaltenproxys (<code>end()</code>)
template < typename Matrix, typename Iterator >
inline
Iterator const
create_end_column_iterator(
Matrix& matrix,
typename Matrix::size_type const& column
){
return Iterator(
matrix,
column + matrix.columns() * matrix.rows()
);
}
}
/// \brief Proxyklasse die eine Zeile eines konstanten <code>matrix</code>-Objekts repräsentiert
template < typename Matrix >
class row_const_proxy: private detail::line_const_proxy< Matrix >{
public:
/// \brief Die Klasseninstanz des Klassentemplats <code>matrix</code> zu der der Proxy gehört
typedef Matrix matrix_type;
/// \brief Typ der Elemente der Matrix
typedef typename Matrix::value_type value_type;
/// \brief Iteratoren für Lesezugriff
typedef detail::row_const_iterator< matrix_type > const_iterator;
/// \brief Iteratoren für Lesezugriff
typedef const_iterator iterator;
/// \brief Typ der Dimensionselemente der Matrix
typedef typename Matrix::size_type size_type;
/// \brief <code>difference_type</code> der Iteratoren
typedef typename const_iterator::difference_type difference_type;
/// \brief Objekterzeugung aus einem Verweis auf ein konstantes <code>matrix</code>-Objekt und
/// einer Zeilennummer
row_const_proxy(matrix_type const& matrix, size_type const& row):
detail::line_const_proxy< matrix_type >(matrix, row){}
/// \brief Lesezugriff auf das Element <code>column_number</code>
///
/// siehe <code>column()</code>
value_type const&
operator[](size_type const& column_number)const{ return column(column_number); }
/// \brief Lesezugriff auf das Element number
value_type const& column(size_type const& number)const{ return *(begin() + number); }
/// \brief Anzahl der Spalten
size_type const columns()const{ return this->matrix_const().columns(); }
/// \brief Anzahl der Spalten
///
/// siehe <code>columns()</code>
size_type const size()const{ return columns(); }
/// \brief Zeile die das Objekt repräsentiert
size_type const pos()const{ return detail::line_const_proxy< matrix_type >::pos(); }
/// \brief Leseiterator auf das erste Element
const_iterator const begin()const{ return cbegin(); }
/// \brief Leseiterator hinter das letzte Element
const_iterator const end()const{ return cend(); }
/// \brief Leseiterator auf das erste Element
const_iterator const cbegin()const{
return detail::create_begin_row_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
/// \brief Leseiterator hinter das letzte Element
const_iterator const cend()const{
return detail::create_end_row_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
};
/// \brief Proxyklasse die eine Spalte eines konstanten <code>matrix</code>-Objekts repräsentiert
template < typename Matrix >
class column_const_proxy: private detail::line_const_proxy< Matrix >{
public:
/// \brief Die Klasseninstanz des Klassentemplats <code>matrix</code> zu der der Proxy gehört
typedef Matrix matrix_type;
/// \brief Typ der Elemente der Matrix
typedef typename Matrix::value_type value_type;
/// \brief Iteratoren für Lesezugriff
typedef detail::column_const_iterator< matrix_type > const_iterator;
/// \brief Iteratoren für Lesezugriff
typedef const_iterator iterator;
/// \brief Typ der Dimensionselemente der Matrix
typedef typename Matrix::size_type size_type;
/// \brief <code>difference_type</code> der Iteratoren
typedef typename const_iterator::difference_type difference_type;
/// \brief Objekterzeugung aus einem Verweis auf ein konstantes <code>matrix</code>-Objekt und
/// einer Spaltennummer
column_const_proxy(matrix_type const& matrix, size_type const& column):
detail::line_const_proxy< matrix_type >(matrix, column){}
/// \brief Lesezugriff auf das Element <code>row_number</code>
///
/// siehe <code>row()</code>
value_type const& operator[](size_type const& row_number)const{ return row(row_number); }
/// \brief Lesezugriff auf das Element number
value_type const& row(size_type const& number)const{ return *(begin() + number); }
/// \brief Anzahl der Zeilen
size_type const rows()const{ return this->matrix_const().rows(); }
/// \brief Anzahl der Zeilen
///
/// siehe <code>rows()</code>
size_type const size()const{ return rows(); }
/// \brief Spalte die das Objekt repräsentiert
size_type const pos()const{ return detail::line_const_proxy< matrix_type >::pos(); }
/// \brief Leseiterator auf das erste Element
const_iterator const begin()const{ return cbegin(); }
/// \brief Leseiterator hinter das letzte Element
const_iterator const end()const{ return cend(); }
/// \brief Leseiterator auf das erste Element
const_iterator const cbegin()const{
return detail::create_begin_column_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
/// \brief Leseiterator hinter das letzte Element
const_iterator const cend()const{
return detail::create_end_column_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
};
/// \brief Proxyklasse die eine Zeile eines <code>matrix</code>-Objekts repräsentiert
template < typename Matrix >
class row_proxy: private detail::line_proxy< Matrix >{
public:
/// \brief Die Klasseninstanz des Klassentemplats <code>matrix</code> zu der der Proxy gehört
typedef Matrix matrix_type;
/// \brief Typ der Elemente der Matrix
typedef typename Matrix::value_type value_type;
/// \brief Iteratoren für Lesezugriff
typedef typename row_const_proxy< matrix_type >::const_iterator const_iterator;
/// \brief Iteratoren für Schreibzugriff
typedef detail::row_iterator< matrix_type > iterator;
/// \brief Typ der Dimensionselemente der Matrix
typedef typename Matrix::size_type size_type;
/// \brief <code>difference_type</code> der Iteratoren
typedef typename row_const_proxy< matrix_type >::difference_type difference_type;
/// \brief Objekterzeugung aus einem Verweis auf ein <code>matrix</code>-Objekt und einer
/// Zeilennummer
row_proxy(matrix_type& matrix, size_type const& row):
detail::line_proxy< matrix_type >(matrix, row){}
/// \brief Schreibzugriff auf das Element <code>column_number</code>
///
/// siehe <code>column()</code>
value_type& operator[](size_type const& column_number)const{ return column(column_number); }
/// \brief Schreibzugriff auf das Element <code>number</code>
value_type& column(size_type const& number)const{ return *(begin() + number); }
/// \brief Anzahl der Spalten
size_type const columns()const{ return this->matrix_const().columns(); }
/// \brief Anzahl der Spalten
///
/// siehe <code>columns()</code>
size_type const size()const{ return columns(); }
/// \brief Zeile die das Objekt repräsentiert
size_type const pos()const{ return detail::line_proxy< matrix_type >::pos(); }
/// \brief Schreibiterator auf das erste Element
iterator const begin()const{
return detail::create_begin_row_iterator< matrix_type, iterator >(this->matrix(), pos());
}
/// \brief Schreibiterator hinter das letzte Element
iterator const end()const{
return detail::create_end_row_iterator< matrix_type, iterator >(this->matrix(), pos());
}
/// \brief Leseiterator auf das erste Element
const_iterator const cbegin()const{
return detail::create_begin_row_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
/// \brief Leseiterator hinter das letzte Element
const_iterator const cend()const{
return detail::create_end_row_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
/// \brief Typumwandlung in <code>row_const_proxy< matrix_type ></code>
operator row_const_proxy< matrix_type >()const{
return row_const_proxy< matrix_type >(this->matrix_const(), this->pos());
}
};
/// \brief Proxyklasse die eine Spalte eines konstanten <code>matrix</code>-Objekts repräsentiert
template < typename Matrix >
class column_proxy: private detail::line_proxy< Matrix >{
public:
/// \brief Die Klasseninstanz des Klassentemplats <code>matrix</code> zu der der Proxy gehört
typedef Matrix matrix_type;
/// \brief Typ der Elemente der Matrix
typedef typename Matrix::value_type value_type;
/// \brief Iteratoren für Lesezugriff
typedef typename column_const_proxy< matrix_type >::const_iterator const_iterator;
/// \brief Iteratoren für Schreibzugriff
typedef detail::column_iterator< matrix_type > iterator;
/// \brief Typ der Dimensionselemente der Matrix
typedef typename Matrix::size_type size_type;
/// \brief <code>difference_type</code> der Iteratoren
typedef typename column_const_proxy< matrix_type >::difference_type difference_type;
/// \brief Objekterzeugung aus einem Verweis auf ein <code>matrix</code>-Objekt und einer
/// Spaltennummer
column_proxy(matrix_type& matrix, size_type const& column):
detail::line_proxy< matrix_type >(matrix, column){}
/// \brief Schreibzugriff auf das Element <code>row_number</code>
///
/// siehe <code>row()</code>
value_type& operator[](size_type const& row_number)const{ return row(row_number); }
/// \brief Schreibzugriff auf das Element number
value_type& row(size_type const& number)const{ return *(begin() + number); }
/// \brief Anzahl der Zeilen
size_type const rows()const{ return this->matrix_const().rows(); }
/// \brief Anzahl der Zeilen
///
/// siehe <code>rows()</code>
size_type const size()const{ return rows(); }
/// \brief Spalte die das Objekt repräsentiert
size_type const pos()const{ return detail::line_proxy< matrix_type >::pos(); }
/// \brief Schreibiterator auf das erste Element
iterator const begin()const{
return detail::create_begin_column_iterator< matrix_type, iterator >(
this->matrix(), pos()
);
}
/// \brief Schreibiterator hinter das letzte Element
iterator const end()const{
return detail::create_end_column_iterator< matrix_type, iterator >(this->matrix(), pos());
}
/// \brief Leseiterator auf das erste Element
const_iterator const cbegin()const{
return detail::create_begin_column_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
/// \brief Leseiterator hinter das letzte Element
const_iterator const cend()const{
return detail::create_end_column_iterator< matrix_type const, const_iterator >(
this->matrix_const(), pos()
);
}
/// \brief Typumwandlung in <code>column_const_proxy< matrix_type ></code>
operator column_const_proxy< matrix_type >()const{
return column_const_proxy< matrix_type >(this->matrix_const(), this->pos());
}
};
namespace detail{
/// \brief Helferfunktion für <code>element_swap()</code>
template < typename Proxy >
inline
void
element_swap_template(
Proxy const& lhs,
Proxy const& rhs
){
typedef typename Proxy::iterator iterator;
using std::swap;
// kompatibilität prüfen
if(lhs.size() != rhs.size()){
throw error::size_unequal("mitrax::element_swap_template<>()", lhs.size(), rhs.size());
}
// Elementweise tauschen
for(
iterator i = lhs.begin(), j = rhs.begin();
i != lhs.end();
++i, ++j
){
swap(*i, *j);
}
}
}
/// \brief Vertauscht Elemente zweier Zeilen
template < typename Matrix >
inline
void
element_swap(row_proxy< Matrix > const& lhs, row_proxy< Matrix > const& rhs){
detail::element_swap_template(lhs, rhs);
}
/// \brief Vertauscht Elemente zweier Spalten
template < typename Matrix >
inline
void
element_swap(column_proxy< Matrix > const& lhs, column_proxy< Matrix > const& rhs){
detail::element_swap_template(lhs, rhs);
}
}
#endif