2424
2525using namespace o2 ::conf;
2626
27+ bool isString (TDataMember const & dm)
28+ {
29+ return strcmp (dm.GetTrueTypeName (), " string" ) == 0 ;
30+ }
31+
2732// a generic looper of data members of a TClass; calling a callback
2833// reused in various functions below
2934void loopOverMembers (TClass* cl, void * obj,
@@ -33,6 +38,10 @@ void loopOverMembers(TClass* cl, void* obj,
3338 for (int i = 0 ; i < memberlist->GetEntries (); ++i) {
3439 auto dm = (TDataMember*)memberlist->At (i);
3540
41+ auto isValidComplex = [dm]() {
42+ return isString (*dm);
43+ };
44+
3645 // filter out static members for now
3746 if (dm->Property () & kIsStatic ) {
3847 continue ;
@@ -41,8 +50,8 @@ void loopOverMembers(TClass* cl, void* obj,
4150 LOG (WARNING) << " Pointer types not supported in ConfigurableParams" ;
4251 continue ;
4352 }
44- if (!dm->IsBasic ()) {
45- LOG (WARNING) << " Complex types not supported in ConfigurableParams" ;
53+ if (!dm->IsBasic () && ! isValidComplex () ) {
54+ LOG (WARNING) << " Generic complex types not supported in ConfigurableParams" ;
4655 continue ;
4756 }
4857 const auto dim = dm->GetArrayDim ();
@@ -69,15 +78,34 @@ std::string getName(const TDataMember* dm, int index, int size)
6978 return namestream.str ();
7079}
7180
81+ const char * asString (TDataMember const & dm, char * pointer)
82+ {
83+ // first check if this is a basic data type, in which case
84+ // we let ROOT do the work
85+ if (auto dt = dm.GetDataType ()) {
86+ return dt->AsString (pointer);
87+ }
88+
89+ // if data member is a std::string just return
90+ else if (isString (dm)) {
91+ return ((std::string*)pointer)->c_str ();
92+ }
93+ // potentially other cases to be added here
94+
95+ LOG (ERROR) << " COULD NOT REPRESENT AS STRING" ;
96+ return nullptr ;
97+ }
98+
7299void _ParamHelper::printParametersImpl (std::string mainkey, TClass* cl, void * obj,
73100 std::map<std::string, ConfigurableParam::EParamProvenance> const * provmap)
74101{
75102 auto printMembers = [&mainkey, obj, provmap](const TDataMember* dm, int index, int size) {
76103 // pointer to object
77104 auto dt = dm->GetDataType ();
78- char * pointer = ((char *)obj) + dm->GetOffset () + index * dt->Size ();
105+ auto TS = dt ? dt->Size () : 0 ;
106+ char * pointer = ((char *)obj) + dm->GetOffset () + index * TS;
79107 const auto name = getName (dm, index, size);
80- std::cout << name << " : " << dt-> AsString ( pointer);
108+ std::cout << name << " : " << asString (*dm, pointer);
81109 if (provmap != nullptr ) {
82110 auto iter = provmap->find (mainkey + " ." + name);
83111 if (iter != provmap->end ()) {
@@ -89,19 +117,84 @@ void _ParamHelper::printParametersImpl(std::string mainkey, TClass* cl, void* ob
89117 loopOverMembers (cl, obj, printMembers);
90118}
91119
120+ // a function converting a string representing a type to the type_info
121+ // because unfortunately typeid(double) != typeid("double")
122+ // but we can take the TDataType (if it exists) as a hint in order to
123+ // minimize string comparisons
124+ std::type_info const & nameToTypeInfo (const char * tname, TDataType const * dt)
125+ {
126+ if (dt) {
127+ switch (dt->GetType ()) {
128+ case kChar_t : {
129+ return typeid (char );
130+ }
131+ case kUChar_t : {
132+ return typeid (unsigned char );
133+ }
134+ case kShort_t : {
135+ return typeid (short );
136+ }
137+ case kUShort_t : {
138+ return typeid (unsigned short );
139+ }
140+ case kInt_t : {
141+ return typeid (int );
142+ }
143+ case kUInt_t : {
144+ return typeid (unsigned int );
145+ }
146+ case kLong_t : {
147+ return typeid (long );
148+ }
149+ case kULong_t : {
150+ return typeid (unsigned long );
151+ }
152+ case kFloat_t : {
153+ return typeid (float );
154+ }
155+ case kDouble_t : {
156+ return typeid (double );
157+ }
158+ case kDouble32_t : {
159+ return typeid (double );
160+ }
161+ case kBool_t : {
162+ return typeid (bool );
163+ }
164+ case kLong64_t : {
165+ return typeid (long long );
166+ }
167+ case kULong64_t : {
168+ return typeid (unsigned long long );
169+ }
170+ default : {
171+ break ;
172+ }
173+ }
174+ }
175+ // if we get here none of the above worked
176+ if (strcmp (tname, " string" ) == 0 || strcmp (tname, " std::string" )) {
177+ return typeid (std::string);
178+ }
179+ LOG (ERROR) << " ENCOUNTERED AN UNSUPPORTED TYPE " << tname << " IN A CONFIGURABLE PARAMETER" ;
180+ return typeid (" ERROR" );
181+ }
182+
92183void _ParamHelper::fillKeyValuesImpl (std::string mainkey, TClass* cl, void * obj, boost::property_tree::ptree* tree,
93- std::map<std::string, std::pair<int , void *>>* keytostoragemap)
184+ std::map<std::string, std::pair<std::type_info const & , void *>>* keytostoragemap)
94185{
95186 boost::property_tree::ptree localtree;
96187 auto fillMap = [obj, &mainkey, &localtree, &keytostoragemap](const TDataMember* dm, int index, int size) {
97188 const auto name = getName (dm, index, size);
98189 auto dt = dm->GetDataType ();
99- char * pointer = ((char *)obj) + dm->GetOffset () + index * dt->Size ();
100- localtree.put (name, dt->AsString (pointer));
190+ auto TS = dt ? dt->Size () : 0 ;
191+ char * pointer = ((char *)obj) + dm->GetOffset () + index * TS;
192+ localtree.put (name, asString (*dm, pointer));
101193
102194 auto key = mainkey + " ." + name;
103- using mapped_t = std::pair<int , void *>;
104- keytostoragemap->insert (std::pair<std::string, mapped_t >(key, mapped_t (dt->GetType (), pointer)));
195+ using mapped_t = std::pair<std::type_info const &, void *>;
196+ auto & ti = nameToTypeInfo (dm->GetTrueTypeName (), dt);
197+ keytostoragemap->insert (std::pair<std::string, mapped_t >(key, mapped_t (ti, pointer)));
105198 };
106199 loopOverMembers (cl, obj, fillMap);
107200 tree->add_child (mainkey, localtree);
@@ -124,16 +217,38 @@ void _ParamHelper::assignmentImpl(std::string mainkey, TClass* cl, void* to, voi
124217 auto assignifchanged = [to, from, &mainkey, provmap](const TDataMember* dm, int index, int size) {
125218 const auto name = getName (dm, index, size);
126219 auto dt = dm->GetDataType ();
127- char * pointerto = ((char *)to) + dm->GetOffset () + index * dt->Size ();
128- char * pointerfrom = ((char *)from) + dm->GetOffset () + index * dt->Size ();
129- if (!isMemblockDifferent (pointerto, pointerfrom, dt->Size ())) {
220+ auto TS = dt ? dt->Size () : 0 ;
221+ char * pointerto = ((char *)to) + dm->GetOffset () + index * TS;
222+ char * pointerfrom = ((char *)from) + dm->GetOffset () + index * TS;
223+
224+ // lambda to update the provenance
225+ auto updateProv = [&mainkey, name, provmap]() {
130226 auto key = mainkey + " ." + name;
131227 auto iter = provmap->find (key);
132228 if (iter != provmap->end ()) {
133229 iter->second = ConfigurableParam::EParamProvenance::kCCDB ; // TODO: change to "current STATE"??
134230 } else {
135231 LOG (WARN) << " KEY " << key << " NOT FOUND WHILE UPDATING PARAMETER PROVENANCE" ;
136232 }
233+ };
234+
235+ // TODO: this could dispatch to the same method used in ConfigurableParam::setValue
236+ // but will be slower
237+
238+ // test if a complicated case
239+ if (isString (*dm)) {
240+ std::string& target = *(std::string*)pointerto;
241+ std::string const & origin = *(std::string*)pointerfrom;
242+ if (target.compare (origin) != 0 ) {
243+ updateProv ();
244+ target = origin;
245+ }
246+ return ;
247+ }
248+
249+ //
250+ if (!isMemblockDifferent (pointerto, pointerfrom, TS)) {
251+ updateProv ();
137252 // actually copy
138253 std::memcpy (pointerto, pointerfrom, dt->Size ());
139254 }
0 commit comments