Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 44 additions & 0 deletions form/root_storage/root_tfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@

#include <Compression.h>
#include <TFile.h>
#include <TKey.h>
#include <TList.h>
#include <TNamed.h>
#include <TObject.h>

#include <cstddef>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
Expand Down Expand Up @@ -79,4 +83,44 @@ void root_tfile_imp::write_descriptor(
}
}

std::optional<std::vector<std::pair<std::string, std::string>>> root_tfile_imp::read_descriptor()
{
if (file_ == nullptr) {
throw std::runtime_error("root_tfile_imp::read_descriptor no file attached for " + name());
}

// Look the key up first so an absent descriptor is told apart from one that fails to read.
// GetKey returns the highest cycle and the key stays owned by the file.
std::string const object_name{descriptor_object_name};
TKey* key = file_->GetKey(object_name.c_str());
if (key == nullptr) {
return std::nullopt;
}

// ReadObj hands ownership of the TList to the caller; SetOwner below extends it to the entries.
std::unique_ptr<TObject> const object{key->ReadObj()};
if (!object) {
throw std::runtime_error("root_tfile_imp::read_descriptor failed to read object '" +
object_name + "' from " + name());
}
auto* list = dynamic_cast<TList*>(object.get());
if (list == nullptr) {
throw std::runtime_error("root_tfile_imp::read_descriptor object '" + object_name + "' in " +
name() + " is not a TList");
}
list->SetOwner(true);

std::vector<std::pair<std::string, std::string>> entries;
entries.reserve(static_cast<std::size_t>(list->GetSize()));
for (TObject const* entry : *list) {
auto const* named = dynamic_cast<TNamed const*>(entry);
if (named == nullptr) {
throw std::runtime_error("root_tfile_imp::read_descriptor object '" + object_name + "' in " +
name() + " holds an entry that is not a TNamed");
}
entries.emplace_back(named->GetName(), named->GetTitle());
}
return entries;
}

std::shared_ptr<TFile> root_tfile_imp::get_tfile() { return file_; }
2 changes: 2 additions & 0 deletions form/root_storage/root_tfile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "storage/storage_file.hpp"

#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
Expand All @@ -25,6 +26,7 @@ namespace form::detail::experimental {
void set_attribute(std::string const& key, std::string const& value) override;

void write_descriptor(std::vector<std::pair<std::string, std::string>> const& entries) override;
std::optional<std::vector<std::pair<std::string, std::string>>> read_descriptor() override;

std::shared_ptr<TFile> get_tfile();

Expand Down
12 changes: 12 additions & 0 deletions form/storage/istorage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
#define FORM_STORAGE_ISTORAGE_HPP

#include "core/placement.hpp"
#include "core/technology.hpp"
#include "core/token.hpp"
#include "form/config.hpp"

#include <cstdint>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -39,6 +41,14 @@ namespace form::detail::experimental {
void const** data,
std::type_info const& type,
form::experimental::config::tech_setting_config const& settings) = 0;

// Reads descriptor entries in their original order.
// Returns std::nullopt if no descriptor is present; throws if the file cannot be opened.
// The major technology selects the backend; the full id selects its settings.
virtual std::optional<std::vector<std::pair<std::string, std::string>>> read_descriptor(
std::string const& file_name,
form::technology::id technology,
form::experimental::config::tech_setting_config const& settings) = 0;
};

class i_storage_writer {
Expand Down Expand Up @@ -73,6 +83,8 @@ namespace form::detail::experimental {

virtual void write_descriptor(
std::vector<std::pair<std::string, std::string>> const& entries) = 0;

virtual std::optional<std::vector<std::pair<std::string, std::string>>> read_descriptor() = 0;
};

class i_storage_write_container {
Expand Down
3 changes: 2 additions & 1 deletion form/storage/storage_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "storage_file.hpp"

#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
Expand All @@ -26,7 +27,7 @@ void storage_file::write_descriptor(std::vector<std::pair<std::string, std::stri
descriptor_ = entries;
}

std::vector<std::pair<std::string, std::string>> const& storage_file::descriptor() const
std::optional<std::vector<std::pair<std::string, std::string>>> storage_file::read_descriptor()
{
return descriptor_;
}
5 changes: 3 additions & 2 deletions form/storage/storage_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "istorage.hpp"

#include <optional>
#include <string>
#include <utility>
#include <vector>
Expand All @@ -21,12 +22,12 @@ namespace form::detail::experimental {
void set_attribute(std::string const& name, std::string const& value) override;

void write_descriptor(std::vector<std::pair<std::string, std::string>> const& entries) override;
std::vector<std::pair<std::string, std::string>> const& descriptor() const;
std::optional<std::vector<std::pair<std::string, std::string>>> read_descriptor() override;

private:
std::string name_;
char mode_;
std::vector<std::pair<std::string, std::string>> descriptor_;
std::optional<std::vector<std::pair<std::string, std::string>>> descriptor_;
};
} // namespace form::detail::experimental

Expand Down
64 changes: 31 additions & 33 deletions form/storage/storage_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <typeinfo>
Expand Down Expand Up @@ -61,6 +62,30 @@ namespace form::detail::experimental {
}
}

std::shared_ptr<i_storage_file> const& storage_reader::open_file(
std::string const& file_name,
form::technology::id technology,
form::experimental::config::tech_setting_config const& settings)
{
if (auto const found = files_.find(file_name); found != files_.end()) {
return found->second;
}
// Cache the file only after all file settings have been applied successfully.
auto opened = create_file(technology, file_name, 'i');
for (auto const& [key, value] : get_file_table(settings, technology, file_name)) {
opened->set_attribute(key, value);
}
return files_.emplace(file_name, std::move(opened)).first->second;
}

