Skip to content

Commit

Permalink
Make branch names for relations more legible for ROOT based I/O (#405)
Browse files Browse the repository at this point in the history
* Add RelationNames and code gen to populate it

* Write branches with proper names in ROOTFrameWriter

* Make the Frame reader use the registry to get branch names

* Make sure that the EDM always is in the registry

* Make sure that the names are populated when they are used

* Make relation branch names start with an underscore

Less prone to accidental collisions. Plus sort of conveying that they
are "hidden"

* Make it possible to read index based files as well

- Keep branch names around for resetting them (since invalidated
branches can no longer provide that information)

* Fix legacy reading

* Manually increase patch to make if clause work properly
  • Loading branch information
tmadlener authored Jun 5, 2023
1 parent 8a3b2ff commit bcc8370
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 61 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ project(podio)
#--- Version -------------------------------------------------------------------
SET( ${PROJECT_NAME}_VERSION_MAJOR 0 )
SET( ${PROJECT_NAME}_VERSION_MINOR 16 )
SET( ${PROJECT_NAME}_VERSION_PATCH 5 )
SET( ${PROJECT_NAME}_VERSION_PATCH 6 )

SET( ${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}" )

Expand Down
2 changes: 2 additions & 0 deletions include/podio/CollectionBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace podio {
// forward declarations
class ICollectionProvider;

struct RelationNames;

class CollectionBase {
protected:
/// default constructor
Expand Down
3 changes: 3 additions & 0 deletions include/podio/CollectionBranches.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "TBranch.h"

#include <string>
#include <vector>

namespace podio::root_utils {
Expand All @@ -15,6 +16,8 @@ struct CollectionBranches {
TBranch* data{nullptr};
std::vector<TBranch*> refs{};
std::vector<TBranch*> vecs{};
std::vector<std::string> refNames{}; ///< The names of the relation branches
std::vector<std::string> vecNames{}; ///< The names of the vector member branches
};

} // namespace podio::root_utils
Expand Down
1 change: 1 addition & 0 deletions include/podio/CollectionBuffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

Expand Down
40 changes: 39 additions & 1 deletion include/podio/DatamodelRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,39 @@

#include <string>
#include <string_view>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>

namespace podio {

/**
* Type alias for storing the names of all Relations and VectorMembers for all
* datatypes of an EDM. Populated for each EDM at code generation time.
* The structure is of each element in the outer vector is:
* - get<0>: The name of the datatype
* - get<1>: The names of all Relations, where OneToManyRelations comes before
* OneToOneRelations (in the order as they appear in the YAML file)
* - get<2>: The names of all VectorMembers (in the order of the file YAML)
*/
using RelationNameMapping =
std::vector<std::tuple<std::string_view, std::vector<std::string_view>, std::vector<std::string_view>>>;

/**
* Information on the names of the OneTo[One|Many]Relations as well as the
* VectorMembers of a datatype
*
* The contents are populated by the code generation, where we simply generate
* static vectors that we make available as const& here.
*/
struct RelationNames {
/// The names of the relations (OneToMany before OneToOne)
const std::vector<std::string_view>& relations;
/// The names of the vector members
const std::vector<std::string_view>& vectorMembers;
};

/**
* Global registry holding information about datamodels and datatypes defined
* therein that are currently known by podio (i.e. which have been dynamically
Expand Down Expand Up @@ -85,14 +113,24 @@ class DatamodelRegistry {
* @param name The name of the EDM that should be registered
* @param definition The datamodel definition from which this EDM has been
* generated in JSON format
* @param relationNames the names of the relations and vector members for all
* datatypes that are defined for this EDM
*
*/
size_t registerDatamodel(std::string name, std::string_view definition);
size_t registerDatamodel(std::string name, std::string_view definition,
const podio::RelationNameMapping& relationNames);

/**
* Get the names of the relations and vector members of a datatype
*/
RelationNames getRelationNames(std::string_view typeName) const;

private:
DatamodelRegistry() = default;
/// The stored definitions
std::vector<std::pair<std::string, std::string_view>> m_definitions{};

std::unordered_map<std::string_view, RelationNames> m_relations{};
};
} // namespace podio

Expand Down
6 changes: 6 additions & 0 deletions python/podio_class_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,14 @@ def _write_edm_def_file(self):
'edm_definition': model_encoder.encode(self.datamodel),
'incfolder': self.incfolder,
'schema_version': self.datamodel.schema_version,
'datatypes': self.datamodel.datatypes,
}

def quoted_sv(string):
return f"\"{string}\"sv"

self.env.filters["quoted_sv"] = quoted_sv

self._write_file('DatamodelDefinition.h',
self._eval_template('DatamodelDefinition.h.jinja2', data))

Expand Down
4 changes: 4 additions & 0 deletions python/templates/Collection.h.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
#include <memory>
#include <cstddef>

namespace podio {
struct RelationNames;
}

{{ utils.namespace_open(class.namespace) }}


Expand Down
42 changes: 36 additions & 6 deletions python/templates/DatamodelDefinition.h.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@ namespace {{ package_name }}::meta {
*/
static constexpr auto {{ package_name }}__JSONDefinition = R"DATAMODELDEF({{ edm_definition }})DATAMODELDEF";


/**
* The names of all relations and vector members for all datatypes
*/
inline podio::RelationNameMapping {{ package_name }}__getRelationNames() {
using namespace std::string_view_literals;
return {
{% for typeName, type in datatypes.items() %}
{"{{ typeName }}"sv,
{ {{ (type.OneToManyRelations + type.OneToOneRelations) | map(attribute="name") | map("quoted_sv") | join(", ") }} },
{ {{ type.VectorMembers | map(attribute="name") | map("quoted_sv") | join(", ")}} },
},
{% endfor %}
};
}

/**
* The schema version at generation time
*/
static constexpr podio::SchemaVersionT schemaVersion = {{ schema_version }};

/**
* The helper class that takes care of registering the datamodel definition to
* the DatamodelRegistry and to provide the index in that registry.
Expand All @@ -19,18 +40,27 @@ static constexpr auto {{ package_name }}__JSONDefinition = R"DATAMODELDEF({{ edm
class DatamodelRegistryIndex {
public:
static size_t value() {
static auto index = DatamodelRegistryIndex(podio::DatamodelRegistry::mutInstance().registerDatamodel("{{ package_name }}", {{ package_name }}__JSONDefinition));
static const auto relationNames = {{ package_name }}__getRelationNames();
static auto index = DatamodelRegistryIndex(podio::DatamodelRegistry::mutInstance().registerDatamodel("{{ package_name }}", {{ package_name }}__JSONDefinition, relationNames));
return index.m_value;
}

private:
DatamodelRegistryIndex(size_t v) : m_value(v) {}
size_t m_value{podio::DatamodelRegistry::NoDefinitionAvailable};
};

/**
* The schema version at generation time
*/
static constexpr podio::SchemaVersionT schemaVersion = {{ schema_version }};

namespace static_registration {
// The usual trick via an IIFE and a const variable that we assign to, to
// ensure that we populate this before everything starts
inline bool ensureRegistration() {
const static auto reg = []() {
return {{ package_name }}::meta::DatamodelRegistryIndex::value() != podio::DatamodelRegistry::NoDefinitionAvailable;
}();
return reg;
}

const auto registrationEnsured = ensureRegistration();
}

} // namespace {{ package_name }}::meta
26 changes: 25 additions & 1 deletion src/DatamodelRegistry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ DatamodelRegistry& DatamodelRegistry::mutInstance() {
return registryInstance;
}

size_t DatamodelRegistry::registerDatamodel(std::string name, std::string_view definition) {
size_t DatamodelRegistry::registerDatamodel(std::string name, std::string_view definition,
const podio::RelationNameMapping& relationNames) {
const auto it = std::find_if(m_definitions.cbegin(), m_definitions.cend(),
[&name](const auto& kvPair) { return kvPair.first == name; });

if (it == m_definitions.cend()) {
int index = m_definitions.size();
m_definitions.emplace_back(name, definition);

for (const auto& [typeName, relations, vectorMembers] : relationNames) {
m_relations.emplace(typeName, RelationNames{relations, vectorMembers});
}

return index;
}

Expand Down Expand Up @@ -60,4 +66,22 @@ const std::string& DatamodelRegistry::getDatamodelName(size_t index) const {
return m_definitions[index].first;
}

RelationNames DatamodelRegistry::getRelationNames(std::string_view typeName) const {
static std::vector<std::string_view> emptyVec{};
if (typeName.substr(0, 24) == "podio::UserDataCollection") {
return {emptyVec, emptyVec};
}

// Strip Collection if necessary
if (typeName.size() > 10 && typeName.substr(typeName.size() - 10) == "Collection") {
typeName = typeName.substr(0, typeName.size() - 10);
}

if (const auto it = m_relations.find(typeName); it != m_relations.end()) {
return it->second;
}

return {emptyVec, emptyVec};
}

} // namespace podio
Loading

0 comments on commit bcc8370

Please sign in to comment.