-
Notifications
You must be signed in to change notification settings - Fork 60
/
Collection.cc.jinja2
272 lines (220 loc) · 9.37 KB
/
Collection.cc.jinja2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
{% import "macros/utils.jinja2" as utils %}
{% import "macros/collections.jinja2" as macros %}
{% from "macros/iterator.jinja2" import iterator_definitions %}
// AUTOMATICALLY GENERATED FILE - DO NOT EDIT
#include "podio/CollectionBufferFactory.h"
#include "podio/SchemaEvolution.h"
#include "{{ incfolder }}{{ class.bare_type }}Collection.h"
#include "{{ incfolder }}DatamodelDefinition.h"
{% if old_schema_version is defined %}
#include "{{ incfolder }}{{ class.bare_type }}v{{ old_schema_version }}Data.h"
{% endif %}
{% for include in includes_coll_cc %}
{{ include }}
{% endfor %}
#if defined(PODIO_JSON_OUTPUT) && !defined(__CLING__)
#include "nlohmann/json.hpp"
#endif
// standard includes
#include <stdexcept>
#include <iomanip>
{{ utils.namespace_open(class.namespace) }}
{% with collection_type = class.bare_type + 'Collection' %}
{{ collection_type }}::{{ collection_type }}() :
m_isValid(false), m_isPrepared(false), m_isSubsetColl(false), m_collectionID(podio::ObjectID::untracked), m_storageMtx(std::make_unique<std::mutex>()), m_storage() {}
{{ collection_type }}::{{ collection_type }}({{ collection_type }}Data&& data, bool isSubsetColl) :
m_isValid(false), m_isPrepared(false), m_isSubsetColl(isSubsetColl), m_collectionID(podio::ObjectID::untracked), m_storageMtx(std::make_unique<std::mutex>()), m_storage(std::move(data)) {}
{{ collection_type }}::~{{ collection_type }}() {
// Need to tell the storage how to clean-up
m_storage.clear(m_isSubsetColl);
}
{{ class.bare_type }} {{ collection_type }}::operator[](std::size_t index) const {
return {{ class.bare_type }}(m_storage.entries[index]);
}
{{ class.bare_type }} {{ collection_type }}::at(std::size_t index) const {
return {{ class.bare_type }}(m_storage.entries.at(index));
}
Mutable{{ class.bare_type }} {{ collection_type }}::operator[](std::size_t index) {
return Mutable{{ class.bare_type }}(podio::utils::MaybeSharedPtr(m_storage.entries[index]));
}
Mutable{{ class.bare_type }} {{ collection_type }}::at(std::size_t index) {
return Mutable{{ class.bare_type }}(podio::utils::MaybeSharedPtr(m_storage.entries.at(index)));
}
std::size_t {{ collection_type }}::size() const {
return m_storage.entries.size();
}
std::size_t {{ collection_type }}::max_size() const {
return m_storage.entries.max_size();
}
bool {{ collection_type }}::empty() const {
return m_storage.entries.empty();
}
void {{ collection_type }}::setSubsetCollection(bool setSubset) {
if (m_isSubsetColl != setSubset && !m_storage.entries.empty()) {
throw std::logic_error("Cannot change the character of a collection that already contains elements");
}
if (setSubset) {
m_storage.makeSubsetCollection();
}
m_isSubsetColl = setSubset;
}
Mutable{{ class.bare_type }} {{ collection_type }}::create() {
if (m_isSubsetColl) {
throw std::logic_error("Cannot create new elements on a subset collection");
}
auto obj = m_storage.entries.emplace_back(new {{ class.bare_type }}Obj());
{% if OneToManyRelations or VectorMembers %}
m_storage.createRelations(obj);
{% endif %}
obj->id = {int(m_storage.entries.size() - 1), m_collectionID};
return Mutable{{ class.bare_type }}(podio::utils::MaybeSharedPtr(obj));
}
void {{ collection_type }}::clear() {
m_storage.clear(m_isSubsetColl);
m_isPrepared = false;
}
void {{ collection_type }}::prepareForWrite() const {
// TODO: Replace this double locking pattern here with an atomic and only one
// lock. Problem: std::atomic is not default movable.
{
std::lock_guard lock{*m_storageMtx};
// If the collection has been prepared already there is nothing to do
if (m_isPrepared) {
return;
}
}
std::lock_guard lock{*m_storageMtx};
// by the time we acquire the lock another thread might have already
// succeeded, so we need to check again now
if (m_isPrepared) {
return;
}
m_storage.prepareForWrite(m_isSubsetColl);
m_isPrepared = true;
}
void {{ collection_type }}::prepareAfterRead() {
// No need to go through this again if we have already done it
if (m_isPrepared) {
return;
}
if (!m_isSubsetColl) {
// Subset collections do not store any data that would require post-processing
m_storage.prepareAfterRead(m_collectionID);
}
// Preparing a collection doesn't affect the underlying I/O buffers, so this
// collection is still prepared
m_isPrepared = true;
}
bool {{ collection_type }}::setReferences(const podio::ICollectionProvider* collectionProvider) {
return m_storage.setReferences(collectionProvider, m_isSubsetColl);
}
void {{ collection_type }}::push_back(const Mutable{{ class.bare_type }}& object) {
// We have to do different things here depending on whether this is a
// subset collection or not. A normal collection cannot collect objects
// that are already part of another collection, while a subset collection
// can only collect such objects
if (!m_isSubsetColl) {
auto obj = object.m_obj;
if (obj->id.index == podio::ObjectID::untracked) {
const auto size = m_storage.entries.size();
obj->id = {static_cast<int>(size), m_collectionID};
m_storage.entries.push_back(obj.release());
{% if OneToManyRelations or VectorMembers %}
m_storage.createRelations(obj.get());
{% endif %}
} else {
throw std::invalid_argument("Object already in a collection. Cannot add it to a second collection");
}
} else {
push_back({{ class.bare_type }}(object));
}
}
void {{ collection_type }}::push_back(const {{ class.bare_type }}& object) {
if (!m_isSubsetColl) {
throw std::invalid_argument("Immutable objects can only be added to subset collections");
}
auto obj = object.m_obj;
if (obj->id.index < 0) {
// This path is only possible if we arrive here from an untracked Mutable object
throw std::invalid_argument("Object needs to be tracked by another collection in order for it to be storable in a subset collection");
}
m_storage.entries.push_back(obj.release());
}
podio::CollectionWriteBuffers {{ collection_type }}::getBuffers() {
return m_storage.getCollectionBuffers(m_isSubsetColl);
}
{% for member in Members %}
{{ macros.vectorized_access(class, member) }}
{% endfor %}
size_t {{ collection_type }}::getDatamodelRegistryIndex() const {
return {{ package_name }}::meta::DatamodelRegistryIndex::value();
}
podio::SchemaVersionT {{ collection_type }}::getSchemaVersion() const {
return {{ package_name }}::meta::schemaVersion;
}
// anonymous namespace for registration with the CollectionBufferFactory. This
// ensures that we don't have to make up arbitrary namespace names here, since
// none of this is publicly visible
namespace {
{{ macros.create_buffers(class, package_name, collection_type, OneToManyRelations, OneToOneRelations, VectorMembers, -1) }}
{#
// SCHEMA EVOLUTION: Not yet required with only ROOT backend
// {% if old_schema_version is defined %}
// {{ macros.create_buffers(class, package_name, collection_type, OneToManyRelations_old, OneToOneRelations_old, VectorMembers_old, old_schema_version) }}
// {% endif %}
#}
// The usual trick with an IIFE and a static variable inside a function and then
// making sure to call that function during shared library loading
bool registerCollection() {
const static auto reg = []() {
auto& factory = podio::CollectionBufferFactory::mutInstance();
factory.registerCreationFunc("{{ class.full_type }}Collection", {{ package_name }}::meta::schemaVersion, createBuffers);
// Make the SchemaEvolution aware of the current version by
// registering a no-op function for this and all preceding versions
// will be overridden whenever an explicit action is required
for (unsigned int schemaVersion=1; schemaVersion< {{ package_name }}::meta::schemaVersion+1; ++schemaVersion) {
podio::SchemaEvolution::mutInstance().registerEvolutionFunc(
"{{ class.full_type }}Collection",
schemaVersion,
{{ package_name }}::meta::schemaVersion,
podio::SchemaEvolution::noOpSchemaEvolution,
podio::SchemaEvolution::Priority::AutoGenerated
);
}
{% if old_schema_version is defined %}
// register a buffer creation function for the schema evolution buffer
// SCHEMA EVOLUTION: Not yet required with only ROOT backend
// factory.registerCreationFunc("{{ class.full_type }}Collection", {{ old_schema_version }}, createBuffersV{{old_schema_version}}); //TODO
//Make the SchemaEvolution aware of any other non-trivial conversion
podio::SchemaEvolution::mutInstance().registerEvolutionFunc(
"{{ class.full_type }}Collection",
{{ old_schema_version }},
{{ package_name }}::meta::schemaVersion,
podio::SchemaEvolution::noOpSchemaEvolution,
podio::SchemaEvolution::Priority::AutoGenerated
);
{% endif %}
return true;
}();
return reg;
}
const auto registeredCollection = registerCollection();
} // namespace
#if defined(PODIO_JSON_OUTPUT) && !defined(__CLING__)
void to_json(nlohmann::json& j, const {{ collection_type }}& collection) {
j = nlohmann::json::array();
const auto subset = collection.isSubsetCollection();
for (auto&& elem : collection) {
if (subset) {
j.emplace_back(elem.id());
} else {
j.emplace_back(elem);
}
}
}
#endif
{% endwith %}
{{ iterator_definitions(class) }}
{{ iterator_definitions(class, prefix='Mutable' ) }}
{{ macros.ostream_operator(class, Members, OneToOneRelations, OneToManyRelations, VectorMembers, use_get_syntax, ostream_collection_settings) }}
{{ utils.namespace_close(class.namespace) }}