Skip to content
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

Add a reader and writer interface #522

Merged
merged 37 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
af26e1b
Change ROOTNTuple{Reader,Writer} to ROOTRNTuple{Reader,Writer}
jmcarcell Jan 25, 2024
9d04697
clang-format
jmcarcell Jan 22, 2024
7c7d387
Use RNTuple{Reader,Writer}
jmcarcell Jan 25, 2024
455cffc
Add test, reader and writer
jmcarcell Feb 6, 2024
6588de8
Change to RNTuple{Reader,Writer} instead ROOTRNTuple{Reader,Writer}
jmcarcell Jan 22, 2024
7417c48
Use std::unique_ptr<T>
jmcarcell Jan 22, 2024
fe78005
Push some changes needed for tests
jmcarcell Jan 22, 2024
1aee85a
Return the reader and writer by value
jmcarcell Jan 23, 2024
fd70b54
Add mising returns
jmcarcell Jan 23, 2024
7d84e15
Add python bindings for the reader and writer by reusing the current
jmcarcell Feb 6, 2024
c60a53c
Remove std::move
jmcarcell Jan 23, 2024
da4b569
Fix #ifs
jmcarcell Jan 23, 2024
d3262d4
Fix pre-commit
jmcarcell Feb 6, 2024
994c7f6
Exclude the new tests from running with sanitizers
jmcarcell Jan 25, 2024
bebfd07
Fix the RNTupleWriter header
jmcarcell Jan 25, 2024
df2fe45
Add another fix
jmcarcell Jan 25, 2024
2b43a3d
Fix also the RNTupleReader
jmcarcell Jan 25, 2024
2ea218b
Update after a rebase
jmcarcell Apr 22, 2024
72e7337
Remove changes in python
jmcarcell Apr 22, 2024
68e6a23
Remove a few methods from the concept and model
jmcarcell Apr 22, 2024
be7662c
Fix clang 12
jmcarcell Apr 22, 2024
e30621e
Fix clang 12
jmcarcell Apr 22, 2024
162a293
Let clang 12 fail
jmcarcell Apr 22, 2024
98bee52
Use final, make error messages a bit more verbose
jmcarcell Apr 29, 2024
6168cb9
Add a new podioIO library
jmcarcell Apr 29, 2024
6655ff9
Add sio files to gitignore
jmcarcell Apr 29, 2024
866731b
Link with podioRootIO
jmcarcell Apr 29, 2024
fb9764b
Remove public definitions
jmcarcell Apr 29, 2024
0ed53e9
Fix style
jmcarcell Apr 29, 2024
648a90b
Fix style
jmcarcell Apr 29, 2024
249c59c
Make sure test exclusion matches new test names
tmadlener May 2, 2024
a74d7aa
Split RTNtuple based interface tests off to make sanitizers run on them
tmadlener May 2, 2024
70a529b
Move unique_ptr instead of releasing and acquiring it
tmadlener May 3, 2024
df642d3
Add read_interface_sio to be excluded when using the Address sanitizer
jmcarcell May 6, 2024
94039e3
Don't check type for SIO
jmcarcell May 12, 2024
f7e67c5
Address comments
jmcarcell May 21, 2024
68053f5
Fix a few more issues
jmcarcell May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tests/unittests/Manifest.toml
# Data Files
*.root
*.dat
*.sio

# Spack build folders
spack*
Expand Down
110 changes: 110 additions & 0 deletions include/podio/Reader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#ifndef PODIO_READER_H
#define PODIO_READER_H

#include "podio/Frame.h"
#include "podio/podioVersion.h"

