Object-oriented Scientific Computing Library: Version 0.910
columnify.h
Go to the documentation of this file.
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.