Skip to content

Commit 779ca8e

Browse files
author
Michal Tichák
committed
reworded docs and removed generic container from QCInputs
1 parent 97af63e commit 779ca8e

File tree

7 files changed

+52
-167
lines changed

7 files changed

+52
-167
lines changed

Framework/include/QualityControl/CheckInterface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class CheckInterface : public core::UserCodeInterface
4848
virtual ~CheckInterface() = default;
4949

5050
/// \brief Returns the quality associated with these objects.
51+
/// \deprecated This function won't be deleted in future releases for compatibility reasons but users should
52+
/// use check(const Data&) for any new Checks.
5153
///
5254
/// @param moMap A map of the the MonitorObjects to check and their full names (i.e. <task_name>/<mo name>) as keys.
5355
/// @return The quality associated with these objects.

Framework/include/QualityControl/QCInputs.h

Lines changed: 39 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
/// \par Example
1818
/// \code{.cpp}
1919
/// QCInputs data;
20-
/// data.insert("count", 42u);
21-
/// if (auto opt = data.get<unsigned>("count")) {
22-
/// std::cout << "Count: " << opt->get() << std::endl;
20+
/// auto* h1 = new TH1F("th11", "th11", 100, 0, 99);
21+
/// data.insert("mo", std::make_shared<MonitorObject>(h1, "taskname", "class1", "TST"));
22+
/// if (auto opt = data.get<MonitorObject>("mo")) {
23+
/// MonitorObject& moObject = opt.value();
24+
/// std::cout << "mo name: " << moObject.getName() << std::endl;
2325
/// }
24-
/// for (const auto& v : data.iterateByType<unsigned>()) {
26+
/// for (const auto& mo : data.iterateByType<MonitorObject>()) {
2527
/// // process each value
2628
/// }
2729
/// \endcode
@@ -52,22 +54,20 @@ concept invocable_r = std::invocable<Function, Args...> &&
5254

