Project
Loading...
Searching...
No Matches
RootConfigParamHelpers.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16#include <TClass.h>
17#include <TDataMember.h>
18#include <TDataType.h>
19#include <TEnum.h>
20#include <TEnumConstant.h>
21#include <TIterator.h>
22#include <TList.h>
23#include <iostream>
24#include <sstream>
25#include <boost/property_tree/ptree.hpp>
26#include <functional>
27
28using namespace o2::framework;
29
30namespace
31{
32bool isString(TDataMember const& dm)
33{
34 return strcmp(dm.GetTrueTypeName(), "string") == 0;
35}
36
37// a generic looper of data members of a TClass; calling a callback
38// reused in various functions below
39void loopOverMembers(TClass* cl, void* obj,
40 std::function<void(TDataMember*, int, int)>&& callback)
41{
42 auto* memberlist = cl->GetListOfDataMembers();
43 for (int i = 0; i < memberlist->GetEntries(); ++i) {
44 auto* dm = (TDataMember*)memberlist->At(i);
45
46 auto isValidComplex = [dm]() {
47 auto typehash = runtime_hash(dm->GetTypeName());
48 return isString(*dm) || dm->IsEnum() || dm->IsSTLContainer() ||
49 (typehash == compile_time_hash("o2::framework::Array2D<int>")) ||
50 (typehash == compile_time_hash("o2::framework::Array2D<float>")) ||
51 (typehash == compile_time_hash("o2::framework::Array2D<double>"));
52 };
53
54 // filter out static members for now
55 if (dm->Property() & kIsStatic) {
56 continue;
57 }
58
59 if (dm->IsaPointer()) {
60 continue;
61 }
62 if (!dm->IsBasic() && !isValidComplex()) {
63 continue;
64 }
65
66 const auto dim = dm->GetArrayDim();
67 // we support very simple vectored data in 1D for now
68 if (dim > 1) {
69 continue;
70 }
71
72 const auto size = (dim == 1) ? dm->GetMaxIndex(dim - 1) : 1; // size of array (1 if scalar)
73 for (int index = 0; index < size; ++index) {
74 callback(dm, index, size);
75 }
76 }
77}
78
79// construct name (in dependence on vector or scalar data and index)
80std::string getName(const TDataMember* dm, int index, int size)
81{
82 std::stringstream namestream;
83 namestream << dm->GetName();
84 if (size > 1) {
85 namestream << "[" << index << "]";
86 }
87 return namestream.str();
88}
89
90void ptreeToMember(boost::property_tree::ptree const& value,
91 char const* tname,
92 TDataMember* dm,
93 void* ptr)
94{
95 auto typehash = runtime_hash(dm->GetTypeName());
96 if (dm->IsSTLContainer()) {
97 switch (typehash) {
98 case compile_time_hash("vector<int>"):
99 *static_cast<std::vector<int>*>(ptr) = vectorFromBranch<int>(value);
100 return;
101 case compile_time_hash("vector<float>"):
102 *static_cast<std::vector<float>*>(ptr) = vectorFromBranch<float>(value);
103 return;
104 case compile_time_hash("vector<double>"):
105 *static_cast<std::vector<double>*>(ptr) = vectorFromBranch<double>(value);
106 return;
107 case compile_time_hash("vector<bool>"):
108 throw std::runtime_error("Bool arrays are not implemented yet");
109 case compile_time_hash("vector<std::string>"):
110 case compile_time_hash("vector<string>"):
111 *static_cast<std::vector<std::string>*>(ptr) = vectorFromBranch<std::string>(value);
112 return;
113 default:
114 throw std::runtime_error("Not an int/float/double/bool vector");
115 }
116 } else {
117 switch (typehash) {
118 case compile_time_hash("o2::framework::Array2D<int>"):
119 *static_cast<Array2D<int>*>(ptr) = array2DFromBranch<int>(value);
120 return;
121 case compile_time_hash("o2::framework::Array2D<float>"):
122 *static_cast<Array2D<float>*>(ptr) = array2DFromBranch<float>(value);
123 return;
124 case compile_time_hash("o2::framework::Array2D<double>"):
125 *static_cast<Array2D<double>*>(ptr) = array2DFromBranch<double>(value);
126 return;
127 }
128 }
129 auto* dt = dm->GetDataType();
130 if (dt != nullptr) {
131 switch (dt->GetType()) {
132 case kChar_t: {
133 *(char*)ptr = value.get_value<char>();
134 return;
135 }
136 case kUChar_t: {
137 *(unsigned char*)ptr = value.get_value<unsigned char>();
138 return;
139 }
140 case kShort_t: {
141 *(short*)ptr = value.get_value<short>();
142 return;
143 }
144 case kUShort_t: {
145 *(unsigned short*)ptr = value.get_value<unsigned short>();
146 return;
147 }
148 case kInt_t: {
149 *(int*)ptr = value.get_value<int>();
150 return;
151 }
152 case kUInt_t: {
153 *(unsigned int*)ptr = value.get_value<unsigned int>();
154 return;
155 }
156 case kLong_t: {
157 *(long*)ptr = value.get_value<long>();
158 return;
159 }
160 case kULong_t: {
161 *(unsigned long*)ptr = value.get_value<unsigned long>();
162 return;
163 }
164 case kFloat_t: {
165 *(float*)ptr = value.get_value<float>();
166 return;
167 }
168 case kDouble_t:
169 case kDouble32_t: {
170 *(double*)ptr = value.get_value<double>();
171 return;
172 }
173 case kBool_t: {
174 *(bool*)ptr = value.get_value<bool>();
175 return;
176 }
177 case kLong64_t: {
178 *(int64_t*)ptr = value.get_value<int64_t>();
179 return;
180 }
181 case kULong64_t: {
182 *(uint64_t*)ptr = value.get_value<uint64_t>();
183 return;
184 }
185 default: {
186 break;
187 }
188 }
189 }
190 // if we get here none of the above worked
191 if (strcmp(tname, "string") == 0 || strcmp(tname, "std::string") == 0) {
192 *(std::string*)ptr = value.get_value<std::string>();
193 }
194 throw std::runtime_error("Unable to override value");
195}
196
197// Convert a DataMember to a ConfigParamSpec
198ConfigParamSpec memberToConfigParamSpec(const char* tname, TDataMember* dm, void* ptr)
199{
200 auto typehash = runtime_hash(dm->GetTypeName());
201 if (dm->IsSTLContainer()) {
202 switch (typehash) {
203 case compile_time_hash("vector<int>"):
204 return ConfigParamSpec{tname, VariantType::ArrayInt, *static_cast<std::vector<int>*>(ptr), {"No help"}};
205 case compile_time_hash("vector<float>"):
206 return ConfigParamSpec{tname, VariantType::ArrayFloat, *static_cast<std::vector<float>*>(ptr), {"No help"}};
207 case compile_time_hash("vector<double>"):
208 return ConfigParamSpec{tname, VariantType::ArrayDouble, *static_cast<std::vector<double>*>(ptr), {"No help"}};
209 case compile_time_hash("vector<bool>"):
210 throw std::runtime_error("bool vector not supported yet");
211 // return ConfigParamSpec{tname, VariantType::ArrayBool, *static_cast<std::vector<bool>*>(ptr), {"No help"}};
212 case compile_time_hash("vector<std::string>"):
213 case compile_time_hash("vector<string>"):
214 return ConfigParamSpec{tname, VariantType::ArrayString, *static_cast<std::vector<std::string>*>(ptr), {"No help"}};
215 default:
216 throw std::runtime_error("Not an int/float/double/bool vector");
217 }
218 } else {
219 switch (typehash) {
220 case compile_time_hash("o2::framework::Array2D<int>"):
221 return ConfigParamSpec{tname, VariantType::Array2DInt, *static_cast<Array2D<int>*>(ptr), {"No help"}};
222 case compile_time_hash("o2::framework::Array2D<float>"):
223 return ConfigParamSpec{tname, VariantType::Array2DFloat, *static_cast<Array2D<float>*>(ptr), {"No help"}};
224 case compile_time_hash("o2::framework::Array2D<double>"):
225 return ConfigParamSpec{tname, VariantType::Array2DDouble, *static_cast<Array2D<double>*>(ptr), {"No help"}};
226 }
227 }
228 auto* dt = dm->GetDataType();
229 if (dt != nullptr) {
230 switch (dt->GetType()) {
231 case kChar_t: {
232 return ConfigParamSpec{tname, VariantType::Int8, *(char*)ptr, {"No help"}};
233 }
234 case kUChar_t: {
235 return ConfigParamSpec{tname, VariantType::UInt8, *(unsigned char*)ptr, {"No help"}};
236 }
237 case kShort_t: {
238 return ConfigParamSpec{tname, VariantType::Int16, *(short*)ptr, {"No help"}};
239 }
240 case kUShort_t: {
241 return ConfigParamSpec{tname, VariantType::UInt16, *(unsigned short*)ptr, {"No help"}};
242 }
243 case kInt_t: {
244 return ConfigParamSpec{tname, VariantType::Int, *(int*)ptr, {"No help"}};
245 }
246 case kUInt_t: {
247 return ConfigParamSpec{tname, VariantType::UInt32, *(unsigned int*)ptr, {"No help"}};
248 }
249 case kLong_t: {
250 return ConfigParamSpec{tname, VariantType::Int64, *(long*)ptr, {"No help"}};
251 }
252 case kULong_t: {
253 return ConfigParamSpec{tname, VariantType::UInt64, *(unsigned long*)ptr, {"No help"}};
254 }
255 case kFloat_t: {
256 return ConfigParamSpec{tname, VariantType::Float, *(float*)ptr, {"No help"}};
257 }
258 case kDouble_t:
259 case kDouble32_t: {
260 return ConfigParamSpec{tname, VariantType::Double, *(double*)ptr, {"No help"}};
261 }
262 case kBool_t: {
263 return ConfigParamSpec{tname, VariantType::Bool, *(bool*)ptr, {"No help"}};
264 }
265 case kLong64_t: {
266 return ConfigParamSpec{tname, VariantType::Int64, *(int64_t*)ptr, {"No help"}};
267 }
268 case kULong64_t: {
269 return ConfigParamSpec{tname, VariantType::UInt64, *(uint64_t*)ptr, {"No help"}};
270 }
271 default: {
272 break;
273 }
274 }
275 }
276 // if we get here none of the above worked
277 if (strcmp(tname, "string") == 0 || strcmp(tname, "std::string") == 0) {
278 return ConfigParamSpec{tname, VariantType::String, *(std::string*)ptr, {"No help"}};
279 }
280 throw std::runtime_error("Cannot use " + std::string(tname));
281}
282} // namespace
283
284namespace o2::framework
285{
286
287std::vector<ConfigParamSpec>
288 RootConfigParamHelpers::asConfigParamSpecsImpl(std::string const& mainKey, TClass* cl, void* obj)
289{
290 std::vector<ConfigParamSpec> specs;
291
292 auto toDataMember = [&mainKey, &specs, obj](TDataMember* dm, int index, int size) {
293 auto* dt = dm->GetDataType();
294 auto TS = dt != nullptr ? dt->Size() : 0;
295 char* ptr = ((char*)obj) + dm->GetOffset() + index * TS;
296 const std::string name = mainKey + "." + getName(dm, index, size);
297
298 specs.push_back(memberToConfigParamSpec(name.c_str(), dm, ptr));
299 };
300
301 loopOverMembers(cl, obj, toDataMember);
302 return specs;
303}
304
307void RootConfigParamHelpers::fillFromPtree(TClass* cl, void* obj, boost::property_tree::ptree const& pt)
308{
309 auto toDataMember = [obj, &pt](TDataMember* dm, int index, int size) {
310 auto* dt = dm->GetDataType();
311 auto TS = dt != nullptr ? dt->Size() : 0;
312 char* ptr = ((char*)obj) + dm->GetOffset() + index * TS;
313 const std::string name = getName(dm, index, size);
314 auto it = pt.get_child_optional(name);
315 if (!it) {
316 return;
317 }
318 ptreeToMember(*it, dm->GetTrueTypeName(), dm, ptr);
319 };
320
321 loopOverMembers(cl, obj, toDataMember);
322}
323
324} // namespace o2::framework
void loopOverMembers(TClass *cl, void *obj, std::function< void(const TDataMember *, int, int)> &&callback)
std::string getName(const TDataMember *dm, int index, int size)
bool isString(TDataMember const &dm)
int32_t i
constexpr uint32_t runtime_hash(char const *str)
consteval uint32_t compile_time_hash(char const *str)
TBranch * ptr
GLsizei const GLchar *const * string
Definition glcorearb.h:809
GLsizeiptr size
Definition glcorearb.h:659
GLuint index
Definition glcorearb.h:781
GLuint const GLchar * name
Definition glcorearb.h:781
GLsizei const GLfloat * value
Definition glcorearb.h:819
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
RuntimeErrorRef runtime_error(const char *)
Array2D< T > array2DFromBranch(boost::property_tree::ptree const &ptree)
std::vector< T > vectorFromBranch(boost::property_tree::ptree const &branch)
std::vector< T, o2::pmr::polymorphic_allocator< T > > vector
return(kp2 - aa - bb) *kp1/aa
Defining DataPointCompositeObject explicitly as copiable.
static std::vector< ConfigParamSpec > asConfigParamSpecsImpl(std::string const &mainkey, TClass *cl, void *obj)
static void fillFromPtree(TClass *cl, void *obj, boost::property_tree::ptree const &pt)