// // Tuple list example. // Copyright (C) 2002 Christian Holm Christensen // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, // MA 02111-1307 USA // /** @file tuple.cc @brief An example of how to make an `ntuple'. This is a small example that shows how to make a list of tuples of numbers. It's not optimized in any way. Especially the allocation could be optimised a lot. One way to do that, is to use an allocator functor. */ #ifndef __IOSTREAM__ #include #endif #ifndef __STDEXCEPT__ #include #endif #ifndef __FSTREAM__ #include #endif namespace cholm { /** Container of tuples. Constrains on the type in the template:
  • must have an extraction operator [istream& operator>>(istream&, T&)]
  • must be assignable.
*/ template class tuple_list { protected: /// The data stored. T* _data; /// Dimension of the tuples. int _n; /// number of tuples int _m; /// Initialise the internal data array. virtual void initialize() { if (_m <= 0) _m = 10; _data = new T[_n * _m]; clear(0); } public: /** nested class for accessing the tuples. The user hardly sees this class. It's meant to assit the user to do more intuitive lookups in a tuple_list, like @code tuple_list data(10); data[0][0] = 0; @endcode */ class tuple { private: /** Pointer into list data array. This just points to the tuple_list internal data, and therefor should never be freed by this object. */ T* _tuple; /** Size of the tuple. This parameter is used for catching out of bounds errors. */ int _n; public: /** Tuple constructor. The internal size is set. @param n Size of the tuple. @param pointer into tuple_list's internal data. */ tuple(int n, T* tuple) : _n(n), _tuple(tuple) {} /// Destructor. Does nothing. virtual ~tuple() {} /** Element access member function. This returns the i'th element in the tuple. @param i The element to access. @return the i'th element, or throws a std::range_error exception if argumetn is out of range. */ T& operator[](int i) { if (i < 0 || i > _n) throw std::range_error("tuple: out of range"); return _tuple[i]; } /** Element access member function (constant version). This returns the i'th element in the tuple. @param i The element to access. @return the i'th element, or throws a std::range_error exception if argumetn is out of range. */ const T& operator[](int i) const { if (i < 0 || i > _n) throw std::range_error("tuple: out of range"); return _tuple[i]; } /// Get the dimension of the tuple int dimension() const { return _n; } }; /** Normal constructor. A list is instanized. @param n The size of the tuples. @param m the initial size of the list. */ tuple_list(int n, int m=10) : _n(n), _m(m) { _data = 0; initialize(); } /** Input cosntructor. A list is instanized from a file. @param n The size of the tuples. @param input an input stream to read the data from. */ tuple_list(int n, std::istream& input) : _n(n) { _m = 0; _data = 0; initialize(); read(input); } /// Desctructor. Frees allocated memory. virtual ~tuple_list() { /* if (_data) delete [] _data; */ } /** operator to return a tuple in the list. @param i the tupel number to get. @return the i'th tuple, or throws a std::range_error exception if argument is out of the allowed range. */ tuple operator[](int i) { if (i < 0 || i >= _m) resize(2 * _m); return tuple(_n, &(_data[_n * i])); } /** operator to return a tuple in the list. @param i the tupel number to get. @return the i'th tuple, or throws a std::range_error exception if argument is out of the allowed range. */ const tuple operator[](int i) const { if (i < 0 || i > _m) throw std::range_error("out of range"); return tuple(_n, &(_data[_n * i])); } /** Clear internal data. @param d the value to set all elements to. */ virtual void clear(T d=0) { for (int i = 0; i < _n * _m; i++) _data[i] = d; } /** Resize the list. @param newsize. The new size to resize to. @param d what to initiaize new elements to. */ virtual void resize(int newsize, T d=0) { if (newsize == _m) return; T* tmp = new T[newsize * _n]; int i = 0; for (i = 0; i < _m * _n || i < newsize * _n; i++) tmp[i] = _data[i]; for (; i < newsize * _n; i++) tmp[i] = d; _data = tmp; _m = newsize; delete [] _data; } /** Read from an input stream. @param input the input stream to read from. */ virtual void read(std::istream& input) { int i = 0; while (!input.eof()) { if (i > _m) resize(2 * _m, 0); for (int j = 0; j < _n; j++) { input >> _data[_n * i + j]; if (input.bad()) throw std::runtime_error("error while reading"); } i++; } } /// Get the size of the list. int size() const { return _m; } /// Get the dimension int dimension() const { return _n; } }; } /// Example program. int main(int arg, char** argv) { // tuple_list throws exceptions :-) try { // Make some output data ... cholm::tuple_list out_data(3, 5); for (int i = 0; i < 10; i++) for (int j = 0; j < out_data.dimension() ; j++) out_data[i][j] = i * 10 + j; // ... and write to disk. std::ofstream out_file("tuple.data"); for (int i = 0; i < out_data.size(); i++) { for (int j = 0; j < out_data.dimension(); j++) out_file << out_data[i][j] << " "; out_file << std::endl; } out_file.close(); // Read from the disk ... std::ifstream in_file("tuple.data"); cholm::tuple_list in_data(out_data.dimension(), in_file); in_file.close(); // ... and show it on standard out. for (int i = 0; i < in_data.size(); i++) { for (int j = 0; j < in_data.dimension(); j++) std::cout << in_data[i][j] << " "; std::cout << std::endl; } } // did any thing bad happen ... catch (exception& e) { // ... yes it did, show what it was ... cerr << e.what() << endl; // ... and fail. return 1; } // success! return 0; }