/*
* mmatrix.h
* (C) Porkolab Zoltan, ELTE, Budapest, Hungary
* (C) 2003
*/
#ifndef MMATRIX_H
#define MMATRIX_H
#include <algorithm>
#include <vector>
#include <map>
#include <stdexcept>
template<typename T>
class mmatrix
{
public:
class index
{
public:
index& put(const int& p) { _index.push_back(p); return *this; }
int size() const {return _index.size(); }
void reset(){_index.clear();}
// a map kulcstípusának rendelkeznie kell egy operator< művelettel:
bool operator<(const index& i2) const
{
return lexicographical_compare(_index.begin(),_index.end(),
i2._index.begin(),i2._index.end());
}
private:
std::vector<int> _index;
};
// gsd: az iterator alapötlete nem volt rossz, de ahelyett,
// hogy újraírjuk az összes metódust, inkább örököljük :-)
class iterator : public std::map<index,T>::iterator
{
public:
// ezt azért, hogy rövidítsünk:
typedef typename std::map<index,T>::iterator base_iterator;
iterator( const base_iterator& bi) : base_iterator(bi) {}
// ez az a művelet, amit át kellett írnuk:
T& operator*() { return base_iterator::operator*().second; }
};
// ugyanez a const_iterator-ral.
class const_iterator : public std::map<index,T>::const_iterator
{
public:
typedef typename std::map<index,T>::const_iterator base_iterator;
const_iterator( const base_iterator& bi) : base_iterator(bi) {}
// ez azért kell, hogy az iterator konvertálódjon const_iterator-rá.
// beszúrtam egy plusz tesztet a főprogram végére.
const_iterator( const iterator& i) : base_iterator(i) {}
const T& operator*() { return base_iterator::operator*().second; }
};
mmatrix(const index& ix);
int dim() const { return _dim; }
iterator begin(); //a matrix elejere mutato iteratort adja vissza
iterator end(); //a matrix vegere mutato
const_iterator begin() const; // kellenek a const_iterator verziok is
const_iterator end() const;
T& at(const index& ix);
T at(const index& ix) const;
T& operator[](const index& ix);
T operator[](const index& ix) const;
private:
std::map<index,T> m;
int _dim;
void check_range(const index& ix) const;
};
template<typename T>
mmatrix<T>::mmatrix(const index& i)
{
_dim=i.size();
}
// gsd: ez még annál is bonyolultabb, mint eredetileg gondoltam :-)
//
// 1. referenciát kellene visszaadnunk az at()-ben, de T() temporális,
// nem tudjuk visszaadni referenciaként.
// 2. a defval-os megoldás sem jó, mert m.at(x) és m.at(y) ugyanaz
// a defval objektum lenne, akkor is, ha x != y. Ez nem szerencsés.
// 3. marad a legegyszerűbb: csináljunk úgy, mint az std::map operator[]
// a nemlétező elemeket létrehozzuk.
// 4. persze, ha "nemlétező" elemet adunk vissza, mint T(), akkor azt
// másolnunk kell, nem hivatkozhatunk rá referenciaként
// 5. apróság: az operator[] szokásosan nem ellenőriz semmit,
// ezért az at() hívja az operator[]-t és nem fordítva.
template<typename T>
T& mmatrix<T>::operator[]( const index& ix)
{
return m[ix]; // néha az egyszerűnél nincsen jobb
// létrehozza az elemet, ha nem létezett.
}
template<typename T>
T mmatrix<T>::operator[]( const index& ix) const
{
// itt muszály körbejárni a dolgot
// mert map::operator[] -nak nincsen const verziója
typename std::map<index,T>::const_iterator ci = m.find(ix);
if ( m.end() != ci )
return ci->second;
else
return T();
}
template<typename T>
void mmatrix<T>::check_range(const index& ix) const
{
//ha nem a matrix dimenziojanak megfelelo indexu ertekre hivatkozik
if( ix.size() != _dim )
{
throw std::out_of_range("bad index"); //kivetelt dob
}
}
template<typename T>
T& mmatrix<T>::at(const index& ix)
{
check_range(ix);
return operator[](ix);
}
template<typename T>
T mmatrix<T>::at(const index& i) const
{
check_range(ix);
return operator[](ix);
}
template<typename T>
typename mmatrix<T>::iterator mmatrix<T>::begin()
{
return iterator(m.begin());
}
template<typename T>
typename mmatrix<T>::iterator mmatrix<T>::end()
{
return iterator(m.end());
}
template<typename T>
typename mmatrix<T>::const_iterator mmatrix<T>::begin() const
{
return const_iterator(m.begin());
}
template<typename T>
typename mmatrix<T>::const_iterator mmatrix<T>::end() const
{
return const_iterator(m.end());
}
#endif