namespace podio {

class Reader {
public:
struct ReaderConcept {
virtual ~ReaderConcept() = default;

virtual podio::Frame readNextFrame(const std::string& name) = 0;
virtual podio::Frame readFrame(const std::string& name, size_t index) = 0;
virtual size_t getEntries(const std::string& name) = 0;
virtual podio::version::Version currentFileVersion() const = 0;
virtual std::vector<std::string_view> getAvailableCategories() const = 0;
virtual const std::string_view getDatamodelDefinition(const std::string& name) const = 0;
virtual std::vector<std::string> getAvailableDatamodels() const = 0;
};

template <typename T>
struct ReaderModel final : public ReaderConcept {
ReaderModel(std::unique_ptr<T> reader) : m_reader(std::move(reader)) {
}
ReaderModel(const ReaderModel&) = delete;
ReaderModel& operator=(const ReaderModel&) = delete;

podio::Frame readNextFrame(const std::string& name) override {
tmadlener marked this conversation as resolved.
Show resolved Hide resolved
auto maybeFrame = m_reader->readNextEntry(name);
if (maybeFrame) {
return maybeFrame;
}
throw std::runtime_error("Failed reading category " + name + " (reading beyond bounds?)");
}

podio::Frame readFrame(const std::string& name, size_t index) override {
auto maybeFrame = m_reader->readEntry(name, index);
if (maybeFrame) {
return maybeFrame;
}
throw std::runtime_error("Failed reading category " + name + " at frame " + std::to_string(index) +
" (reading beyond bounds?)");
}
size_t getEntries(const std::string& name) override {
return m_reader->getEntries(name);
}
podio::version::Version currentFileVersion() const override {
return m_reader->currentFileVersion();
}

std::vector<std::string_view> getAvailableCategories() const override {
return m_reader->getAvailableCategories();
}

const std::string_view getDatamodelDefinition(const std::string& name) const override {
return m_reader->getDatamodelDefinition(name);
}

std::vector<std::string> getAvailableDatamodels() const override {
return m_reader->getAvailableDatamodels();
}

std::unique_ptr<T> m_reader;
};

std::unique_ptr<ReaderConcept> m_self{nullptr};

template <typename T>
Reader(std::unique_ptr<T>);

podio::Frame readNextFrame(const std::string& name) {
return m_self->readNextFrame(name);
}
podio::Frame readNextEvent() {
return readNextFrame(podio::Category::Event);
}
podio::Frame readFrame(const std::string& name, size_t index) {
return m_self->readFrame(name, index);
}
podio::Frame readEvent(size_t index) {
return readFrame(podio::Category::Event, index);
}
size_t getEntries(const std::string& name) {
return m_self->getEntries(name);
}
size_t getEvents() {
jmcarcell marked this conversation as resolved.
Show resolved Hide resolved
return getEntries(podio::Category::Event);
}
podio::version::Version currentFileVersion() const {
return m_self->currentFileVersion();
}
std::vector<std::string_view> getAvailableCategories() const {
return m_self->getAvailableCategories();
}
const std::string_view getDatamodelDefinition(const std::string& name) const {
return m_self->getDatamodelDefinition(name);
}
std::vector<std::string> getAvailableDatamodels() const {
return m_self->getAvailableDatamodels();
}
};

Reader makeReader(const std::string& filename);
Reader makeReader(const std::vector<std::string>& filename);

} // namespace podio

#endif // PODIO_READER_H
86 changes: 86 additions & 0 deletions include/podio/Writer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#ifndef PODIO_WRITER_H
#define PODIO_WRITER_H

#include "podio/Frame.h"
#include "podio/podioVersion.h"

