#ifndef JSON_HH_INCLUDED #define JSON_HH_INCLUDED #include "foreach.hh" #include "stringutil.hh" #include "Table.hh" #include "TObject.h" #include "TMemberInspector.h" #include "TDataMember.h" #include "TClass.h" #include "TDataType.h" #include "TTimeStamp.h" #include #include #include #include #include "Vec.hh" #include "Hit.hh" #include "Trk.hh" #include "Det.hh" #include "Mat.hh" #include using stringutil::quote; using stringutil::split; using stringutil::exec; struct JsonDumper { virtual string field_sep() {return ", \n"+indent;} virtual string keyval_sep() {return ": ";} virtual string obj_brace1() {indent += " "; return "{\n"+indent;} virtual string obj_brace2() { int newsize = indent.length()-4; if (newsize<0) newsize = 0; indent.resize(newsize); return "}"; } virtual string lst_brace1() {return "[";} virtual string lst_brace2() {return "]";} virtual string str_quote() {return "\"";} virtual ~JsonDumper() {} string indent; vector veto_names; //dox: names of members to be be ignored in tobject output JsonDumper () : indent("") {} string operator()(int d) { return str(d); } string operator()(unsigned int d) { return str(d); } string operator()(long int d) { return str(d); } string operator()(ULong64_t d) { return str(d); } string operator()(double d) { if (std::isinf(d) || std::isnan(abs(d))) return operator()( str(d) ); // treat as string: add quotes // for hit (and track) times, the standard precission of 6 is not enough. stringstream stream; stream << setprecision(9) << d ; return stream.str(); } string operator()(float d) { if (std::isinf(d) || std::isnan(abs(d))) return operator()( str(d) ); // treat as string: add quotes return str(d); } string operator()(const string& s) { return str_quote() + s + str_quote(); } string operator()(const Vec& v) // alternative, compact formatting { string fs = ", "; return "{ \"x\""+keyval_sep()+str(v.x)+fs + "\"y\""+keyval_sep()+str(v.y)+fs + "\"z\""+keyval_sep()+str(v.z) + "}"; } template string operator()( const string& key, const T& value , bool last = false ) { if (last) return operator()(key) + keyval_sep()+ operator()( value ); else return operator()(key) + keyval_sep()+ operator()( value )+field_sep() ; } template< typename T> string operator()( const std::vector & v ) { if (v.size() == 0 ) return lst_brace1()+lst_brace2(); string r = lst_brace1(); enumerate(i,elem,v) { if (i) r += field_sep(); r += operator()(elem); } r+=lst_brace2(); return r; } template string operator()( const std::map& m) { if ( m.size() == 0 ) { return "{}" ;} string r = obj_brace1(); bool first = true; foreach_map( k, v, m ) { if (first ) first = false; else r += field_sep(); r += operator()( str(k )); // keys must be strings in json r += keyval_sep(); r += operator()(v); } return r+obj_brace2(); } struct _TDump : public TMemberInspector { JsonDumper& self; string _str; bool first; const vector* veto_names; _TDump(JsonDumper& d): self(d), _str( d.obj_brace1() ), first(true), veto_names(0) {} void Inspect(TClass *cl, const char *pname, const char *mname, const void *addr) { TDataMember *member = cl->GetDataMember(mname); if (!member ) return; if (string(pname)!="") return; string type = member->GetFullTypeName(); string field = mname; if ( veto_names && contains( *veto_names, field ) ) { // skip this member return; } if ( field == "fUniqueID" || field == "fBits" || field == "isDefined_") return; // not interested string value = "\"\""; if (getenv("AADBGJSON")) { print ( type, field, member->IsBasic(), member->IsSTLContainer() ); } if ( member->IsBasic() ) { value = member->GetDataType()->AsString( (void*) addr ); } // for some reason, on some machines, I have trouble with Ulong64_t // using the above method... try following workaround if ( type == "ULong64_t" ) { ostringstream ss; ss << *((ULong64_t*) addr); value = ss.str(); } if ( member->IsSTLContainer() ) { if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "map") value = self( * (std::map*) addr ); } if ( type == "Vec" ) value = self( * (Vec*) addr ); if ( type == "string" ) value = ( self( * (string*) addr ) ); if ( type == "TString" ) value = ( self( ((TString*)addr)->Data() ) ); if ( type == "TTimeStamp" ) value = ( self ( ((TTimeStamp*)addr)->AsString() )); if ( !first) _str+= self.field_sep(); _str += quote(field) + self.keyval_sep() + value; first = false; } string str() { _str += self.obj_brace2(); return _str; } }; string operator()(const Hit& hit ) { return obj_brace1() + operator() ( "id", hit.id )+ operator() ( "channel_id", int(hit.channel_id) )+ operator() ( "tdc" , hit.tdc )+ operator() ( "tot" , hit.tot )+ operator() ( "trig" , hit.trig )+ operator() ( "pmt_id" , hit.pmt_id )+ operator() ( "t" , hit.t )+ operator() ( "a" , hit.a )+ operator() ( "pos" , hit.pos )+ operator() ( "dir" , hit.dir )+ // operator() ( "pure_t" , hit.pure_t )+ // operator() ( "pure_a" , hit.pure_a )+ operator() ( "type" , hit.type )+ operator() ( "origin" , hit.origin )+ operator() ( "pattern_flags" , hit.pattern_flags , true ) + obj_brace2(); } string operator()(const TObject& obj ) { _TDump d(*this); d.veto_names = &veto_names; (const_cast(obj)).ShowMembers(d); return d.str(); } }; struct CompactJsonDumper : public JsonDumper { virtual string field_sep() {return ", ";} virtual string obj_brace1() {return "{ ";} virtual string obj_brace2() {return "} ";} }; struct Dumper { Table table; Dumper () : table( split("type name value comment") ) {} void record( string type, string name , string value, string comment ) { table << type << name << value << comment; } string operator()(int d) { return str(d); } string operator()(double d) { return str(d); } string operator()(const string& s) { return s; } string operator()(const Vec& v) { string fs = ", "; return str(v.x)+fs+ str(v.y)+fs+ str(v.z); } template< typename T> string operator()( const std::vector & v ) { return str( v.size() )+" entries"; } template string operator()( const std::map& m) { return str( m.size() )+" entries"; } struct _TDump : public TMemberInspector { Dumper& self; string _str; bool first; const vector* veto_names; _TDump(Dumper& d): self(d), first(true) {} void Inspect(TClass *cl, const char *pname, const char *mname, const void *addr) { TDataMember *member = cl->GetDataMember(mname); if (!member ) return; if (string(pname)!="") return; string type = member->GetFullTypeName(); string field = mname; string comment = member->GetTitle(); if ( field == "fUniqueID" || field == "fBits" || field == "isDefined_") return; // not interested if ( veto_names && contains( *veto_names, field )) return; string value = "\"\""; if ( member->IsBasic() ) { value = self( member->GetDataType()->AsString( (void*) addr ) ); } if ( member->IsSTLContainer() ) { if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "vector" ) value = self( * (std::vector*) addr ); if ( type == "map") value = self( * (std::map*) addr ); } if ( type == "Vec" ) value = self( * (Vec*) addr ); if ( type == "string" ) value = quote ( self( * (string*) addr ) ); if ( type == "TString" ) value = quote ( self( ((TString*)addr)->Data() ) ); if ( type == "TTimeStamp" ) value = quote( self ( ((TTimeStamp*)addr)->AsString("s") )); // s= compact self.record( type, field, value, replace_all(comment,"dox: ","") ); } }; /*! convert the object to json. Members who's name occurs in veto_names will be omitted */ string operator()(const TObject& obj, const vector& veto_names = {} ) { table.resize(1); // just keep header row _TDump d(*this); d.veto_names = &veto_names; (const_cast(obj)).ShowMembers(d); return table.str(); } }; struct StdoutDumper : public Dumper { void operator() (const TObject& obj ) { cout << Dumper::operator()(obj) << endl; } }; //--------------------------------------------------------- inline void write_aa3d( Evt& evt, Det& det, string directory = "~/www/aa3d/", string detevtfilename = "detevt.js.gz", string javascript = "" , bool verbose = true, bool copy_files = true, bool copy_index = true ) { if (!getenv("AADIR")) { cout << " cannot write aa3d event display : AADIR not set" << endl; return; } string dr = string(getenv("AADIR"))+"/aa3d/"; if ( copy_files ) { if (verbose) print ("copying event display web application to "+directory); exec( "mkdir "+directory ); exec( "cp -r "+dr+"*.js "+dr+"aa3d.html "+dr+"libs "+dr+"textures "+directory ); if (copy_index) exec( "cp index.html " +directory ); } string fn = detevtfilename; bool zip = false; if ( Filedesc(fn).ext == "gz" ) { fn = Filedesc(fn).chopext(); zip = true; } if (verbose) print ("writing json event and detector to "+directory+fn); ofstream f ( (directory + "/" + fn).c_str() ); JsonDumper j; f << "det =" << j(det) << ";" << endl; f << "evt =" << j(evt) << ";" << endl; f << javascript << endl; f.close(); if (zip) { if (verbose) print("gzipping det+evt file."); exec ("gzip -f "+ directory+"/"+fn); } if (verbose) { print ("=========================================================="); print (" Event Display Ready!"); print (" Point your browser to " + directory +"/?f="+detevtfilename); print ("=========================================================="); } } extern JsonDumper jsons; //extern Dumper dumps; // dumps to string //extern StdoutDumper dump; // dumps to stdout #endif