-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[rfile] Introduce RFile first prototype #19958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,138 @@ | ||||||||||
/// \file ROOT/RFile.hxx | ||||||||||
/// \ingroup Base ROOT7 | ||||||||||
/// \author Giacomo Parolini <[email protected]> | ||||||||||
/// \date 2025-03-19 | ||||||||||
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback | ||||||||||
/// is welcome! | ||||||||||
|
||||||||||
#ifndef ROOT7_RFile | ||||||||||
#define ROOT7_RFile | ||||||||||
|
||||||||||
#include <ROOT/RError.hxx> | ||||||||||
|
||||||||||
#include <memory> | ||||||||||
#include <string_view> | ||||||||||
#include <typeinfo> | ||||||||||
|
||||||||||
class TFile; | ||||||||||
class TKey; | ||||||||||
|
||||||||||
namespace ROOT { | ||||||||||
namespace Experimental { | ||||||||||
|
||||||||||
class RFile; | ||||||||||
struct RFileKeyInfo; | ||||||||||
|
||||||||||
namespace Internal { | ||||||||||
|
||||||||||
ROOT::RLogChannel &RFileLog(); | ||||||||||
|
||||||||||
} // namespace Internal | ||||||||||
|
||||||||||
/** | ||||||||||
\class ROOT::Experimental::RFile | ||||||||||
\ingroup RFile | ||||||||||
\brief An interface to read from, or write to, a ROOT file, as well as performing other common operations. | ||||||||||
|
||||||||||
TODO: more in-depth explanation | ||||||||||
*/ | ||||||||||
class RFile final { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A larger docstring for the class documentation would be desirable, but it
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Considering we're not defining any virtual method (including the destructor) I don't see how the user could effectively inherit this class anyway. If we change our mind later we can just remove the |
||||||||||
enum PutFlags { | ||||||||||
kPutAllowOverwrite = 0x1, | ||||||||||
kPutOverwriteKeepCycle = 0x2, | ||||||||||
}; | ||||||||||
|
||||||||||
std::unique_ptr<TFile> fFile; | ||||||||||
|
||||||||||
// Outlined to avoid including TFile.h | ||||||||||
explicit RFile(std::unique_ptr<TFile> file); | ||||||||||
|
||||||||||
/// Gets object `path` from the file and returns an **owning** pointer to it. | ||||||||||
/// The caller should immediately wrap it into a unique_ptr of the type described by `type`. | ||||||||||
[[nodiscard]] void *GetUntyped(std::string_view path, const std::type_info &type) const; | ||||||||||
|
||||||||||
/// Writes `obj` to file, without taking its ownership. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this makes it clearer?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An explanation of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I see now that this is private, so the request has low priority. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about the "a copy of" part; the object is not really copied in memory, it's just serialized into the file. At least, that's the mental model that the both us and the user should have, regardless of how TFile actually implements it |
||||||||||
void PutUntyped(std::string_view path, const std::type_info &type, const void *obj, std::uint32_t flags); | ||||||||||
|
||||||||||
/// \see Put | ||||||||||
template <typename T> | ||||||||||
void PutInternal(std::string_view path, const T &obj, std::uint32_t flags) | ||||||||||
{ | ||||||||||
PutUntyped(path, typeid(T), &obj, flags); | ||||||||||
} | ||||||||||
|
||||||||||
/// Given `path`, returns the TKey corresponding to the object at that path (assuming the path is fully split, i.e. | ||||||||||
/// "a/b/c" always means "object 'c' inside directory 'b' inside directory 'a'"). | ||||||||||
/// IMPORTANT: `path` must have been validated/normalized via ValidateAndNormalizePath() (see RFile.cxx). | ||||||||||
TKey *GetTKey(std::string_view path) const; | ||||||||||
|
||||||||||
public: | ||||||||||
// This is arbitrary, but it's useful to avoid pathological cases | ||||||||||
static constexpr int kMaxPathNesting = 1000; | ||||||||||
|
||||||||||
///// Factory methods ///// | ||||||||||
|
||||||||||
/// Opens the file for reading | ||||||||||
static std::unique_ptr<RFile> Open(std::string_view path); | ||||||||||
|
||||||||||
/// Opens the file for reading/writing, overwriting it if it already exists | ||||||||||
static std::unique_ptr<RFile> Recreate(std::string_view path); | ||||||||||
|
||||||||||
/// Opens the file for updating | ||||||||||
static std::unique_ptr<RFile> OpenForUpdate(std::string_view path); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
|
||||||||||
///// Instance methods ///// | ||||||||||
|
||||||||||
// Outlined to avoid including TFile.h | ||||||||||
~RFile(); | ||||||||||
|
||||||||||
/// Retrieves an object from the file. | ||||||||||
/// `path` should be a string such that `IsValidPath(path) == true`, otherwise an exception will be thrown. | ||||||||||
/// If the object is not there returns a null pointer. | ||||||||||
template <typename T> | ||||||||||
std::unique_ptr<T> Get(std::string_view path) const | ||||||||||
{ | ||||||||||
void *obj = GetUntyped(path, typeid(T)); | ||||||||||
return std::unique_ptr<T>(static_cast<T *>(obj)); | ||||||||||
} | ||||||||||
|
||||||||||
/// Puts an object into the file. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
/// The application retains ownership of the object. | ||||||||||
/// `path` should be a string such that `IsValidPath(path) == true`, otherwise an exception will be thrown. | ||||||||||
/// | ||||||||||
/// Throws a RException if `path` already identifies a valid object or directory. | ||||||||||
/// Throws a RException if the file was opened in read-only mode. | ||||||||||
template <typename T> | ||||||||||
void Put(std::string_view path, const T &obj) | ||||||||||
{ | ||||||||||
PutInternal(path, obj, /* flags = */ 0); | ||||||||||
} | ||||||||||
|
||||||||||
/// Puts an object into the file, overwriting any previously-existing object at that path. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment above |
||||||||||
/// The application retains ownership of the object. | ||||||||||
/// | ||||||||||
/// If an object already exists at that path, it is kept as a backup cycle unless `backupPrevious` is false. | ||||||||||
/// Note that even if `backupPrevious` is false, any existing cycle except the latest will be preserved. | ||||||||||
/// | ||||||||||
/// Throws a RException if `path` is already the path of a directory. | ||||||||||
/// Throws a RException if the file was opened in read-only mode. | ||||||||||
template <typename T> | ||||||||||
void Overwrite(std::string_view path, const T &obj, bool backupPrevious = true) | ||||||||||
{ | ||||||||||
std::uint32_t flags = kPutAllowOverwrite; | ||||||||||
flags |= backupPrevious * kPutOverwriteKeepCycle; | ||||||||||
PutInternal(path, obj, flags); | ||||||||||
} | ||||||||||
|
||||||||||
/// Writes all objects to disk with the file structure. | ||||||||||
/// Returns the number of bytes written. | ||||||||||
size_t Write(); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the number of bytes written make sense here if the other write functions return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which other write functions? You mean There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
or
Suggested change
|
||||||||||
|
||||||||||
/// Flushes the RFile if needed and closes it, disallowing any further reading or writing. | ||||||||||
void Close(); | ||||||||||
}; | ||||||||||
|
||||||||||
} // namespace Experimental | ||||||||||
} // namespace ROOT | ||||||||||
|
||||||||||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After yesterday's discussion, is it wise to put this in
io/v7
? Version numbers in file names or configs will just create headaches. How about putting it inio/rfile
, where it can remain also in the future?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the end I just put it in
io/io
to avoid CMake headaches. Since it's always built anyway it doesn't make much of a difference in my opinion.