5355
/// \brief Heterogeneous storage for named QC input objects.
5456
///
55-
/// Stores values in an std::any-based container keyed by strings,
57+
/// Stores values in an std::unordered_map<std::string, std::any> while
5658
/// offering type-safe get, iteration, filtering, and transformation.
57-
/// Example of such container is transparent_unordered_map at the end of this file
58-
template <typename ContainerMap>
59-
class QCInputsGeneric
59+
class QCInputs
6060
{
6161
public:
62-
QCInputsGeneric() = default;
62+
QCInputs() = default;
6363

6464
/// \brief Retrieve the object stored under the given key with matching type.
6565
/// \tparam Result Expected stored type.
6666
/// \param key Identifier for the stored object.
6767
/// \returns Optional reference to const Result if found desired item of type Result.
6868
/// \par Example
6969
/// \code{.cpp}
70-
/// if (auto opt = data.get<unsigned>("count")) {
70+
/// if (auto opt = data.get<MonitorObject>("mo")) {
7171
/// if (opt.has_value()){
7272
/// const unsigned& value = opt.value(); // careful about using auto here as we want to invoke implicit conversion operator of reference_wrapper
7373
/// }
@@ -82,7 +82,8 @@ class QCInputsGeneric
8282
/// \param args Arguments forwarded to T's constructor.
8383
/// \par Example
8484
/// \code{.cpp}
85-
/// data.emplace<std::string>("greeting", "hello");
85+
/// auto* h1 = new TH1F("th11", "th11", 100, 0, 99);
86+
/// data.emplace<MonitorObject>("mo", h1, "taskname", "class1", "TST");
8687
/// \endcode
8788
template <typename T, typename... Args>
8889
void emplace(std::string_view key, Args&&... args);
@@ -93,7 +94,8 @@ class QCInputsGeneric
9394
/// \param value Const reference to the value to insert.
9495
/// \par Example
9596
/// \code{.cpp}
96-
/// data.insert("count", 10u);
97+
/// auto* h1 = new TH1F("th11", "th11", 100, 0, 99);
98+
/// data.insert("mo", std::make_shared<MonitorObject>(h1, "taskname", "class1", "TST"));
9799
/// \endcode
98100
template <typename T>
99101
void insert(std::string_view key, const T& value);
@@ -103,7 +105,7 @@ class QCInputsGeneric
103105
/// \returns Range of const references to stored Result instances.
104106
/// \par Example
105107
/// \code{.cpp}
106-
/// for (auto& val : data.iterateByResultype<unsigned>()) {
108+
/// for (auto& mo : data.iterateByType<MonitorObject>()) {
107109
/// // use val
108110
/// }
109111
/// \endcode
@@ -117,9 +119,9 @@ class QCInputsGeneric
117119
/// \returns Range of const references to Result passing the filter.
118120
/// \par Example
119121
/// \code{.cpp}
120-
/// auto even = [](auto const& pair) { return pair.second % 2 == 0; };
121-
/// for (auto& val : data.iterateByTypeAndFilter<unsigned>(even)) {
122-
/// // use val
122+
/// auto nameFilter = [](auto const& pair) { return pair.second->getName() == "name"; };
123+
/// for (auto& mo : data.iterateByTypeAndFilter<MonitorObject>(nameFilter)) {
124+
/// // use mo
123125
/// }
124126
/// \endcode
125127
template <typename Result, std::predicate<const std::pair<std::string_view, const Result*>&> Pred>
@@ -138,8 +140,9 @@ class QCInputsGeneric
138140
/// \par Example
139141
/// \code{.cpp}
140142
/// // if we stored some MOs that are not TH1F, these will be filtered out of results
141-
/// auto toHistogram = [](auto const& p) { return dynamic_cast<TH1F*>(p.second->getObject()); };
142-
/// for (auto& h : data.iterateByTypeFilterAndTransform<MonitorObject, TH1F>([](auto const& p){ return p.first=="histo"; }, toHistogram)) {
143+
/// auto toHistogram = [](auto const& p) -> const auto* { return dynamic_cast<TH1F*>(p.second->getObject()); };
144+
/// auto nameFilter = [](auto const& p){ return p.first == "histo"; };
145+
/// for (auto& h : data.iterateByTypeFilterAndTransform<MonitorObject, TH1F>(nameFilter, toHistogram)) {
143146
/// // use histogram h
144147
/// }
145148
/// \endcode
@@ -155,33 +158,26 @@ class QCInputsGeneric
155158
size_t size() const noexcept;
156159

157160
private:
158-
ContainerMap mObjects;
159-
};
160-
161-
/// \brief Transparent hash functor for string and string_view.
162-
///
163-
/// Enables heterogeneous lookup in unordered maps keyed by std::string.
164-
struct StringHash {
165-
using is_transparent = void; // Required for heterogeneous lookup
166-
167-
std::size_t operator()(const std::string& str) const
168-
{
169-
return std::hash<std::string>{}(str);
170-
}
171-
172-
std::size_t operator()(std::string_view sv) const
173-
{
174-
return std::hash<std::string_view>{}(sv);
175-
}
161+
/// \brief Transparent hash functor for string and string_view.
162+
///
163+
/// Enables heterogeneous lookup in unordered maps keyed by std::string.
164+
struct StringHash {
165+
using is_transparent = void; // Required for heterogeneous lookup
166+
167+
std::size_t operator()(const std::string& str) const
168+
{
169+
return std::hash<std::string>{}(str);
170+
}
171+
172+
std::size_t operator()(std::string_view sv) const
173+
{
174+
return std::hash<std::string_view>{}(sv);
175+
}
176+
};
177+
178+
std::unordered_map<std::string, std::any, StringHash, std::equal_to<>> mObjects;
176179
};
177180

178-
/// \brief Unordered map storing std::any values with heterogeneous key lookup. It was chosen based on benchmark
179-
/// in testQCInputs.cxx
180-
using transparent_unordered_map = std::unordered_map<std::string, std::any, StringHash, std::equal_to<>>;
181-
182-
/// \brief Default alias for QC inputs using transparent_unordered_map container.
183-
using QCInputs = QCInputsGeneric<transparent_unordered_map>;
184-
185181
} // namespace o2::quality_control::core
186182

187183
#include "QCInputs.inl"

