-
Notifications
You must be signed in to change notification settings - Fork 60
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
Add a LinkNavigator utility #646
Merged
Merged
Changes from 14 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
0fcb837
Add AssociationNavigator utility class and tests
tmadlener 0c445b0
Rename Association to Link
tmadlener e7cad28
Default initialize the internal maps
tmadlener 90b6cde
Make navigator work with links between same types
tmadlener 8de96ad
Remove more mentions of assocations
tmadlener 38aee33
Avoid depending on an order in the linked objects
tmadlener bd447e3
Remove unnecessary include
tmadlener af1e4f8
Add documentation
tmadlener 58aa607
Make dependent types usable in c++17
tmadlener 46bc442
Documentation fixes as suggested
tmadlener 6dadc4a
Make directional overloads take a tag argument
tmadlener 9837182
Rename overload selection tags and refine docstring wording
tmadlener d6fed94
Use correct overload in tests
tmadlener d137132
Update docs to new naming scheme
tmadlener 3ddeb5c
Make sure documentation and code are consistent
tmadlener 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 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 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,171 @@ | ||
#ifndef PODIO_LINKNAVIGATOR_H | ||
#define PODIO_LINKNAVIGATOR_H | ||
|
||
#include <map> | ||
#include <tuple> | ||
#include <type_traits> | ||
#include <utility> | ||
#include <vector> | ||
|
||
namespace podio { | ||
|
||
namespace detail::links { | ||
/// A small struct that simply bundles an object and its weight for a more | ||
/// convenient return value for the LinkNavigator | ||
/// | ||
/// @note In most uses the names of the members should not really matter as it | ||
/// is possible to us this via structured bindings | ||
template <typename T> | ||
struct WeightedObject { | ||
WeightedObject(T obj, float w) : o(obj), weight(w) { | ||
} | ||
T o; ///< The object | ||
float weight; ///< The weight in the link | ||
|
||
bool operator==(const WeightedObject<T>& other) const { | ||
return other.o == o && other.weight == weight; | ||
} | ||
}; | ||
|
||
/// Simple struct tag for overload selection in LinkNavigator below | ||
struct ReturnFromTag {}; | ||
/// Simple struct tag for overload selection in LinkNavigator below | ||
struct ReturnToTag {}; | ||
} // namespace detail::links | ||
|
||
/// Tag variable to select the lookup of *From* objects have links with a *To* | ||
/// object in podio::LinkNavigator::getLinked | ||
static constexpr detail::links::ReturnFromTag ReturnFrom; | ||
/// Tag variable to select the lookup of *To* objects that have links with a | ||
/// *From* object in podio::LinkNavigator::getLinked | ||
static constexpr detail::links::ReturnToTag ReturnTo; | ||
|
||
/// A helper class to more easily handle one-to-many links. | ||
/// | ||
/// Internally simply populates two maps in its constructor and then queries | ||
/// them to retrieve objects that are linked with another. | ||
/// | ||
/// @note There are no guarantees on the order of the objects in these maps. | ||
/// Hence, there are also no guarantees on the order of the returned objects, | ||
/// even if there inherintly is an order to them in the underlying links | ||
/// collection. | ||
template <typename LinkCollT> | ||
class LinkNavigator { | ||
using FromT = typename LinkCollT::from_type; | ||
using ToT = typename LinkCollT::to_type; | ||
|
||
template <typename T> | ||
using WeightedObject = detail::links::WeightedObject<T>; | ||
|
||
public: | ||
/// Construct a navigator from an link collection | ||
LinkNavigator(const LinkCollT& links); | ||
|
||
/// We do only construct from a collection | ||
LinkNavigator() = delete; | ||
LinkNavigator(const LinkNavigator&) = default; | ||
LinkNavigator& operator=(const LinkNavigator&) = default; | ||
LinkNavigator(LinkNavigator&&) = default; | ||
LinkNavigator& operator=(LinkNavigator&&) = default; | ||
~LinkNavigator() = default; | ||
|
||
/// Get all the *From* objects and weights that have links with the passed | ||
/// object | ||
/// | ||
/// You will get this overload if you pass the podio::LookupFrom tag as second | ||
tmadlener marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// argument | ||
/// | ||
/// @note This overload works always, even if the LinkCollection that was used | ||
/// to construct this instance of the LinkNavigator has the same From and To | ||
/// types. | ||
/// | ||
/// @param object The object that is labeled *To* in the link | ||
/// @param . tag variable for selecting this overload | ||
/// | ||
/// @returns A vector of all objects and their weights that have links with | ||
/// the passed object | ||
std::vector<WeightedObject<FromT>> getLinked(const ToT& object, podio::detail::links::ReturnFromTag) const { | ||
const auto& [begin, end] = m_to2from.equal_range(object); | ||
std::vector<WeightedObject<FromT>> result; | ||
result.reserve(std::distance(begin, end)); | ||
|
||
for (auto it = begin; it != end; ++it) { | ||
result.emplace_back(it->second); | ||
} | ||
return result; | ||
} | ||
|
||
/// Get all the *From* objects and weights that have links with the passed | ||
/// object | ||
/// | ||
/// @note This overload will automatically do the right thing (TM) in case the | ||
/// LinkCollection that has been passed to construct this LinkNavigator has | ||
/// different From and To types. | ||
/// | ||
/// @param object The object that is labeled *To* in the link | ||
/// | ||
/// @returns A vector of all objects and their weights that have links with | ||
/// the passed object | ||
template <typename ToU = ToT> | ||
std::enable_if_t<!std::is_same_v<FromT, ToU>, std::vector<WeightedObject<FromT>>> getLinked(const ToT& object) const { | ||
return getLinked(object, podio::ReturnFrom); | ||
} | ||
|
||
/// Get all the *To* objects and weights that have links with the passed | ||
/// object | ||
/// | ||
/// You will get this overload if you pass the podio::LookupTo tag as second | ||
tmadlener marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// argument | ||
/// | ||
/// @note This overload works always, even if the LinkCollection that was used | ||
/// to construct this instance of the LinkNavigator has the same From and To | ||
/// types. | ||
/// | ||
/// @param object The object that is labeled *From* in the link | ||
/// @param . tag variable for selecting this overload | ||
/// | ||
/// @returns A vector of all objects and their weights that have links with | ||
/// the passed object | ||
std::vector<WeightedObject<ToT>> getLinked(const FromT& object, podio::detail::links::ReturnToTag) const { | ||
const auto& [begin, end] = m_from2to.equal_range(object); | ||
std::vector<WeightedObject<ToT>> result; | ||
result.reserve(std::distance(begin, end)); | ||
|
||
for (auto it = begin; it != end; ++it) { | ||
result.emplace_back(it->second); | ||
} | ||
return result; | ||
} | ||
|
||
/// Get all the *To* objects and weights that have links with the passed | ||
/// object | ||
/// | ||
/// @note This overload will automatically do the right thing (TM) in case the | ||
/// LinkCollection that has been passed to construct this LinkNavigator has | ||
/// different From and To types. | ||
/// | ||
/// @param object The object that is labeled *From* in the link | ||
/// | ||
/// @returns A vector of all objects and their weights that have links with | ||
/// the passed object | ||
template <typename FromU = FromT> | ||
std::enable_if_t<!std::is_same_v<FromU, ToT>, std::vector<WeightedObject<ToT>>> getLinked(const FromT& object) const { | ||
return getLinked(object, podio::ReturnTo); | ||
} | ||
|
||
private: | ||
std::multimap<FromT, WeightedObject<ToT>> m_from2to{}; ///< Map the from to the to objects | ||
std::multimap<ToT, WeightedObject<FromT>> m_to2from{}; ///< Map the to to the from objects | ||
}; | ||
|
||
template <typename LinkCollT> | ||
LinkNavigator<LinkCollT>::LinkNavigator(const LinkCollT& links) { | ||
for (const auto& [from, to, weight] : links) { | ||
m_from2to.emplace(std::piecewise_construct, std::forward_as_tuple(from), std::forward_as_tuple(to, weight)); | ||
m_to2from.emplace(std::piecewise_construct, std::forward_as_tuple(to), std::forward_as_tuple(from, weight)); | ||
} | ||
} | ||
|
||
} // namespace podio | ||
|
||
#endif // PODIO_LINKNAVIGATOR_H |
This file contains 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 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 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
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.
With the implicit question whether we should lift this object out of the (implicitly private)
detail
namespace, since it is in principle user facing.