Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-03-28 07:48:28

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2025 Wouter Deconinck
0003 //
0004 // Modern datamodel glue for podio >= 1.3
0005 // This file uses podio's built-in TypeList support instead of code generation
0006 
0007 #pragma once
0008 
0009 #include <stdexcept>
0010 #include <string_view>
0011 #include <unordered_map>
0012 #include <type_traits>
0013 #include <fmt/format.h>
0014 #include <podio/CollectionBase.h>
0015 #include <podio/utilities/TypeHelpers.h>
0016 
0017 // Use umbrella headers if available (podio >= 1.3)
0018 #include "services/io/podio/datamodel_includes.h"
0019 
0020 // PodioTypeMap provides type traits for podio types
0021 // This mirrors the structure written by the legacy python generator,
0022 // and puts the types in the format expected by JANA2.
0023 template <typename T> struct PodioTypeMap {
0024   using collection_t = typename T::collection_type;
0025   using mutable_t    = typename T::mutable_type;
0026 };
0027 
0028 // CollectionVisitorMap builds a dispatch table from podio collection type names
0029 // to type-safe visitor functions for a given Visitor type.
0030 //
0031 // The Visitor template parameter is expected to be a callable type (e.g. a
0032 // functor, lambda, or class with operator()) that can be invoked for each
0033 // supported concrete collection type:
0034 //
0035 //   void operator()(const ConcreteCollectionType&);
0036 //
0037 // CollectionVisitorMap is instantiated once per Visitor (see VisitPodioCollection
0038 // below). At construction time it registers all EDM4hep and EDM4eic data and
0039 // link collection types by mapping their static typeName to a function that
0040 // will:
0041 //   1. downcast the generic podio::CollectionBase reference to the concrete
0042 //      collection type, and
0043 //   2. call the Visitor with that concrete collection.
0044 //
0045 // This map is then used by VisitPodioCollection to look up the correct
0046 // handler at runtime based on collection.getTypeName(), providing a
0047 // type-safe implementation of the visitor pattern over podio collections.
0048 template <typename Visitor> class CollectionVisitorMap {
0049 public:
0050   using FunctionType = void (*)(Visitor&, const podio::CollectionBase&);
0051 
0052 private:
0053   std::unordered_map<std::string_view, FunctionType> m_map;
0054 
0055   template <typename CollectionT>
0056   static void visitCollection(Visitor& visitor, const podio::CollectionBase& collection) {
0057     static_assert(std::is_base_of_v<podio::CollectionBase, CollectionT>,
0058                   "CollectionT must be derived from podio::CollectionBase");
0059     visitor(*static_cast<const CollectionT*>(&collection));
0060   }
0061 
0062   template <typename CollectionT> void addToMap() {
0063     m_map[CollectionT::typeName] = &visitCollection<CollectionT>;
0064   }
0065 
0066   template <typename DataT> void addDataTypeToMap() { addToMap<typename DataT::collection_type>(); }
0067 
0068   template <typename... DataTypes>
0069   void addAllDataCollections(podio::utils::TypeList<DataTypes...>) {
0070     (addDataTypeToMap<DataTypes>(), ...);
0071   }
0072 
0073   template <typename... LinkTypes>
0074   void addAllLinkCollections(podio::utils::TypeList<LinkTypes...>) {
0075     (addDataTypeToMap<LinkTypes>(), ...);
0076   }
0077 
0078 public:
0079   CollectionVisitorMap() {
0080     // Add all EDM4hep and EDM4eic data collection types
0081     addAllDataCollections(typename edm4hep::edm4hepDataTypes{});
0082     addAllDataCollections(typename edm4eic::edm4eicDataTypes{});
0083 
0084     // Add all EDM4hep and EDM4eic link collections
0085     addAllLinkCollections(typename edm4hep::edm4hepLinkTypes{});
0086     addAllLinkCollections(typename edm4eic::edm4eicLinkTypes{});
0087   }
0088 
0089   const auto& getMap() const { return m_map; }
0090 };
0091 
0092 // VisitPodioCollection is a visitor adaptor for type-safe processing of podio collections.
0093 //
0094 // This template implements a runtime-dispatch visitor pattern for
0095 // podio::CollectionBase instances. It uses the collection's
0096 // runtime type name together with CollectionVisitorMap to look up the
0097 // concrete collection type and call the provided @p Visitor on it.
0098 //
0099 // template parameter Visitor
0100 //   A type that models a callable taking a const reference to each
0101 //   supported concrete podio collection type. In practice, this means
0102 //   that for every collection type CollectionT registered in
0103 //   CollectionVisitorMap, the following expression must be well-formed:
0104 //
0105 //     visitor(const CollectionT&);
0106 //
0107 //   This can be satisfied either by giving Visitor a suitable
0108 //   operator() overload, or by providing free / member functions
0109 //   that are invocable with const CollectionT&.
0110 //
0111 // Usage:
0112 //   - Construct or obtain a Visitor instance.
0113 //   - Call VisitPodioCollection<Visitor>::operator() with the visitor
0114 //     and a podio::CollectionBase reference. The adaptor will:
0115 //       1. Look up the collection's concrete type by getTypeName().
0116 //       2. Cast the podio::CollectionBase to the matching concrete
0117 //          collection type.
0118 //       3. Invoke the visitor with a const CollectionT& argument.
0119 //
0120 // If the collection type name is not known to the registered EDM4hep or
0121 // EDM4eic datamodels, operator() throws std::runtime_error with a
0122 // descriptive error message.
0123 template <typename Visitor> struct VisitPodioCollection {
0124   void operator()(Visitor& visitor, const podio::CollectionBase& collection) {
0125     // Build the map once (static initialization)
0126     static const CollectionVisitorMap<Visitor> visitorMap;
0127 
0128     auto typeName = collection.getTypeName();
0129     auto it       = visitorMap.getMap().find(typeName);
0130 
0131     if (it != visitorMap.getMap().end()) {
0132       it->second(visitor, collection);
0133     } else {
0134       throw std::runtime_error(fmt::format(
0135           "Unrecognized podio typename: {}.\n"
0136           "This type was not found in the supported datamodels (EDM4hep, EDM4eic).\n"
0137           "Possible causes:\n"
0138           "  - The type is not defined in EDM4hep or EDM4eic datamodels.\n"
0139           "  - You may be using an incompatible or outdated version of the datamodels.\n"
0140           "  - There may be a typo in the type name.\n"
0141           "Please check your datamodel installation and ensure you are using compatible versions.",
0142           typeName));
0143     }
0144   }
0145 };