Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:10:38

0001 /// \file ROOT/RDirectory.hxx
0002 /// \ingroup Base ROOT7
0003 /// \author Axel Naumann <axel@cern.ch>
0004 /// \date 2015-07-31
0005 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
0006 /// is welcome!
0007 
0008 /*************************************************************************
0009  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
0010  * All rights reserved.                                                  *
0011  *                                                                       *
0012  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0013  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0014  *************************************************************************/
0015 
0016 #ifndef ROOT7_RDirectory
0017 #define ROOT7_RDirectory
0018 
0019 #include "ROOT/RDirectoryEntry.hxx"
0020 #include "ROOT/RLogger.hxx"
0021 
0022 #include <iterator>
0023 #include <memory>
0024 #include <type_traits>
0025 #include <unordered_map>
0026 #include <string>
0027 #include <string_view>
0028 
0029 namespace ROOT {
0030 namespace Experimental {
0031 
0032 /// Logging for generic IO functionality.
0033 RLogChannel &IOLog();
0034 
0035 /**
0036   Objects of this class are thrown to signal that no key with that name exists.
0037  */
0038 class RDirectoryUnknownKey: public std::exception {
0039    std::string fKeyName;
0040 
0041 public:
0042    RDirectoryUnknownKey(std::string_view keyName): fKeyName(keyName) {}
0043    const char *what() const noexcept final { return fKeyName.c_str(); }
0044 };
0045 
0046 /**
0047   Objects of this class are thrown to signal that the value known under the
0048   given name .
0049  */
0050 class RDirectoryTypeMismatch: public std::exception {
0051    std::string fKeyName;
0052    // FIXME: add expected and actual type names.
0053 public:
0054    RDirectoryTypeMismatch(std::string_view keyName): fKeyName(keyName) {}
0055    const char *what() const noexcept final { return fKeyName.c_str(); }
0056 };
0057 
0058 /**
0059  Key/value store of objects.
0060 
0061  Given a name, a `RDirectory` can store and retrieve an object. It will manage
0062  shared ownership through a `shared_ptr`.
0063 
0064  Example:
0065   RDirectory dirMC;
0066   RDirectory dirHiggs;
0067 
0068   dirMC.Add("higgs", histHiggsMC);
0069   dirHiggs.Add("mc", histHiggsMC);
0070 
0071  */
0072 
0073 class RDirectory {
0074    // TODO: ContentMap_t should allow lookup by string_view while still providing
0075    // storage of names.
0076 
0077    /// The directory content is a hashed map of name => `Internal::RDirectoryEntry`.
0078    using ContentMap_t = std::unordered_map<std::string, Internal::RDirectoryEntry>;
0079 
0080    /// The `RDirectory`'s content.
0081    ContentMap_t fContent;
0082 
0083    template <class T>
0084    struct ToContentType {
0085       using decaytype = typename std::decay<T>::type;
0086       using type =
0087          typename std::enable_if<!std::is_pointer<decaytype>::value && !std::is_member_pointer<decaytype>::value &&
0088                                     !std::is_void<decaytype>::value,
0089                                  decaytype>::type;
0090    };
0091    template <class T>
0092    using ToContentType_t = typename ToContentType<T>::type;
0093 
0094 public:
0095    /// Create an object of type `T` (passing some arguments to its constructor).
0096    /// The `RDirectory` will have shared ownership of the object.
0097    ///
0098    /// \param name  - Key of the object.
0099    /// \param args  - arguments to be passed to the constructor of `T`
0100    template <class T, class... ARGS>
0101    std::shared_ptr<ToContentType_t<T>> Create(std::string_view name, ARGS &&... args)
0102    {
0103       auto ptr = std::make_shared<ToContentType_t<T>>(std::forward<ARGS>(args)...);
0104       Add(name, ptr);
0105       return ptr;
0106    }
0107 
0108    /// Find the RDirectoryEntry associated to the name. Returns empty RDirectoryEntry if
0109    /// nothing is found.
0110    Internal::RDirectoryEntry Find(std::string_view name) const
0111    {
0112       auto idx = fContent.find(std::string(name));
0113       if (idx == fContent.end())
0114          return nullptr;
0115       return idx->second;
0116    }
0117 
0118    /**
0119    Status of the call to Find<T>(name).
0120    */
0121    enum class EFindStatus {
0122       kValidValue,      ///< Value known for this key name and type
0123       kValidValueBase,  ///< Value known for this key name and base type
0124       kKeyNameNotFound, ///< No key is known for this name
0125       kTypeMismatch     ///< The provided type does not match the value's type.
0126    };
0127 
0128    /// Find the RDirectoryEntry associated with the name.
0129    /// \returns empty RDirectoryEntry in `first` if nothing is found, or if the type does not
0130    ///    match the expected type. `second` contains the reason.
0131    /// \note if `second` is kValidValue, then static_pointer_cast<`T`>(`first`.GetPointer())
0132    ///    is shared_ptr<`T`> to initially stored object
0133    /// \note if `second` is kValidValueBase, then `first`.CastPointer<`T`>()
0134    ///    is a valid cast to base class `T` of the stored object
0135    template <class T>
0136    std::pair<Internal::RDirectoryEntry, EFindStatus> Find(std::string_view name) const
0137    {
0138       auto idx = fContent.find(std::string(name));
0139       if (idx == fContent.end())
0140          return {nullptr, EFindStatus::kKeyNameNotFound};
0141       if (idx->second.GetTypeInfo() == typeid(ToContentType_t<T>))
0142          return {idx->second, EFindStatus::kValidValue};
0143       if (idx->second.CastPointer<ToContentType_t<T>>())
0144          return {idx->second, EFindStatus::kValidValueBase};
0145       return {nullptr, EFindStatus::kTypeMismatch};
0146    }
0147 
0148    /// Get the object for a key. `T` can be the object's type or a base class.
0149    /// The `RDirectory` will return the same object for subsequent calls to
0150    /// `Get().`
0151    /// \returns a `shared_ptr` to the object or its base.
0152    /// \throws RDirectoryUnknownKey if no object is stored under this name.
0153    /// \throws RDirectoryTypeMismatch if the object stored under this name is of
0154    ///   a type that is not a derived type of `T`.
0155    template <class T>
0156    std::shared_ptr<ToContentType_t<T>> Get(std::string_view name)
0157    {
0158       const auto &pair = Find<T>(name);
0159       const Internal::RDirectoryEntry &entry = pair.first;
0160       EFindStatus status = pair.second;
0161       switch (status) {
0162       case EFindStatus::kValidValue: return std::static_pointer_cast<ToContentType_t<T>>(entry.GetPointer());
0163       case EFindStatus::kValidValueBase: return entry.CastPointer<ToContentType_t<T>>();
0164       case EFindStatus::kTypeMismatch:
0165          // FIXME: add expected versus actual type name as c'tor args
0166          throw RDirectoryTypeMismatch(name);
0167       case EFindStatus::kKeyNameNotFound: throw RDirectoryUnknownKey(name);
0168       }
0169       return nullptr; // never happens
0170    }
0171 
0172    /// Add an existing object (rather a `shared_ptr` to it) to the RDirectory.
0173    /// The RDirectory will have shared ownership.
0174    template <class T>
0175    void Add(std::string_view name, const std::shared_ptr<T> &ptr)
0176    {
0177       Internal::RDirectoryEntry entry(ptr);
0178       // FIXME: CXX17: insert_or_assign
0179       std::string sName(name);
0180       auto idx = fContent.find(sName);
0181       if (idx != fContent.end()) {
0182          R__LOG_WARNING(IOLog()) << "Replacing object with name \"" << name << "\"" << std::endl;
0183          idx->second.swap(entry);
0184       } else {
0185          fContent[sName].swap(entry);
0186       }
0187    }
0188 
0189    /// Remove entry from RDirectory (if exists)
0190    bool Remove(std::string_view name)
0191    {
0192       std::string sName(name);
0193       auto idx = fContent.find(sName);
0194       if (idx != fContent.end()) {
0195          fContent.erase(idx);
0196          return true;
0197       }
0198       return false;
0199    }
0200 
0201 
0202    /// Dedicated, process-wide RDirectory.
0203    ///
0204    /// \note This is *not* thread-safe. You will need to syncronize yourself. In
0205    /// general it's a bad idea to use a global collection in a multi-threaded
0206    /// environment; ROOT itself does not make use of it. It is merely offered for
0207    /// historical, process-wide object registration by name. Instead, pass a
0208    /// pointer to the object where you need to access it - this is also much
0209    /// faster than a lookup by name.
0210    static RDirectory &Heap();
0211 };
0212 
0213 } // namespace Experimental
0214 } // namespace ROOT
0215 
0216 #endif