Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/tools/rcsv_ntuple is written in an unsupported language. File is not indexed.

0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003 
0004 #ifndef tools_rcsv_ntuple
0005 #define tools_rcsv_ntuple
0006 
0007 // A simple ntuple class to read at the csv format.
0008 // (csv = comma separated value).
0009 
0010 // This reader can be use to read file at the hippodraw format
0011 // which is :
0012 // - one header line for the ntuple title.
0013 // - one csv line for column names.
0014 // - data at csv format.
0015 
0016 #include "rntuple"
0017 
0018 #include <istream>
0019 #include <sstream>
0020 
0021 #include "vfind"
0022 #include "vmanip"
0023 #include "words"
0024 #include "snums"
0025 #include "sto"
0026 #include "s2time"
0027 #include "chars"
0028 #include "strip"
0029 #include "cids"
0030 #include "ntuple_binding"
0031 #include "sout"
0032 #include "num2s"
0033 //#include "srep"
0034 
0035 #ifdef TOOLS_MEM
0036 #include "mem"
0037 #endif
0038 
0039 namespace tools {
0040 namespace rcsv {
0041 
0042 class ntuple : public virtual read::intuple {
0043   typedef read::intuple parent;
0044 public: //read::intuple
0045   virtual void start() {
0046     m_reader.clear();
0047     m_reader.seekg(0,std::ios::beg);
0048     if(m_hippo) {
0049       skip_line(m_reader,m_sz);
0050       skip_line(m_reader,m_sz);
0051     }
0052   }
0053   virtual bool next() {
0054     if(!m_sep) return false; //not inited.
0055     if(m_reader.tellg()>=m_sz) return false;
0056     // first time we are at bol but else we are at eol.
0057     char c;
0058     m_reader.get(c);
0059     if(c==LF()){
0060       if(m_reader.tellg()>=m_sz) {
0061         //eof. Tell caller to stop looping on ntuple rows.
0062         return false;
0063       }
0064       //eol. Next char read is going to be at bol.
0065     } else {
0066       m_reader.putback(c);
0067       //bol
0068     }
0069     // ready for a new row :
0070 
0071     while(skip_comment(m_reader,m_sz)){}
0072     if(m_reader.tellg()>=m_sz) return false;
0073 
0074     return _read_line();
0075   }
0076 
0077   virtual read::icol* find_icol(const std::string& a_name){
0078     return find_named<read::icol>(m_cols,a_name);
0079   }
0080 
0081   virtual const std::vector<read::icol*>& columns() const {return m_cols;}
0082 
0083   virtual const std::string& title() const {return m_title;}
0084 
0085   virtual bool number_of_entries(tools::uint64 & a_value) const {
0086     if(!m_sep) {a_value = 0;return false;} //not inited.
0087     ntuple& self = const_cast<ntuple&>(*this);
0088     if(m_rows==(-1)) {
0089       self.m_rows = 0;
0090       self.start();
0091       while(self.next()) {self.m_rows++;}
0092     }
0093     a_value = (uint64)m_rows;
0094     return true;
0095   }
0096 public:
0097   template <class T>
0098   class column : public virtual read::icolumn<T> {
0099     typedef read::icolumn<T> parent;
0100   public:
0101     static cid id_class() {
0102       static const T s_v = T(); //do that for T = std::string.
0103       return 200+_cid(s_v);
0104     }
0105   public: //icol
0106     virtual void* cast(cid a_class) const {
0107       if(void* p = cmp_cast<column>(this,a_class)) {return p;}
0108       return parent::cast(a_class);
0109     }
0110     virtual cid id_cls() const {return id_class();}
0111   public: //icol
0112     virtual const std::string& name() const {return m_name;}
0113     virtual bool fetch_entry() const {
0114       if(m_user_var) *m_user_var = m_tmp;
0115       return true;
0116     }
0117   public: //icolumn<T>
0118     virtual bool get_entry(T& a_v) const {
0119       a_v = m_tmp;
0120       return true;
0121     }
0122   public:
0123     column(const std::string& a_name,T* a_user_var = 0)
0124     :m_name(a_name)
0125     ,m_tmp(T())
0126     ,m_user_var(a_user_var) //not owner
0127     {}
0128     virtual ~column(){}
0129   protected:
0130     column(const column& a_from)
0131     :read::icol(a_from)
0132     ,parent(a_from)
0133     ,m_name(a_from.m_name)
0134     ,m_tmp(a_from.m_tmp)
0135     ,m_user_var(a_from.m_user_var)
0136     {}
0137     column& operator=(const column& a_from){
0138       m_name = a_from.m_name;
0139       m_tmp = a_from.m_tmp;
0140       m_user_var = a_from.m_user_var;
0141       return *this;
0142     }
0143   public:
0144     // should be used in ntuple _read_line only :
0145     void set_value(const T& a_v){m_tmp = a_v;}
0146   protected:
0147     std::string m_name;
0148     T m_tmp;
0149     T* m_user_var;
0150   };
0151 
0152 #ifdef TOOLS_MEM
0153 public:
0154   static const std::string& s_class() {
0155     static const std::string s_v("tools::rcsv::ntuple");
0156     return s_v;
0157   }
0158 #endif
0159 public:
0160   ntuple(std::istream& a_reader)
0161   :m_reader(a_reader)
0162   ,m_title()
0163   ,m_sep(0)
0164   ,m_vec_sep(';')
0165   ,m_sz(0)
0166   ,m_rows(-1)
0167   ,m_hippo(false)
0168   {
0169 #ifdef TOOLS_MEM
0170     mem::increment(s_class().c_str());
0171 #endif
0172   }
0173   virtual ~ntuple() {
0174     safe_clear<read::icol>(m_cols);
0175 #ifdef TOOLS_MEM
0176     mem::decrement(s_class().c_str());
0177 #endif
0178   }
0179 protected:
0180   ntuple(const ntuple& a_from)
0181   :parent(a_from)
0182   ,m_reader(a_from.m_reader)
0183   ,m_title(a_from.m_title)
0184   ,m_sep(a_from.m_sep)
0185   ,m_vec_sep(a_from.m_vec_sep)
0186   ,m_sz(a_from.m_sz)
0187   ,m_rows(-1)
0188   ,m_hippo(a_from.m_hippo)
0189   {
0190 #ifdef TOOLS_MEM
0191     mem::increment(s_class().c_str());
0192 #endif
0193   }
0194   ntuple& operator=(const ntuple& a_from){
0195     m_title = a_from.m_title;
0196     m_sep = a_from.m_sep;
0197     m_vec_sep = a_from.m_vec_sep;
0198     m_hippo = a_from.m_hippo;
0199     m_rows = a_from.m_rows;
0200     return *this;
0201   }
0202 public:
0203   void set_vec_sep(char a_c) {m_vec_sep = a_c;}
0204   void set_sep(char a_c) {m_sep = a_c;}
0205   void set_hippo(bool a_hippo) {m_hippo = a_hippo;}
0206 
0207   std::istream& istrm() {return m_reader;}
0208 
0209 /* use file::is_hippo for that.
0210   static bool is_hippo(std::ostream& a_out,std::istream& a_reader) {
0211     // analyse two first data line.
0212 
0213     a_reader.clear();
0214     a_reader.seekg(0,std::ios::end);
0215     std::streampos sz = a_reader.tellg();
0216     a_reader.seekg(0,std::ios::beg);
0217     if(!sz) {
0218       a_out << "tools::rcsv::ntuple::is_hippo :"
0219             << " stream is empty."
0220             << std::endl;
0221       return false;
0222     } //file empty.
0223 
0224     std::string _title;
0225     if(!read_line(a_reader,sz,_title)) return false;
0226     std::string _s;
0227     if(!read_line(a_reader,sz,_s)) return false;
0228     if(_s.find('\t')==std::string::npos) return false;
0229 
0230     //std::vector<std::string> labels;
0231     //words(s,"\t",false,labels);
0232     //return labels.size()?true:false;
0233 
0234     return true;
0235   }
0236 */
0237   static bool find_sep(std::ostream& a_out,
0238                        std::istream& a_reader,bool a_hippo,
0239                        bool a_verbose,
0240                        char& a_sep){
0241     // analyse first data line to find the char separator.
0242 
0243     a_reader.clear();
0244     a_reader.seekg(0,std::ios::end);
0245     std::streampos sz = a_reader.tellg();
0246     a_reader.seekg(0,std::ios::beg);
0247     if(!sz) {
0248       a_out << "tools::rcsv::ntuple::find_sep :"
0249             << " stream is empty."
0250             << std::endl;
0251       a_sep = 0;
0252       return false;
0253     } //file empty.
0254     if(a_verbose) a_out << "file size " << sz << std::endl;
0255 
0256     if(a_hippo) { //skip first two lines :
0257       if(!skip_line(a_reader,sz)) {a_sep = 0;return false;}
0258       if(!skip_line(a_reader,sz)) {a_sep = 0;return false;}
0259     } else {
0260       while(skip_comment(a_reader,sz)){}
0261     }
0262     if(a_reader.tellg()>=sz) {a_sep=0;return false;} //no data line.
0263 
0264     // get first data line :
0265     std::string sfirst;
0266    {char c;
0267     while(true) {
0268       if(a_reader.tellg()>=sz) break;
0269       a_reader.get(c);
0270       if((c==CR())||(c==LF())) break;
0271       sfirst += c;
0272     }}
0273     if(sfirst.empty()) {
0274       a_out << "tools::rcsv::ntuple::find_set :"
0275             << " first datat line is empty."
0276             << std::endl;
0277       a_sep = 0;
0278       return false;
0279     }
0280     if(a_verbose) a_out << "first data line \"" << sfirst << "\"" << std::endl;
0281 
0282     //guess sep from first data line :
0283     std::istringstream strm(sfirst.c_str());
0284     double d;
0285     strm >> d;
0286     std::streampos pos = strm.tellg();
0287     if(pos==std::streampos(-1)) {
0288       a_out << "tools::rcsv::ntuple::find_sep :"
0289             << " first line does not start with a number."
0290             << std::endl;
0291       a_sep = 0;
0292       return false;
0293     } //not a number.
0294     if(a_verbose) a_out << "first number " << d
0295                         << " ending at pos " << pos << std::endl;
0296     if(pos>=(std::streampos)sfirst.size()) {
0297       a_out << "tools::rcsv::ntuple::find_sep :"
0298             << " no separator found in first line."
0299             << " pos " << pos
0300             << " sfirst.size() " << sfirst.size()
0301             << std::endl;
0302       a_sep = 0;
0303       return false;
0304     } //no sep.
0305 
0306     strm.get(a_sep);
0307 
0308     return true;
0309   }
0310 
0311 public:
0312   bool initialize(std::ostream& a_out,
0313                   char a_sep = 0, //guessed
0314                   const std::string& a_suffix = "x", //col suffix
0315                   bool a_verbose = false) {
0316     safe_clear<read::icol>(m_cols);
0317     m_sep = 0;
0318     m_sz = 0;
0319     m_rows = -1;
0320 
0321     if(a_suffix.empty()) {
0322       a_out << "tools::rcsv::ntuple::initialize : expect a column suffix." << std::endl;
0323       return false;
0324     }
0325 
0326     m_reader.clear();
0327     m_reader.seekg(0,std::ios::end);
0328     m_sz = m_reader.tellg();
0329     m_reader.seekg(0,std::ios::beg);
0330     if(!m_sz) {
0331       a_out << "tools::rcsv::ntuple::initialize :"
0332             << " stream is empty."
0333             << std::endl;
0334       return false; //file empty.
0335     }
0336     if(a_verbose) a_out << "file size " << m_sz << std::endl;
0337 
0338     std::vector<std::string> labels;
0339     if(m_hippo) { //skip first two lines :
0340       std::string _title;
0341       if(!read_line(m_reader,m_sz,_title)) {
0342         a_out << "tools::rcsv::ntuple::initialize : read_line() failed." << std::endl;
0343         m_sz = 0;
0344         m_rows = -1;
0345         return false;
0346       }
0347       std::string _s;
0348       if(!read_line(m_reader,m_sz,_s)) {
0349         a_out << "tools::rcsv::ntuple::initialize : (2) read_line() failed." << std::endl;
0350         m_sz = 0;
0351         m_rows = -1;
0352         return false;
0353       }
0354       words(_s,"\t",false,labels); //false for glast.tnt that has a trailing \t.
0355     } else {
0356       while(skip_comment(m_reader,m_sz)){}
0357     }
0358     if(m_reader.tellg()>=m_sz) {
0359       a_out << "tools::rcsv::ntuple::initialize : tellg() >= sz." << std::endl;
0360       m_sz = 0;
0361       m_rows = -1;
0362       return false;
0363     }
0364 
0365     // get first data line :
0366     std::string sfirst;
0367   {{char c;
0368     while(true) {
0369       if(m_reader.tellg()>=m_sz) break;
0370       m_reader.get(c);
0371       if((c==CR())||(c==LF())) break;
0372       sfirst += c;
0373     }}
0374     if(sfirst.empty()) {
0375       a_out << "tools::rcsv::ntuple::initialize :"
0376             << " first datat line is empty."
0377             << std::endl;
0378       m_sz = 0;
0379       m_rows = -1;
0380       return false;
0381     }}
0382     if(a_verbose) a_out << "first data line \"" << sfirst << "\"" << std::endl;
0383 
0384     if(a_sep) {
0385       m_sep = a_sep;
0386     } else {
0387       //guess sep from first data line :
0388       std::istringstream strm(sfirst.c_str());
0389       double d;
0390       strm >> d;
0391       std::streampos pos = strm.tellg();
0392       if(pos==std::streampos(-1)) {
0393         a_out << "tools::rcsv::ntuple::initialize :"
0394               << " first line does not start with a number."
0395               << std::endl;
0396         m_sz = 0;
0397         m_rows = -1;
0398         return false;
0399       }
0400       if(a_verbose) a_out << "first number " << d << " ending at pos " << pos << std::endl;
0401       if(pos>=(std::streampos)sfirst.size()) {
0402         a_out << "tools::rcsv::ntuple::initialize :"
0403               << " no separator found in first line."
0404               << std::endl;
0405         m_sz = 0;
0406         m_rows = -1;
0407         return false;
0408       }
0409       strm.get(m_sep);
0410     }
0411     if(a_verbose) a_out << "sep " << (int)m_sep << std::endl;
0412 
0413     // in case sep is ' ', there is an ambiguity with some leading
0414     // space in front of first number.
0415     if(m_sep==' ') strip(sfirst,leading,' ');
0416 
0417     std::vector<std::string> ws;
0418    {std::string sep;
0419     sep += m_sep;
0420     words(sfirst,sep,m_hippo?false:true,ws);}
0421 
0422     // look if words are numbers :
0423     if(a_verbose) a_out << "words " << ws.size() << std::endl;
0424     unsigned int index = 0;
0425     std::vector<std::string>::iterator it;
0426     for(it=ws.begin();it!=ws.end();++it,index++) {
0427       if(a_verbose) a_out << "word " << sout(*it) << "" << std::endl;
0428 /* with glast.tnt there is trailing \t that will induce an extra empty column.
0429       if((*it).empty()) {
0430         // do not accept :
0431         //   <num><sep><num><sep><sep><num>...
0432         // but accept a trailing <sep> (glast.tnt) :
0433         //   <num><sep><num>....<sep><num><sep>
0434         if(index==(ws.size()-1)) {
0435           break;
0436         } else {
0437           a_out << "tools::rcsv::ntuple::initialize :"
0438                 << " empty word."
0439                 << std::endl;
0440           safe_clear<read::icol>(m_cols);
0441           m_sep = 0;
0442           m_sz = 0;
0443           m_rows = -1;
0444           return false;
0445         }
0446       }
0447 */
0448       std::string name = a_suffix;
0449       if(!numas<uint64>(m_cols.size(),name)){}
0450       if(m_hippo) {
0451         if(index>=labels.size()) {
0452           a_out << "tools::rcsv::ntuple::initialize :"
0453                 << " warning : not enough labels."
0454                 << std::endl;
0455         } else {
0456           name = labels[index];
0457         }
0458       }
0459       double d;
0460       if(to<double>(*it,d)) {
0461         if(a_verbose) a_out << "number " << d << std::endl;
0462         create_column<double>(name);
0463       } else {
0464         time_t time;
0465         if(s2time(*it,time)) {
0466           create_column<csv_time>(name);
0467         } else {
0468           std::vector<double> v;
0469           std::string vec_sep;vec_sep += m_vec_sep;
0470           if(snums<double>(*it,vec_sep,v)&&v.size()) {
0471             create_column< std::vector<double> >(name);
0472           } else {
0473             create_column<std::string>(name);
0474           }
0475         }
0476       }
0477     }
0478     size_t num = m_cols.size();
0479     if(!num) {
0480       a_out << "tools::rcsv::ntuple::initialize :"
0481             << " zero columns."
0482             << std::endl;
0483       m_sep = 0;
0484       m_sz = 0;
0485       m_rows = -1;
0486       return false;
0487     }
0488 
0489     return true;
0490   }
0491 
0492   static const std::string& s_cid(cid a_id) {
0493 
0494 #define TOOLS_RCSV_NTUPLE_IF_CID(a__name,a__type) \
0495     if(a_id==column<a__type>::id_class()) {\
0496       static const std::string s_v(#a__name);\
0497       return s_v;\
0498     }
0499 
0500 #define TOOLS_RCSV_NTUPLE_IF_VEC_CID(a__name,a__type) \
0501     if(a_id==column< std::vector<a__type> >::id_class()) {\
0502       static const std::string s_v(#a__name+std::string("[]"));\
0503       return s_v;\
0504     }
0505 
0506          TOOLS_RCSV_NTUPLE_IF_CID(char,char)
0507     else TOOLS_RCSV_NTUPLE_IF_CID(short,short)
0508     else TOOLS_RCSV_NTUPLE_IF_CID(int,int)
0509     else TOOLS_RCSV_NTUPLE_IF_CID(int64,int64)
0510 
0511     else TOOLS_RCSV_NTUPLE_IF_CID(float,float)
0512     else TOOLS_RCSV_NTUPLE_IF_CID(double,double)
0513 
0514     else TOOLS_RCSV_NTUPLE_IF_CID(uchar,uchar)
0515     else TOOLS_RCSV_NTUPLE_IF_CID(ushort,ushort)
0516     else TOOLS_RCSV_NTUPLE_IF_CID(uint,uint32)   //WARNING
0517     else TOOLS_RCSV_NTUPLE_IF_CID(uint64,uint64)
0518 
0519     else TOOLS_RCSV_NTUPLE_IF_CID(bool,bool)
0520     else if(a_id==column<std::string>::id_class()) {
0521       static const std::string s_v("string");
0522       return s_v;
0523     }
0524 
0525     else if(a_id==column<csv_time>::id_class()) {
0526       static const std::string s_v("time");
0527       return s_v;
0528     }
0529 
0530     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(char,char)
0531     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(short,short)
0532     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(int,int)
0533     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(int64,int64)
0534 
0535     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(float,float)
0536     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(double,double)
0537 
0538     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(uchar,uchar)
0539     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(ushort,ushort)
0540     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(uint,uint32)   //WARNING
0541     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(uint64,uint64)
0542 
0543     else TOOLS_RCSV_NTUPLE_IF_VEC_CID(bool,bool)
0544     else if(a_id==column< std::vector<std::string> >::id_class()) {
0545       static const std::string s_v("string[]");
0546       return s_v;
0547     }
0548 
0549 #undef TOOLS_RCSV_NTUPLE_IF_CID
0550 #undef TOOLS_RCSV_NTUPLE_IF_VEC_CID
0551 
0552     else {
0553       static const std::string s_v("unknown");
0554       return s_v;
0555     }
0556   }
0557 
0558   void dump_columns(std::ostream& a_out) const {
0559     if((m_sep>=32)&&(m_sep<=126)) { //printable
0560       a_out << "separator is '" << m_sep << "'" << std::endl;
0561     } else {
0562       a_out << "separator is " << (unsigned int)m_sep << std::endl;
0563     }
0564     a_out << "number of columns " << m_cols.size() << std::endl;
0565     std::vector<read::icol*>::const_iterator it;
0566     for(it=m_cols.begin();it!=m_cols.end();++it) {
0567       a_out << sout((*it)->name())
0568             << " " << s_cid((*it)->id_cls())
0569             << std::endl;
0570     }
0571   }
0572 public:
0573   typedef std::pair<std::string,std::string> col_desc;
0574 
0575   bool initialize(std::ostream& a_out,const ntuple_binding& a_bd = ntuple_binding()) {
0576     // it assumes a "commented header".
0577 
0578     safe_clear<read::icol>(m_cols);
0579     m_sep = 0;
0580     m_sz = 0;
0581     m_rows = -1;
0582     m_hippo = false;
0583 
0584     m_reader.clear();
0585     m_reader.seekg(0,std::ios::end);
0586     m_sz = m_reader.tellg();
0587     m_reader.seekg(0,std::ios::beg);
0588     if(!m_sz) {
0589       a_out << "tools::rcsv::ntuple::initialize(booking) :"
0590             << " stream is empty."
0591             << std::endl;
0592       return false; //file empty.
0593     }
0594     //if(a_verbose) a_out << "file size " << m_sz << std::endl;
0595 
0596     std::string _title;
0597     char _sep,_vec_sep;
0598     std::vector<col_desc> _cols;
0599     if(!read_commented_header(a_out,m_reader,_title,_sep,_vec_sep,_cols)) return false;
0600 
0601     m_sep = _sep;
0602     m_title = _title;
0603 
0604     tools_vforcit(col_desc,_cols,it) {
0605       const std::string& type = (*it).first;
0606       const std::string& name = (*it).second;
0607 
0608 #define TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(a__name,a__type) \
0609       if(type==(std::string(#a__name)+"[]")) {\
0610         create_column< std::vector<a__type> >(name,a_bd.find_variable< std::vector<a__type> >(name));\
0611       }
0612 
0613       // see cid2s() for string types.
0614 
0615            if(type=="char")   create_column<char>(name,a_bd.find_variable<char>(name));
0616       else if(type=="short")  create_column<short>(name,a_bd.find_variable<short>(name));
0617       else if(type=="int")    create_column<int>(name,a_bd.find_variable<int>(name));
0618       else if(type=="float")  create_column<float>(name,a_bd.find_variable<float>(name));
0619       else if(type=="double") create_column<double>(name,a_bd.find_variable<double>(name));
0620       else if(type=="string") create_column<std::string>(name,a_bd.find_variable<std::string>(name));
0621 
0622       else if(type=="uchar")  create_column<unsigned char>(name,a_bd.find_variable<unsigned char>(name));
0623       else if(type=="ushort") create_column<unsigned short>(name,a_bd.find_variable<unsigned short>(name));
0624       else if(type=="uint")   create_column<uint32>(name,a_bd.find_variable<uint32>(name)); //WARNING
0625       else if(type=="bool")   create_column<bool>(name,a_bd.find_variable<bool>(name));
0626       else if(type=="int64")  create_column<int64>(name,a_bd.find_variable<int64>(name));
0627       else if(type=="uint64") create_column<uint64>(name,a_bd.find_variable<uint64>(name));
0628 
0629       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(char,char)
0630       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(short,short)
0631       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(int,int)
0632       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(float,float)
0633       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(double,double)
0634 
0635       else if(type=="string[]") create_column< std::vector<std::string> >(name,a_bd.find_variable< std::vector<std::string> >(name));
0636 
0637       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(uchar,uchar)
0638       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(ushort,ushort)
0639       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(uint,uint32)   //WARNING
0640       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(bool,bool)
0641       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(int64,int64)
0642       else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(uint64,uint64)
0643 
0644       else {
0645         a_out << "tools::rcsv::ntuple::initialize(booking) :"
0646               << " unhandled column type " << sout(type)
0647               << std::endl;
0648         safe_clear<read::icol>(m_cols);
0649         m_sep = 0;
0650         m_sz = 0;
0651         m_rows = -1;
0652         m_hippo = false;
0653         return false;
0654       }
0655 
0656 #undef TOOLS_RCSV_NTUPLE_CREATE_VEC_COL
0657 
0658     }
0659 
0660     size_t num = m_cols.size();
0661     if(!num) {
0662       a_out << "tools::rcsv::ntuple::initialize(booking) :"
0663             << " zero columns."
0664             << std::endl;
0665       return false;
0666     }
0667 
0668     //a_out << "tools::rroot::ntuple::initialize :"
0669     //      << " number of columns " << num << "."
0670     //      << std::endl;
0671 
0672     return true;
0673   }
0674 
0675   bool initialize_from_commented_header(std::ostream& a_out) { // it assumes a "commented header".
0676     std::string _title;
0677     char _sep,_vec_sep;
0678     std::vector<col_desc> _cols;
0679     if(!read_commented_header(a_out,m_reader,_title,_sep,_vec_sep,_cols)) return false;
0680     ntuple_binding nbd;
0681    {tools_vforcit(col_desc,_cols,it) nbd.add_column_no_var((*it).second);} //user_var is 0.
0682     return initialize(a_out,nbd);
0683   }
0684 
0685   bool get_row() const {
0686     bool status = true;
0687     tools_vforcit(read::icol*,m_cols,it) {
0688       if(!(*it)->fetch_entry()) status = false;
0689     }
0690     return status;
0691   }
0692 
0693 protected:
0694   bool read_commented_header(std::ostream& a_out,std::istream& a_reader,
0695                              std::string& a_title,char& a_sep,char& a_vec_sep,std::vector<col_desc>& a_cols) {
0696     // analyse first lines starting with '#'.
0697     a_title.clear();
0698     a_sep = 0;
0699     a_cols.clear();
0700 
0701     a_reader.clear();
0702     a_reader.seekg(0,std::ios::end);
0703     std::streampos sz = a_reader.tellg();
0704     a_reader.seekg(0,std::ios::beg);
0705     if(!sz) {
0706       a_out << "tools::rcsv::ntuple::read_commented_header :"
0707             << " stream is empty."
0708             << std::endl;
0709       return false;
0710     } //file empty.
0711 
0712 
0713     std::string _class;
0714 
0715     while(true) {
0716       if(a_reader.tellg()>=sz) break;
0717       //we should be at bol :
0718       char c;
0719       a_reader.get(c);
0720       a_reader.putback(c);
0721       if(c!='#') break; //finished, probably a data line now.
0722       std::string line;
0723       if(!read_line(a_reader,sz,line)) break; //or return false ?
0724 
0725       std::vector<std::string> _words;
0726       words(line," ",false,_words);
0727       if(!_words.size()) {
0728         a_out << "tools::rcsv::ntuple::read_commented_header :"
0729               << " syntax error : empty header line."
0730               << std::endl;
0731         return false;
0732       }
0733       if((_words[0]=="#class")) {
0734         if(_words.size()!=2) {
0735           a_out << "tools::rcsv::ntuple::read_commented_header :"
0736                 << " syntax error in " << sout(line)
0737                 << std::endl;
0738           return false;
0739         }
0740         _class = _words[1];
0741       } else if(_words[0]=="#title") {
0742         if(_words.size()<1) {
0743           a_out << "tools::rcsv::ntuple::read_commented_header :"
0744                 << " syntax error in " << sout(line)
0745                 << std::endl;
0746           return false;
0747         }
0748         if(_words.size()==1)  {
0749           a_title.clear();
0750         } else {
0751           std::string::size_type pos = line.find(_words[0]);
0752           pos += _words[0].size()+1;
0753           a_title = line.substr(pos,line.size()-pos);
0754         }
0755       } else if((_words[0]=="#separator")) {
0756         if(_words.size()!=2) {
0757           a_out << "tools::rcsv::ntuple::read_commented_header :"
0758                 << " syntax error in " << sout(line)
0759                 << std::endl;
0760           return false;
0761         }
0762         unsigned int uisep;
0763         if(!to(_words[1],uisep)) {
0764           a_out << "tools::rcsv::ntuple::read_commented_header :"
0765                 << " syntax error in " << sout(line)
0766                 << std::endl;
0767           return false;
0768         }
0769         a_sep = (char)uisep;
0770       } else if((_words[0]=="#vector_separator")) {
0771         if(_words.size()!=2) {
0772           a_out << "tools::rcsv::ntuple::read_commented_header :"
0773                 << " syntax error in " << sout(line)
0774                 << std::endl;
0775           return false;
0776         }
0777         unsigned int uisep;
0778         if(!to(_words[1],uisep)) {
0779           a_out << "tools::rcsv::ntuple::read_commented_header :"
0780                 << " syntax error in " << sout(line)
0781                 << std::endl;
0782           return false;
0783         }
0784         a_vec_sep = (char)uisep;
0785       } else if((_words[0]=="#column")) {
0786         if(_words.size()<2) {
0787           a_out << "tools::rcsv::ntuple::read_commented_header :"
0788                 << " syntax error in " << sout(line)
0789                 << std::endl;
0790           return false;
0791         }
0792         std::string stype = _words[1];
0793         std::string label;
0794         if(_words.size()==2) {
0795           label.clear();
0796         } else {
0797           std::string::size_type pos = line.find(_words[1]);
0798           pos += _words[1].size()+1;
0799           label = line.substr(pos,line.size()-pos);
0800         }
0801         //a_out << "column " << stype << " " << sout(label) << std::endl;
0802         a_cols.push_back(col_desc(stype,label));
0803       } else {
0804         a_out << "tools::rcsv::ntuple::read_commented_header :"
0805               << " syntax error in " << sout(line)
0806               << ", unknown keyword " << sout(_words[0])
0807               << std::endl;
0808         //return false;
0809       }
0810     }
0811 
0812 /*
0813     a_out << "class " << _class << std::endl;
0814     a_out << "title " << _title << std::endl;
0815     a_out << "separator " << _separator << std::endl;
0816 */
0817 
0818     return true;
0819   }
0820 
0821 protected:
0822   template <class T>
0823   column<T>* create_column(const std::string& a_name,T* a_user_var = 0){
0824     if(find_named<read::icol>(m_cols,a_name)) return 0;
0825     column<T>* col = new column<T>(a_name,a_user_var);
0826     if(!col) return 0;
0827     m_cols.push_back(col);
0828     return col;
0829   }
0830 
0831 protected:
0832   static bool read_line(std::istream& a_reader,std::streampos a_sz,std::string& a_s){
0833     a_s.clear();
0834     char c;
0835     while(true) {
0836       if(a_reader.tellg()>=a_sz) {a_s.clear();return false;}
0837       a_reader.get(c);
0838       if(c==CR()) continue;
0839       if(c==LF()) break; //eol.
0840       a_s += c;
0841     }
0842     return true;
0843   }
0844 
0845   static bool skip_line(std::istream& a_reader,std::streampos a_sz){
0846     char c;
0847     while(true) {
0848       if(a_reader.tellg()>=a_sz) return false;
0849       a_reader.get(c);
0850       if(c==LF()) break;
0851     }
0852     return true;
0853   }
0854 
0855   static bool skip_comment(std::istream& a_reader,std::streampos a_sz){
0856     //ret true = we had a commented line, false : a data line or nothing.
0857     if(a_reader.tellg()>=a_sz) return false;
0858     //we should be at bol :
0859     char c;
0860     a_reader.get(c);
0861     if(c=='#') {
0862       return skip_line(a_reader,a_sz);
0863       //eol. Next char should be bol.
0864     } else {
0865       a_reader.putback(c);
0866       return false;
0867     }
0868   }
0869 
0870   template <class T>
0871   static bool _read(std::istream& a_reader,std::streampos,char,T& a_v) {
0872     a_reader >> a_v;
0873     if(a_reader.tellg()==std::streampos(-1)) {a_v = 0;return false;}
0874     //std::cout << "debug : _read(double) " << a_v << std::endl;
0875     return true;
0876   }
0877   static bool _read_time(std::istream& a_reader,std::streampos a_sz,char a_sep,time_t& a_v) {
0878     std::string _s;
0879     char c;
0880     while(true){
0881       if(a_reader.tellg()>=a_sz) break;
0882       a_reader.get(c);
0883       if((c==a_sep)||(c==CR())||(c==LF())) {
0884         a_reader.putback(c);
0885         break;
0886       }
0887       _s += c;
0888     }
0889     if(!s2time(_s,a_v)) return false;
0890     return true;
0891   }
0892   static bool _read(std::istream& a_reader,std::streampos a_sz,char a_sep,std::string& a_v) {
0893     a_v.clear();
0894     char c;
0895     while(true){
0896       if(a_reader.tellg()>=a_sz) break;
0897       a_reader.get(c);
0898       if((c==a_sep)||(c==CR())||(c==LF())) {
0899         a_reader.putback(c);
0900         break;
0901       }
0902       a_v += c;
0903     }
0904     return true;
0905   }
0906 
0907   static bool _vec_read(std::istream& a_reader,std::streampos a_sz,
0908                         std::istringstream&,std::vector<std::string>&,
0909                         char a_sep,const std::string& a_vec_sep,
0910                         std::vector<std::string>& a_v) {
0911     std::string _s;
0912     if(!_read(a_reader,a_sz,a_sep,_s)) return false;
0913     //replace(_s,"\\"+a_vec_sep,"@@");
0914     words(_s,a_vec_sep,true,a_v);
0915     //tools_vforit(std::string,a_v,it) replace(*it,"@@",a_vec_sep);
0916     return true;
0917   }
0918 
0919   template <class T>
0920   static bool _vec_read(std::istream& a_reader,std::streampos a_sz,
0921                         std::istringstream& a_iss,std::vector<std::string>& a_tmp,
0922                         char a_sep,const std::string& a_vec_sep,
0923                         std::vector<T>& a_v) {
0924     std::string _s;
0925     if(!_read(a_reader,a_sz,a_sep,_s)) return false;
0926     if(!snums<T>(_s,a_iss,a_tmp,a_vec_sep,a_v)) return false;
0927     return true;
0928   }
0929 
0930 protected:
0931   bool _read_line() {
0932     // have to loop on all columns !
0933     typedef read::icol icol_t;
0934 
0935     typedef ntuple::column<char> col_char;
0936     typedef ntuple::column<short> col_short;
0937     typedef ntuple::column<int> col_int;
0938     typedef ntuple::column<float> col_float;
0939     typedef ntuple::column<double> col_double;
0940     typedef std::string string_t;
0941     typedef ntuple::column<string_t> col_string_t;
0942 
0943     typedef ntuple::column<uchar> col_uchar;
0944     typedef ntuple::column<ushort> col_ushort;
0945     typedef ntuple::column<uint32> col_uint32;
0946     typedef ntuple::column<bool> col_bool;
0947     typedef ntuple::column<int64> col_int64;
0948     typedef ntuple::column<uint64> col_uint64;
0949 
0950     typedef ntuple::column<csv_time> col_time;
0951 
0952     typedef ntuple::column< std::vector<char> > col_vec_char;
0953     typedef ntuple::column< std::vector<short> > col_vec_short;
0954     typedef ntuple::column< std::vector<int32> > col_vec_int;
0955     typedef ntuple::column< std::vector<float> > col_vec_float;
0956     typedef ntuple::column< std::vector<double> > col_vec_double;
0957     typedef ntuple::column< std::vector<std::string> > col_vec_string_t;
0958 
0959     typedef ntuple::column< std::vector<uchar> > col_vec_uchar;
0960     typedef ntuple::column< std::vector<ushort> > col_vec_ushort;
0961     typedef ntuple::column< std::vector<uint32> > col_vec_uint32;
0962     typedef ntuple::column< std::vector<bool> > col_vec_bool;
0963     typedef ntuple::column< std::vector<int64> > col_vec_int64;
0964     typedef ntuple::column< std::vector<uint64> > col_vec_uint64;
0965 
0966     std::string vec_sep;vec_sep += m_vec_sep;
0967     std::istringstream iss;
0968     std::vector<std::string> tmp;
0969 
0970     size_t index = 0;
0971     size_t num = m_cols.size();
0972     std::vector<icol_t*>::const_iterator it;
0973     for(it=m_cols.begin();it!=m_cols.end();++it,index++) {
0974 
0975 #define TOOLS_RCSV_NTUPLE_IF_COL(a__type) \
0976       if(col_##a__type* _col_##a__type = id_cast<icol_t,col_##a__type>(*(*it))) {\
0977         a__type v;\
0978         if(!_read(m_reader,m_sz,m_sep,v)) return false;\
0979         _col_##a__type->set_value(v);\
0980       }
0981 
0982 #define TOOLS_RCSV_NTUPLE_IF_VEC_COL(a__type) \
0983       if(col_vec_##a__type* _col_vec_##a__type = id_cast<icol_t,col_vec_##a__type>(*(*it))) {\
0984         std::vector<a__type> v;\
0985         if(!_vec_read(m_reader,m_sz,iss,tmp,m_sep,vec_sep,v)) return false;\
0986         _col_vec_##a__type->set_value(v);\
0987       }
0988 
0989            TOOLS_RCSV_NTUPLE_IF_COL(char)
0990       else TOOLS_RCSV_NTUPLE_IF_COL(short)
0991       else TOOLS_RCSV_NTUPLE_IF_COL(int)
0992       else TOOLS_RCSV_NTUPLE_IF_COL(float)
0993       else TOOLS_RCSV_NTUPLE_IF_COL(double)
0994       else TOOLS_RCSV_NTUPLE_IF_COL(string_t)
0995 
0996       else TOOLS_RCSV_NTUPLE_IF_COL(uchar)
0997       else TOOLS_RCSV_NTUPLE_IF_COL(ushort)
0998       else TOOLS_RCSV_NTUPLE_IF_COL(uint32)
0999       else TOOLS_RCSV_NTUPLE_IF_COL(bool)
1000       else TOOLS_RCSV_NTUPLE_IF_COL(int64)
1001       else TOOLS_RCSV_NTUPLE_IF_COL(uint64)
1002 
1003       else if(col_time* _col_time = id_cast<icol_t,col_time>(*(*it))) {
1004         time_t v;
1005         if(!_read_time(m_reader,m_sz,m_sep,v)) return false;
1006         csv_time ct;ct.m_l = long(v);
1007         _col_time->set_value(ct);
1008       }
1009 
1010       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(char)
1011       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(short)
1012       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(int)
1013       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(float)
1014       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(double)
1015       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(string_t)
1016 
1017       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(uchar)
1018       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(ushort)
1019       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(uint32)
1020       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(bool)
1021       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(int64)
1022       else TOOLS_RCSV_NTUPLE_IF_VEC_COL(uint64)
1023 
1024 #undef TOOLS_RCSV_NTUPLE_IF_COL
1025 #undef TOOLS_RCSV_NTUPLE_IF_VEC_COL
1026 
1027       else {
1028         //std::cout << "column cast failed." << std::endl;
1029         return false;
1030       }
1031 
1032       if(index==(num-1)) { //read up to LF()
1033         char c;
1034         while(true){
1035           if(m_reader.tellg()>=m_sz) break;
1036           m_reader.get(c);
1037           if(c==LF()) break;
1038         }
1039       } else { //read sep :
1040         char sep;
1041         m_reader.get(sep);
1042       }
1043     }
1044     return true;
1045   }
1046 protected:
1047   std::istream& m_reader;
1048   std::string m_title;
1049   char m_sep;
1050   char m_vec_sep;
1051   std::vector<read::icol*> m_cols;
1052   std::streampos m_sz;
1053   int m_rows; //to optimize number_of_entries().
1054   bool m_hippo;
1055 };
1056 
1057 }}
1058 
1059 
1060 #include <fstream>
1061 
1062 namespace tools {
1063 namespace rcsv {
1064 
1065 class fntuple : public ntuple {
1066   typedef ntuple parent;
1067 public:
1068   static const std::string& s_class() {
1069     static const std::string s_v("tools::rcsv::fntuple");
1070     return s_v;
1071   }
1072 public:
1073   fntuple(const std::string& a_file)
1074   :parent(m_freader)
1075   ,m_file(a_file)
1076   {}
1077   virtual ~fntuple() {m_freader.close();}
1078 protected:
1079   fntuple(const fntuple& a_from)
1080   :read::intuple(a_from)
1081   ,parent(a_from)
1082   ,m_file(a_from.m_file)
1083   {}
1084   fntuple& operator=(const fntuple& a_from){
1085     parent::operator=(a_from);
1086     m_file = a_from.m_file;
1087     return *this;
1088   }
1089 public:
1090   bool open(){
1091     m_freader.open(m_file.c_str());
1092     return m_freader.fail()?false:true;
1093   }
1094   bool initialize(std::ostream& a_out,
1095                   char a_sep = 0, //guessed
1096                   const std::string& a_suffix = "x", //col suffix
1097                   bool a_verbose = false) {
1098     if(!m_freader.is_open()) {
1099       m_freader.open(m_file.c_str());
1100       if(m_freader.fail()) {
1101         a_out << "tools::rcsv::fntuple::initialize :"
1102               << " can't open " << m_file << "."
1103               << std::endl;
1104         return false;
1105       }
1106     }
1107     return parent::initialize(a_out,a_sep,a_suffix,a_verbose);
1108   }
1109 protected:
1110   std::string m_file;
1111   std::ifstream m_freader;
1112 };
1113 
1114 }}
1115 
1116 #endif