#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::exec; using stringutil::quote; using stringutil::split; 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 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(); int dim = member->GetArrayDim(); 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() && dim == 0 ) { 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 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