Framework/include/QualityControl/QCInputs.inl

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@
2020
namespace o2::quality_control::core
2121
{
2222

23-
template <typename ContainerMap>
2423
template <typename Result>
25-
std::optional<std::reference_wrapper<const Result>> QCInputsGeneric<ContainerMap>::get(std::string_view key)
24+
std::optional<std::reference_wrapper<const Result>> QCInputs::get(std::string_view key)
2625
{
2726
if (const auto foundIt = mObjects.find(key); foundIt != mObjects.end()) {
2827
if (auto* casted = std::any_cast<Result>(&foundIt->second); casted != nullptr) {
@@ -32,16 +31,14 @@ std::optional<std::reference_wrapper<const Result>> QCInputsGeneric<ContainerMap
3231
return std::nullopt;
3332
}
3433

35-
template <typename ContainerMap>
3634
template <typename Result, typename... Args>
37-
void QCInputsGeneric<ContainerMap>::emplace(std::string_view key, Args&&... args)
35+
void QCInputs::emplace(std::string_view key, Args&&... args)
3836
{
3937
mObjects.emplace(key, std::any{ std::in_place_type<Result>, std::forward<Args>(args)... });
4038
}
4139

42-
template <typename ContainerMap>
4340
template <typename T>
44-
void QCInputsGeneric<ContainerMap>::insert(std::string_view key, const T& value)
41+
void QCInputs::insert(std::string_view key, const T& value)
4542
{
4643
mObjects.insert({ std::string{ key }, value });
4744
}
@@ -102,25 +99,22 @@ static constexpr auto pointer_to_reference = std::views::transform(
10299

103100
} // namespace internal
104101

105-
template <typename ContainerMap>
106102
template <typename T>
107-
auto QCInputsGeneric<ContainerMap>::iterateByType() const
103+
auto QCInputs::iterateByType() const
108104
{
109105
using namespace internal;
110106
return mObjects | any_to_specific<T> | filter_nullptr_in_pair | pair_to_value_const_ref;
111107
}
112108

113-
template <typename ContainerMap>
114109
template <typename T, std::predicate<const std::pair<std::string_view, const T*>&> Pred>
115-
auto QCInputsGeneric<ContainerMap>::iterateByTypeAndFilter(Pred&& filter) const
110+
auto QCInputs::iterateByTypeAndFilter(Pred&& filter) const
116111
{
117112
using namespace internal;
118113
return mObjects | any_to_specific<T> | filter_nullptr_in_pair | std::views::filter(filter) | pair_to_value_const_ref;
119114
}
120115

121-
template <typename ContainerMap>
122116
template <typename StoredType, typename ResultingType, std::predicate<const std::pair<std::string_view, const StoredType*>&> Pred, invocable_r<const ResultingType*, const StoredType*> Transform>
123-
auto QCInputsGeneric<ContainerMap>::iterateByTypeFilterAndTransform(Pred&& filter, Transform&& transform) const
117+
auto QCInputs::iterateByTypeFilterAndTransform(Pred&& filter, Transform&& transform) const
124118
{
125119
using namespace internal;
126120
return mObjects |
@@ -133,8 +127,7 @@ auto QCInputsGeneric<ContainerMap>::iterateByTypeFilterAndTransform(Pred&& filte
133127
pointer_to_reference;
134128
}
135129

136-
template <typename ContainerMap>
137-
size_t QCInputsGeneric<ContainerMap>::size() const noexcept
130+
inline size_t QCInputs::size() const noexcept
138131
{
139132
return mObjects.size();
140133
}

Framework/include/QualityControl/QCInputsAdapters.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ inline auto iterateMonitorObjects(const QCInputs& data);
6060
inline auto iterateMonitorObjects(const QCInputs& data, std::string_view taskName);
6161

6262
/// \brief Retrieve the first MonitorObject of type StoredType matching both name and task.
63-
/// \tparam StoredType Type of MonitorObject or subclass to retrieve.
63+
/// \tparam StoredType Type of MonitorObject or stored class to retrieve.
6464
/// \param data QCInputs to search.
6565
/// \param objectName Name of the MonitorObject.
6666
/// \param taskName Name of the originating task.
@@ -70,7 +70,7 @@ std::optional<std::reference_wrapper<const StoredType>> getMonitorObject(const Q
7070

7171
// returns first occurence of MO with given name (possible name clash)
7272
/// \brief Retrieve the first MonitorObject of type StoredType matching name.
73-
/// \tparam StoredType Type of MonitorObject or subclass to retrieve.
73+
/// \tparam StoredType Type of MonitorObject or stored class to retrieve.
7474
/// \param data QCInputs to search.
7575
/// \param objectName Name of the MonitorObject.
7676
/// \returns Optional reference to const StoredType if found.

Framework/include/QualityControl/QCInputsAdapters.inl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ inline auto iterateQualityObjects(const QCInputs& data)
9191
inline auto iterateQualityObjects(const QCInputs& data, std::string_view checkName)
9292
{
9393
const auto filterQOByName = [checkName](const auto& pair) {
94-
return std::string_view(pair.second->getName()) == checkName;
94+
return std::string_view(pair.second->getCheckName()) == checkName;
9595
};
9696
return data.iterateByTypeAndFilter<QualityObject>(filterQOByName);
9797
}

Framework/src/QCInputsAdapters.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace o2::quality_control::core
2222
std::optional<std::reference_wrapper<const QualityObject>> getQualityObject(const QCInputs& data, std::string_view objectName)
2323
{
2424
const auto filterQOByName = [objectName](const auto& pair) {
25-
return std::string_view(pair.second->GetName()) == objectName;
25+
return std::string_view(pair.second->getCheckName()) == objectName;
2626
};
2727
for (const auto& qo : data.iterateByTypeAndFilter<QualityObject>(filterQOByName)) {
2828
return { qo };

Framework/test/testQCInputs.cxx

Lines changed: 0 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -131,112 +131,6 @@ TEST_CASE("Data - raw pointers", "[Data]")
131131
REQUIRE(count == 2);
132132
}
133133

134-
using stdmap = std::map<std::string, std::any, std::less<>>;
135-
using boostflatmap = boost::container::flat_map<std::string, std::any, std::less<>>;
136-
137-
TEMPLATE_TEST_CASE("Data - inserting fundamental types", "[.Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
138-
{
139-
constexpr size_t iterations = 20'000;
140-
141-
BENCHMARK("insert size_t")
142-
{
143-
QCInputsGeneric<TestType> data;
144-
// for (size_t i = 0; i != iterations; ++i) {
145-
for (size_t i = iterations; i != 0; --i) {
146-
data.insert(std::to_string(i), i);
147-
}
148-
};
149-
}
150-
151-
TEMPLATE_TEST_CASE("Data - iterating fundamental types", "[.Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
152-
{
153-
constexpr size_t iterations = 20000;
154-
QCInputsGeneric<TestType> data;
155-
for (size_t i = 0; i != iterations; ++i) {
156-
data.insert(std::to_string(i), i);
157-
}
158-
159-
REQUIRE(data.size() == iterations);
160-
BENCHMARK("iterate size_t")
161-
{
162-
REQUIRE(data.size() == iterations);
163-
size_t r{};
164-
size_t count{};
165-
for (const auto& v : data.template iterateByType<size_t>()) {
166-
r += v;
167-
count++;
168-
}
169-
REQUIRE(count == iterations);
170-
};
171-
}
172-
173-
TEMPLATE_TEST_CASE("Data - get fundamental types", "[.Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
174-
{
175-
constexpr size_t iterations = 20000;
176-
QCInputsGeneric<TestType> data;
177-
for (size_t i = 0; i != iterations; ++i) {
178-
data.insert(std::to_string(i), i);
179-
}
180-
181-
REQUIRE(data.size() == iterations);
182-
BENCHMARK("iterate size_t")
183-
{
184-
size_t r{};
185-
size_t count{};
186-
for (size_t i = 0; i != iterations; ++i) {
187-
auto opt = data.template get<size_t>(std::to_string(i));
188-
r += opt.value();
189-
auto& v = opt.value();
190-
count++;
191-
}
192-
REQUIRE(count == iterations);
193-
};
194-
}
195-
196-
std::string generateRandomString(size_t length)
197-
{
198-
static constexpr std::string_view CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
199-
thread_local std::mt19937 generator(std::random_device{}());
200-
std::uniform_int_distribution<size_t> distribution(0, CHARACTERS.length() - 1);
201-
202-
std::string random_string;
203-
random_string.reserve(length);
204-
for (size_t i = 0; i < length; ++i) {
205-
random_string += CHARACTERS[distribution(generator)];
206-
}
207-
return random_string;
208-
}
209-
210-
TEMPLATE_TEST_CASE("Data - inserting and iterating MOs", "[.Data-benchmark]", stdmap, boostflatmap, transparent_unordered_map)
211-
{
212-
constexpr size_t iterations = 1000;
213-
std::vector<std::shared_ptr<MonitorObject>> MOs;
214-
215-
for (size_t i = 0; i != iterations; ++i) {
216-
const auto name = generateRandomString(20);
217-
auto* h = new TH1F(name.c_str(), name.c_str(), 100, 0, 99);
218-
std::shared_ptr<MonitorObject> mo = std::make_shared<MonitorObject>(h, "taskname", "class1", "TST");
219-
MOs.push_back(mo);
220-
}
221-
222-
BENCHMARK("insert - iterate MOs")
223-
{
224-
QCInputsGeneric<TestType> data;
225-
for (const auto& mo : MOs) {
226-
data.insert(mo->getFullName(), mo);
227-
}
228-
229-
const auto filterMOByName = [](const auto& pair) {
230-
return std::string_view(pair.second->GetName()) == "nonexistent";
231-
};
232-
233-
const auto getInternalObject = [](const MonitorObject* ptr) -> const auto* {
234-
return dynamic_cast<const TH1F*>(ptr->getObject());
235-
};
236-
REQUIRE(data.template iterateByTypeFilterAndTransform<MonitorObject, TH1F>(filterMOByName, getInternalObject).empty());
237-
};
238-
}
239-
240134
TEST_CASE("Data adapters - helper functions", "[Data]")
241135
{
242136

0 commit comments

Comments
 (0)