// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_rcsv_ntuple #define tools_rcsv_ntuple // A simple ntuple class to read at the csv format. // (csv = comma separated value). // This reader can be use to read file at the hippodraw format // which is : // - one header line for the ntuple title. // - one csv line for column names. // - data at csv format. #include "rntuple" #include #include #include "vmanip" #include "tokenize" #include "snums" #include "sto" #include "s2time" #include "charmanip" #include "strip" #include "cids" #include "ntuple_binding" #include "sout" #include "num2s" #include namespace tools { namespace rcsv { class ntuple : public virtual read::intuple { typedef read::intuple parent; public: //read::intuple virtual void start() { m_reader.clear(); m_reader.seekg(0,std::ios::beg); if(m_hippo) { skip_line(m_reader,m_sz); skip_line(m_reader,m_sz); } } virtual bool next() { if(!m_sep) return false; //not inited. if(m_reader.tellg()>=m_sz) return false; // first time we are at bol but else we are at eol. char c; m_reader.get(c); if(c==LF()){ if(m_reader.tellg()>=m_sz) { //eof. Tell caller to stop looping on ntuple rows. return false; } //eol. Next char read is going to be at bol. } else { m_reader.putback(c); //bol } // ready for a new row : while(skip_comment(m_reader,m_sz)){} if(m_reader.tellg()>=m_sz) return false; return _read_line(); } virtual read::icol* find_icol(const std::string& a_name){ return find_named(m_cols,a_name); } virtual const std::vector& columns() const {return m_cols;} virtual const std::string& title() const {return m_title;} virtual bool number_of_entries(tools::uint64 & a_value) const { if(!m_sep) {a_value = 0;return false;} //not inited. ntuple& self = const_cast(*this); if(m_rows==(-1)) { self.m_rows = 0; self.start(); while(self.next()) {self.m_rows++;} } a_value = (uint64)m_rows; return true; } public: template class column : public virtual read::icolumn { typedef read::icolumn parent; public: static cid id_class() { static const T s_v = T(); //do that for T = std::string. return 200+_cid(s_v); } public: //icol virtual void* cast(cid a_class) const { if(void* p = cmp_cast(this,a_class)) {return p;} return parent::cast(a_class); } virtual cid id_cls() const {return id_class();} public: //icol virtual const std::string& name() const {return m_name;} virtual bool fetch_entry() const { if(m_user_var) *m_user_var = m_tmp; return true; } public: //icolumn virtual bool get_entry(T& a_v) const { a_v = m_tmp; return true; } public: column(const std::string& a_name,T* a_user_var = 0) :m_name(a_name) ,m_tmp(T()) ,m_user_var(a_user_var) //not owner {} virtual ~column(){} protected: column(const column& a_from) :read::icol(a_from) ,parent(a_from) ,m_name(a_from.m_name) ,m_tmp(a_from.m_tmp) ,m_user_var(a_from.m_user_var) {} column& operator=(const column& a_from){ m_name = a_from.m_name; m_tmp = a_from.m_tmp; m_user_var = a_from.m_user_var; return *this; } public: // should be used in ntuple _read_line only : void set_value(const T& a_v){m_tmp = a_v;} protected: std::string m_name; T m_tmp; T* m_user_var; }; public: ntuple(std::istream& a_reader) :m_reader(a_reader) ,m_title() ,m_sep(0) ,m_vec_sep(';') ,m_sz(0) ,m_rows(-1) ,m_hippo(false) { } virtual ~ntuple() { safe_clear(m_cols); } protected: ntuple(const ntuple& a_from) :parent(a_from) ,m_reader(a_from.m_reader) ,m_title(a_from.m_title) ,m_sep(a_from.m_sep) ,m_vec_sep(a_from.m_vec_sep) ,m_sz(a_from.m_sz) ,m_rows(-1) ,m_hippo(a_from.m_hippo) { } ntuple& operator=(const ntuple& a_from){ m_title = a_from.m_title; m_sep = a_from.m_sep; m_vec_sep = a_from.m_vec_sep; m_hippo = a_from.m_hippo; m_rows = a_from.m_rows; return *this; } public: void set_vec_sep(char a_c) {m_vec_sep = a_c;} void set_sep(char a_c) {m_sep = a_c;} void set_hippo(bool a_hippo) {m_hippo = a_hippo;} std::istream& istrm() {return m_reader;} static bool find_sep(std::ostream& a_out, std::istream& a_reader,bool a_hippo, bool a_verbose, char& a_sep){ // analyse first data line to find the char separator. a_reader.clear(); a_reader.seekg(0,std::ios::end); std::streampos sz = a_reader.tellg(); a_reader.seekg(0,std::ios::beg); if(!sz) { a_out << "tools::rcsv::ntuple::find_sep :" << " stream is empty." << std::endl; a_sep = 0; return false; } //file empty. if(a_verbose) a_out << "file size " << sz << std::endl; if(a_hippo) { //skip first two lines : if(!skip_line(a_reader,sz)) {a_sep = 0;return false;} if(!skip_line(a_reader,sz)) {a_sep = 0;return false;} } else { while(skip_comment(a_reader,sz)){} } if(a_reader.tellg()>=sz) {a_sep=0;return false;} //no data line. // get first data line : std::string sfirst; {char c; while(true) { if(a_reader.tellg()>=sz) break; a_reader.get(c); if((c==CR())||(c==LF())) break; sfirst += c; }} if(sfirst.empty()) { a_out << "tools::rcsv::ntuple::find_set :" << " first datat line is empty." << std::endl; a_sep = 0; return false; } if(a_verbose) a_out << "first data line \"" << sfirst << "\"" << std::endl; //guess sep from first data line : std::istringstream strm(sfirst.c_str()); double d; strm >> d; std::streampos pos = strm.tellg(); if(pos==std::streampos(-1)) { a_out << "tools::rcsv::ntuple::find_sep :" << " first line does not start with a number." << std::endl; a_sep = 0; return false; } //not a number. if(a_verbose) a_out << "first number " << d << " ending at pos " << pos << std::endl; if(pos>=(std::streampos)sfirst.size()) { a_out << "tools::rcsv::ntuple::find_sep :" << " no separator found in first line." << " pos " << pos << " sfirst.size() " << sfirst.size() << std::endl; a_sep = 0; return false; } //no sep. strm.get(a_sep); return true; } public: bool initialize(std::ostream& a_out, char a_sep = 0, //guessed const std::string& a_suffix = "x", //col suffix bool a_verbose = false) { safe_clear(m_cols); m_sep = 0; m_sz = 0; m_rows = -1; if(a_suffix.empty()) { a_out << "tools::rcsv::ntuple::initialize : expect a column suffix." << std::endl; return false; } m_reader.clear(); m_reader.seekg(0,std::ios::end); m_sz = m_reader.tellg(); m_reader.seekg(0,std::ios::beg); if(!m_sz) { a_out << "tools::rcsv::ntuple::initialize :" << " stream is empty." << std::endl; return false; //file empty. } if(a_verbose) a_out << "file size " << m_sz << std::endl; std::vector labels; if(m_hippo) { //skip first two lines : std::string _title; if(!read_line(m_reader,m_sz,_title)) { a_out << "tools::rcsv::ntuple::initialize : read_line() failed." << std::endl; m_sz = 0; m_rows = -1; return false; } std::string _s; if(!read_line(m_reader,m_sz,_s)) { a_out << "tools::rcsv::ntuple::initialize : (2) read_line() failed." << std::endl; m_sz = 0; m_rows = -1; return false; } words(_s,"\t",false,labels); //false for glast.tnt that has a trailing \t. } else { while(skip_comment(m_reader,m_sz)){} } if(m_reader.tellg()>=m_sz) { a_out << "tools::rcsv::ntuple::initialize : tellg() >= sz." << std::endl; m_sz = 0; m_rows = -1; return false; } // get first data line : std::string sfirst; {{char c; while(true) { if(m_reader.tellg()>=m_sz) break; m_reader.get(c); if((c==CR())||(c==LF())) break; sfirst += c; }} if(sfirst.empty()) { a_out << "tools::rcsv::ntuple::initialize :" << " first datat line is empty." << std::endl; m_sz = 0; m_rows = -1; return false; }} if(a_verbose) a_out << "first data line \"" << sfirst << "\"" << std::endl; if(a_sep) { m_sep = a_sep; } else { //guess sep from first data line : std::istringstream strm(sfirst.c_str()); double d; strm >> d; std::streampos pos = strm.tellg(); if(pos==std::streampos(-1)) { a_out << "tools::rcsv::ntuple::initialize :" << " first line does not start with a number." << std::endl; m_sz = 0; m_rows = -1; return false; } if(a_verbose) a_out << "first number " << d << " ending at pos " << pos << std::endl; if(pos>=(std::streampos)sfirst.size()) { a_out << "tools::rcsv::ntuple::initialize :" << " no separator found in first line." << std::endl; m_sz = 0; m_rows = -1; return false; } strm.get(m_sep); } if(a_verbose) a_out << "sep " << (int)m_sep << std::endl; // in case sep is ' ', there is an ambiguity with some leading // space in front of first number. if(m_sep==' ') strip(sfirst,leading,' '); std::vector ws; {std::string sep; sep += m_sep; words(sfirst,sep,m_hippo?false:true,ws);} // look if words are numbers : if(a_verbose) a_out << "words " << ws.size() << std::endl; unsigned int index = 0; std::vector::iterator it; for(it=ws.begin();it!=ws.end();++it,index++) { if(a_verbose) a_out << "word " << sout(*it) << "" << std::endl; std::string name = a_suffix; if(!numas(m_cols.size(),name)){} if(m_hippo) { if(index>=labels.size()) { a_out << "tools::rcsv::ntuple::initialize :" << " warning : not enough labels." << std::endl; } else { name = labels[index]; } } double d; if(to(*it,d)) { if(a_verbose) a_out << "number " << d << std::endl; create_column(name); } else { time_t time; if(s2time(*it,time)) { create_column(name); } else { std::vector v; std::string vec_sep;vec_sep += m_vec_sep; if(snums(*it,vec_sep,v)&&v.size()) { create_column< std::vector >(name); } else { create_column(name); } } } } size_t num = m_cols.size(); if(!num) { a_out << "tools::rcsv::ntuple::initialize :" << " zero columns." << std::endl; m_sep = 0; m_sz = 0; m_rows = -1; return false; } return true; } static const std::string& s_cid(cid a_id) { #define TOOLS_RCSV_NTUPLE_IF_CID(a__name,a__type) \ if(a_id==column::id_class()) {\ static const std::string s_v(#a__name);\ return s_v;\ } #define TOOLS_RCSV_NTUPLE_IF_VEC_CID(a__name,a__type) \ if(a_id==column< std::vector >::id_class()) {\ static const std::string s_v(#a__name+std::string("[]"));\ return s_v;\ } TOOLS_RCSV_NTUPLE_IF_CID(char,char) else TOOLS_RCSV_NTUPLE_IF_CID(short,short) else TOOLS_RCSV_NTUPLE_IF_CID(int,int) else TOOLS_RCSV_NTUPLE_IF_CID(int64,int64) else TOOLS_RCSV_NTUPLE_IF_CID(float,float) else TOOLS_RCSV_NTUPLE_IF_CID(double,double) else TOOLS_RCSV_NTUPLE_IF_CID(uchar,uchar) else TOOLS_RCSV_NTUPLE_IF_CID(ushort,ushort) else TOOLS_RCSV_NTUPLE_IF_CID(uint,uint32) //WARNING else TOOLS_RCSV_NTUPLE_IF_CID(uint64,uint64) else TOOLS_RCSV_NTUPLE_IF_CID(bool,bool) else if(a_id==column::id_class()) { static const std::string s_v("string"); return s_v; } else if(a_id==column::id_class()) { static const std::string s_v("time"); return s_v; } else TOOLS_RCSV_NTUPLE_IF_VEC_CID(char,char) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(short,short) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(int,int) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(int64,int64) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(float,float) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(double,double) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(uchar,uchar) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(ushort,ushort) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(uint,uint32) //WARNING else TOOLS_RCSV_NTUPLE_IF_VEC_CID(uint64,uint64) else TOOLS_RCSV_NTUPLE_IF_VEC_CID(bool,bool) else if(a_id==column< std::vector >::id_class()) { static const std::string s_v("string[]"); return s_v; } #undef TOOLS_RCSV_NTUPLE_IF_CID #undef TOOLS_RCSV_NTUPLE_IF_VEC_CID else { static const std::string s_v("unknown"); return s_v; } } void dump_columns(std::ostream& a_out) const { if((m_sep>=32)&&(m_sep<=126)) { //printable a_out << "separator is '" << m_sep << "'" << std::endl; } else { a_out << "separator is " << (unsigned int)m_sep << std::endl; } a_out << "number of columns " << m_cols.size() << std::endl; std::vector::const_iterator it; for(it=m_cols.begin();it!=m_cols.end();++it) { a_out << sout((*it)->name()) << " " << s_cid((*it)->id_cls()) << std::endl; } } public: typedef std::pair col_desc; bool initialize(std::ostream& a_out,const ntuple_binding& a_bd = ntuple_binding()) { // it assumes a "commented header". safe_clear(m_cols); m_sep = 0; m_sz = 0; m_rows = -1; m_hippo = false; m_reader.clear(); m_reader.seekg(0,std::ios::end); m_sz = m_reader.tellg(); m_reader.seekg(0,std::ios::beg); if(!m_sz) { a_out << "tools::rcsv::ntuple::initialize(booking) :" << " stream is empty." << std::endl; return false; //file empty. } std::string _title; char _sep,_vec_sep; std::vector _cols; if(!read_commented_header(a_out,m_reader,_title,_sep,_vec_sep,_cols)) return false; m_sep = _sep; m_title = std::move(_title); tools_vforcit(col_desc,_cols,it) { const std::string& type = (*it).first; const std::string& name = (*it).second; #define TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(a__name,a__type) \ if(type==(std::string(#a__name)+"[]")) {\ create_column< std::vector >(name,a_bd.find_variable< std::vector >(name));\ } // see cid2s() for string types. if(type=="char") create_column(name,a_bd.find_variable(name)); else if(type=="short") create_column(name,a_bd.find_variable(name)); else if(type=="int") create_column(name,a_bd.find_variable(name)); else if(type=="float") create_column(name,a_bd.find_variable(name)); else if(type=="double") create_column(name,a_bd.find_variable(name)); else if(type=="string") create_column(name,a_bd.find_variable(name)); else if(type=="uchar") create_column(name,a_bd.find_variable(name)); else if(type=="ushort") create_column(name,a_bd.find_variable(name)); else if(type=="uint") create_column(name,a_bd.find_variable(name)); //WARNING else if(type=="bool") create_column(name,a_bd.find_variable(name)); else if(type=="int64") create_column(name,a_bd.find_variable(name)); else if(type=="uint64") create_column(name,a_bd.find_variable(name)); else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(char,char) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(short,short) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(int,int) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(float,float) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(double,double) else if(type=="string[]") create_column< std::vector >(name,a_bd.find_variable< std::vector >(name)); else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(uchar,uchar) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(ushort,ushort) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(uint,uint32) //WARNING else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(bool,bool) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(int64,int64) else TOOLS_RCSV_NTUPLE_CREATE_VEC_COL(uint64,uint64) else { a_out << "tools::rcsv::ntuple::initialize(booking) :" << " unhandled column type " << sout(type) << std::endl; safe_clear(m_cols); m_sep = 0; m_sz = 0; m_rows = -1; m_hippo = false; return false; } #undef TOOLS_RCSV_NTUPLE_CREATE_VEC_COL } size_t num = m_cols.size(); if(!num) { a_out << "tools::rcsv::ntuple::initialize(booking) :" << " zero columns." << std::endl; m_sep = 0; m_sz = 0; m_rows = -1; m_hippo = false; return false; } {tools_vforcit(column_binding,a_bd.columns(),it) { if(!find_named(m_cols,(*it).name())) { a_out << "tools::rcsv::ntuple::initialize :" << " error : for column binding with name " << sout((*it).name()) << ", no ntuple column found." << std::endl; safe_clear(m_cols); m_sep = 0; m_sz = 0; m_rows = -1; m_hippo = false; return false; } }} return true; } bool initialize_from_commented_header(std::ostream& a_out) { // it assumes a "commented header". std::string _title; char _sep,_vec_sep; std::vector _cols; if(!read_commented_header(a_out,m_reader,_title,_sep,_vec_sep,_cols)) return false; ntuple_binding nbd; {tools_vforcit(col_desc,_cols,it) nbd.add_column_no_var((*it).second);} //user_var is 0. return initialize(a_out,nbd); } bool get_row() const { bool status = true; tools_vforcit(read::icol*,m_cols,it) { if(!(*it)->fetch_entry()) status = false; } return status; } protected: bool read_commented_header(std::ostream& a_out,std::istream& a_reader, std::string& a_title,char& a_sep,char& a_vec_sep,std::vector& a_cols) { // analyse first lines starting with '#'. a_title.clear(); a_sep = 0; a_cols.clear(); a_reader.clear(); a_reader.seekg(0,std::ios::end); std::streampos sz = a_reader.tellg(); a_reader.seekg(0,std::ios::beg); if(!sz) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " stream is empty." << std::endl; return false; } //file empty. std::string _class; while(true) { if(a_reader.tellg()>=sz) break; //we should be at bol : char c; a_reader.get(c); a_reader.putback(c); if(c!='#') break; //finished, probably a data line now. std::string line; if(!read_line(a_reader,sz,line)) break; //or return false ? std::vector _words; words(line," ",false,_words); if(!_words.size()) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error : empty header line." << std::endl; return false; } if((_words[0]=="#class")) { if(_words.size()!=2) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << std::endl; return false; } _class = _words[1]; } else if(_words[0]=="#title") { if(_words.size()<1) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << std::endl; return false; } if(_words.size()==1) { a_title.clear(); } else { std::string::size_type pos = line.find(_words[0]); pos += _words[0].size()+1; a_title = line.substr(pos,line.size()-pos); } } else if((_words[0]=="#separator")) { if(_words.size()!=2) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << std::endl; return false; } unsigned int uisep; if(!to(_words[1],uisep)) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << std::endl; return false; } a_sep = (char)uisep; } else if((_words[0]=="#vector_separator")) { if(_words.size()!=2) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << std::endl; return false; } unsigned int uisep; if(!to(_words[1],uisep)) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << std::endl; return false; } a_vec_sep = (char)uisep; } else if((_words[0]=="#column")) { if(_words.size()<2) { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << std::endl; return false; } std::string stype = _words[1]; std::string label; if(_words.size()==2) { label.clear(); } else { std::string::size_type pos = line.find(_words[1]); pos += _words[1].size()+1; label = line.substr(pos,line.size()-pos); } //a_out << "column " << stype << " " << sout(label) << std::endl; a_cols.push_back(col_desc(stype,label)); } else { a_out << "tools::rcsv::ntuple::read_commented_header :" << " syntax error in " << sout(line) << ", unknown keyword " << sout(_words[0]) << std::endl; } } return true; } protected: template column* create_column(const std::string& a_name,T* a_user_var = 0){ if(find_named(m_cols,a_name)) return 0; column* col = new column(a_name,a_user_var); if(!col) return 0; m_cols.push_back(col); return col; } protected: static bool read_line(std::istream& a_reader,std::streampos a_sz,std::string& a_s){ a_s.clear(); char c; while(true) { if(a_reader.tellg()>=a_sz) {a_s.clear();return false;} a_reader.get(c); if(c==CR()) continue; if(c==LF()) break; //eol. a_s += c; } return true; } static bool skip_line(std::istream& a_reader,std::streampos a_sz){ char c; while(true) { if(a_reader.tellg()>=a_sz) return false; a_reader.get(c); if(c==LF()) break; } return true; } static bool skip_comment(std::istream& a_reader,std::streampos a_sz){ //ret true = we had a commented line, false : a data line or nothing. if(a_reader.tellg()>=a_sz) return false; //we should be at bol : char c; a_reader.get(c); if(c=='#') { return skip_line(a_reader,a_sz); //eol. Next char should be bol. } else { a_reader.putback(c); return false; } } template static bool _read(std::istream& a_reader,std::streampos,char,T& a_v) { a_reader >> a_v; if(a_reader.tellg()==std::streampos(-1)) {a_v = 0;return false;} return true; } static bool _read_time(std::istream& a_reader,std::streampos a_sz,char a_sep,time_t& a_v) { std::string _s; char c; while(true){ if(a_reader.tellg()>=a_sz) break; a_reader.get(c); if((c==a_sep)||(c==CR())||(c==LF())) { a_reader.putback(c); break; } _s += c; } if(!s2time(_s,a_v)) return false; return true; } static bool _read(std::istream& a_reader,std::streampos a_sz,char a_sep,std::string& a_v) { a_v.clear(); char c; while(true){ if(a_reader.tellg()>=a_sz) break; a_reader.get(c); if((c==a_sep)||(c==CR())||(c==LF())) { a_reader.putback(c); break; } a_v += c; } return true; } static bool _vec_read(std::istream& a_reader,std::streampos a_sz, std::istringstream&,std::vector&, char a_sep,const std::string& a_vec_sep, std::vector& a_v) { std::string _s; if(!_read(a_reader,a_sz,a_sep,_s)) return false; words(_s,a_vec_sep,true,a_v); return true; } template static bool _vec_read(std::istream& a_reader,std::streampos a_sz, std::istringstream& a_iss,std::vector& a_tmp, char a_sep,const std::string& a_vec_sep, std::vector& a_v) { std::string _s; if(!_read(a_reader,a_sz,a_sep,_s)) return false; if(!snums(_s,a_iss,a_tmp,a_vec_sep,a_v)) return false; return true; } protected: bool _read_line() { // have to loop on all columns ! typedef read::icol icol_t; typedef ntuple::column col_char; typedef ntuple::column col_short; typedef ntuple::column col_int; typedef ntuple::column col_float; typedef ntuple::column col_double; typedef std::string string_t; typedef ntuple::column col_string_t; typedef ntuple::column col_uchar; typedef ntuple::column col_ushort; typedef ntuple::column col_uint32; typedef ntuple::column col_bool; typedef ntuple::column col_int64; typedef ntuple::column col_uint64; typedef ntuple::column col_time; typedef ntuple::column< std::vector > col_vec_char; typedef ntuple::column< std::vector > col_vec_short; typedef ntuple::column< std::vector > col_vec_int; typedef ntuple::column< std::vector > col_vec_float; typedef ntuple::column< std::vector > col_vec_double; typedef ntuple::column< std::vector > col_vec_string_t; typedef ntuple::column< std::vector > col_vec_uchar; typedef ntuple::column< std::vector > col_vec_ushort; typedef ntuple::column< std::vector > col_vec_uint32; typedef ntuple::column< std::vector > col_vec_bool; typedef ntuple::column< std::vector > col_vec_int64; typedef ntuple::column< std::vector > col_vec_uint64; std::string vec_sep;vec_sep += m_vec_sep; std::istringstream iss; std::vector tmp; size_t index = 0; size_t num = m_cols.size(); std::vector::const_iterator it; for(it=m_cols.begin();it!=m_cols.end();++it,index++) { #define TOOLS_RCSV_NTUPLE_IF_COL(a__type) \ if(col_##a__type* _col_##a__type = id_cast(*(*it))) {\ a__type v;\ if(!_read(m_reader,m_sz,m_sep,v)) return false;\ _col_##a__type->set_value(v);\ } #define TOOLS_RCSV_NTUPLE_IF_VEC_COL(a__type) \ if(col_vec_##a__type* _col_vec_##a__type = id_cast(*(*it))) {\ std::vector v;\ if(!_vec_read(m_reader,m_sz,iss,tmp,m_sep,vec_sep,v)) return false;\ _col_vec_##a__type->set_value(v);\ } TOOLS_RCSV_NTUPLE_IF_COL(char) else TOOLS_RCSV_NTUPLE_IF_COL(short) else TOOLS_RCSV_NTUPLE_IF_COL(int) else TOOLS_RCSV_NTUPLE_IF_COL(float) else TOOLS_RCSV_NTUPLE_IF_COL(double) else TOOLS_RCSV_NTUPLE_IF_COL(string_t) else TOOLS_RCSV_NTUPLE_IF_COL(uchar) else TOOLS_RCSV_NTUPLE_IF_COL(ushort) else TOOLS_RCSV_NTUPLE_IF_COL(uint32) else TOOLS_RCSV_NTUPLE_IF_COL(bool) else TOOLS_RCSV_NTUPLE_IF_COL(int64) else TOOLS_RCSV_NTUPLE_IF_COL(uint64) else if(col_time* _col_time = id_cast(*(*it))) { time_t v; if(!_read_time(m_reader,m_sz,m_sep,v)) return false; csv_time ct;ct.m_l = long(v); _col_time->set_value(ct); } else TOOLS_RCSV_NTUPLE_IF_VEC_COL(char) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(short) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(int) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(float) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(double) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(string_t) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(uchar) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(ushort) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(uint32) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(bool) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(int64) else TOOLS_RCSV_NTUPLE_IF_VEC_COL(uint64) #undef TOOLS_RCSV_NTUPLE_IF_COL #undef TOOLS_RCSV_NTUPLE_IF_VEC_COL else { return false; } if(index==(num-1)) { //read up to LF() char c; while(true){ if(m_reader.tellg()>=m_sz) break; m_reader.get(c); if(c==LF()) break; } } else { //read sep : char sep; m_reader.get(sep); } } return true; } protected: std::istream& m_reader; std::string m_title; char m_sep; char m_vec_sep; std::vector m_cols; std::streampos m_sz; int m_rows; //to optimize number_of_entries(). bool m_hippo; }; }} #endif