Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:25:08

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