1717#include < optional>
1818#include < string>
1919#include < vector>
20+ #include < iostream>
2021
2122using namespace o2 ::framework::data_matcher;
2223
23- namespace o2
24- {
25- namespace framework
24+ namespace o2 ::framework
2625{
2726
2827enum QueryBuilderState {
@@ -42,7 +41,13 @@ enum QueryBuilderState {
4241 IN_END_QUERY,
4342 IN_STRING,
4443 IN_NUMBER,
45- IN_ERROR
44+ IN_ERROR,
45+ IN_BEGIN_ATTRIBUTES,
46+ IN_END_ATTRIBUTES,
47+ IN_BEGIN_KEY,
48+ IN_END_KEY,
49+ IN_BEGIN_VALUE,
50+ IN_END_VALUE
4651};
4752
4853std::vector<InputSpec> DataDescriptorQueryBuilder::parse (char const * config)
@@ -61,8 +66,11 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
6166 std::optional<std::string> currentBinding;
6267 std::optional<std::string> currentOrigin;
6368 std::optional<std::string> currentDescription;
69+ std::optional<std::string> currentKey;
70+ std::optional<std::string> currentValue;
6471 std::optional<header::DataHeader::SubSpecificationType> currentSubSpec;
6572 std::optional<uint64_t > currentTimeModulo;
73+ Lifetime currentLifetime = Lifetime::Timeframe;
6674 size_t currentNumber;
6775
6876 auto error = [&errorString, &states](std::string const & s) {
@@ -79,7 +87,7 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
7987 expectedSeparators = sep;
8088 };
8189
82- auto assignLastStringMatch = [&next, &cur, &error, &pushState, &nodes ](std::string const & what, size_t maxSize, std::optional<std::string>& s, QueryBuilderState nextState) {
90+ auto assignLastStringMatch = [&next, &cur, &error, &pushState](std::string const & what, int maxSize, std::optional<std::string>& s, QueryBuilderState nextState) {
8391 if ((next - cur == 0 ) || (next - cur > maxSize)) {
8492 error (what + " needs to be between 1 and " + std::to_string (maxSize) + " char long" );
8593 return false ;
@@ -95,7 +103,7 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
95103 return true ;
96104 };
97105
98- auto assignLastNumericMatch = [&next, &cur, &error, &pushState, ¤tNumber](std::string const & what , auto & value,
106+ auto assignLastNumericMatch = [&next, &cur, &error, &pushState, ¤tNumber](std::string const &, auto & value,
99107 QueryBuilderState nextState) {
100108 if ((next - cur == 0 )) {
101109 error (" number expected" );
@@ -112,7 +120,9 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
112120 return true ;
113121 };
114122
115- auto buildMatchingTree = [&nodes](std::string const & binding) -> InputSpec {
123+ std::vector<ConfigParamSpec> attributes;
124+
125+ auto buildMatchingTree = [&nodes](std::string const & binding, std::vector<ConfigParamSpec> attributes) -> InputSpec {
116126 auto lastMatcher =
117127 std::make_unique<DataDescriptorMatcher>(DataDescriptorMatcher::Op::Just,
118128 StartTimeValueMatcher (ContextRef{0 }));
@@ -124,7 +134,13 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
124134 assert (lastMatcher.get () == nullptr );
125135 lastMatcher = std::move (tmp);
126136 }
127- return InputSpec{binding, std::move (*lastMatcher.release ())};
137+ Lifetime lifetime = Lifetime::Timeframe;
138+ for (auto & attribute : attributes) {
139+ if (attribute.name == " lifetime" && attribute.defaultValue .get <std::string>() == " condition" ) {
140+ lifetime = Lifetime::Condition;
141+ }
142+ }
143+ return InputSpec{binding, std::move (*lastMatcher.release ()), lifetime, attributes};
128144 };
129145
130146 while (states.empty () == false ) {
@@ -151,6 +167,7 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
151167 } break ;
152168 case IN_BEGIN_MATCHER: {
153169 nodes.clear ();
170+ attributes.clear ();
154171 pushState (IN_BEGIN_BINDING);
155172 } break ;
156173 case IN_BEGIN_BINDING: {
@@ -174,34 +191,58 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
174191 } break ;
175192 case IN_BEGIN_ORIGIN: {
176193 pushState (IN_END_ORIGIN);
177- token (IN_STRING, " /;" );
194+ token (IN_STRING, " /;? " );
178195 } break ;
179196 case IN_END_ORIGIN: {
180- if (assignLastStringMatch (" origin" , 4 , currentOrigin, IN_BEGIN_DESCRIPTION)) {
197+ if (*next == ' /' && assignLastStringMatch (" origin" , 4 , currentOrigin, IN_BEGIN_DESCRIPTION)) {
198+ nodes.push_back (OriginValueMatcher{*currentOrigin});
199+ } else if (*next == ' ;' && assignLastStringMatch (" origin" , 4 , currentOrigin, IN_END_MATCHER)) {
181200 nodes.push_back (OriginValueMatcher{*currentOrigin});
201+ } else if (*next == ' ?' && assignLastStringMatch (" origin" , 4 , currentOrigin, IN_BEGIN_ATTRIBUTES)) {
202+ nodes.push_back (OriginValueMatcher{*currentOrigin});
203+ } else if (*next == ' \0 ' && assignLastStringMatch (" origin" , 4 , currentOrigin, IN_END_MATCHER)) {
204+ nodes.push_back (OriginValueMatcher{*currentOrigin});
205+ } else {
206+ error (" origin needs to be between 1 and 4 char long" );
182207 }
183208 } break ;
184209 case IN_BEGIN_DESCRIPTION: {
185210 pushState (IN_END_DESCRIPTION);
186- token (IN_STRING, " /;" );
211+ token (IN_STRING, " /;? " );
187212 } break ;
188213 case IN_END_DESCRIPTION: {
189- if (assignLastStringMatch (" description" , 16 , currentDescription, IN_BEGIN_SUBSPEC)) {
214+ if (*next == ' / ' && assignLastStringMatch (" description" , 16 , currentDescription, IN_BEGIN_SUBSPEC)) {
190215 nodes.push_back (DescriptionValueMatcher{*currentDescription});
216+ } else if (*next == ' ;' && assignLastStringMatch (" description" , 16 , currentDescription, IN_END_MATCHER)) {
217+ nodes.push_back (DescriptionValueMatcher{*currentDescription});
218+ } else if (*next == ' ?' && assignLastStringMatch (" description" , 16 , currentDescription, IN_BEGIN_ATTRIBUTES)) {
219+ nodes.push_back (DescriptionValueMatcher{*currentDescription});
220+ } else if (*next == ' \0 ' && assignLastStringMatch (" description" , 16 , currentDescription, IN_BEGIN_ATTRIBUTES)) {
221+ nodes.push_back (DescriptionValueMatcher{*currentDescription});
222+ } else {
223+ error (" description needs to be between 1 and 16 char long" );
191224 }
192225 } break ;
193226 case IN_BEGIN_SUBSPEC: {
194227 pushState (IN_END_SUBSPEC);
195- token (IN_NUMBER, " ;%" );
228+ token (IN_NUMBER, " ;%? " );
196229 } break ;
197230 case IN_END_SUBSPEC: {
198- if (assignLastNumericMatch (" subspec" , currentSubSpec, IN_BEGIN_TIMEMODULO)) {
231+ if (*next == ' %' && assignLastNumericMatch (" subspec" , currentSubSpec, IN_BEGIN_TIMEMODULO)) {
232+ nodes.push_back (SubSpecificationTypeValueMatcher{*currentSubSpec});
233+ } else if (*next == ' ?' && assignLastNumericMatch (" subspec" , currentSubSpec, IN_BEGIN_ATTRIBUTES)) {
234+ nodes.push_back (SubSpecificationTypeValueMatcher{*currentSubSpec});
235+ } else if (*next == ' ;' && assignLastNumericMatch (" subspec" , currentSubSpec, IN_END_MATCHER)) {
236+ nodes.push_back (SubSpecificationTypeValueMatcher{*currentSubSpec});
237+ } else if (*next == ' \0 ' && assignLastNumericMatch (" subspec" , currentSubSpec, IN_END_MATCHER)) {
199238 nodes.push_back (SubSpecificationTypeValueMatcher{*currentSubSpec});
239+ } else {
240+ error (" Expected a number" );
200241 }
201242 } break ;
202243 case IN_BEGIN_TIMEMODULO: {
203244 pushState (IN_END_TIMEMODULO);
204- token (IN_NUMBER, " ;" );
245+ token (IN_NUMBER, " ;? " );
205246 } break ;
206247 case IN_END_TIMEMODULO: {
207248 assignLastNumericMatch (" timemodulo" , currentTimeModulo, IN_ERROR);
@@ -211,16 +252,62 @@ std::vector<InputSpec> DataDescriptorQueryBuilder::parse(char const* config)
211252 error (" Remove trailing ;" );
212253 continue ;
213254 }
214- result.push_back (buildMatchingTree (*currentBinding));
255+ result.push_back (buildMatchingTree (*currentBinding, attributes ));
215256 if (*cur == ' \0 ' ) {
216257 pushState (IN_END_QUERY);
217258 } else if (*cur == ' ;' ) {
218259 cur += 1 ;
219260 pushState (IN_BEGIN_MATCHER);
220261 } else {
221- error (" Unexpected character" + std::string (cur, 1 ));
262+ error (" Unexpected character " + std::string (cur, 1 ));
263+ }
264+ } break ;
265+ case IN_BEGIN_ATTRIBUTES: {
266+ pushState (IN_BEGIN_KEY);
267+ } break ;
268+ case IN_BEGIN_KEY: {
269+ pushState (IN_END_KEY);
270+ token (IN_STRING, " =" );
271+ } break ;
272+ case IN_END_KEY: {
273+ if (*next == ' =' ) {
274+ assignLastStringMatch (" key" , 1000 , currentKey, IN_BEGIN_VALUE);
275+ } else {
276+ error (" missing value for attribute key" );
222277 }
223278 } break ;
279+ case IN_BEGIN_VALUE: {
280+ pushState (IN_END_VALUE);
281+ token (IN_STRING, " &;" );
282+ } break ;
283+ case IN_END_VALUE: {
284+ if (*next == ' &' ) {
285+ assignLastStringMatch (" value" , 1000 , currentValue, IN_END_VALUE);
286+ if (*currentKey == " lifetime" && currentValue == " condition" ) {
287+ currentLifetime = Lifetime::Condition;
288+ }
289+ attributes.push_back (ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}});
290+ }
291+ if (*next == ' ;' ) {
292+ assignLastStringMatch (" value" , 1000 , currentValue, IN_END_ATTRIBUTES);
293+ if (*currentKey == " lifetime" && currentValue == " condition" ) {
294+ currentLifetime = Lifetime::Condition;
295+ }
296+ attributes.push_back (ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}});
297+ }
298+ if (*next == ' \0 ' ) {
299+ assignLastStringMatch (" value" , 1000 , currentValue, IN_END_ATTRIBUTES);
300+ if (*currentKey == " lifetime" && currentValue == " condition" ) {
301+ currentLifetime = Lifetime::Condition;
302+ }
303+ attributes.push_back (ConfigParamSpec{*currentKey, VariantType::String, *currentValue, {}});
304+ } else {
305+ error (" missing value for string value" );
306+ }
307+ } break ;
308+ case IN_END_ATTRIBUTES: {
309+ pushState (IN_END_MATCHER);
310+ } break ;
224311 case IN_ERROR: {
225312 throw std::runtime_error (" Parse error: " + errorString);
226313 } break ;
@@ -336,5 +423,4 @@ std::smatch DataDescriptorQueryBuilder::getTokens(std::string const& nodeString)
336423 return m;
337424}
338425
339- } // namespace framework
340- } // namespace o2
426+ } // namespace o2::framework
0 commit comments