-
Notifications
You must be signed in to change notification settings - Fork 67
Expand file tree
/
Copy pathCollection.cc.jinja2
More file actions
243 lines (199 loc) · 8.34 KB
/
Copy pathCollection.cc.jinja2
File metadata and controls
243 lines (199 loc) · 8.34 KB
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
{% 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 "{{ incfolder }}{{ class.bare_type }}Collection.h"
#include "{{ incfolder }}DatamodelDefinition.h"
{% for include in includes_coll_cc %}
{{ include }}
{% endfor %}
// 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(0), 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(0), 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 }}(m_storage.entries[index]);
}
Mutable{{ class.bare_type }} {{ collection_type }}::at(std::size_t index) {
return Mutable{{ class.bare_type }}(m_storage.entries.at(index));
}
std::size_t {{ collection_type }}::size() const {
return m_storage.entries.size();
}
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 }}(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({{ 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 = {(int)size, m_collectionID};
m_storage.entries.push_back(obj);
{% if OneToManyRelations or VectorMembers %}
m_storage.createRelations(obj);
{% endif %}
} else {
throw std::invalid_argument("Object already in a collection. Cannot add it to a second collection");
}
} else {
const auto obj = object.m_obj;
if (obj->id.index < 0) {
throw std::invalid_argument("Objects can only be stored in a subset collection if they are already elements of a collection");
}
m_storage.entries.push_back(obj);
// No need to handle any relations here, since this is already done by the
// "owning" collection
}
}
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 {
podio::CollectionReadBuffers createBuffers(bool isSubset) {
auto readBuffers = podio::CollectionReadBuffers{};
readBuffers.data = isSubset ? nullptr : new {{ class.bare_type }}DataContainer;
// The number of ObjectID vectors is either 1 or the sum of OneToMany and
// OneToOne relations
const auto nRefs = isSubset ? 1 : {{ OneToManyRelations | length }} + {{ OneToOneRelations | length }};
readBuffers.references = new podio::CollRefCollection(nRefs);
for (auto& ref : *readBuffers.references) {
// Make sure to place usable buffer pointers here
ref = std::make_unique<std::pmr::vector<podio::ObjectID>>();
}
readBuffers.vectorMembers = new podio::VectorMembersInfo();
if (!isSubset) {
readBuffers.vectorMembers->reserve({{ VectorMembers | length }});
{% for member in VectorMembers %}
readBuffers.vectorMembers->emplace_back("{{ member.full_type }}", new std::pmr::vector<{{ member.full_type }}>);
{% endfor %}
}
readBuffers.createCollection = [](podio::CollectionReadBuffers buffers, bool isSubsetColl) {
{{ collection_type }}Data data(buffers, isSubsetColl);
return std::make_unique<{{ collection_type }}>(std::move(data), isSubsetColl);
};
readBuffers.recast = [](podio::CollectionReadBuffers& buffers) {
if (buffers.data) {
buffers.data = podio::CollectionWriteBuffers::asVector<{{ class.full_type }}Data>(buffers.data);
}
{% if VectorMembers %}
{% for member in VectorMembers %}
(*buffers.vectorMembers)[{{ loop.index0 }}].second = podio::CollectionWriteBuffers::asVector<{{ member.full_type }}>((*buffers.vectorMembers)[{{ loop.index0 }}].second);
{% endfor %}
{% endif %}
};
return readBuffers;
}
// The usual trick with an IIFE and a static variable inside a funtion 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);
return true;
}();
return reg;
}
const auto registeredCollection = registerCollection();
} // namespace
#ifdef PODIO_JSON_OUTPUT
void to_json(nlohmann::json& j, const {{ collection_type }}& collection) {
j = nlohmann::json::array();
for (auto&& elem : collection) {
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) }}