Skip to content

Commit a051543

Browse files
committed
DPL: add initial facility for complex queries on DataHeader
This introduces a facility to do complex queries with a given DataHeader, e.g. leave one of the fields undetermined or pick only certain combinations. At the moment this is just a helper class, but it is one of the requirements to have more flexibility in the `InputSpec` definition and possibly in other ancillary tasks. The query itself is expressed in terms of a query tree, see the example test_DataDescriptorMatcher.cxx for more details.
1 parent 8abb483 commit a051543

File tree

3 files changed

+267
-0
lines changed

3 files changed

+267
-0
lines changed

Framework/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ set(TEST_SRCS
210210
test/test_DanglingInputs.cxx
211211
test/test_DanglingOutputs.cxx
212212
test/test_DataAllocator.cxx
213+
test/test_DataDescriptorMatcher.cxx
213214
test/test_DataProcessorSpec.cxx
214215
test/test_DataRefUtils.cxx
215216
test/test_DataRelayer.cxx
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
#ifndef o2_framework_DataDescriptorMatcher_H_INCLUDED
11+
#define o2_framework_DataDescriptorMatcher_H_INCLUDED
12+
13+
#include "Headers/DataHeader.h"
14+
15+
#include <cstdint>
16+
#include <string>
17+
#include <variant>
18+
19+
namespace o2
20+
{
21+
namespace framework
22+
{
23+
24+
/// Something which can be matched against a header::DataOrigin
25+
class OriginValueMatcher
26+
{
27+
public:
28+
OriginValueMatcher(std::string const& s)
29+
: mValue{ s }
30+
{
31+
}
32+
33+
bool match(header::DataHeader const& header) const
34+
{
35+
return strncmp(header.dataOrigin.str, mValue.c_str(), 4) == 0;
36+
}
37+
38+
private:
39+
std::string mValue;
40+
};
41+
42+
/// Something which can be matched against a header::DataDescription
43+
class DescriptionValueMatcher
44+
{
45+
public:
46+
DescriptionValueMatcher(std::string const& s)
47+
: mValue{ s }
48+
{
49+
}
50+
51+
bool match(header::DataHeader const& header) const
52+
{
53+
return strncmp(header.dataDescription.str, mValue.c_str(), 8) == 0;
54+
}
55+
56+
private:
57+
std::string mValue;
58+
};
59+
60+
/// Something which can be matched against a header::SubSpecificationType
61+
class SubSpecificationTypeValueMatcher
62+
{
63+
public:
64+
/// The passed string @a s is the expected numerical value for
65+
/// the SubSpecification type.
66+
SubSpecificationTypeValueMatcher(std::string const& s)
67+
{
68+
mValue = strtoull(s.c_str(), nullptr, 10);
69+
}
70+
71+
SubSpecificationTypeValueMatcher(uint64_t v)
72+
{
73+
mValue = v;
74+
}
75+
bool match(header::DataHeader const& header) const
76+
{
77+
return header.subSpecification == mValue;
78+
}
79+
80+
private:
81+
uint64_t mValue;
82+
};
83+
84+
/// Something which can be matched against a header::SubSpecificationType
85+
class ConstantValueMatcher
86+
{
87+
public:
88+
/// The passed string @a s is the expected numerical value for
89+
/// the SubSpecification type.
90+
ConstantValueMatcher(bool value)
91+
{
92+
mValue = value;
93+
}
94+
bool match(header::DataHeader const& header) const
95+
{
96+
return mValue;
97+
}
98+
99+
private:
100+
bool mValue;
101+
};
102+
103+
template <typename DESCRIPTOR>
104+
struct DescriptorMatcherTrait {
105+
};
106+
107+
template <>
108+
struct DescriptorMatcherTrait<header::DataOrigin> {
109+
using Matcher = framework::OriginValueMatcher;
110+
};
111+
112+
template <>
113+
struct DescriptorMatcherTrait<header::DataDescription> {
114+
using Matcher = DescriptionValueMatcher;
115+
};
116+
117+
template <>
118+
struct DescriptorMatcherTrait<header::DataHeader::SubSpecificationType> {
119+
using Matcher = SubSpecificationTypeValueMatcher;
120+
};
121+
122+
class DataDescriptorMatcher;
123+
using Node = std::variant<OriginValueMatcher, DescriptionValueMatcher, SubSpecificationTypeValueMatcher, std::unique_ptr<DataDescriptorMatcher>, ConstantValueMatcher>;
124+
125+
// A matcher for a given O2 Data Model descriptor. We use a variant to hold
126+
// the different kind of matchers so that we can have a hierarchy or
127+
// DataDescriptionMatcher in the future (e.g. to handle OR / AND clauses) or we
128+
// can apply it to the whole DataHeader.
129+
class DataDescriptorMatcher
130+
{
131+
public:
132+
enum struct Op { Or,
133+
And,
134+
Xor };
135+
136+
DataDescriptorMatcher(Node&& lhs, Op op, Node&& rhs)
137+
: mOp{ op },
138+
mLeft{ std::move(lhs) },
139+
mRight{ std::move(rhs) }
140+
{
141+
}
142+
143+
inline ~DataDescriptorMatcher() = default;
144+
145+
bool match(header::DataHeader const& d) const
146+
{
147+
auto eval = [&d](auto&& arg) -> bool {
148+
using T = std::decay_t<decltype(arg)>;
149+
if constexpr (std::is_same_v<T, std::unique_ptr<DataDescriptorMatcher>>) {
150+
return arg->match(d);
151+
} else {
152+
return arg.match(d);
153+
}
154+
};
155+
auto leftValue = std::visit(eval, mLeft);
156+
auto rightValue = std::visit(eval, mRight);
157+
158+
switch (mOp) {
159+
case Op::Or:
160+
return leftValue || rightValue;
161+
case Op::And:
162+
return leftValue && rightValue;
163+
case Op::Xor:
164+
return leftValue ^ rightValue;
165+
}
166+
};
167+
168+
private:
169+
Op mOp;
170+
Node mLeft;
171+
Node mRight;
172+
};
173+
174+
} // naemspace framework
175+
} // namespace o2
176+
177+
#endif // o2_framework_DataDescriptorMatcher_H_INCLUDED
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
#define BOOST_TEST_MODULE Test Framework DataDescriptorMatcher
12+
#define BOOST_TEST_MAIN
13+
#define BOOST_TEST_DYN_LINK
14+
15+
#include <boost/test/unit_test.hpp>
16+
#include "Framework/DataDescriptorMatcher.h"
17+
18+
using namespace o2::framework;
19+
using namespace o2::header;
20+
21+
BOOST_AUTO_TEST_CASE(TestSimpleMatching)
22+
{
23+
DataHeader header0;
24+
header0.dataOrigin = "TPC";
25+
header0.dataDescription = "CLUSTERS";
26+
header0.subSpecification = 1;
27+
28+
DataHeader header1;
29+
header1.dataOrigin = "ITS";
30+
header1.dataDescription = "TRACKLET";
31+
header1.subSpecification = 2;
32+
33+
DataHeader header2;
34+
header2.dataOrigin = "TPC";
35+
header2.dataDescription = "TRACKLET";
36+
header2.subSpecification = 1;
37+
38+
DataHeader header3;
39+
header3.dataOrigin = "TPC";
40+
header3.dataDescription = "CLUSTERS";
41+
header3.subSpecification = 0;
42+
43+
DataHeader header4;
44+
header4.dataOrigin = "TRD";
45+
header4.dataDescription = "TRACKLET";
46+
header4.subSpecification = 0;
47+
48+
DataDescriptorMatcher matcher{
49+
OriginValueMatcher{ "TPC" },
50+
DataDescriptorMatcher::Op::And,
51+
std::make_unique<DataDescriptorMatcher>(
52+
DescriptionValueMatcher{ "CLUSTERS" },
53+
DataDescriptorMatcher::Op::And,
54+
std::make_unique<DataDescriptorMatcher>(
55+
SubSpecificationTypeValueMatcher{ 1 },
56+
DataDescriptorMatcher::Op::And,
57+
ConstantValueMatcher{ true }))
58+
};
59+
60+
BOOST_CHECK(matcher.match(header0) == true);
61+
BOOST_CHECK(matcher.match(header1) == false);
62+
BOOST_CHECK(matcher.match(header2) == false);
63+
BOOST_CHECK(matcher.match(header3) == false);
64+
BOOST_CHECK(matcher.match(header4) == false);
65+
66+
DataDescriptorMatcher matcher1{
67+
OriginValueMatcher{ "TPC" },
68+
DataDescriptorMatcher::Op::Or,
69+
OriginValueMatcher{ "ITS" }
70+
};
71+
72+
BOOST_CHECK(matcher1.match(header0) == true);
73+
BOOST_CHECK(matcher1.match(header1) == true);
74+
BOOST_CHECK(matcher1.match(header2) == true);
75+
BOOST_CHECK(matcher1.match(header3) == true);
76+
BOOST_CHECK(matcher1.match(header4) == false);
77+
78+
DataDescriptorMatcher matcher2{
79+
ConstantValueMatcher{ true },
80+
DataDescriptorMatcher::Op::And,
81+
DescriptionValueMatcher{ "TRACKLET" }
82+
};
83+
84+
BOOST_CHECK(matcher2.match(header0) == false);
85+
BOOST_CHECK(matcher2.match(header1) == true);
86+
BOOST_CHECK(matcher2.match(header2) == true);
87+
BOOST_CHECK(matcher2.match(header3) == false);
88+
BOOST_CHECK(matcher2.match(header4) == true);
89+
}

0 commit comments

Comments
 (0)