-
Notifications
You must be signed in to change notification settings - Fork 158
[QC-1298] Extensible interface for accessing QC data sources #2589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
becce3a
[QC-1298] first version of Data
2d2c61d
iterators in the middle of work
2b03079
filtering iterators working
1589aa7
version 2
047fdf2
Data used in aggregators
e34ad39
benchmarks
eb0740c
helpers implemented
a2cea35
data definition moved to inl file
3a90b19
rename Data to QCInputs
8074bbb
docs
97af63e
iterateQualityObjects with check name
779ca8e
reworded docs and removed generic container from QCInputs
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| // Copyright 2025 CERN and copyright holders of ALICE O2. | ||
| // See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. | ||
| // All rights not expressly granted are reserved. | ||
| // | ||
| // This software is distributed under the terms of the GNU General Public | ||
| // License v3 (GPL Version 3), copied verbatim in the file "COPYING". | ||
| // | ||
| // In applying this license CERN does not waive the privileges and immunities | ||
| // granted to it by virtue of its status as an Intergovernmental Organization | ||
| // or submit itself to any jurisdiction. | ||
|
|
||
| /// | ||
| /// \file QCInputs.h | ||
| /// \author Michal Tichak | ||
| /// \brief Generic container for heterogeneous QC input data. | ||
| /// | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// QCInputs data; | ||
| /// auto* h1 = new TH1F("th11", "th11", 100, 0, 99); | ||
| /// data.insert("mo", std::make_shared<MonitorObject>(h1, "taskname", "class1", "TST")); | ||
| /// if (auto opt = data.get<MonitorObject>("mo")) { | ||
| /// MonitorObject& moObject = opt.value(); | ||
| /// std::cout << "mo name: " << moObject.getName() << std::endl; | ||
| /// } | ||
| /// for (const auto& mo : data.iterateByType<MonitorObject>()) { | ||
| /// // process each value | ||
| /// } | ||
| /// \endcode | ||
| /// | ||
|
|
||
| #ifndef QC_CORE_DATA_H | ||
| #define QC_CORE_DATA_H | ||
|
|
||
| #include <any> | ||
| #include <concepts> | ||
| #include <functional> | ||
| #include <memory> | ||
| #include <optional> | ||
| #include <string> | ||
| #include <ranges> | ||
| #include <type_traits> | ||
|
|
||
| namespace o2::quality_control::core | ||
| { | ||
|
|
||
| /// \brief Requires a callable to return exactly the specified type. | ||
| /// \tparam Function Callable type to invoke. | ||
| /// \tparam Result Expected return type. | ||
| /// \tparam Args Argument types for invocation. | ||
| template <typename Function, typename Result, typename... Args> | ||
| concept invocable_r = std::invocable<Function, Args...> && | ||
| std::same_as<std::invoke_result_t<Function, Args...>, Result>; | ||
|
|
||
| /// \brief Heterogeneous storage for named QC input objects. | ||
| /// | ||
| /// Stores values in an std::unordered_map<std::string, std::any> while | ||
| /// offering type-safe get, iteration, filtering, and transformation. | ||
| class QCInputs | ||
| { | ||
| public: | ||
| QCInputs() = default; | ||
|
|
||
| /// \brief Retrieve the object stored under the given key with matching type. | ||
| /// \tparam Result Expected stored type. | ||
| /// \param key Identifier for the stored object. | ||
| /// \returns Optional reference to const Result if found desired item of type Result. | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// if (auto opt = data.get<MonitorObject>("mo")) { | ||
| /// if (opt.has_value()){ | ||
| /// const unsigned& value = opt.value(); // careful about using auto here as we want to invoke implicit conversion operator of reference_wrapper | ||
| /// } | ||
| /// } | ||
| /// \endcode | ||
| template <typename Result> | ||
| std::optional<std::reference_wrapper<const Result>> get(std::string_view key); | ||
|
|
||
| /// \brief Construct and store an object of type T under the given key. | ||
| /// \tparam T Type to construct and store. | ||
| /// \param key Identifier under which to store the object. | ||
| /// \param args Arguments forwarded to T's constructor. | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// auto* h1 = new TH1F("th11", "th11", 100, 0, 99); | ||
| /// data.emplace<MonitorObject>("mo", h1, "taskname", "class1", "TST"); | ||
| /// \endcode | ||
| template <typename T, typename... Args> | ||
| void emplace(std::string_view key, Args&&... args); | ||
|
|
||
| /// \brief Store a copy of value under the given key. | ||
| /// \tparam T Type of the value to store. | ||
| /// \param key Identifier under which to store the value. | ||
| /// \param value Const reference to the value to insert. | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// auto* h1 = new TH1F("th11", "th11", 100, 0, 99); | ||
| /// data.insert("mo", std::make_shared<MonitorObject>(h1, "taskname", "class1", "TST")); | ||
| /// \endcode | ||
| template <typename T> | ||
| void insert(std::string_view key, const T& value); | ||
|
|
||
| /// \brief Iterate over all stored objects matching type Result. | ||
| /// \tparam Result Type filter for iteration. | ||
| /// \returns Range of const references to stored Result instances. | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// for (auto& mo : data.iterateByType<MonitorObject>()) { | ||
| /// // use val | ||
| /// } | ||
| /// \endcode | ||
| template <typename Result> | ||
| auto iterateByType() const; | ||
|
|
||
| /// \brief Iterate over stored objects of type Result satisfying a predicate. | ||
| /// \tparam Result type filter for iteration. | ||
| /// \tparam Pred Callable predicate on (key, Result*) pairs. | ||
| /// \param filter Predicate to apply for filtering entries. | ||
| /// \returns Range of const references to Result passing the filter. | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// auto nameFilter = [](auto const& pair) { return pair.second->getName() == "name"; }; | ||
| /// for (auto& mo : data.iterateByTypeAndFilter<MonitorObject>(nameFilter)) { | ||
| /// // use mo | ||
| /// } | ||
| /// \endcode | ||
| template <typename Result, std::predicate<const std::pair<std::string_view, const Result*>&> Pred> | ||
| auto iterateByTypeAndFilter(Pred&& filter) const; | ||
|
|
||
| /// \brief Filter entries of type Stored, then transform to type Result. | ||
| /// \tparam Stored Original stored type for filtering. | ||
| /// \tparam Result Target type after transformation. | ||
| /// \tparam Pred Callable predicate on (key, Stored*) pairs. | ||
| /// \tparam Transform Callable transforming Stored* to Result*. | ||
| /// This Callable can return nullptr but it will be filtered out | ||
| /// from results | ||
| /// \param filter Predicate to apply before transformation. | ||
| /// \param transform Callable to convert Stored to Result. | ||
| /// \returns Range of const references to resulting objects. | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// // if we stored some MOs that are not TH1F, these will be filtered out of results | ||
| /// auto toHistogram = [](auto const& p) -> const auto* { return dynamic_cast<TH1F*>(p.second->getObject()); }; | ||
| /// auto nameFilter = [](auto const& p){ return p.first == "histo"; }; | ||
| /// for (auto& h : data.iterateByTypeFilterAndTransform<MonitorObject, TH1F>(nameFilter, toHistogram)) { | ||
| /// // use histogram h | ||
| /// } | ||
| /// \endcode | ||
| template <typename Stored, typename Result, std::predicate<const std::pair<std::string_view, const Stored*>&> Pred, invocable_r<const Result*, const Stored*> Transform> | ||
| auto iterateByTypeFilterAndTransform(Pred&& filter, Transform&& transform) const; | ||
|
|
||
| /// \brief Number of stored entries. | ||
| /// \returns Size of the underlying container. | ||
| /// \par Example | ||
| /// \code{.cpp} | ||
| /// size_t n = data.size(); | ||
| /// \endcode | ||
| size_t size() const noexcept; | ||
|
|
||
| private: | ||
| /// \brief Transparent hash functor for string and string_view. | ||
| /// | ||
| /// Enables heterogeneous lookup in unordered maps keyed by std::string. | ||
| struct StringHash { | ||
| using is_transparent = void; // Required for heterogeneous lookup | ||
|
|
||
| std::size_t operator()(const std::string& str) const | ||
| { | ||
| return std::hash<std::string>{}(str); | ||
| } | ||
|
|
||
| std::size_t operator()(std::string_view sv) const | ||
| { | ||
| return std::hash<std::string_view>{}(sv); | ||
| } | ||
| }; | ||
|
|
||
| std::unordered_map<std::string, std::any, StringHash, std::equal_to<>> mObjects; | ||
| }; | ||
|
|
||
| } // namespace o2::quality_control::core | ||
|
|
||
| #include "QCInputs.inl" | ||
|
|
||
| #endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add a note that users should prefer the other one and this one is for backwards-compatibility.