Files
geant4/source/externals/g4tools/include/tools/rcsv_ntuple
T
2022-07-01 10:44:02 +02:00

1117 lines
33 KiB
Plaintext

// 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 <istream>
#include <sstream>
#include "vfind"
#include "vmanip"
#include "words"
#include "snums"
#include "sto"
#include "s2time"
#include "chars"
#include "strip"
#include "cids"
#include "ntuple_binding"
#include "sout"
#include "num2s"
//#include "srep"
#ifdef TOOLS_MEM
#include "mem"
#endif
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<read::icol>(m_cols,a_name);
}
virtual const std::vector<read::icol*>& 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<ntuple&>(*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 T>
class column : public virtual read::icolumn<T> {
typedef read::icolumn<T> 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<column>(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<T>
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;
};
#ifdef TOOLS_MEM
public:
static const std::string& s_class() {
static const std::string s_v("tools::rcsv::ntuple");
return s_v;
}
#endif
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)
{
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
virtual ~ntuple() {
safe_clear<read::icol>(m_cols);
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
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)
{
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
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;}
/* use file::is_hippo for that.
static bool is_hippo(std::ostream& a_out,std::istream& a_reader) {
// analyse two first data line.
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::is_hippo :"
<< " stream is empty."
<< std::endl;
return false;
} //file empty.
std::string _title;
if(!read_line(a_reader,sz,_title)) return false;
std::string _s;
if(!read_line(a_reader,sz,_s)) return false;
if(_s.find('\t')==std::string::npos) return false;
//std::vector<std::string> labels;
//words(s,"\t",false,labels);
//return labels.size()?true:false;
return true;
}
*/
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<read::icol>(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<std::string> 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<std::string> 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<std::string>::iterator it;
for(it=ws.begin();it!=ws.end();++it,index++) {
if(a_verbose) a_out << "word " << sout(*it) << "" << std::endl;
/* with glast.tnt there is trailing \t that will induce an extra empty column.
if((*it).empty()) {
// do not accept :
// <num><sep><num><sep><sep><num>...
// but accept a trailing <sep> (glast.tnt) :
// <num><sep><num>....<sep><num><sep>
if(index==(ws.size()-1)) {
break;
} else {
a_out << "tools::rcsv::ntuple::initialize :"
<< " empty word."
<< std::endl;
safe_clear<read::icol>(m_cols);
m_sep = 0;
m_sz = 0;
m_rows = -1;
return false;
}
}
*/
std::string name = a_suffix;
if(!numas<uint64>(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<double>(*it,d)) {
if(a_verbose) a_out << "number " << d << std::endl;
create_column<double>(name);
} else {
time_t time;
if(s2time(*it,time)) {
create_column<csv_time>(name);
} else {
std::vector<double> v;
std::string vec_sep;vec_sep += m_vec_sep;
if(snums<double>(*it,vec_sep,v)&&v.size()) {
create_column< std::vector<double> >(name);
} else {
create_column<std::string>(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<a__type>::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<a__type> >::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<std::string>::id_class()) {
static const std::string s_v("string");
return s_v;
}
else if(a_id==column<csv_time>::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<std::string> >::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<read::icol*>::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<std::string,std::string> col_desc;
bool initialize(std::ostream& a_out,const ntuple_binding& a_bd = ntuple_binding()) {
// it assumes a "commented header".
safe_clear<read::icol>(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.
}
//if(a_verbose) a_out << "file size " << m_sz << std::endl;
std::string _title;
char _sep,_vec_sep;
std::vector<col_desc> _cols;
if(!read_commented_header(a_out,m_reader,_title,_sep,_vec_sep,_cols)) return false;
m_sep = _sep;
m_title = _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<a__type> >(name,a_bd.find_variable< std::vector<a__type> >(name));\
}
// see cid2s() for string types.
if(type=="char") create_column<char>(name,a_bd.find_variable<char>(name));
else if(type=="short") create_column<short>(name,a_bd.find_variable<short>(name));
else if(type=="int") create_column<int>(name,a_bd.find_variable<int>(name));
else if(type=="float") create_column<float>(name,a_bd.find_variable<float>(name));
else if(type=="double") create_column<double>(name,a_bd.find_variable<double>(name));
else if(type=="string") create_column<std::string>(name,a_bd.find_variable<std::string>(name));
else if(type=="uchar") create_column<unsigned char>(name,a_bd.find_variable<unsigned char>(name));
else if(type=="ushort") create_column<unsigned short>(name,a_bd.find_variable<unsigned short>(name));
else if(type=="uint") create_column<uint32>(name,a_bd.find_variable<uint32>(name)); //WARNING
else if(type=="bool") create_column<bool>(name,a_bd.find_variable<bool>(name));
else if(type=="int64") create_column<int64>(name,a_bd.find_variable<int64>(name));
else if(type=="uint64") create_column<uint64>(name,a_bd.find_variable<uint64>(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<std::string> >(name,a_bd.find_variable< std::vector<std::string> >(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<read::icol>(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;
return false;
}
//a_out << "tools::rroot::ntuple::initialize :"
// << " number of columns " << num << "."
// << std::endl;
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<col_desc> _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<col_desc>& 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<std::string> _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 false;
}
}
/*
a_out << "class " << _class << std::endl;
a_out << "title " << _title << std::endl;
a_out << "separator " << _separator << std::endl;
*/
return true;
}
protected:
template <class T>
column<T>* create_column(const std::string& a_name,T* a_user_var = 0){
if(find_named<read::icol>(m_cols,a_name)) return 0;
column<T>* col = new column<T>(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 <class T>
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;}
//std::cout << "debug : _read(double) " << a_v << std::endl;
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<std::string>&,
char a_sep,const std::string& a_vec_sep,
std::vector<std::string>& a_v) {
std::string _s;
if(!_read(a_reader,a_sz,a_sep,_s)) return false;
//replace(_s,"\\"+a_vec_sep,"@@");
words(_s,a_vec_sep,true,a_v);
//tools_vforit(std::string,a_v,it) replace(*it,"@@",a_vec_sep);
return true;
}
template <class T>
static bool _vec_read(std::istream& a_reader,std::streampos a_sz,
std::istringstream& a_iss,std::vector<std::string>& a_tmp,
char a_sep,const std::string& a_vec_sep,
std::vector<T>& a_v) {
std::string _s;
if(!_read(a_reader,a_sz,a_sep,_s)) return false;
if(!snums<T>(_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<char> col_char;
typedef ntuple::column<short> col_short;
typedef ntuple::column<int> col_int;
typedef ntuple::column<float> col_float;
typedef ntuple::column<double> col_double;
typedef std::string string_t;
typedef ntuple::column<string_t> col_string_t;
typedef ntuple::column<uchar> col_uchar;
typedef ntuple::column<ushort> col_ushort;
typedef ntuple::column<uint32> col_uint32;
typedef ntuple::column<bool> col_bool;
typedef ntuple::column<int64> col_int64;
typedef ntuple::column<uint64> col_uint64;
typedef ntuple::column<csv_time> col_time;
typedef ntuple::column< std::vector<char> > col_vec_char;
typedef ntuple::column< std::vector<short> > col_vec_short;
typedef ntuple::column< std::vector<int32> > col_vec_int;
typedef ntuple::column< std::vector<float> > col_vec_float;
typedef ntuple::column< std::vector<double> > col_vec_double;
typedef ntuple::column< std::vector<std::string> > col_vec_string_t;
typedef ntuple::column< std::vector<uchar> > col_vec_uchar;
typedef ntuple::column< std::vector<ushort> > col_vec_ushort;
typedef ntuple::column< std::vector<uint32> > col_vec_uint32;
typedef ntuple::column< std::vector<bool> > col_vec_bool;
typedef ntuple::column< std::vector<int64> > col_vec_int64;
typedef ntuple::column< std::vector<uint64> > col_vec_uint64;
std::string vec_sep;vec_sep += m_vec_sep;
std::istringstream iss;
std::vector<std::string> tmp;
size_t index = 0;
size_t num = m_cols.size();
std::vector<icol_t*>::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<icol_t,col_##a__type>(*(*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<icol_t,col_vec_##a__type>(*(*it))) {\
std::vector<a__type> 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<icol_t,col_time>(*(*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 {
//std::cout << "column cast failed." << std::endl;
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<read::icol*> m_cols;
std::streampos m_sz;
int m_rows; //to optimize number_of_entries().
bool m_hippo;
};
}}
#include <fstream>
namespace tools {
namespace rcsv {
class fntuple : public ntuple {
typedef ntuple parent;
public:
static const std::string& s_class() {
static const std::string s_v("tools::rcsv::fntuple");
return s_v;
}
public:
fntuple(const std::string& a_file)
:parent(m_freader)
,m_file(a_file)
{}
virtual ~fntuple() {m_freader.close();}
protected:
fntuple(const fntuple& a_from)
:read::intuple(a_from)
,parent(a_from)
,m_file(a_from.m_file)
{}
fntuple& operator=(const fntuple& a_from){
parent::operator=(a_from);
m_file = a_from.m_file;
return *this;
}
public:
bool open(){
m_freader.open(m_file.c_str());
return m_freader.fail()?false:true;
}
bool initialize(std::ostream& a_out,
char a_sep = 0, //guessed
const std::string& a_suffix = "x", //col suffix
bool a_verbose = false) {
if(!m_freader.is_open()) {
m_freader.open(m_file.c_str());
if(m_freader.fail()) {
a_out << "tools::rcsv::fntuple::initialize :"
<< " can't open " << m_file << "."
<< std::endl;
return false;
}
}
return parent::initialize(a_out,a_sep,a_suffix,a_verbose);
}
protected:
std::string m_file;
std::ifstream m_freader;
};
}}
#endif