![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2006-2012, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 #ifndef O2SCL_COLUMNIFY_H 00024 #define O2SCL_COLUMNIFY_H 00025 00026 /** \file columnify.h 00027 \brief Functions to create output in columns 00028 */ 00029 00030 #include <iostream> 00031 #include <string> 00032 #include <vector> 00033 #include <o2scl/misc.h> 00034 #include <o2scl/array.h> 00035 00036 #ifndef DOXYGENP 00037 namespace o2scl { 00038 #endif 00039 00040 /** \brief Create nicely formatted columns from a table of strings 00041 00042 This is a brute-force approach of order \f$ \mathrm{ncols} 00043 \times \mathrm{nrows} \f$. The column widths and spacings of are 00044 computed by exhaustively examining all strings in every column. 00045 00046 \future Move the screenify() functionality from misc.h into 00047 this class? 00048 \future It might be better to allow the string table 00049 to be specified with iterators. 00050 */ 00051 class columnify { 00052 00053 public: 00054 00055 columnify() { 00056 } 00057 00058 /// Align the left-hand sides 00059 static const int align_left=1; 00060 /// Align the right-hand sides 00061 static const int align_right=2; 00062 /// Center, slightly to the left if spacing is uneven 00063 static const int align_lmid=3; 00064 /// Center, slightly to the right if spacing is uneven 00065 static const int align_rmid=4; 00066 /// Align with decimal points 00067 static const int align_dp=5; 00068 /** \brief Align negative numbers to the left and use a space for 00069 positive numbers 00070 */ 00071 static const int align_lnum=6; 00072 00073 /** \brief Take \c table and create a new object \c ctable with 00074 appropriately formatted columns 00075 00076 The table of strings should be stored in \c table in 00077 "column-major" order (<tt>table[ncols][nrows]</tt>), so that 00078 \c table has the interpretation of a set of columns to be 00079 aligned. Before calling align(), \c ctable should be allocated 00080 so that at least the first \c nrows entries can be assigned, 00081 and \c align_spec should contain \c ncols entries specifying 00082 the style of alignment for each column. 00083 00084 The first argument can be any type which is accessible 00085 using two applications of <tt>operator[]</tt>, such 00086 as <tt>string **</tt>, <tt>vector<string>[]</tt>, or 00087 <tt>vector<vector<string> > </tt> 00088 */ 00089 template<class mat_string_t, class vec_string_t, class vec_int_t> 00090 int align(const mat_string_t &table, size_t ncols, size_t nrows, 00091 vec_string_t &ctable, vec_int_t &align_spec) { 00092 00093 // Make space for the size information 00094 size_t *csizes=new size_t[ncols], *csizes2=new size_t[ncols]; 00095 for(size_t i=0;i<ncols;i++) { 00096 csizes[i]=0; 00097 csizes2[i]=0; 00098 } 00099 00100 // Compute the sizes of all the entries in all of the columns so 00101 // we know how many spaces to add 00102 for(size_t i=0;i<ncols;i++) { 00103 for(size_t j=0;j<nrows;j++) { 00104 00105 // If we're aligning with decimal points, we need to compute 00106 // the maximum width to the left and the right of the 00107 // decimal point separately 00108 00109 if (align_spec[i]==align_dp) { 00110 size_t loc=table[i][j].find('.'); 00111 std::string left, right; 00112 if (loc!=std::string::npos) { 00113 left=table[i][j].substr(0,loc+1); 00114 right=table[i][j].substr(loc+1, 00115 table[i][j].length()-loc-1); 00116 } else { 00117 left=table[i][j]+' '; 00118 right=""; 00119 } 00120 if (left.length()>csizes[i]) csizes[i]=left.length(); 00121 if (right.length()>csizes2[i]) csizes2[i]=right.length(); 00122 00123 } else { 00124 00125 // Otherwise just find the maximum width of each column 00126 if (table[i][j].length()>csizes[i]) csizes[i]=table[i][j].length(); 00127 00128 } 00129 00130 } 00131 } 00132 00133 // Go through row by row, adding enough spaces to make one string 00134 // per row 00135 for(size_t j=0;j<nrows;j++) { 00136 00137 std::string tmp=""; 00138 00139 for(size_t i=0;i<ncols;i++) { 00140 00141 // Handle each alignment case separately 00142 if (align_spec[i]==align_right) { 00143 00144 for(size_t k=table[i][j].length();k<csizes[i];k++) { 00145 tmp+=' '; 00146 } 00147 tmp+=table[i][j]; 00148 if (i!=ncols-1) tmp+=' '; 00149 00150 } else if (align_spec[i]==align_left) { 00151 00152 tmp+=table[i][j]; 00153 for(size_t k=table[i][j].length();k<csizes[i];k++) { 00154 tmp+=' '; 00155 } 00156 if (i!=ncols-1) tmp+=' '; 00157 00158 } else if (align_spec[i]==align_lmid) { 00159 00160 size_t le=(csizes[i]-table[i][j].length())/2; 00161 size_t ri=csizes[i]-table[i][j].length()-le; 00162 for(size_t k=0;k<le;k++) tmp+=' '; 00163 tmp+=table[i][j]; 00164 for(size_t k=0;k<ri;k++) tmp+=' '; 00165 if (i!=ncols-1) tmp+=' '; 00166 00167 } else if (align_spec[i]==align_rmid) { 00168 00169 size_t ri=(csizes[i]-table[i][j].length())/2; 00170 size_t le=csizes[i]-table[i][j].length()-ri; 00171 for(size_t k=0;k<le;k++) tmp+=' '; 00172 tmp+=table[i][j]; 00173 for(size_t k=0;k<ri;k++) tmp+=' '; 00174 if (i!=ncols-1) tmp+=' '; 00175 00176 } else if (align_spec[i]==align_dp) { 00177 00178 size_t loc=table[i][j].find('.'); 00179 std::string left, right; 00180 if (loc!=std::string::npos) { 00181 left=table[i][j].substr(0,loc+1); 00182 right=table[i][j].substr(loc+1, 00183 table[i][j].length()-loc-1); 00184 } else { 00185 left=table[i][j]+' '; 00186 right=""; 00187 } 00188 00189 for(size_t k=left.length();k<csizes[i];k++) tmp+=' '; 00190 tmp+=left; 00191 tmp+=right; 00192 for(size_t k=right.length();k<csizes2[i];k++) tmp+=' '; 00193 if (i!=ncols-1) tmp+=' '; 00194 00195 } else if (align_spec[i]==align_lnum) { 00196 00197 if (table[i][j].length()==csizes[i]) { 00198 tmp+=table[i][j]; 00199 } else { 00200 if (table[i][j][0]>='0' && table[i][j][0]<='9') { 00201 tmp+=' '; 00202 tmp+=table[i][j]; 00203 for(size_t k=table[i][j].length();k<csizes[i]-1;k++) { 00204 tmp+=' '; 00205 } 00206 } else { 00207 tmp+=table[i][j]; 00208 for(size_t k=table[i][j].length();k<csizes[i];k++) { 00209 tmp+=' '; 00210 } 00211 } 00212 } 00213 if (i!=ncols-1) tmp+=' '; 00214 } 00215 00216 // Proceed to the next column 00217 } 00218 00219 // Add the row to the user-specified array and go to the next row 00220 ctable[j]=tmp; 00221 00222 } 00223 00224 // Free the memory assocated with the column widths 00225 delete[] csizes; 00226 delete[] csizes2; 00227 00228 return 0; 00229 } 00230 00231 }; 00232 00233 /** \brief A operator for simple matrix output using \c operator() 00234 00235 The type \c mat_t can be any matrix type which allows 00236 individual element access using \c operator()(size_t,size_t). 00237 00238 This outputs all of the matrix elements using output settings 00239 specified by \c os. The alignment performed by \ref columnify 00240 using columnify::align_dp, i.e. the numbers are aligned by 00241 their decimal points. If the numbers have no decimal points, 00242 then the decimal point is assumed to be to the right of the 00243 last character in the string represetation of the number. 00244 */ 00245 template<class mat_t> int matrix_out_paren(std::ostream &os, mat_t &A, 00246 size_t nrows, size_t ncols) { 00247 00248 columnify co; 00249 std::string **stab; 00250 pointer_2d_alloc<std::string> pa; 00251 pa.allocate(stab,ncols,nrows); 00252 //stab=o2scl::new_2d_array<std::string>(ncols,nrows); 00253 std::vector<std::string> ctable(nrows); 00254 std::vector<int> alig(ncols); 00255 00256 for(size_t j=0;j<ncols;j++) { 00257 alig[j]=columnify::align_dp; 00258 for(size_t i=0;i<nrows;i++) { 00259 stab[j][i]=dtos(A(i,j),os); 00260 } 00261 } 00262 co.align(stab,ncols,nrows,ctable,alig); 00263 for(size_t i=0;i<nrows;i++) { 00264 os << ctable[i] << std::endl; 00265 } 00266 00267 //o2scl::delete_2d_array(stab,ncols); 00268 pa.free(stab,ncols); 00269 00270 return 0; 00271 } 00272 00273 /** \brief A operator for simple complex matrix output using \c operator() 00274 00275 \todo Doesn't this only work for GSL matrices? Compare this to the 00276 corresponding vector functions 00277 */ 00278 template<class mat_t> int matrix_cx_out_paren(std::ostream &os, mat_t &A, 00279 size_t nrows, size_t ncols) { 00280 00281 columnify co; 00282 std::string **stab; 00283 pointer_2d_alloc<std::string> pa; 00284 pa.allocate(stab,ncols,nrows); 00285 // stab=o2scl::new_2d_array<std::string>(ncols,nrows); 00286 std::vector<std::string> ctable(nrows); 00287 std::vector<int> alig(ncols); 00288 00289 for(size_t j=0;j<ncols;j++) { 00290 alig[j]=columnify::align_left; 00291 for(size_t i=0;i<nrows;i++) { 00292 stab[j][i]=((std::string)"(")+dtos(A(i,j).dat[0],os)+ 00293 ((std::string)",")+dtos(A(i,j).dat[1],os)+((std::string)")"); 00294 } 00295 } 00296 co.align(stab,ncols,nrows,ctable,alig); 00297 for(size_t i=0;i<nrows;i++) { 00298 os << ctable[i] << std::endl; 00299 } 00300 00301 //o2scl::delete_2d_array(stab,ncols); 00302 pa.free(stab,ncols); 00303 00304 return 0; 00305 } 00306 00307 /** \brief A operator for simple matrix output using \c operator[] 00308 00309 The type \c mat_t can be any 2d-array type which allows 00310 individual element access using \c [size_t][size_t] 00311 00312 This outputs all of the matrix elements using output settings 00313 specified by \c os. The alignment performed by \ref columnify 00314 using columnify::align_dp, i.e. the numbers are aligned by 00315 their decimal points. If the numbers have no decimal points, 00316 then the decimal point is assumed to be to the right of the 00317 last character in the string represetation of the number. 00318 00319 \future If all of the matrix elements are positive integers 00320 and scientific mode is not set, then we can avoid printing 00321 the extra spaces. 00322 */ 00323 template<class mat_t> int matrix_out(std::ostream &os, mat_t &A, 00324 size_t nrows, size_t ncols) { 00325 00326 columnify co; 00327 std::string **stab; 00328 pointer_2d_alloc<std::string> pa; 00329 pa.allocate(stab,ncols,nrows); 00330 // stab=o2scl::new_2d_array<std::string>(ncols,nrows); 00331 std::vector<std::string> ctable(nrows); 00332 std::vector<int> alig(ncols); 00333 00334 for(size_t j=0;j<ncols;j++) { 00335 alig[j]=columnify::align_dp; 00336 for(size_t i=0;i<nrows;i++) { 00337 stab[j][i]=dtos(A[i][j],os); 00338 } 00339 } 00340 co.align(stab,ncols,nrows,ctable,alig); 00341 for(size_t i=0;i<nrows;i++) { 00342 os << ctable[i] << std::endl; 00343 } 00344 00345 pa.free(stab,ncols); 00346 //o2scl::delete_2d_array(stab,ncols); 00347 00348 return 0; 00349 } 00350 00351 #ifndef DOXYGENP 00352 } 00353 #endif 00354 00355 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).