// 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 = 2048, const int c = 256) { 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; }; template int set(const int row, const int col, const T& val) { ostringstream os; os << val; return set(row, col,os.str()); } 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; }; template int set(const string& row, const string& col, const T& val) { ostringstream os; os << val; return set(row, col,os.str()); } 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(const string& instring, const char coldelim = '\t', const char rowdelim = '\n') { istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); }; void readwithoutlabels(const char *p, const char coldelim = '\t', const char rowdelim = '\n') { string instring(p); 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(const string& instring, const char coldelim = '\t', const char rowdelim = '\n') { istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); }; void readwithlabels(const char *p, const char coldelim = '\t', const char rowdelim = '\n') { string instring(p); istringstream is(instring); readwithoutlabels(is, coldelim, rowdelim); }; 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; }; 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; } 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; }; 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; } 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 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 (clabel[c].getval() == val) { col = c; return 1; } } } return 0; }; int writewithlabels(ostream& out, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1) { 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() << rowdelim; for (i = 0; i < lowest_available_row; i++) { 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; } }; int writewithlabels(string& ostring, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1) { ostringstream os; int retval = writewithlabels(os, coldelim, rowdelim,includelastrowdelim); ostring = os.str(); return retval; } int writewithoutlabels(ostream& out, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1) { int i, j; for (i = 0; i < lowest_available_row; i++) { // 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; } }; int writewithoutlabels(string& ostring, const char coldelim = '\t', const char rowdelim = '\n', const bool includelastrowdelim = 1) { ostringstream os; int retval = writewithoutlabels(os, coldelim, rowdelim,includelastrowdelim); ostring = os.str(); return retval; } void 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; } }; }; // Test program int main(int argc, char *argv[]) { if (argc < 2) { cerr << "Usage: stable files_containing_Infinity\n"; return -1; } stable intab; stable outtab; stable parsetab; for (int a = 1; a < argc; a++) { string prefix; parsetab.readwithoutlabels(argv[a], '.', '/'); parsetab.get(parsetab.nrows()-1,0,prefix); // Get string between last '/' and first following '.' 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); outtab.set(prefix,suffix,value); } } int endcol = outtab.ncols(); int jlscol, jlsSIcol; outtab.findcollabel("\"jpeg-ls",jlscol); outtab.findcollabel("\"jpeg-lsSI",jlsSIcol); double jlsval, jlsSIval; for (int r = 0; r < outtab.nrows(); r++) { outtab.get(r,jlscol,jlsval); outtab.get(r,jlsSIcol,jlsSIval); if (jlsval < jlsSIval) outtab.set(r,endcol,jlsval); else outtab.set(r,endcol,jlsSIval); } outtab.setcollabel(endcol,"LSbest"); outtab.print(); ofstream o("losslesstable"); outtab.writewithlabels(o); o.close(); cout << "Reparse of last file:\n"; string lastfile; parsetab.writewithoutlabels(lastfile,'.','/',0); cout << lastfile << endl; }