// Source: "Software Design ...", John A Robinson, Newnes, 2004, Chapter 17. #include #include #include #include #include using namespace std; class tcell { // Structure of each cell in the table: basic unit of the collection bool cellused; int rowindex; int colindex; string content; public: tcell() { cellused = 0; 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; }; }; class stable { // The 2D table of tcells plus row and column labels 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 public: stable(const int r = 1024, const int c = 1024) { 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() { for (int i = 0; i < max_rows; i++) { if (cell[i]) delete [] cell[i]; } delete [] cell; delete [] clabel; delete [] rlabel; }; void 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; } int nrows() { return lowest_available_row; } int ncols() { return lowest_available_col; } int 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 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 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; }; void readwithoutlabels(istream& in, const char coldelim = '\t', const char rowdelim = '\n') { // Read from file. reset(); string line; int r = 0; while(!in.eof()) { getline(in,line,rowdelim); if ((line == "")&&in.eof()) // Nothing after final rowdelim break; int c = 0; string temp; string::size_type currpos, delimpos; currpos = 0; setrowlabel(r,""); while ((delimpos = line.find(coldelim, currpos)) != string::npos){ temp = line.substr(currpos,delimpos-currpos); set(r,c++,temp); currpos = delimpos+1; } temp = line.substr(currpos); set(r,c,temp); r++; } for (int c = 0; c < lowest_available_col; c++) clabel[c].setval(""); }; void readwithoutlabels(string& instring, const char coldelim = '\t', const char rowdelim = '\n') { istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); }; void readwithlabels(ifstream& in, const char coldelim = '\t', const char rowdelim = '\n') { // Read from file. reset(); string line; int r = -1; while(!in.eof()) { getline(in,line, rowdelim); if ((line == "")&&in.eof()) // Nothing after final rowdelim break; int c = -1; 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++; } }; void readwithlabels(string& instring, const char coldelim = '\t', const char rowdelim = '\n') { istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); }; // May later need versions of set that have int in one of row // and col and string in the other. But for now, just do both same. int set(const string& row, const string& col, const 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){ // Not already in array. (Note inefficiency: usually will // call set(...) when labels not yet used, but every time do // futile linear search through all all labels) if (lowest_available_row == max_rows) return -1; // Otherwise, using r = lowest_available_row and // move lowest_available_row up rlabel[lowest_available_row].setval(row); if (!cell[lowest_available_row]) cell[lowest_available_row] = new tcell[max_cols]; lowest_available_row++; } for (int c = 0; c < lowest_available_col; c++) { if (clabel[c].getval() == col) { cell[r][c].setval(val); return 0; } } // Not already in array. (Note inefficiency: as for rows) if (lowest_available_col == max_cols) return -1; clabel[lowest_available_col].setval(col); cell[r][lowest_available_col].setval(val); lowest_available_col++; return 0; }; int 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 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 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; } int 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 find(const string& val, int& row, int& col) { int r, c; for (r = 0; r < lowest_available_row; r++) for (c = 0; c < lowest_available_col; c++) { if (cell[r][c].used()) { if (cell[r][c].getval() == val) { row = r; col = c; return 1; } } } return 0; }; int 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 findcollabel(const string& val, int& col) { for (int c = 0; c < lowest_available_col; c++) { if (clabel[c].used()) { if (rlabel[c].getval() == val) { col = c; return 1; } } } return 0; }; int writewithlabels(ofstream& out, const char coldelim = '\t') { out << coldelim; // Top left corner: No label int i, j; for (i = 0; i < lowest_available_col-1; i++) out << clabel[i].getval() << coldelim; out << clabel[i].getval() << endl; for (i = 0; i < lowest_available_row; i++) { out << rlabel[i].getval() << coldelim; for (j = 0; j < lowest_available_col-1; j++) out << cell[i][j].getval() << coldelim; out << cell[i][j].getval() << endl; } }; int writewithoutlabels(ofstream& out, const char coldelim = '\t') { int i, j; for (i = 0; i < lowest_available_row; i++) { for (j = 0; j < lowest_available_col-1; j++) out << cell[i][j].getval() << coldelim; out << cell[i][j].getval() << endl; } }; void print() { cout << setw(8) << "\t"; // Top left corner: No label int i; for (i = 0; i < lowest_available_col; i++) cout << setw(8) << clabel[i].getval() << "\t"; cout << endl; for (i = 0; i < lowest_available_row; i++) { cout << setw(8) << rlabel[i].getval() << "\t"; for (int j = 0; j < lowest_available_col; j++) cout << setw(8) << cell[i][j].getval() << "\t"; cout << endl; } }; }; // Test program int main(int argc, char *argv[]) { if (argc < 3) { cerr << "Usage: stable files_containing_Infinity\n"; return -1; } stable intab; stable outtab; stable parsetable; for (int a = 1; a < argc; a++) { string fname(argv[a]); parsetable.readwithoutlabels(fname, '.', '/'); ifstream i(argv[a]); if (i == 0) { cerr << "can't open " << argv[a] << endl; return -1; } intab.readwithoutlabels(i, ' '); i.close(); int row, col; if (intab.find("Infinity",row, col)) { string value; intab.get(row,col-1,value); string suffix; intab.get(row-1,0,suffix); string prefix; parsetable.get(parsetable.nrows()-1,0,prefix); outtab.set(prefix,suffix,value); } } outtab.print(); ofstream o("losslesstable"); outtab.writewithlabels(o); o.close(); }