-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathCollection.cc.jinja2
213 lines (177 loc) · 7.35 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
{% 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 "{{ 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[](unsigned int index) const {
return {{ class.bare_type }}(m_storage.entries[index]);
}
{{ class.bare_type }} {{ collection_type }}::at(unsigned int index) const {
return {{ class.bare_type }}(m_storage.entries.at(index));
}
Mutable{{ class.bare_type }} {{ collection_type }}::operator[](unsigned int index) {
return Mutable{{ class.bare_type }}(m_storage.entries[index]);
}
Mutable{{ class.bare_type }} {{ collection_type }}::at(unsigned int index) {
return Mutable{{ class.bare_type }}(m_storage.entries.at(index));
}
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);
}
podio::CollectionReadBuffers {{ collection_type }}::createBuffers() /*const*/ {
// Very cumbersome way at the moment. We get the actual buffers to have the
// references and vector members sized appropriately (we will use this
// information to create new buffers outside)
auto collBuffers = m_storage.getCollectionBuffers(m_isSubsetColl);
auto readBuffers = podio::CollectionReadBuffers{};
readBuffers.references = collBuffers.references;
readBuffers.vectorMembers = collBuffers.vectorMembers;
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;
}
podio::CollectionReadBuffers {{ collection_type }}::createSchemaEvolvableBuffers(int readSchemaVersion, podio::Backend /*backend*/) /*const*/ {
// no version difference -> no-op
if (readSchemaVersion == {{ class.schema_version }}) {
return createBuffers();
}
// default is no-op as well
return createBuffers();
}
{% for member in Members %}
{{ macros.vectorized_access(class, member) }}
{% endfor %}
size_t {{ collection_type }}::getDatamodelRegistryIndex() const {
return {{ package_name }}::meta::DatamodelRegistryIndex::value();
}
#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) }}