00001 #ifndef mbl_table_h 00002 #define mbl_table_h 00003 //: 00004 // \file 00005 // \author Kevin de Souza 00006 // \date 05-Aug-2004 00007 // \brief Container for tabulated data suitable for reading/writing to delimited text files 00008 00009 #include <vcl_map.h> 00010 #include <vcl_iosfwd.h> 00011 #include <vcl_vector.h> 00012 #include <vcl_string.h> 00013 00014 //: Container for tabulated data suitable for reading/writing to delimited text files. 00015 // 00016 // Table comprises a number of columns of double-precision data. 00017 // Each column is headed by a text string (which may contain whitespace but not end-of-line). 00018 // Column headers must be unique. 00019 // Columns are separated by a delimiter character (e.g. "\t"). 00020 // The delimiter character must not occur in any of the entries! 00021 // The delimiter character is optional at the end of a row. 00022 // Each row must be terminated by an end-of-line (including the last row). 00023 // Each column of data is stored as a vector of doubles and associated with the column header string. 00024 class mbl_table 00025 { 00026 public: 00027 00028 //: Constructor 00029 // \param delim The delimiter character. 00030 mbl_table(const char delim='\t'); 00031 00032 00033 //: Constructor 00034 // \param delim The delimiter character. 00035 // \param headers The column headers (in order). 00036 mbl_table(const char delim, 00037 const vcl_vector<vcl_string>& headers); 00038 00039 00040 //: Return the number of columns 00041 unsigned num_cols() const; 00042 00043 00044 //: Return the number of rows 00045 unsigned num_rows() const; 00046 00047 00048 //: Get the column of data corresponding to a particular heading. 00049 // \param header String identifying the desired column. 00050 // \return true if there is a column with the specified heading. 00051 // \retval column A vector containing the values of the requested column. 00052 bool get_column(const vcl_string& header, 00053 vcl_vector<double>& column) const; 00054 00055 00056 //: Returns true if column exists 00057 bool column_exists(const vcl_string& header) const; 00058 00059 00060 //: Get a specified row of data. 00061 // \param r Index of the desired row. 00062 // \return true if there is a row with the specified index. 00063 // \retval row A vector containing the values of the requested row. 00064 bool get_row(const unsigned& r, 00065 vcl_vector<double>& row) const; 00066 00067 00068 //: Get the list of column headers (in column order). 00069 // \retval headers The list of column headers. 00070 void get_column_headers(vcl_vector<vcl_string>& headers) const; 00071 00072 00073 //: Append a column of data with its own heading. 00074 // \param header String identifying the column. 00075 // \param column A vector containing the values of the column. 00076 // \return true If the column was added. 00077 // \note The new column must be the same length as existing columns. 00078 bool append_column(const vcl_string& header, 00079 const vcl_vector<double>& column); 00080 00081 00082 //: Append an empty column with its own heading. 00083 // \param header String identifying the column. 00084 // \param val Default value to initialize all elements of the new column. 00085 // \return true If the column was added. 00086 // \note The new column will be the same length as existing columns. 00087 bool append_column(const vcl_string& header, 00088 const double val=0); 00089 00090 00091 //: Append a row of data. 00092 // \return true if the row was added. 00093 // \param row A vector containing the values of the new row. 00094 // \note The new row must be the same length as existing rows. 00095 bool append_row(const vcl_vector<double>& row); 00096 00097 00098 //: Append an empty row. 00099 // \return true If the row was added. 00100 // \param val Default value to initialize all elements of the new row. 00101 // \note The new row will be the same length as existing rows. 00102 bool append_row(const double val=0); 00103 00104 00105 //: Set the value of an existing element. 00106 // \param header The string identifying the column to be modified. 00107 // \param r The row index of the element to be modified. 00108 // \param value The new value to use for the modified element. 00109 // \return False if the column does not exist or the row index is not valid. 00110 // \note This function is intended only for existing elements. 00111 bool set_element(const vcl_string& header, 00112 const unsigned r, 00113 const double value); 00114 00115 00116 //: Get the value of an existing element. 00117 // \param header The string identifying the column of interest. 00118 // \param r The row index of the element of interest. 00119 // \return The value of the requested element (undefined if the element 00120 // does not exist). 00121 // \retval success If provided, will be used to indicate whether the 00122 // specified element existed. 00123 // \note This function is intended only for existing elements. 00124 // \note It is recommended that you provide and check the parameter success. 00125 double get_element(const vcl_string& header, 00126 const unsigned r, 00127 bool* success=0) const; 00128 00129 00130 //: Load this table's data from specified text stream. 00131 // Any existing data is lost. 00132 // \return true if table was read successfully from the stream. 00133 bool read(vcl_istream& is); 00134 00135 00136 //: Save this table's data to specified text stream. 00137 void write(vcl_ostream& os) const; 00138 00139 00140 //: Create a new table of subset of columns defined by headers 00141 // \retval new_table a subtable 00142 // \param headers subset of column headers 00143 // \return true if all columns in headers existed in "this" and were copied 00144 bool subtable(mbl_table &new_table, const vcl_vector<vcl_string> &headers) const; 00145 00146 00147 //: Is another table identical to this one? 00148 // \note The normal behaviour of this function is to return false as soon 00149 // as a discrepancy is found. However, if verbosity>=2 this function will 00150 // compare all corresponding elements (providing that the table dimensions match). 00151 bool operator==(const mbl_table& rhs) const; 00152 00153 00154 //: Is another table different from this one? 00155 // \sa operator==() 00156 bool operator!=(const mbl_table& rhs) const; 00157 00158 00159 //: Set the tolerance used to determine whether table entries are equal. 00160 // \param tol The tolerance should be a small positive number, eg 1e-19. 00161 // \param frac Whether the tolerance is applied as a fractional difference. 00162 static void set_tolerance(const double& tol, 00163 const bool& fract=false); 00164 00165 00166 //: Set the level of verbosity used for error output. 00167 // \param v The verbosity should be a small integer, eg -3 to 3. 00168 // Larger values cause more detailed output. 00169 // Default level is 0. 00170 // \note Currently only levels 1 and 2 are defined: level 1 provides some 00171 // feedback for equality testing; level 2 also causes the equality operator 00172 // to check all corresponding elements of a table. 00173 static void set_verbosity(const int& v); 00174 00175 00176 protected: 00177 00178 //: Read a series of characters from the stream until a delimiter character or eol. 00179 // \param is The input stream. 00180 // \return true if a non-empty string was successfully read. 00181 // \retval str The string which was read. 00182 // \retval eol Whether the stream is at end-of-line after reading the string. 00183 // \retval eof Whether the stream is at end-of-file after reading the string. 00184 bool read_delimited_string(vcl_istream& is, 00185 vcl_string& str, 00186 bool& eol, 00187 bool& eof); 00188 00189 //: The character delimiting each column. 00190 char delimiter_; 00191 00192 //: The column headers (in order) 00193 vcl_vector<vcl_string> column_headers_; 00194 00195 //: Map a column header string to column index 00196 vcl_map<vcl_string, unsigned> header_to_column_index_; 00197 00198 //: The table data, arranged as column vectors of double data. 00199 vcl_vector<vcl_vector<double> > columns_; 00200 00201 }; 00202 00203 #endif // mbl_table_h