// Copyright (C) 2010, Guy Barrand. All rights reserved. // See the file tools.license for terms. #ifndef tools_wcsv_ntuple #define tools_wcsv_ntuple // A simple ntuple class to write at the csv format. // (csv = comma separated value). // Each add_row() write a row at the csv format. #include "vfind" #include "vmanip" #include #include "scast" #include "ntuple_booking" #include "sout" //#include "srep" namespace tools { namespace wcsv { class ntuple { public: static const std::string& s_class() { static const std::string s_v("tools::wcsv::ntuple"); return s_v; } public: class icol { public: virtual ~icol(){} public: virtual void* cast(cid) const = 0; virtual cid id_cls() const = 0; public: virtual void add() = 0; virtual const std::string& name() const = 0; }; public: template class column : public virtual icol { public: static cid id_class() { static const T s_v = T(); //do that for T = std::string. return _cid(s_v); } virtual void* cast(cid a_class) const { if(void* p = cmp_cast(this,a_class)) {return p;} else return 0; } virtual cid id_cls() const {return id_class();} public: //icol virtual void add() { m_writer << m_tmp; m_tmp = m_def; } virtual const std::string& name() const {return m_name;} public: column(std::ostream& a_writer,const std::string& a_name,const T& a_def) :m_writer(a_writer) ,m_name(a_name),m_def(a_def),m_tmp(a_def) {} virtual ~column(){} protected: column(const column& a_from) :icol(a_from) ,m_writer(a_from.m_writer) ,m_name(a_from.m_name) ,m_def(a_from.m_def) ,m_tmp(a_from.m_tmp) {} column& operator=(const column& a_from){ m_name = a_from.m_name; m_def = a_from.m_def; m_tmp = a_from.m_tmp; return *this; } public: bool fill(const T& a_value) {m_tmp = a_value;return true;} protected: std::ostream& m_writer; std::string m_name; T m_def; T m_tmp; }; /* template static void escape(T&,const std::string&){} static void escape(std::string& a_s,const std::string& a_sep){ replace(a_s,a_sep,"\\"+a_sep); //if changing here, change rcsv_ntuple/_vec_read() too. } */ template class std_vector_column : public virtual icol { public: static cid id_class() {return _cid_std_vector();} virtual void* cast(cid a_class) const { if(void* p = cmp_cast(this,a_class)) {return p;} else return 0; } virtual cid id_cls() const {return id_class();} public: //icol virtual void add() { if(m_user_vec.empty()) { //m_writer << "none"; } else { //std::string sep;sep+=m_vec_sep; //T value; typedef typename std::vector::const_iterator it_t; for(it_t it=m_user_vec.begin();it!=m_user_vec.end();++it) { if(it!=m_user_vec.begin()) m_writer << m_vec_sep; m_writer << *it; //value = *it;escape(value,sep); //m_writer << value; } } } virtual const std::string& name() const {return m_name;} public: std_vector_column(std::ostream& a_writer,const std::string& a_name,std::vector& a_user_vec,char a_vec_sep) :m_writer(a_writer) ,m_name(a_name) ,m_user_vec(a_user_vec) ,m_vec_sep(a_vec_sep) {} virtual ~std_vector_column(){} protected: std_vector_column(const std_vector_column& a_from) :icol(a_from) ,m_writer(a_from.m_writer) ,m_name(a_from.m_name) ,m_user_vec(a_from.m_user_vec) ,m_vec_sep(a_from.m_vec_sep) {} std_vector_column& operator=(const std_vector_column& a_from){ m_name = a_from.m_name; m_vec_sep = a_from.m_vec_sep; return *this; } protected: std::ostream& m_writer; std::string m_name; std::vector& m_user_vec; char m_vec_sep; }; public: ntuple(std::ostream& a_writer,char a_sep = ',',char a_vec_sep = ';') :m_writer(a_writer) ,m_sep(a_sep) ,m_vec_sep(a_vec_sep) {} ntuple(std::ostream& a_writer, std::ostream& a_out, //for errors. const ntuple_booking& a_bkg, char a_sep = ',',char a_vec_sep = ';') :m_writer(a_writer) ,m_sep(a_sep) ,m_vec_sep(a_vec_sep) ,m_title(a_bkg.title()) { const std::vector& cols = a_bkg.columns(); std::vector::const_iterator it; for(it=cols.begin();it!=cols.end();++it){ if((*it).cls_id()==_cid(char(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(short(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(int(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(float(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(double(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(std::string())) { create_column((*it).name()); } else if((*it).cls_id()==_cid(byte(0))) { create_column((*it).name()); } else if((*it).cls_id()==_cid((unsigned short)0)) { create_column((*it).name()); } else if((*it).cls_id()==_cid((unsigned int)0)) { create_column((*it).name()); } else if((*it).cls_id()==_cid(bool(true))) { create_column((*it).name()); } else if((*it).cls_id()==_cid(uint64(0))) { create_column((*it).name()); #define TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(a__type) \ } else if((*it).cls_id()==_cid_std_vector()) {\ std::vector* vec = (std::vector*)(*it).user_obj();\ if(vec) {\ create_column((*it).name(),*vec);\ } else {\ a_out << "tools::wcsv_ntuple :"\ << " for std::vector column " << sout((*it).name())\ << ", the user vector pointer is null."\ << std::endl;\ tools::clear(m_cols);\ return;\ } TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(char) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(short) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(int) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(float) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(double) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(std::string) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(uchar) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(ushort) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(uint32) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(bool) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(int64) TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(uint64) #undef TOOLS_WCSV_NTUPLE_CREATE_VEC_COL } else { a_out << "tools::wcsv::ntuple :" << " for column " << sout((*it).name()) << ", type with cid " << (*it).cls_id() << " not yet handled." << std::endl; //throw tools::clear(m_cols); return; } } } virtual ~ntuple() { tools::clear(m_cols); } protected: ntuple(const ntuple& a_from) :m_writer(a_from.m_writer) ,m_sep(a_from.m_sep) ,m_vec_sep(a_from.m_vec_sep) ,m_title(a_from.m_title) {} ntuple& operator=(const ntuple& a_from){ m_sep = a_from.m_sep; m_vec_sep = a_from.m_vec_sep; m_title = a_from.m_title; return *this; } public: void write_hippo_header() { m_writer << m_title << std::endl; std::vector::const_iterator it; for(it=m_cols.begin();it!=m_cols.end();++it){ if(it!=m_cols.begin()) m_writer << '\t'; m_writer << (*it)->name(); } m_writer << std::endl; } bool write_commented_header(std::ostream& a_out) { // commented header similar to the histo case. m_writer << "#class " << s_class() << std::endl; m_writer << "#title " << m_title << std::endl; m_writer << "#separator " << (unsigned int)m_sep << std::endl; m_writer << "#vector_separator " << (unsigned int)m_vec_sep << std::endl; bool status = true; {for(unsigned int count=0;countid_cls(),sid)) { a_out << "tools::wcsv::ntuple::write_commented_header :" << " unknow column type id " << _col->id_cls() << std::endl; status = false; //but we continue. } else { m_writer << "#column " << sid << " " << _col->name() << std::endl; } }} return status; } template column* create_column(const std::string& a_name,const T& a_def = T()) { if(find_named(m_cols,a_name)) return 0; column* col = new column(m_writer,a_name,a_def); if(!col) return 0; m_cols.push_back(col); return col; } template std_vector_column* create_column(const std::string& a_name,std::vector& a_user_vec) { //NOTE : to optimize, we do not handle a default std::vector value logic. if(find_named(m_cols,a_name)) return 0; std_vector_column* col = new std_vector_column(m_writer,a_name,a_user_vec,m_vec_sep); if(!col) return 0; m_cols.push_back(col); return col; } template column* find_column(const std::string& a_name) { icol* col = find_named(m_cols,a_name); if(!col) return 0; return id_cast >(*col); } bool add_row() { if(m_cols.empty()) return false; std::vector::iterator it; it=m_cols.begin(); (*it)->add(); it++; for(;it!=m_cols.end();++it) { m_writer << m_sep; (*it)->add(); } m_writer << std::endl; return true; } const std::vector& columns() const {return m_cols;} void set_title(const std::string& a_value) {m_title = a_value;} const std::string& title() const {return m_title;} protected: std::ostream& m_writer; char m_sep; char m_vec_sep; std::string m_title; std::vector m_cols; }; }} #endif