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