namespace podio {

class Writer {
public:
struct WriterConcept {
virtual ~WriterConcept() = default;

virtual void writeFrame(const podio::Frame& frame, const std::string& category) = 0;
virtual void writeFrame(const podio::Frame& frame, const std::string& category,
const std::vector<std::string>& collections) = 0;
virtual void writeEvent(const podio::Frame& frame) = 0;
virtual void writeEvent(const podio::Frame& frame, const std::vector<std::string>& collections) = 0;
virtual void finish() = 0;
};

template <typename T>
struct WriterModel final : public WriterConcept {
WriterModel(std::unique_ptr<T> writer) : m_writer(std::move(writer)) {
}
WriterModel(const WriterModel&) = delete;
WriterModel& operator=(const WriterModel&) = delete;
WriterModel(WriterModel&&) = default;
WriterModel& operator=(WriterModel&&) = default;

~WriterModel() = default;

void writeFrame(const podio::Frame& frame, const std::string& category) override {
return m_writer->writeFrame(frame, category);
}
void writeFrame(const podio::Frame& frame, const std::string& category,
const std::vector<std::string>& collections) override {
return m_writer->writeFrame(frame, category, collections);
}
void writeEvent(const podio::Frame& frame) override {
return writeFrame(frame, podio::Category::Event);
}
void writeEvent(const podio::Frame& frame, const std::vector<std::string>& collections) override {
return writeFrame(frame, podio::Category::Event, collections);
}
void finish() override {
return m_writer->finish();
}
std::unique_ptr<T> m_writer{nullptr};
};

std::unique_ptr<WriterConcept> m_self{nullptr};

template <typename T>
Writer(std::unique_ptr<T> reader) : m_self(std::make_unique<WriterModel<T>>(std::move(reader))) {
}

Writer(const Writer&) = delete;
Writer& operator=(const Writer&) = delete;
Writer(Writer&&) = default;
Writer& operator=(Writer&&) = default;

~Writer() = default;

void writeFrame(const podio::Frame& frame, const std::string& category) {
return m_self->writeFrame(frame, category);
}
void writeFrame(const podio::Frame& frame, const std::string& category, const std::vector<std::string>& collections) {
return m_self->writeFrame(frame, category, collections);
}
void writeEvent(const podio::Frame& frame) {
return writeFrame(frame, podio::Category::Event);
}
void writeEvent(const podio::Frame& frame, const std::vector<std::string>& collections) {
return writeFrame(frame, podio::Category::Event, collections);
}
void finish() {
return m_self->finish();
}
};

Writer makeWriter(const std::string& filename, const std::string& type = "default");

} // namespace podio

#endif // PODIO_WRITER_H
21 changes: 20 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,25 @@ if(ENABLE_SIO)
LIST(APPEND INSTALL_LIBRARIES podioSioIO podioSioIODict)
endif()

# --- IO
set(io_sources
Writer.cc
Reader.cc
)

set(io_headers
${PROJECT_SOURCE_DIR}/include/podio/Writer.h
${PROJECT_SOURCE_DIR}/include/podio/Reader.h
)

PODIO_ADD_LIB_AND_DICT(podioIO "${io_headers}" "${io_sources}" io_selection.xml)
target_link_libraries(podioIO PUBLIC podio::podio podio::podioRootIO)
if(ENABLE_SIO)
target_link_libraries(podioIO PUBLIC podio::podioSioIO)
endif()

