File indexing completed on 2025-09-18 09:25:07
0001 #ifndef PODIO_DETAIL_LINK_H
0002 #define PODIO_DETAIL_LINK_H
0003
0004 #include "podio/detail/LinkFwd.h"
0005 #include "podio/detail/LinkObj.h"
0006 #include "podio/utilities/MaybeSharedPtr.h"
0007 #include "podio/utilities/StaticConcatenate.h"
0008 #include "podio/utilities/TypeHelpers.h"
0009 #include <string_view>
0010
0011 #ifdef PODIO_JSON_OUTPUT
0012 #include "nlohmann/json.hpp"
0013 #endif
0014
0015 #include <functional>
0016 #include <ostream>
0017 #include <type_traits>
0018 #include <utility> // std::swap
0019
0020 namespace podio {
0021
0022
0023
0024
0025 template <typename FromT, typename ToT, bool Mutable>
0026 class LinkT {
0027
0028
0029
0030 static_assert(std::is_same_v<detail::GetDefaultHandleType<FromT>, FromT>,
0031 "Links need to be instantiated with the default types!");
0032 static_assert(std::is_same_v<detail::GetDefaultHandleType<ToT>, ToT>,
0033 "Links need to be instantiated with the default types!");
0034
0035 using LinkObjT = LinkObj<FromT, ToT>;
0036 friend LinkCollection<FromT, ToT>;
0037 friend LinkCollectionIteratorT<FromT, ToT, Mutable>;
0038 friend LinkT<FromT, ToT, !Mutable>;
0039 friend std::hash<LinkT>;
0040
0041
0042
0043 template <typename FromU, typename ToU>
0044 constexpr static bool sameTypes = std::is_same_v<FromU, FromT> && std::is_same_v<ToU, ToT>;
0045
0046
0047
0048 template <typename T>
0049 static constexpr bool isFromOrToT = detail::isInTuple<T, std::tuple<FromT, ToT>>;
0050
0051
0052
0053 template <typename T>
0054 static constexpr bool isMutableFromOrToT =
0055 detail::isInTuple<T,
0056 std::tuple<FromT, ToT, detail::GetMutableHandleType<FromT>, detail::GetMutableHandleType<ToT>>>;
0057
0058 public:
0059 using mutable_type = podio::MutableLink<FromT, ToT>;
0060 using value_type = podio::Link<FromT, ToT>;
0061 using collection_type = podio::LinkCollection<FromT, ToT>;
0062
0063 static constexpr std::string_view typeName =
0064 utils::static_concatenate_v<detail::link_name_prefix, FromT::typeName, detail::link_name_infix, ToT::typeName,
0065 detail::link_name_suffix>;
0066
0067 LinkT() : m_obj(new LinkObjT{}, podio::utils::MarkOwned) {
0068 }
0069
0070
0071 LinkT(float weight) : m_obj(new LinkObjT{}, podio::utils::MarkOwned) {
0072 m_obj->data.weight = weight;
0073 }
0074
0075
0076 LinkT(const LinkT& other) = default;
0077
0078
0079 LinkT& operator=(LinkT other) & {
0080 swap(*this, other);
0081 return *this;
0082 }
0083 LinkT& operator=(LinkT other) && = delete;
0084
0085
0086 template <typename FromU, typename ToU>
0087 requires Mutable && sameTypes<FromU, ToU>
0088 operator LinkT<FromU, ToU, false>() const {
0089 return Link<FromU, ToU>(m_obj);
0090 }
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 template <typename FromU = FromT, typename ToU = ToT>
0101 requires sameTypes<FromU, ToU>
0102 MutableLink<FromU, ToU> clone(bool cloneRelations = true) const {
0103 auto tmp = new LinkObjT(podio::ObjectID{}, m_obj->data);
0104 if (cloneRelations) {
0105 if (m_obj->m_from) {
0106 tmp->m_from = std::make_unique<FromT>(*m_obj->m_from);
0107 }
0108 if (m_obj->m_to) {
0109 tmp->m_to = std::make_unique<ToT>(*m_obj->m_to);
0110 }
0111 }
0112 return MutableLink<FromU, ToU>(podio::utils::MaybeSharedPtr(tmp, podio::utils::MarkOwned));
0113 }
0114
0115
0116 template <bool Mut = Mutable>
0117 requires(!Mut && !Mutable)
0118 static Link<FromT, ToT> makeEmpty() {
0119 return {nullptr};
0120 }
0121
0122
0123 ~LinkT() = default;
0124
0125
0126 float getWeight() const {
0127 return m_obj->data.weight;
0128 }
0129
0130
0131 template <bool Mut = Mutable>
0132 requires(Mut && Mutable)
0133 void setWeight(float value) {
0134 m_obj->data.weight = value;
0135 }
0136
0137
0138 const FromT getFrom() const {
0139 if (!m_obj->m_from) {
0140 return FromT::makeEmpty();
0141 }
0142 return FromT(*(m_obj->m_from));
0143 }
0144
0145
0146
0147
0148
0149
0150 template <typename FromU>
0151 requires(Mutable && std::is_same_v<detail::GetDefaultHandleType<FromU>, FromT> &&
0152 detail::isDefaultHandleType<FromU>)
0153 void setFrom(FromU value) {
0154 m_obj->m_from = std::make_unique<detail::GetDefaultHandleType<FromU>>(value);
0155 }
0156
0157
0158
0159
0160
0161
0162 template <typename FromU>
0163 requires(Mutable && std::is_same_v<detail::GetMutableHandleType<FromT>, FromU> &&
0164 detail::isMutableHandleType<FromU>)
0165 void setFrom(FromU value) {
0166 setFrom(detail::GetDefaultHandleType<FromU>(value));
0167 }
0168
0169
0170
0171
0172
0173
0174 template <typename FromU>
0175 requires(Mutable && detail::isInterfaceInitializableFrom<FromT, FromU>)
0176 void setFrom(FromU value) {
0177 setFrom(FromT(value));
0178 }
0179
0180
0181 const ToT getTo() const {
0182 if (!m_obj->m_to) {
0183 return ToT::makeEmpty();
0184 }
0185 return ToT(*(m_obj->m_to));
0186 }
0187
0188
0189
0190
0191
0192
0193 template <typename ToU>
0194 requires(Mutable && std::is_same_v<detail::GetDefaultHandleType<ToU>, ToT> && detail::isDefaultHandleType<ToU>)
0195 void setTo(ToU value) {
0196 m_obj->m_to = std::make_unique<detail::GetDefaultHandleType<ToU>>(value);
0197 }
0198
0199
0200
0201
0202
0203
0204 template <typename ToU>
0205 requires(Mutable && std::is_same_v<detail::GetMutableHandleType<ToT>, ToU> && detail::isMutableHandleType<ToU>)
0206 void setTo(ToU value) {
0207 setTo(detail::GetDefaultHandleType<ToU>(value));
0208 }
0209
0210
0211
0212
0213
0214
0215 template <typename ToU>
0216 requires(Mutable && detail::isInterfaceInitializableFrom<ToT, ToU>)
0217 void setTo(ToU value) {
0218 setTo(ToT(value));
0219 }
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 template <typename T>
0230 requires(!std::is_same_v<ToT, FromT> && isFromOrToT<T>)
0231 T get() const {
0232 if constexpr (std::is_same_v<T, FromT>) {
0233 return getFrom();
0234 } else {
0235 return getTo();
0236 }
0237 }
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248 template <size_t Index>
0249 requires(Index < 3)
0250 auto get() const {
0251 if constexpr (Index == 0) {
0252 return getFrom();
0253 } else if constexpr (Index == 1) {
0254 return getTo();
0255 } else {
0256 return getWeight();
0257 }
0258 }
0259
0260
0261
0262
0263
0264
0265
0266
0267 template <typename T>
0268 requires(Mutable && !std::is_same_v<ToT, FromT> &&
0269 (isMutableFromOrToT<T> || detail::isInterfaceInitializableFrom<ToT, T> ||
0270 detail::isInterfaceInitializableFrom<FromT, T>))
0271 void set(T value) {
0272 if constexpr (std::is_same_v<T, FromT>) {
0273 setFrom(std::move(value));
0274 } else if constexpr (std::is_same_v<T, ToT>) {
0275 setTo(std::move(value));
0276 } else if constexpr (detail::isInterfaceInitializableFrom<FromT, T> &&
0277 !detail::isInterfaceInitializableFrom<ToT, T>) {
0278 setFrom(std::move(value));
0279 } else if constexpr (detail::isInterfaceInitializableFrom<ToT, T> &&
0280 !detail::isInterfaceInitializableFrom<FromT, T>) {
0281 setTo(std::move(value));
0282 } else {
0283 static_assert(detail::always_false<T>, "Argument type is ambiguous, can't determine link direction");
0284 }
0285 }
0286
0287
0288 bool isAvailable() const {
0289 return m_obj;
0290 }
0291
0292
0293 void unlink() {
0294 m_obj = podio::utils::MaybeSharedPtr<LinkObjT>(nullptr);
0295 }
0296
0297
0298 podio::ObjectID getObjectID() const {
0299 if (m_obj) {
0300 return m_obj->id;
0301 }
0302 return podio::ObjectID{};
0303 }
0304
0305 podio::ObjectID id() const {
0306 return getObjectID();
0307 }
0308
0309 bool operator==(const LinkT& other) const {
0310 return m_obj == other.m_obj;
0311 }
0312
0313 bool operator!=(const LinkT& other) const {
0314 return !(*this == other);
0315 }
0316
0317 template <typename FromU, typename ToU>
0318 requires sameTypes<FromU, ToU>
0319 bool operator==(const LinkT<FromU, ToU, !Mutable>& other) const {
0320 return m_obj == other.m_obj;
0321 }
0322
0323 template <typename FromU, typename ToU>
0324 requires sameTypes<FromU, ToU>
0325 bool operator!=(const LinkT<FromU, ToU, !Mutable>& other) const {
0326 return !(*this == other);
0327 }
0328
0329 bool operator<(const LinkT& other) const {
0330 return m_obj < other.m_obj;
0331 }
0332
0333 friend void swap(LinkT& a, LinkT& b) {
0334 using std::swap;
0335 swap(a.m_obj, b.m_obj);
0336 }
0337
0338 private:
0339
0340 explicit LinkT(podio::utils::MaybeSharedPtr<LinkObjT> obj) : m_obj(std::move(obj)) {
0341 }
0342
0343 template <bool Mut = Mutable>
0344 requires(!Mut && !Mutable)
0345 LinkT(LinkObjT* obj) : m_obj(podio::utils::MaybeSharedPtr<LinkObjT>(obj)) {
0346 }
0347
0348 podio::utils::MaybeSharedPtr<LinkObjT> m_obj{nullptr};
0349 };
0350
0351 template <typename FromT, typename ToT>
0352 std::ostream& operator<<(std::ostream& os, const Link<FromT, ToT>& link) {
0353 if (!link.isAvailable()) {
0354 return os << "[not available]";
0355 }
0356
0357 return os << " id: " << link.id() << '\n'
0358 << " weight: " << link.getWeight() << '\n'
0359 << " from: " << link.getFrom().id() << '\n'
0360 << " to: " << link.getTo().id() << '\n';
0361 }
0362
0363 #if defined(PODIO_JSON_OUTPUT) && !defined(__CLING__)
0364 template <typename FromT, typename ToT>
0365 void to_json(nlohmann::json& j, const podio::LinkT<FromT, ToT, false>& link) {
0366 j = nlohmann::json{{"weight", link.getWeight()}};
0367
0368 j["from"] = nlohmann::json{{"collectionID", link.getFrom().getObjectID().collectionID},
0369 {"index", link.getFrom().getObjectID().index}};
0370
0371 j["to"] = nlohmann::json{{"collectionID", link.getTo().getObjectID().collectionID},
0372 {"index", link.getTo().getObjectID().index}};
0373 }
0374 #endif
0375
0376 }
0377
0378 template <typename FromT, typename ToT, bool Mutable>
0379 struct std::hash<podio::LinkT<FromT, ToT, Mutable>> {
0380 std::size_t operator()(const podio::LinkT<FromT, ToT, Mutable>& obj) const {
0381 return std::hash<typename podio::LinkT<FromT, ToT, Mutable>::LinkObjT*>{}(obj.m_obj.get());
0382 }
0383 };
0384
0385 #endif