Logo ROOT   6.12/07
Reference Guide
TDirectory.hxx
Go to the documentation of this file.
1 /// \file ROOT/TDirectory.h
2 /// \ingroup Base ROOT7
3 /// \author Axel Naumann <axel@cern.ch>
4 /// \date 2015-07-31
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6 /// is welcome!
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #ifndef ROOT7_TDirectory
17 #define ROOT7_TDirectory
18 
19 #include "ROOT/TLogger.hxx"
20 #include "ROOT/TDirectoryEntry.hxx"
21 
22 #include <iterator>
23 #include <memory>
24 #include <type_traits>
25 #include <unordered_map>
26 #include <string>
27 #include <RStringView.h>
28 
29 namespace ROOT {
30 namespace Experimental {
31 
32 /**
33  Objects of this class are thrown to signal that no key with that name exists.
34  */
35 class TDirectoryUnknownKey: public std::exception {
36  std::string fKeyName;
37 
38 public:
39  TDirectoryUnknownKey(std::string_view keyName): fKeyName(keyName) {}
40  const char *what() const noexcept final { return fKeyName.c_str(); }
41 };
42 
43 /**
44  Objects of this class are thrown to signal that the value known under the
45  given name .
46  */
47 class TDirectoryTypeMismatch: public std::exception {
48  std::string fKeyName;
49  // FIXME: add expected and actual type names.
50 public:
51  TDirectoryTypeMismatch(std::string_view keyName): fKeyName(keyName) {}
52  const char *what() const noexcept final { return fKeyName.c_str(); }
53 };
54 
55 /**
56  Key/value store of objects.
57 
58  Given a name, a `TDirectory` can store and retrieve an object. It will manage
59  shared ownership through a `shared_ptr`.
60 
61  Example:
62  TDirectory dirMC;
63  TDirectory dirHiggs;
64 
65  dirMC.Add("higgs", histHiggsMC);
66  dirHiggs.Add("mc", histHiggsMC);
67 
68  */
69 
70 class TDirectory {
71  // TODO: ContentMap_t should allow lookup by string_view while still providing
72  // storage of names.
73 
74  /// The directory content is a hashed map of name => `Internal::TDirectoryEntry`.
75  using ContentMap_t = std::unordered_map<std::string, Internal::TDirectoryEntry>;
76 
77  /// The `TDirectory`'s content.
79 
80  template <class T>
81  struct ToContentType {
82  using decaytype = typename std::decay<T>::type;
83  using type =
84  typename std::enable_if<!std::is_pointer<decaytype>::value && !std::is_member_pointer<decaytype>::value &&
85  !std::is_void<decaytype>::value,
87  };
88  template <class T>
90 
91 public:
92  /// Create an object of type `T` (passing some arguments to its constructor).
93  /// The `TDirectory` will have shared ownership of the object.
94  ///
95  /// \param name - Key of the object.
96  /// \param args - arguments to be passed to the constructor of `T`
97  template <class T, class... ARGS>
98  std::shared_ptr<ToContentType_t<T>> Create(std::string_view name, ARGS &&... args)
99  {
100  auto ptr = std::make_shared<ToContentType_t<T>>(std::forward<ARGS>(args)...);
101  Add(name, ptr);
102  return ptr;
103  }
104 
105  /// Find the TDirectoryEntry associated to the name. Returns empty TDirectoryEntry if
106  /// nothing is found.
108  {
109  auto idx = fContent.find(std::string(name));
110  if (idx == fContent.end())
111  return nullptr;
112  return idx->second;
113  }
114 
115  /**
116  Status of the call to Find<T>(name).
117  */
118  enum class EFindStatus {
119  kValidValue, ///< Value known for this key name and type
120  kValidValueBase, ///< Value known for this key name and base type
121  kKeyNameNotFound, ///< No key is known for this name
122  kTypeMismatch ///< The provided type does not match the value's type.
123  };
124 
125  /// Find the TDirectoryEntry associated with the name.
126  /// \returns empty TDirectoryEntry in `first` if nothing is found, or if the type does not
127  /// match the expected type. `second` contains the reason.
128  /// \note if `second` is kValidValue, then static_pointer_cast<`T`>(`first`.GetPointer())
129  /// is shared_ptr<`T`> to initially stored object
130  /// \note if `second` is kValidValueBase, then `first`.CastPointer<`T`>()
131  /// is a valid cast to base class `T` of the stored object
132  template <class T>
133  std::pair<Internal::TDirectoryEntry, EFindStatus> Find(std::string_view name) const
134  {
135  auto idx = fContent.find(std::string(name));
136  if (idx == fContent.end())
137  return {nullptr, EFindStatus::kKeyNameNotFound};
138  if (idx->second.GetTypeInfo() == typeid(ToContentType_t<T>))
139  return {idx->second, EFindStatus::kValidValue};
140  if (idx->second.CastPointer<ToContentType_t<T>>())
141  return {idx->second, EFindStatus::kValidValueBase};
142  return {nullptr, EFindStatus::kTypeMismatch};
143  }
144 
145  /// Get the object for a key. `T` can be the object's type or a base class.
146  /// The `TDirectory` will return the same object for subsequent calls to
147  /// `Get().`
148  /// \returns a `shared_ptr` to the object or its base.
149  /// \throws TDirectoryUnknownKey if no object is stored under this name.
150  /// \throws TDirectoryTypeMismatch if the object stored under this name is of
151  /// a type that is not a derived type of `T`.
152  template <class T>
153  std::shared_ptr<ToContentType_t<T>> Get(std::string_view name)
154  {
155  const auto &pair = Find<T>(name);
156  const Internal::TDirectoryEntry &entry = pair.first;
157  EFindStatus status = pair.second;
158  switch (status) {
159  case EFindStatus::kValidValue: return std::static_pointer_cast<ToContentType_t<T>>(entry.GetPointer());
160  case EFindStatus::kValidValueBase: return entry.CastPointer<ToContentType_t<T>>();
161  case EFindStatus::kTypeMismatch:
162  // FIXME: add expected versus actual type name as c'tor args
163  throw TDirectoryTypeMismatch(name);
164  case EFindStatus::kKeyNameNotFound: throw TDirectoryUnknownKey(name);
165  }
166  return nullptr; // never happens
167  }
168 
169  /// Add an existing object (rather a `shared_ptr` to it) to the TDirectory.
170  /// The TDirectory will have shared ownership.
171  template <class T>
172  void Add(std::string_view name, const std::shared_ptr<T> &ptr)
173  {
174  Internal::TDirectoryEntry entry(ptr);
175  // FIXME: CXX17: insert_or_assign
176  std::string sName(name);
177  auto idx = fContent.find(sName);
178  if (idx != fContent.end()) {
179  R__LOG_HERE(ELogLevel::kWarning, "CORE") << "Replacing object with name \"" << name << "\"" << std::endl;
180  idx->second.swap(entry);
181  } else {
182  fContent[sName].swap(entry);
183  }
184  }
185 
186  /// Dedicated, process-wide TDirectory.
187  ///
188  /// \note This is *not* thread-safe. You will need to syncronize yourself. In
189  /// general it's a bad idea to use a global collection in a multi-threaded
190  /// environment; ROOT itself does not make use of it. It is merely offered for
191  /// historical, process-wide object registration by name. Instead, pass a
192  /// pointer to the object where you need to access it - this is also much
193  /// faster than a lookup by name.
194  static TDirectory &Heap();
195 };
196 
197 } // namespace Experimental
198 } // namespace ROOT
199 
200 #endif
#define ARGS(alist)
Definition: gifencode.c:10
basic_string_view< char > string_view
Definition: RStringView.h:35
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Internal::TDirectoryEntry Find(std::string_view name) const
Find the TDirectoryEntry associated to the name.
Definition: TDirectory.hxx:107
double T(double x)
Definition: ChebyshevPol.h:34
TDirectoryTypeMismatch(std::string_view keyName)
Definition: TDirectory.hxx:51
void Add(std::string_view name, const std::shared_ptr< T > &ptr)
Add an existing object (rather a shared_ptr to it) to the TDirectory.
Definition: TDirectory.hxx:172
TDirectoryUnknownKey(std::string_view keyName)
Definition: TDirectory.hxx:39
typename std::enable_if<!std::is_pointer< decaytype >::value &&!std::is_member_pointer< decaytype >::value &&!std::is_void< decaytype >::value, decaytype >::type type
Definition: TDirectory.hxx:86
typename ToContentType< T >::type ToContentType_t
Definition: TDirectory.hxx:89
EFindStatus
Status of the call to Find<T>(name).
Definition: TDirectory.hxx:118
std::unordered_map< std::string, Internal::TDirectoryEntry > ContentMap_t
The directory content is a hashed map of name => Internal::TDirectoryEntry.
Definition: TDirectory.hxx:75
Warnings about likely unexpected behavior.
ContentMap_t fContent
The TDirectory&#39;s content.
Definition: TDirectory.hxx:78
std::pair< Internal::TDirectoryEntry, EFindStatus > Find(std::string_view name) const
Find the TDirectoryEntry associated with the name.
Definition: TDirectory.hxx:133
std::shared_ptr< ToContentType_t< T > > Create(std::string_view name, ARGS &&... args)
Create an object of type T (passing some arguments to its constructor).
Definition: TDirectory.hxx:98
Objects of this class are thrown to signal that the value known under the given name ...
Definition: TDirectory.hxx:47
typename std::decay< T >::type decaytype
Definition: TDirectory.hxx:82
void Add(THist< DIMENSIONS, PRECISION_TO, STAT_TO... > &to, const THist< DIMENSIONS, PRECISION_FROM, STAT_FROM... > &from)
Add two histograms.
Definition: THist.hxx:308
int type
Definition: TGX11.cxx:120
const char * what() const noexcept final
Definition: TDirectory.hxx:52
const char * what() const noexcept final
Definition: TDirectory.hxx:40
#define R__LOG_HERE(LEVEL, GROUP)
Definition: TLogger.hxx:122
Key/value store of objects.
Definition: TDirectory.hxx:70
Objects of this class are thrown to signal that no key with that name exists.
Definition: TDirectory.hxx:35
std::shared_ptr< ToContentType_t< T > > Get(std::string_view name)
Get the object for a key.
Definition: TDirectory.hxx:153
char name[80]
Definition: TGX11.cxx:109