Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:06:09

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