// Source: "Software Design ...", John A Robinson, Newnes, 2004, page 384. // Implementation of stable class // John Robinson 2003 // Version 0.1 25 August 2003 // Only public functions not defined here are nrows() and ncols() and // the template versions of set/get/find. All these are in // stable.h header file. #include "stable.h" #include #include #include #include using namespace std; // Read and write are private member functions that support the public // withlabels and withoutlabels versions. void stable::read(istream& in, const bool withlabels, const char coldelim, const char rowdelim) { // Read from file with or without labels. reset(); string line; int startindex; // -1 for with labels, because first row and // column are before zeroth row and colum; // 0 for without labels. if (withlabels) startindex = -1; else startindex = 0; int r = startindex; while(!in.eof()) { getline(in,line, rowdelim); if ((line == "")&&in.eof()) // Nothing after final rowdelim break; int c = startindex; string temp; string::size_type currpos, delimpos; currpos = 0; while ((delimpos = line.find(coldelim, currpos)) != string::npos){ temp = line.substr(currpos,delimpos-currpos); if ((r ==-1)&&(c==-1)) { if (currpos != delimpos) { cout << "Warning: readwithlabels from file that doesn't begin with a column\n\ delimiter. The first entry will be lost.\n"; } c++; } else if (r == -1) setcollabel(c++,temp); else if (c == -1) { setrowlabel(r,temp); c++; } else set(r,c++,temp); currpos = delimpos+1; } temp = line.substr(currpos); if (r == -1) setcollabel(c,temp); else if (c == -1) setrowlabel(r,temp); else set(r,c,temp); r++; } if (!withlabels) { // Reset all labels for (r = 0; r < lowest_available_row; r++) rlabel[r].setval(""); for (int c = 0; c < lowest_available_col; c++) clabel[c].setval(""); } } int stable::write(ostream& out, const bool withlabels, const char coldelim, const char rowdelim, const bool includelastrowdelim) { int i, j; if (withlabels) { out << coldelim; // Top left corner: No label for (i = 0; i < lowest_available_col-1; i++) out << clabel[i].getval() << coldelim; out << clabel[i].getval() << rowdelim; } for (i = 0; i < lowest_available_row; i++) { if (withlabels) out << rlabel[i].getval() << coldelim; // Don't output column delimiters after last entry on a row int last_used = lowest_available_col-1; while ((last_used >= 0) && !cell[i][last_used].used()) last_used--; for (j = 0; j < last_used; j++) out << cell[i][j].getval() << coldelim; if (last_used >= 0) out << cell[i][j].getval(); if ((i < lowest_available_row-1) || includelastrowdelim) out << rowdelim; } } // Remaining functions are public. See stable.h for usage stable::stable(const int r, const int c) { max_rows = r; max_cols = c; lowest_available_row = 0; lowest_available_col = 0; rlabel = new tcell[max_rows]; // Row labels clabel = new tcell[max_cols]; // Column labels cell = new tcell *[max_rows]; // All the cells for (int i = 0; i < max_rows; i++) cell[i] = 0; } stable::~stable() { for (int i = 0; i < max_rows; i++) { if (cell[i]) delete [] cell[i]; } delete [] cell; delete [] clabel; delete [] rlabel; } void stable::reset() { // Clean up the table for reuse for (int i = 0; i < max_rows; i++) { if (cell[i]) { for (int j = 0; j < max_cols; j++) cell[i][j].delval(); } } lowest_available_row = 0; lowest_available_col = 0; } // In header files, set/get come in pairs. Here are the sets are defined // first, then all the gets // set functions int stable::set(const int row, const int col, const string& val) { if ((row < 0)||(col < 0)||(row >= max_rows)||(col >= max_cols)) return -1; if (row >= lowest_available_row) { while (lowest_available_row <= row) { if (!cell[lowest_available_row]) cell[lowest_available_row] = new tcell[max_cols]; lowest_available_row++; } } if (col >= lowest_available_col) lowest_available_col = col+1; if (!cell[row]) cell[row] = new tcell[max_cols]; cell[row][col].setval(val); return 0; } int stable::set(const string& row, const string& col, const string& val) { int r; // Integer value of row if (!findrowlabel(row, r)) { // Not already in array. if (lowest_available_row == max_rows) return -1; // Otherwise, use r = lowest_available_row and // move lowest_available_row up r = lowest_available_row++; rlabel[r].setval(row); if (!cell[r]) cell[r] = new tcell[max_cols]; } int c; // Integer value of column if (findcollabel(col, c)) { cell[r][c].setval(val); return 0; } // Not already in array. if (lowest_available_col == max_cols) return -1; c = lowest_available_col++; clabel[c].setval(col); cell[r][c].setval(val); return 0; } int stable::setrowlabel(const int row, const string& val) { if ((row < 0)||(row >= max_rows)) return -1; if (row >= lowest_available_row) { while (lowest_available_row <= row) { if (!cell[lowest_available_row]) cell[lowest_available_row] = new tcell[max_cols]; lowest_available_row++; } } rlabel[row].setval(val); return 0; } int stable::setcollabel(const int col, const string& val) { if ((col < 0)||(col >= max_cols)) return -1; if (col >= lowest_available_col) lowest_available_col = col+1; clabel[col].setval(val); return 0; } // get functions int stable::get(const int row, const int col, string& val) { if ((row < 0)||(col < 0)||(row >= max_rows)||(col >= max_cols)){ val = ""; return -1; } if (!cell[row][col].used()) { // Works for row, col greater than lowest_available too val = ""; return 0; } val = cell[row][col].getval(); return 1; } int stable::get(const string& row, const string& col, string& val) { int r; // Integer value of row for (r = 0; r < lowest_available_row; r++) { if (rlabel[r].getval() == row) break; } if (r == lowest_available_row) { val = ""; return 0; } for (int c = 0; c < lowest_available_col; c++) { if (clabel[c].getval() == col) { val = cell[r][c].getval(); return 1; } } val = ""; return 0; } int stable::getrowlabel(const int row, string& val) { if ((row < 0)||(row >= max_rows)) { val = ""; return -1; } if (!rlabel[row].used()) { val = ""; return 0; } val = rlabel[row].getval(); return 1; } int stable::getcollabel(const int col, string& val) { if ((col < 0)||(col >= max_cols)) { val = ""; return -1; } if (!clabel[col].used()) { val = ""; return 0; } val = clabel[col].getval(); return 1; } // find functions // Note that the basic find uses findafter int stable::findafter(const string& val, int& row, int& col) { if ((row < 0)||(col < 0)||(row >= lowest_available_row)|| (col >= lowest_available_col)) return 0; for (int r = row; r < lowest_available_row; r++) { // First loop for start row starting at col+1 for (int c = col+1; c < lowest_available_col; c++) { if (cell[r][c].used()) { if (cell[r][c].getval() == val) { row = r; col = c; return 1; } } } // Remaining loops start at column 0 col = 0; } return 0; } int stable::findbefore(const string& val, int& row, int& col) { if ((row < 0)||(col < 0)||(row >= lowest_available_row)|| (col >= lowest_available_col)) return 0; for (int r = row; r >= 0; r--) { // First loop for start row starting at col-1 for (int c = col-1; c >= 0; c--) { if (cell[r][c].used()) { if (cell[r][c].getval() == val) { row = r; col = c; return 1; } } } // Remaining loops start at last column col = lowest_available_col-1; } return 0; } int stable::find(const string& val, int& row, int& col) { row = 0; col = 0; // Have to test (0,0) before using findafter(). if (cell[0][0].used() && (cell[0][0].getval() == val)) return 1; return findafter(val, row, col); } int stable::findrowlabel(const string& val, int& row) { for (int r = 0; r < lowest_available_row; r++) { if (rlabel[r].used()) { if (rlabel[r].getval() == val) { row = r; return 1; } } } return 0; } int stable::findcollabel(const string& val, int& col) { for (int c = 0; c < lowest_available_col; c++) { if (clabel[c].used()) { if (clabel[c].getval() == val) { col = c; return 1; } } } return 0; } // Read and write functions void stable::readwithoutlabels(istream& in, const char coldelim, const char rowdelim) { read(in, false, coldelim, rowdelim); } void stable::readwithoutlabels(const string& instring, const char coldelim, const char rowdelim) { istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); } void stable::readwithoutlabels(const char *p, const char coldelim, const char rowdelim) { string instring(p); istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); } void stable::readwithlabels(istream& in, const char coldelim, const char rowdelim) { read(in, true, coldelim, rowdelim); } void stable::readwithlabels(const string& instring, const char coldelim, const char rowdelim) { istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); } void stable::readwithlabels(const char *p, const char coldelim, const char rowdelim) { string instring(p); istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); } int stable::writewithlabels(ostream& out, const char coldelim, const char rowdelim, const bool includelastrowdelim) { return write(out, true, coldelim, rowdelim, includelastrowdelim); } int stable::writewithlabels(string& ostring, const char coldelim, const char rowdelim, const bool includelastrowdelim) { ostringstream os; int retval = writewithlabels(os, coldelim, rowdelim,includelastrowdelim); ostring = os.str(); return retval; } int stable::writewithoutlabels(ostream& out, const char coldelim, const char rowdelim, const bool includelastrowdelim) { return write(out, false, coldelim, rowdelim, includelastrowdelim); } int stable::writewithoutlabels(string& ostring, const char coldelim, const char rowdelim, const bool includelastrowdelim) { ostringstream os; int retval = writewithoutlabels(os, coldelim, rowdelim,includelastrowdelim); ostring = os.str(); return retval; } // print is a debug function really void stable::print() { cout << "\t"; // Top left corner: No label int i; for (i = 0; i < lowest_available_col; i++) cout << clabel[i].getval().substr(0,6) << "\t"; cout << endl; for (i = 0; i < lowest_available_row; i++) { cout << rlabel[i].getval().substr(0,6) << "\t"; for (int j = 0; j < lowest_available_col; j++) cout << cell[i][j].getval().substr(0,6) << "\t"; cout << endl; } }