1111#include < ROOT/RError.hxx>
1212
1313#include < memory>
14+ #include < iostream>
1415#include < string_view>
1516#include < typeinfo>
1617
17- class TFile ;
18+ class TIterator ;
1819class TKey ;
20+ class TFile ;
1921
2022namespace ROOT {
2123namespace Experimental {
@@ -29,6 +31,92 @@ ROOT::RLogChannel &RFileLog();
2931
3032} // namespace Internal
3133
34+ /* *
35+ \class ROOT::Experimental::RFileKeyInfo
36+ \ingroup RFile
37+ \brief Information about an RFile object's Key.
38+
39+ Every object inside a ROOT file has an associated "Key" which contains metadata on the object, such as its name, type
40+ etc.
41+ Querying this information can be done via RFile::GetKeys() or RFile::GetKeysNonRecursive. Reading an object's Key
42+ doesn't deserialize the full object, so it's a relatively lightweight operation.
43+ */
44+ struct RFileKeyInfo {
45+ std::string fName ;
46+ std::string fTitle ;
47+ std::string fClassName ;
48+ std::uint16_t fCycle ;
49+ };
50+
51+ // / The iterable returned by RFile::GetKeys() and RFile::GetKeysNonRecursive()
52+ class RFileKeyIterable final {
53+ using Pattern_t = std::string;
54+
55+ TFile *fFile ;
56+ Pattern_t fPattern ;
57+ std::uint32_t fFlags = 0 ;
58+
59+ public:
60+ enum EFlags {
61+ kNone = 0 ,
62+ kRecursive = 1 << 0 ,
63+ };
64+
65+ class RIterator {
66+ friend class RFileKeyIterable ;
67+
68+ struct RIterStackElem {
69+ // This is ugly, but TList returns an (owning) pointer to a polymorphic TIterator...and we need this class
70+ // to be copy-constructible.
71+ std::shared_ptr<TIterator> fIter ;
72+ std::string fDirPath ;
73+
74+ RIterStackElem (TIterator *it, const std::string &path = " " ) : fIter (it), fDirPath (path) {}
75+ // NOTE: outlined to avoid including TIterator.h
76+ ~RIterStackElem ();
77+
78+ // fDirPath doesn't need to be compared because it's implied by fIter.
79+ bool operator ==(const RIterStackElem &other) const { return fIter == other.fIter ; }
80+ };
81+
82+ std::vector<RIterStackElem> fIterStack ;
83+ Pattern_t fPattern ;
84+ const TKey *fCurKey = nullptr ;
85+ std::uint16_t fRootDirNesting = 0 ;
86+ std::uint32_t fFlags = 0 ;
87+
88+ void Advance ();
89+
90+ // NOTE: `iter` here is an owning pointer (or null)
91+ RIterator (TIterator *iter, Pattern_t pattern, std::uint32_t flags);
92+
93+ public:
94+ using iterator = RIterator;
95+ using iterator_category = std::forward_iterator_tag;
96+ using difference_type = std::ptrdiff_t ;
97+ using value_type = RFileKeyInfo;
98+ using pointer = const value_type *;
99+ using reference = const value_type &;
100+
101+ iterator &operator ++()
102+ {
103+ Advance ();
104+ return *this ;
105+ }
106+ value_type operator *();
107+ bool operator !=(const iterator &rh) const { return !(*this == rh); }
108+ bool operator ==(const iterator &rh) const { return fIterStack == rh.fIterStack ; }
109+ };
110+
111+ RFileKeyIterable (TFile *file, std::string_view rootDir, std::uint32_t flags)
112+ : fFile (file), fPattern (std::string(rootDir)), fFlags (flags)
113+ {
114+ }
115+
116+ RIterator begin () const ;
117+ RIterator end () const ;
118+ };
119+
32120/* *
33121\class ROOT::Experimental::RFile
34122\ingroup RFile
@@ -103,8 +191,7 @@ class RFile final {
103191
104192 std::unique_ptr<TFile> fFile ;
105193
106- // Outlined to avoid including TFile.h
107- explicit RFile (std::unique_ptr<TFile> file);
194+ explicit RFile (std::unique_ptr<TFile> file) : fFile(std::move(file)) {}
108195
109196 // / Gets object `path` from the file and returns an **owning** pointer to it.
110197 // / The caller should immediately wrap it into a unique_ptr of the type described by `type`.
@@ -147,7 +234,7 @@ public:
147234
148235 // /// Instance methods /////
149236
150- // Outlined to avoid including TFile.h
237+ // NOTE: outlined to avoid including TFile.h
151238 ~RFile ();
152239
153240 // / Retrieves an object from the file.
@@ -196,6 +283,31 @@ public:
196283
197284 // / Flushes the RFile if needed and closes it, disallowing any further reading or writing.
198285 void Close ();
286+
287+ // / Returns an iterable over all paths of objects written into this RFile starting at path "rootPath".
288+ // / The returned paths are always "absolute" paths: they are not relative to `rootPath`.
289+ // / Keys relative to directories are not returned: only those relative to leaf objects are.
290+ // / If `rootPath` is the path of a leaf object, only `rootPath` itself will be returned.
291+ // / This recurses on all the subdirectories of `rootPath`. If you only want the immediate children of `rootPath`,
292+ // / use GetKeysNonRecursive().
293+ RFileKeyIterable GetKeys (std::string_view rootPath = " " ) const
294+ {
295+ return RFileKeyIterable (fFile .get (), rootPath, RFileKeyIterable::kRecursive );
296+ }
297+
298+ // / Returns an iterable over all paths of objects written into this RFile contained in the directory "rootPath".
299+ // / The returned paths are always "absolute" paths: they are not relative to `rootPath`.
300+ // / Keys relative to directories are not returned: only those relative to leaf objects are.
301+ // / If `rootPath` is the path of a leaf object, only `rootPath` itself will be returned.
302+ // / This only returns the immediate children of `rootPath`. If you want to recurse into the subdirectories of
303+ // / `rootPath`, use GetKeys().
304+ RFileKeyIterable GetKeysNonRecursive (std::string_view rootPath = " " ) const
305+ {
306+ return RFileKeyIterable (fFile .get (), rootPath, RFileKeyIterable::kNone );
307+ }
308+
309+ // / Prints the internal structure of this RFile to the given stream.
310+ void Print (std::ostream &out = std::cout) const ;
199311};
200312
201313} // namespace Experimental
0 commit comments