# --- Install everything
install(TARGETS podio podioDict podioRootIO podioRootIODict ${INSTALL_LIBRARIES}
install(TARGETS podio podioDict podioRootIO podioRootIODict podioIO ${INSTALL_LIBRARIES}
EXPORT podioTargets
DESTINATION "${CMAKE_INSTALL_LIBDIR}")

Expand All @@ -153,6 +170,8 @@ install(FILES
${CMAKE_CURRENT_BINARY_DIR}/libpodioDict_rdict.pcm
${CMAKE_CURRENT_BINARY_DIR}/podioRootIODictDict.rootmap
${CMAKE_CURRENT_BINARY_DIR}/libpodioRootIODict_rdict.pcm
${CMAKE_CURRENT_BINARY_DIR}/podioIODictDict.rootmap
${CMAKE_CURRENT_BINARY_DIR}/libpodioIODict_rdict.pcm
DESTINATION "${CMAKE_INSTALL_LIBDIR}")

if (ENABLE_SIO)
Expand Down
75 changes: 75 additions & 0 deletions src/Reader.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "podio/Reader.h"

#include "podio/ROOTReader.h"
#if PODIO_ENABLE_RNTUPLE
#include "podio/RNTupleReader.h"
#endif
#if PODIO_ENABLE_SIO
#include "podio/SIOReader.h"
#endif

#include "TFile.h"
#include "TKey.h"
#include <memory>

namespace podio {

template <typename T>
Reader::Reader(std::unique_ptr<T> reader) : m_self(std::make_unique<ReaderModel<T>>(std::move(reader))) {
}

Reader makeReader(const std::string& filename) {
return makeReader(std::vector<std::string>{filename});
}

Reader makeReader(const std::vector<std::string>& filenames) {

auto suffix = filenames[0].substr(filenames[0].find_last_of(".") + 1);
for (size_t i = 1; i < filenames.size(); ++i) {
if (filenames[i].substr(filenames[i].find_last_of(".") + 1) != suffix) {
throw std::runtime_error("All files must have the same extension");
}
}

if (suffix == "root") {
TFile* file = TFile::Open(filenames[0].c_str());
bool hasRNTuple = false;

for (auto key : *file->GetListOfKeys()) {
auto tkey = dynamic_cast<TKey*>(key);

if (tkey && std::string(tkey->GetClassName()) == "ROOT::Experimental::RNTuple") {
hasRNTuple = true;
break;
}
}
if (hasRNTuple) {
#if PODIO_ENABLE_RNTUPLE
auto actualReader = std::make_unique<RNTupleReader>();
actualReader->openFiles(filenames);
Reader reader{std::move(actualReader)};
return reader;
#else
throw std::runtime_error("ROOT RNTuple reader not available. Please recompile with ROOT RNTuple support.");
#endif
} else {
auto actualReader = std::make_unique<ROOTReader>();
actualReader->openFiles(filenames);
Reader reader{std::move(actualReader)};
return reader;
}
} else if (suffix == "sio") {
#if PODIO_ENABLE_SIO
auto actualReader = std::make_unique<SIOReader>();
actualReader->openFile(filenames[0]);
Reader reader{std::move(actualReader)};
return reader;
#else
throw std::runtime_error("SIO reader not available. Please recompile with SIO support.");
#endif
}

throw std::runtime_error("Unknown file extension: " + suffix);
}

} // namespace podio
44 changes: 44 additions & 0 deletions src/Writer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include "podio/Writer.h"

#include "podio/ROOTWriter.h"
#if PODIO_ENABLE_RNTUPLE
#include "podio/RNTupleWriter.h"
#endif
#if PODIO_ENABLE_SIO
#include "podio/SIOWriter.h"
#endif

#include <memory>

namespace podio {

Writer makeWriter(const std::string& filename, const std::string& type) {

auto endsWith = [](const std::string& str, const std::string& suffix) {
return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
};

auto lower = [](std::string str) {
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); });
return str;
};

if ((type == "default" && endsWith(filename, ".root")) || lower(type) == "root") {
return Writer{std::make_unique<ROOTWriter>(filename)};
} else if (lower(type) == "rntuple") {
#if PODIO_ENABLE_RNTUPLE
return Writer{std::make_unique<RNTupleWriter>(filename)};
#else
throw std::runtime_error("ROOT RNTuple writer not available. Please recompile with ROOT RNTuple support.");
#endif
} else if (endsWith(filename, ".sio")) {
#if PODIO_ENABLE_SIO
return Writer{std::make_unique<SIOWriter>(filename)};
#else
throw std::runtime_error("SIO writer not available. Please recompile with SIO support.");
#endif
}
throw std::runtime_error("Unknown file type for file " + filename + " with type " + type);
}

} // namespace podio
6 changes: 6 additions & 0 deletions src/io_selection.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<lcgdict>
<selection>
<class name="podio::Reader"/>
<class name="podio::Writer"/>
</selection>
jmcarcell marked this conversation as resolved.
Show resolved Hide resolved
</lcgdict>
6 changes: 4 additions & 2 deletions tests/CTestCustom.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ if ((NOT "@FORCE_RUN_ALL_TESTS@" STREQUAL "ON") AND (NOT "@USE_SANITIZER@" STREQ
write_frame_root
read_frame_root

write_interface_root
read_interface_root

write_python_frame_sio
read_python_frame_sio

Expand Down Expand Up @@ -71,13 +74,12 @@ if ((NOT "@FORCE_RUN_ALL_TESTS@" STREQUAL "ON") AND (NOT "@USE_SANITIZER@" STREQ
set(CTEST_CUSTOM_TESTS_IGNORE
${CTEST_CUSTOM_TESTS_IGNORE}

write_sio
read_sio
read_and_write_sio
write_timed_sio
read_timed_sio
write_frame_sio
read_frame_sio
read_interface_sio
read_frame_legacy_sio
read_and_write_frame_sio
)
Expand Down
Loading