Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-06 09:30:08

0001 #ifndef PODIO_GENERICPARAMETERS_H
0002 #define PODIO_GENERICPARAMETERS_H
0003 
0004 #include "podio/utilities/TypeHelpers.h"
0005 
0006 #include <algorithm>
0007 #include <iostream>
0008 #include <iterator>
0009 #include <map>
0010 #include <memory>
0011 #include <mutex>
0012 #include <optional>
0013 #include <string>
0014 #include <vector>
0015 
0016 #if PODIO_ENABLE_SIO
0017 namespace sio {
0018 class read_device;
0019 class write_device;
0020 using version_type = uint32_t; // from sio/definitions
0021 } // namespace sio
0022 #endif
0023 
0024 namespace podio {
0025 
0026 /// The types which are supported in the GenericParameters
0027 using SupportedGenericDataTypes = std::tuple<int, float, std::string, double>;
0028 
0029 /// Static bool for determining if a type T is a supported GenericParameters type
0030 template <typename T>
0031 inline constexpr bool isSupportedGenericDataType = detail::isAnyOrVectorOf<T, SupportedGenericDataTypes>;
0032 
0033 /// Concept to be used for templates that should only be present for actually supported data types
0034 template <typename T>
0035 concept ValidGenericDataType = isSupportedGenericDataType<T>;
0036 
0037 /// GenericParameters objects allow one to store generic named parameters of type
0038 ///  int, float and string or vectors of these types.
0039 ///  They can be used  to store (user) meta data that is
0040 ///  run, event or collection dependent.
0041 ///  (based on lcio::LCParameters)
0042 ///
0043 /// @author F. Gaede, DESY
0044 /// @date Apr 2020
0045 class GenericParameters {
0046 public:
0047   template <typename T>
0048   using MapType = std::map<std::string, std::vector<T>>;
0049 
0050 private:
0051   // need mutex pointers for having the possibility to copy/move GenericParameters
0052   using MutexPtr = std::unique_ptr<std::mutex>;
0053 
0054 public:
0055   GenericParameters() = default;
0056 
0057   /// GenericParameters are copyable
0058   /// @note This is currently mainly done to keep the ROOT I/O happy, because
0059   /// that needs a copy constructor
0060   GenericParameters(const GenericParameters&);
0061   GenericParameters& operator=(const GenericParameters&) = delete;
0062 
0063   /// GenericParameters are default moveable
0064   GenericParameters(GenericParameters&&) = default;
0065   GenericParameters& operator=(GenericParameters&&) = default;
0066 
0067   ~GenericParameters() = default;
0068 
0069   template <ValidGenericDataType T>
0070   std::optional<T> get(const std::string& key) const;
0071 
0072   /// Store (a copy of) the passed value under the given key
0073   template <ValidGenericDataType T>
0074   void set(const std::string& key, T value);
0075 
0076   /// Overload for catching const char* setting for string values
0077   void set(const std::string& key, const char* value) {
0078     set<std::string>(key, std::string(value));
0079   }
0080 
0081   /// Overload for catching initializer list setting of string vector values
0082   void set(const std::string& key, std::vector<std::string> values) {
0083     set<std::vector<std::string>>(key, std::move(values));
0084   }
0085 
0086   /// Overload for catching initializer list setting for vector values
0087   template <ValidGenericDataType T>
0088   void set(const std::string& key, std::initializer_list<T>&& values) {
0089     set<std::vector<T>>(key, std::move(values));
0090   }
0091 
0092   /// Load multiple key value pairs simultaneously
0093   template <typename T, template <typename...> typename VecLike>
0094   void loadFrom(VecLike<std::string> keys, VecLike<std::vector<T>> values);
0095 
0096   /// Get the number of elements stored under the given key for a type
0097   template <ValidGenericDataType T>
0098   size_t getN(const std::string& key) const;
0099 
0100   /// Get all available keys for a given type
0101   template <ValidGenericDataType T>
0102   std::vector<std::string> getKeys() const;
0103 
0104   /// Get all the available values for a given type
0105   template <ValidGenericDataType T>
0106   std::tuple<std::vector<std::string>, std::vector<std::vector<T>>> getKeysAndValues() const;
0107 
0108   /// erase all elements
0109   void clear() {
0110     _intMap.clear();
0111     _floatMap.clear();
0112     _doubleMap.clear();
0113     _stringMap.clear();
0114   }
0115 
0116   void print(std::ostream& os = std::cout, bool flush = true) const;
0117 
0118   /// Check if no parameter is stored (i.e. if all internal maps are empty)
0119   bool empty() const {
0120     return _intMap.empty() && _floatMap.empty() && _doubleMap.empty() && _stringMap.empty();
0121   }
0122 
0123 #if PODIO_ENABLE_SIO
0124   friend void writeGenericParameters(sio::write_device& device, const GenericParameters& parameters);
0125   friend void readGenericParameters(sio::read_device& device, GenericParameters& parameters, sio::version_type version);
0126 #endif
0127 
0128   /// Get a reference to the internal map for a given type
0129   template <typename T>
0130   const MapType<detail::GetVectorType<T>>& getMap() const {
0131     if constexpr (std::is_same_v<detail::GetVectorType<T>, int>) {
0132       return _intMap;
0133     } else if constexpr (std::is_same_v<detail::GetVectorType<T>, float>) {
0134       return _floatMap;
0135     } else if constexpr (std::is_same_v<detail::GetVectorType<T>, double>) {
0136       return _doubleMap;
0137     } else {
0138       return _stringMap;
0139     }
0140   }
0141 
0142 private:
0143   /// Get a reference to the internal map for a given type
0144   template <typename T>
0145   MapType<detail::GetVectorType<T>>& getMap() {
0146     if constexpr (std::is_same_v<detail::GetVectorType<T>, int>) {
0147       return _intMap;
0148     } else if constexpr (std::is_same_v<detail::GetVectorType<T>, float>) {
0149       return _floatMap;
0150     } else if constexpr (std::is_same_v<detail::GetVectorType<T>, double>) {
0151       return _doubleMap;
0152     } else {
0153       return _stringMap;
0154     }
0155   }
0156 
0157   /// Get the mutex that guards the map for the given type
0158   template <typename T>
0159   std::mutex& getMutex() const {
0160     if constexpr (std::is_same_v<detail::GetVectorType<T>, int>) {
0161       return *(m_intMtx.get());
0162     } else if constexpr (std::is_same_v<detail::GetVectorType<T>, float>) {
0163       return *(m_floatMtx.get());
0164     } else if constexpr (std::is_same_v<detail::GetVectorType<T>, double>) {
0165       return *(m_doubleMtx.get());
0166     } else {
0167       return *(m_stringMtx.get());
0168     }
0169   }
0170 
0171 private:
0172   MapType<int> _intMap{};                                       ///< The map storing the integer values
0173   mutable MutexPtr m_intMtx{std::make_unique<std::mutex>()};    ///< The mutex guarding the integer map
0174   MapType<float> _floatMap{};                                   ///< The map storing the float values
0175   mutable MutexPtr m_floatMtx{std::make_unique<std::mutex>()};  ///< The mutex guarding the float map
0176   MapType<std::string> _stringMap{};                            ///< The map storing the string values
0177   mutable MutexPtr m_stringMtx{std::make_unique<std::mutex>()}; ///< The mutex guarding the string map
0178   MapType<double> _doubleMap{};                                 ///< The map storing the double values
0179   mutable MutexPtr m_doubleMtx{std::make_unique<std::mutex>()}; ///< The mutex guarding the double map
0180 };
0181 
0182 template <ValidGenericDataType T>
0183 std::optional<T> GenericParameters::get(const std::string& key) const {
0184   const auto& map = getMap<T>();
0185   auto& mtx = getMutex<T>();
0186   std::lock_guard lock{mtx};
0187   const auto it = map.find(key);
0188   if (it == map.end()) {
0189     return std::nullopt;
0190   }
0191 
0192   // We have to check whether the return type is a vector or a single value
0193   if constexpr (detail::isVector<T>) {
0194     return it->second;
0195   } else {
0196     const auto& iv = it->second;
0197     if (iv.empty()) {
0198       return std::nullopt;
0199     }
0200     return iv[0];
0201   }
0202 }
0203 
0204 template <ValidGenericDataType T>
0205 void GenericParameters::set(const std::string& key, T value) {
0206   auto& map = getMap<T>();
0207   auto& mtx = getMutex<T>();
0208 
0209   if constexpr (detail::isVector<T>) {
0210     std::lock_guard lock{mtx};
0211     map.insert_or_assign(key, std::move(value));
0212   } else {
0213     // Wrap the value into a vector with exactly one entry and store that
0214     std::vector<T> v = {std::move(value)};
0215     std::lock_guard lock{mtx};
0216     map.insert_or_assign(key, std::move(v));
0217   }
0218 }
0219 
0220 template <ValidGenericDataType T>
0221 size_t GenericParameters::getN(const std::string& key) const {
0222   const auto& map = getMap<T>();
0223   auto& mtx = getMutex<T>();
0224   std::lock_guard lock{mtx};
0225   if (const auto it = map.find(key); it != map.end()) {
0226     return it->second.size();
0227   }
0228   return 0;
0229 }
0230 
0231 template <ValidGenericDataType T>
0232 std::vector<std::string> GenericParameters::getKeys() const {
0233   std::vector<std::string> keys;
0234   const auto& map = getMap<T>();
0235   keys.reserve(map.size());
0236   {
0237     auto& mtx = getMutex<T>();
0238     std::lock_guard lock{mtx};
0239     std::transform(map.begin(), map.end(), std::back_inserter(keys), [](const auto& pair) { return pair.first; });
0240   }
0241 
0242   return keys;
0243 }
0244 
0245 template <ValidGenericDataType T>
0246 std::tuple<std::vector<std::string>, std::vector<std::vector<T>>> GenericParameters::getKeysAndValues() const {
0247   std::vector<std::vector<T>> values;
0248   std::vector<std::string> keys;
0249   auto& mtx = getMutex<T>();
0250   const auto& map = getMap<T>();
0251   {
0252     // Lock to avoid concurrent changes to the map while we get the stored
0253     // values
0254     std::lock_guard lock{mtx};
0255     values.reserve(map.size());
0256     keys.reserve(map.size());
0257 
0258     for (const auto& [k, v] : map) {
0259       keys.emplace_back(k);
0260       values.emplace_back(v);
0261     }
0262   }
0263   return {keys, values};
0264 }
0265 
0266 template <typename T, template <typename...> typename VecLike>
0267 void GenericParameters::loadFrom(VecLike<std::string> keys, VecLike<std::vector<T>> values) {
0268   auto& map = getMap<T>();
0269   auto& mtx = getMutex<T>();
0270 
0271   std::lock_guard lock{mtx};
0272   for (size_t i = 0; i < keys.size(); ++i) {
0273     map.emplace(std::move(keys[i]), std::move(values[i]));
0274   }
0275 }
0276 
0277 } // namespace podio
0278 #endif