/* * 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