// Source: "Software Design ...", John A Robinson, Newnes, 2004, page 380. // Header for stable class // John Robinson 2003 // Version 0.1 25 August 2003 #include #include #include using namespace std; // tcell provides the structure of each cell in the stable class. It may // be used separately for other collections if desired. // Lightweight: all member functions defined inline here. class tcell { bool cellused; int rowindex; int colindex; string content; public: tcell() { cellused = 0; content = ""; rowindex = colindex = -1; }; ~tcell() { }; void setindices(const int r, const int c) { rowindex = r; colindex = c; }; void setval(const string& cont) { cellused = 1; content = cont; }; void delval() { cellused = 0; content = ""; }; const string getval() { return content; }; const int row() { return rowindex; }; const int col() { return colindex; }; const bool used() { return cellused; }; }; // stable provides a 2D table of tcells plus row and column labels, // with facilities as outlined in member functions below. class stable { // Comments on private members are for reference only. Users // should not infer implications about how stable is implemented. int max_rows; // Set on instantiation int max_cols; // Set on instantiation int lowest_available_row; // Row numbers equal to or higher than // this are not yet used. int lowest_available_col; // No rows have entries is this or any // higher numbered column tcell *rlabel; // Row labels are outsize the table itself // in a 1D array tcell *clabel; // Column labels are outsize the table itself // in a 1D array tcell **cell; // The array of pointers to arrays (rows) of cells // read() and write() functions are called by the public // interfaces and simply encapsulate the two alternatives of // reading/writing with and without labels void read(istream& in, const bool withlabels, const char coldelim, const char rowdelim); int write(ostream& out, const bool withlabels, const char coldelim, const char rowdelim, const bool includelastrowdelim); public: stable(const int r = 2048, const int c = 256); // Users may instantiate with default parameters and not incur an // excessive memory hit. Only if the number of columns is expected // to be greater than 256 or the number of rows greater than 2048 // need the parameters be used ~stable(); void reset(); // Clean up the table for reuse int nrows() { return lowest_available_row; } int ncols() { return lowest_available_col; } int maxrows() { return max_rows; } int maxcols() { return max_cols; } // set and get functions work on individual cells of the stable, // or on the row or column labels. They allow setting and getting // of any data types that have istream ostream operators defined // to allow the types to be represented as strings. // set returns -1 if outside stable size limits; 0 otherwise // get returns -1 if outside size limits; 0 if row-col indices // not used or label not found; 1 otherwise. int set(const int row, const int col, const string& val); int get(const int row, const int col, string& val); // set/get the value at coords (col, row) in the table to val // For get, if the value is unused, returns 0 and val = "". template int set(const int row, const int col, const T& val) { ostringstream os; os << val; return set(row, col,os.str()); } template int get(const int row, const int col, T& val) { string thestring; int retval = get(row, col, thestring); istringstream is(thestring); is >> val; return retval; } // As above, for arbitrary types that can be represented as strings int set(const string& row, const string& col, const string& val); int get(const string& row, const string& col, string& val); // set/get the value with row, column labels as specified to val template int set(const string& row, const string& col, const T& val) { ostringstream os; os << val; return set(row, col,os.str()); } template int get(const string& row, const string& col, T& val) { string thestring; int retval = get(row, col, thestring); istringstream is(thestring); is >> val; return retval; } // As above, for arbitrary types that can be represented as strings int setrowlabel(const int row, const string& val); int setcollabel(const int col, const string& val); int getrowlabel(const int row, string& val); int getcollabel(const int col, string& val); // Explicitly set/get the row/column label with given index // Find functions look for a particular entry after or before // the specified (col,row) coordinates, where "after"/"before" // defined according to raster ordering of stable. If found, // return 1 and row, col set to coordinates. If not found, // return 0 and row, col are garbage. int findafter(const string& val, int& row, int& col); // Find (col, row) coords of next occurence in table of val // after the (col, row) values on input. template int findafter(const T& val, int& row, int& col) { ostringstream os; os << val; return findafter(os.str(), row, col); } // As above, for arbitrary types that can be represented as strings int findbefore(const string& val, int& row, int& col); // Find (col, row) coords of previous occurence in table of val // before the (col, row) values on input. template int findbefore(const T& val, int& row, int& col) { ostringstream os; os << val; return findbefore(os.str(), row, col); } // As above, for arbitrary types that can be represented as strings int find(const string& val, int& row, int& col); // Find coords of first occurence of val in table template int find(const T& val, int& row, int& col) { ostringstream os; os << val; return find(os.str(), row, col); } // As above, for arbitrary types that can be represented as strings int findrowlabel(const string& val, int& row); int findcollabel(const string& val, int& col); // Find index of row/col label with value val // Reading functions allow reading from a stream or a string. The // input is parsed according to the specified row and column // delimiters. The newly read information overwrites anything that // was previously in the stable. // Reading can either be withlabels -- meaning the source stream/string // has labels at the top and left hand side or withoutlabels. In the // latter case, the labels will be set to empty strings. // Writing functions are symmetric to reading functions with an // additional parameter that says whether to output the final // rows rowdelim at the very end. void readwithoutlabels(istream& in, const char coldelim = '\t', const char rowdelim = '\n'); void readwithoutlabels(const string& instring, const char coldelim = '\t', const char rowdelim = '\n'); void readwithoutlabels(const char *p, const char coldelim = '\t', const char rowdelim = '\n'); void readwithlabels(istream& in, const char coldelim = '\t', const char rowdelim = '\n'); void readwithlabels(const string& instring, const char coldelim = '\t', const char rowdelim = '\n'); void readwithlabels(const char *p, const char coldelim = '\t', const char rowdelim = '\n'); int writewithlabels(ostream& out, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1); int writewithlabels(string& ostring, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1); int writewithoutlabels(ostream& out, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1); int writewithoutlabels(string& ostring, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1); // print is a debugging function that prints out a truncated // version of each item in the table. void print(); };