std::optional<std::vector<std::pair<std::string, std::string>>> storage_reader::read_descriptor(
std::string const& file_name,
form::technology::id technology,
form::experimental::config::tech_setting_config const& settings)
{
return open_file(file_name, technology, settings)->read_descriptor();
}

std::uint64_t storage_reader::get_index(
token const& token,
std::string const& id,
Expand All @@ -82,20 +107,11 @@ void storage_reader::prime(token const& token,
auto cont_key = std::make_pair(token.file_name(), token.container_name());
auto cont = read_containers_.find(cont_key);
if (cont == read_containers_.end()) {
auto file = files_.find(token.file_name());
if (file == files_.end()) {
file =
files_.insert({token.file_name(), create_file(token.technology(), token.file_name(), 'i')})
.first;
for (auto const& [key, value] :
get_file_table(settings, token.technology(), token.file_name())) {
file->second->set_attribute(key, value);
}
}
auto const& file = open_file(token.file_name(), token.technology(), settings);
cont = read_containers_
.insert({cont_key, create_read_container(token.technology(), token.container_name())})
.first;
cont->second->set_file(file->second);
cont->second->set_file(file);
for (auto const& [key, value] :
get_container_table(settings, token.technology(), token.container_name())) {
cont->second->set_attribute(key, value);
Expand Down Expand Up @@ -125,24 +141,15 @@ std::map<std::string, std::uint64_t> const& storage_reader::index_map(

auto cont = read_containers_.find(cont_key);
if (cont == read_containers_.end()) {
auto file = files_.find(token.file_name());
if (file == files_.end()) {
file =
files_.insert({token.file_name(), create_file(token.technology(), token.file_name(), 'i')})
.first;
for (auto const& [key, value] :
get_file_table(settings, token.technology(), token.file_name())) {
file->second->set_attribute(key, value);
}
}
auto const& file = open_file(token.file_name(), token.technology(), settings);
cont = read_containers_
.insert({cont_key, create_read_container(token.technology(), token.container_name())})
.first;
for (auto const& [key, value] :
get_container_table(settings, token.technology(), token.container_name())) {
cont->second->set_attribute(key, value);
}
cont->second->set_file(file->second);
cont->second->set_file(file);
}

std::map<std::string, std::uint64_t> index;
Expand Down Expand Up @@ -172,20 +179,11 @@ void storage_reader::read_container(token const& token,
auto cont_key = std::make_pair(token.file_name(), token.container_name());
auto cont = read_containers_.find(cont_key);
if (cont == read_containers_.end()) {
auto file = files_.find(token.file_name());
if (file == files_.end()) {
file =
files_.insert({token.file_name(), create_file(token.technology(), token.file_name(), 'i')})
.first;
for (auto const& [key, value] :
get_file_table(settings, token.technology(), token.file_name())) {
file->second->set_attribute(key, value);
}
}
auto const& file = open_file(token.file_name(), token.technology(), settings);
cont = read_containers_
.insert({cont_key, create_read_container(token.technology(), token.container_name())})
.first;
cont->second->set_file(file->second);
cont->second->set_file(file);
for (auto const& [key, value] :
get_container_table(settings, token.technology(), token.container_name())) {
cont->second->set_attribute(key, value);
Expand Down
10 changes: 10 additions & 0 deletions form/storage/storage_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility> // for std::pair
#include <vector>

namespace form::detail::experimental {

Expand All @@ -33,8 +35,16 @@ namespace form::detail::experimental {
void const** data,
std::type_info const& type,
form::experimental::config::tech_setting_config const& settings) override;
std::optional<std::vector<std::pair<std::string, std::string>>> read_descriptor(
std::string const& file_name,
form::technology::id technology,
form::experimental::config::tech_setting_config const& settings) override;

private:
std::shared_ptr<i_storage_file> const& open_file(
std::string const& file_name,
form::technology::id technology,
form::experimental::config::tech_setting_config const& settings);
std::map<std::string, std::uint64_t> const& index_map(
token const& token, form::experimental::config::tech_setting_config const& settings);

Expand Down
11 changes: 9 additions & 2 deletions test/form/form_basics_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,13 +495,20 @@ TEST_CASE("storage_writer: the descriptor reaches the file it names", "[form]")
TEST_CASE("storage_file: the generic backend keeps the descriptor it is given", "[form]")
{
storage_file file{"generic.dat", 'o'};
CHECK(file.descriptor().empty());
CHECK_FALSE(file.read_descriptor().has_value());

std::vector<std::pair<std::string, std::string>> const entries{
{std::string{descriptor_layout_version_key}, std::string{form_layout_version}},
{std::string{descriptor_technologies_key}, "generic"}};
file.write_descriptor(entries);
CHECK(file.descriptor() == entries);
CHECK(file.read_descriptor() == entries);
}

TEST_CASE("storage_file: an empty descriptor is still a descriptor", "[form]")
{
storage_file file{"generic_empty.dat", 'o'};
file.write_descriptor({});
CHECK(file.read_descriptor() == std::vector<std::pair<std::string, std::string>>{});
}

TEST_CASE("persistence_reader basic operations", "[form]")
Expand Down
Loading
Loading