Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-01 08:45:49

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