339 lines
9.8 KiB
Plaintext
339 lines
9.8 KiB
Plaintext
// 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 <ostream>
|
|
|
|
#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 T>
|
|
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<column>(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 <class T>
|
|
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 T>
|
|
class std_vector_column : public virtual icol {
|
|
public:
|
|
static cid id_class() {return _cid_std_vector<T>();}
|
|
virtual void* cast(cid a_class) const {
|
|
if(void* p = cmp_cast<std_vector_column>(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<T>::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<T>& 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<T>& 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<column_booking>& cols = a_bkg.columns();
|
|
std::vector<column_booking>::const_iterator it;
|
|
for(it=cols.begin();it!=cols.end();++it){
|
|
|
|
if((*it).cls_id()==_cid(char(0))) {
|
|
create_column<char>((*it).name());
|
|
} else if((*it).cls_id()==_cid(short(0))) {
|
|
create_column<short>((*it).name());
|
|
} else if((*it).cls_id()==_cid(int(0))) {
|
|
create_column<int>((*it).name());
|
|
} else if((*it).cls_id()==_cid(float(0))) {
|
|
create_column<float>((*it).name());
|
|
} else if((*it).cls_id()==_cid(double(0))) {
|
|
create_column<double>((*it).name());
|
|
} else if((*it).cls_id()==_cid(std::string())) {
|
|
create_column<std::string>((*it).name());
|
|
|
|
} else if((*it).cls_id()==_cid(byte(0))) {
|
|
create_column<byte>((*it).name());
|
|
} else if((*it).cls_id()==_cid((unsigned short)0)) {
|
|
create_column<unsigned short>((*it).name());
|
|
} else if((*it).cls_id()==_cid((unsigned int)0)) {
|
|
create_column<unsigned int>((*it).name());
|
|
} else if((*it).cls_id()==_cid(bool(true))) {
|
|
create_column<bool>((*it).name());
|
|
} else if((*it).cls_id()==_cid(uint64(0))) {
|
|
create_column<uint64>((*it).name());
|
|
|
|
#define TOOLS_WCSV_NTUPLE_CREATE_VEC_COL(a__type) \
|
|
} else if((*it).cls_id()==_cid_std_vector<a__type>()) {\
|
|
std::vector<a__type>* vec = (std::vector<a__type>*)(*it).user_obj();\
|
|
if(vec) {\
|
|
create_column<a__type>((*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<icol>(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<icol>(m_cols);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual ~ntuple() {
|
|
tools::clear<icol>(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<icol*>::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;count<m_cols.size();count++) {
|
|
icol* _col = m_cols[count];
|
|
std::string sid;
|
|
if(!cid2s(_col->id_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 <class T>
|
|
column<T>* create_column(const std::string& a_name,const T& a_def = T()) {
|
|
if(find_named<icol>(m_cols,a_name)) return 0;
|
|
column<T>* col = new column<T>(m_writer,a_name,a_def);
|
|
if(!col) return 0;
|
|
m_cols.push_back(col);
|
|
return col;
|
|
}
|
|
|
|
template <class T>
|
|
std_vector_column<T>* create_column(const std::string& a_name,std::vector<T>& a_user_vec) {
|
|
//NOTE : to optimize, we do not handle a default std::vector value logic.
|
|
if(find_named<icol>(m_cols,a_name)) return 0;
|
|
std_vector_column<T>* col = new std_vector_column<T>(m_writer,a_name,a_user_vec,m_vec_sep);
|
|
if(!col) return 0;
|
|
m_cols.push_back(col);
|
|
return col;
|
|
}
|
|
|
|
template <class T>
|
|
column<T>* find_column(const std::string& a_name) {
|
|
icol* col = find_named<icol>(m_cols,a_name);
|
|
if(!col) return 0;
|
|
return id_cast<icol, column<T> >(*col);
|
|
}
|
|
|
|
bool add_row() {
|
|
if(m_cols.empty()) return false;
|
|
std::vector<icol*>::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<icol*>& 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<icol*> m_cols;
|
|
};
|
|
|
|
}}
|
|
|
|
#endif
|