Peano
Loading...
Searching...
No Matches
DataModel.py
Go to the documentation of this file.
1# This file is part of the DaStGen2 project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3import dastgen2
4import os
5
6
7class DataModel(object):
8 """! Represents on DaStGen2 object, i.e. one data model.
9
10 full_qualified_name Full qualified name. Please pass in in C++ convention i.e. with
11 :: separating the namespaces.
12
13 """
14
16 self,
17 full_qualified_name,
18 has_nondefault_constructor=True,
19 embed_attributes_into_data_store=False,
20 ):
21 """!
22
23 Construct the data modell
24
25 public_fields: C++ string
26 This will be used to add public fields to the class, and each
27 attribute can feed into this string. However, you can also
28 modify it yourself.
29
30 """
31 self._full_qualified_name = full_qualified_name
32 self._attributes = []
33 self._aspects = []
34 self.has_nondefault_constructor = has_nondefault_constructor
35 self._embed_attributes_into_data_store = embed_attributes_into_data_store
36 self.public_fields = ""
38
39 def set_full_qualified_name(self, full_qualified_name):
40 self._full_qualified_name = full_qualified_name
41
42 def add_attribute(self, attribute):
43 attribute.use_data_store = self._embed_attributes_into_data_store
44 self._attributes.append(attribute)
45
46 def add_or_replace_attribute(self, attribute):
47 """
48 Check first whether attribute already exists. If it does, replace it.
49 """
50
51 attribute.use_data_store = self._embed_attributes_into_data_store
52
53 for i, att in enumerate(self._attributes):
54 if att._name == attribute._name:
55 self._attributes[i] = attribute
56 return
57
58 # if we make it here, it's a new attribute.
59 self._attributes.append(attribute)
60 return
61
62 def add_aspect(self, aspect):
63 aspect.set_model(self)
64 self._aspects.append(aspect)
65
66 _Header_Template_Without_Data_Store = """
67//
68// Generated by DaStGen2 (C) 2020 Tobias Weinzierl
69//
70// For DaStGen's copyright, visit www.peano-framework.org. These generated files
71// however are not subject of copyright, i.e. feel free to add your copyright in
72// here
73//
74#pragma once
75
76#include <string>
77
78{ATTRIBUTE_INCLUDES}
79{ASPECT_INCLUDES}
80{ADDITIONAL_INCLUDES}
81
82{OPEN_NAMESPACES}
83 struct {UNQUALIFIED_CLASS_NAME};
84{CLOSE_NAMESPACES}
85
86
87struct {FULL_QUALIFIED_CLASS_NAME} {{
88 public:
89{PUBLIC_FIELDS}
90
91 {UNQUALIFIED_CLASS_NAME}() {{}}
92 {UNQUALIFIED_CLASS_NAME}{CONSTRUCTOR_ARGUMENTS};
93
94
95{METHOD_DECLARATIONS}
96
97{ASPECT_METHOD_DECLARATIONS}
98 std::string toString() const;
99
100 private:
101{ATTRIBUTE_DECLARATIONS}
102
103{ASPECT_ATTRIBUTES}
104
105}};
106
107 """
108
109 _Header_Template_With_Data_Store = """
110//
111// Generated by DaStGen2 (C) 2020 Tobias Weinzierl
112//
113// For DaStGen's copyright, visit www.peano-framework.org. These generated files
114// however are not subject of copyright, i.e. feel free to add your copyright in
115// here
116//
117#pragma once
118
119#include <string>
120
121{ASPECT_INCLUDES}
122
123{OPEN_NAMESPACES}
124 struct {UNQUALIFIED_CLASS_NAME};
125{CLOSE_NAMESPACES}
126
127
128struct {FULL_QUALIFIED_CLASS_NAME} {{
129 public:
130{PUBLIC_FIELDS}
131
132 {UNQUALIFIED_CLASS_NAME}() {{}}
133 {UNQUALIFIED_CLASS_NAME}{CONSTRUCTOR_ARGUMENTS};
134
135{METHOD_DECLARATIONS}
136
137{ASPECT_METHOD_DECLARATIONS}
138 std::string toString() const;
139
140 private:
141 struct DataStore {{
142{ATTRIBUTE_DECLARATIONS}
143 }};
144
145{ASPECT_ATTRIBUTES}
146
147 DataStore _dataStore;
148}};
149
150 """
151
153 """
154 Generates the list of constructor arguments needed to fully
155 instantiate an object of the class the datamodel generates.
156 """
157 result = "("
158 is_first = True
159 for attribute in self._attributes:
160 if (
161 attribute._is_static
162 or attribute._is_const_static
163 or attribute._is_constexpr
164 or attribute._is_const
165 ):
166 continue
167 for entry in attribute.get_constructor_arguments():
168 if not is_first:
169 result += ", "
170 is_first = False
171 result += entry[1] + " _" + entry[0]
172 result += ")"
173 return result
174
176 use_default_constructor = True
177 for attribute in self._attributes:
178 use_default_constructor = (
179 use_default_constructor and attribute.use_default_copy_constructor()
180 )
181 return use_default_constructor
182
183 def write_header_file(self, full_qualified_filename):
184 """!
185 writes the header file for your data model.
186 """
187 d = {}
188 d["ATTRIBUTE_INCLUDES"] = ""
189 for attribute in self._attributes:
190 d["ATTRIBUTE_INCLUDES"] += attribute.get_includes()
191
192 d["UNQUALIFIED_CLASS_NAME"] = dastgen2.get_unqualified_class_name(
194 )
195 d["FULL_QUALIFIED_CLASS_NAME"] = self._full_qualified_name
196 d["OPEN_NAMESPACES"] = ""
197 d["CLOSE_NAMESPACES"] = ""
198 d["ADDITIONAL_INCLUDES"] = self.additional_includes
199 d["SETTER_GETTER_DECLARATIONS"] = ""
200 for i in dastgen2.get_namespaces(self._full_qualified_name):
201 d["OPEN_NAMESPACES"] += "namespace " + i + "{\n"
202 d["CLOSE_NAMESPACES"] += "}\n"
203
204 d["PUBLIC_FIELDS"] = self.public_fields
205 for attribute in self._attributes:
206 d["PUBLIC_FIELDS"] += attribute.get_public_fields()
207
208 d["ATTRIBUTE_DECLARATIONS"] = ""
209 for attribute in self._attributes:
210 d["ATTRIBUTE_DECLARATIONS"] += attribute.get_attribute_declaration_string()
211
212 d["METHOD_DECLARATIONS"] = ""
213 for attribute in self._attributes:
214 if attribute.ifdefs != []:
215 d["METHOD_DECLARATIONS"] += dastgen2.construct_ifdef_string(
216 attribute.ifdefs
217 )
218 for method in attribute.get_methods(
219 self._full_qualified_name, for_declaration=True
220 ):
221 d["METHOD_DECLARATIONS"] += " "
222 if attribute.expose_in_header_file:
223 d["METHOD_DECLARATIONS"] += " inline "
224 d["METHOD_DECLARATIONS"] += method[1] + " " + method[0] + ";\n"
225 if attribute.ifdefs != []:
226 d["METHOD_DECLARATIONS"] += "#endif \n"
227
228 d["ASPECT_ATTRIBUTES"] = ""
229 d["ASPECT_METHOD_DECLARATIONS"] = ""
230 # Inlcudes to peano4 should not exist in tarch
231 # As tarch do not uses the definition Dimensions, but peano4 needs it (2 or 3 for example)
232 d["ASPECT_INCLUDES"] = ""
233 for i in self._aspects:
234
235 d["ASPECT_ATTRIBUTES"] += i.get_attributes() + "\n"
236 d["ASPECT_METHOD_DECLARATIONS"] += (
237 i.get_method_declarations(self._full_qualified_name) + "\n"
238 )
239 include = i.get_include()
240 # Do not include peano4 aspects in tarch files, due to the dimensions definitions
241 filtered_includes = ""
242 for line in include.split("\n"):
243 if not("tarch" in d["FULL_QUALIFIED_CLASS_NAME"] and line.startswith('#include "peano4')):
244 filtered_includes += line + "\n"
245
246 d["ASPECT_INCLUDES"] += filtered_includes+ "\n"
247 d["CONSTRUCTOR_ARGUMENTS"] = self._get_constructor_arguments()
249 d["METHOD_DECLARATIONS"] += (
250 " "
251 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
252 + "(const "
253 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
254 + "& copy) = default;"
255 )
256 else:
257 d["METHOD_DECLARATIONS"] += (
258 " "
259 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
260 + "(const "
261 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
262 + "& copy);"
263 )
264
265 if full_qualified_filename.find("/") != -1:
266 path = full_qualified_filename[0 : full_qualified_filename.rfind("/")]
267 if not os.path.exists(path):
268 os.mkdir(path)
269 with open(full_qualified_filename, "w") as output:
271 output.write(self._Header_Template_With_Data_Store.format(**d))
272 else:
273 output.write(self._Header_Template_Without_Data_Store.format(**d))
274
275 self.__generate_accessors(output, False)
276 output.write("\n\n\n")
277
279 """
280
281 In this generation business, I faced multiple issues with initialisation
282 lists: where are comma if some fields are not defined, which fields can
283 I copy directly, and which ones do I have to copy manually, and so forth.
284
285
286 """
287 output.write(
289 + "::"
290 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
292 )
293
294 output.write("{\n")
295 for attribute in self._attributes:
296 if (
297 attribute._is_static
298 or attribute._is_const_static
299 or attribute._is_constexpr
300 or attribute._is_const
301 ):
302 # no need to copy static class fields.
303 continue
304
305 if attribute.ifdefs != []:
306 output.write(dastgen2.construct_ifdef_string(attribute.ifdefs))
307 output.write(
308 "set"
309 + attribute._name[0].title()
310 + attribute._name[1:].split("[")[0]
311 + "( __"
312 + attribute._name.split("[")[0]
313 + ");\n"
314 )
315 if attribute.ifdefs != []:
316 output.write("#endif \n")
317 output.write("}\n")
318
320 output.write(
321 "std::string " + self._full_qualified_name + "::toString() const {\n"
322 )
323 output.write(" std::ostringstream out;\n")
324 output.write(' out << "(";\n')
325 for attribute in self._attributes:
326 if attribute.ifdefs != []:
327 output.write(dastgen2.construct_ifdef_string(attribute.ifdefs))
328 if self._attributes.index(attribute) != 0:
329 output.write(""" out << ","; \n""")
330 output.write(
331 ' out << "'
332 + attribute._name
333 + '=" << '
334 + attribute.get_to_string()
335 + ";\n"
336 )
337 if attribute.ifdefs != []:
338 output.write("#endif \n")
339
340 output.write(' out << ")";\n')
341 output.write(" return out.str();\n")
342 output.write("}\n\n\n")
343
345 output.write(
347 + "::"
348 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
349 + "( const "
350 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
351 + "& copy ) {\n"
352 )
353 for attribute in self._attributes:
354 if (
355 attribute._is_static
356 or attribute._is_const_static
357 or attribute._is_constexpr
358 or attribute._is_const
359 ):
360 # no need to copy static class fields.
361 continue
362 if attribute.ifdefs != []:
363 output.write(dastgen2.construct_ifdef_string(attribute.ifdefs))
364 uppercase_name = attribute.name[0].upper() + attribute.name[1:]
365 output.write(
366 " set" + uppercase_name + "( copy.get" + uppercase_name + "() );\n"
367 )
368 if attribute.ifdefs != []:
369 output.write("#endif \n")
370 output.write("}\n\n\n")
371
372 def __generate_accessors(self, output, is_cpp_file):
373 """!
374
375 Generate getter/setter functions.
376
377 Generate all the setters and getters and use get_methods() to
378 construct them for the individual attributes.
379
380 output: File object
381 File object that will be written to.
382
383 is_cpp_file: Boolean.
384 True if the output is intended to be the .cpp file. False if it's
385 the header file.
386
387 """
388 for attribute in self._attributes:
389 if attribute.expose_in_header_file != is_cpp_file:
390 if attribute.ifdefs != []:
391 output.write(dastgen2.construct_ifdef_string(attribute.ifdefs))
392 for method in attribute.get_methods(
393 self._full_qualified_name, for_declaration=False
394 ):
395 output.write(
396 method[1]
397 + " "
399 + "::"
400 + method[0]
401 + " {\n"
402 )
403 output.write(attribute.get_method_body(method[0]))
404 output.write("}\n\n\n")
405 if attribute.ifdefs != []:
406 output.write("#endif \n\n\n")
407
408 def write_implementation_file(self, full_qualified_filename):
409 """!
410 writes the implementation (.cpp) file for your data model.
411 """
412 with open(full_qualified_filename, "w") as output:
413 output.write(
414 '#include "'
415 + dastgen2.get_unqualified_class_name(self._full_qualified_name)
416 + '.h"\n\n\n'
417 )
418
419 output.write(
420 """
421#include <sstream>
422#include <algorithm>
423
424
425
426"""
427 )
428
429 # inserting include statements that the compiler will not accept in the header file
430 for aspect in self._aspects:
431 if hasattr(aspect, "implementation_file_includes"):
432 output.write( aspect.implementation_file_includes )
433
436 output.write("\n\n\n")
437
438 if not self.__use_default_copy_constructor():
440 output.write("\n\n\n")
441
443 output.write("\n\n\n")
444
445 self.__generate_accessors(output, True)
446 output.write("\n\n\n")
447
448 for aspect in self._aspects:
449 output.write(aspect.get_implementation(self._full_qualified_name))
450
452 for i in self._attributes:
453 i.expose_in_header_file = True
Represents on DaStGen2 object, i.e.
Definition DataModel.py:7
write_implementation_file(self, full_qualified_filename)
writes the implementation (.cpp) file for your data model.
Definition DataModel.py:408
_get_constructor_arguments(self)
Generates the list of constructor arguments needed to fully instantiate an object of the class the da...
Definition DataModel.py:152
__generate_constructor_definition(self, output)
In this generation business, I faced multiple issues with initialisation lists: where are comma if so...
Definition DataModel.py:278
__generate_accessors(self, output, is_cpp_file)
Generate getter/setter functions.
Definition DataModel.py:372
add_attribute(self, attribute)
Definition DataModel.py:42
write_header_file(self, full_qualified_filename)
writes the header file for your data model.
Definition DataModel.py:183
__generate_toString_definition(self, output)
Definition DataModel.py:319
__init__(self, full_qualified_name, has_nondefault_constructor=True, embed_attributes_into_data_store=False)
Construct the data modell.
Definition DataModel.py:20
set_full_qualified_name(self, full_qualified_name)
Definition DataModel.py:39
add_or_replace_attribute(self, attribute)
Check first whether attribute already exists.
Definition DataModel.py:46
__generate_explicit_copy_constructor(self, output)
Definition DataModel.py:344