Line data Source code
1 : // DUNE DAQ modification notice:
2 : // This file has been modified from the original ATLAS oks source for the DUNE DAQ project.
3 : // Fork baseline commit: oks-08-03-04 (2022-04-14).
4 : // Renamed since fork: no.
5 :
6 : #define _OksBuildDll_
7 :
8 : #include "oks/class.hpp"
9 : #include "oks/cstring.hpp"
10 : #include "oks/index.hpp"
11 : #include "oks/kernel.hpp"
12 : #include "oks/method.hpp"
13 : #include "oks/object.hpp"
14 : #include "oks/profiler.hpp"
15 : #include "oks/relationship.hpp"
16 : #include "oks/xml.hpp"
17 :
18 : #include "ers/ers.hpp"
19 : #include "logging/Logging.hpp"
20 :
21 : #include <stdlib.h>
22 :
23 : #include <algorithm>
24 : #include <stdexcept>
25 : #include <string>
26 :
27 : namespace dunedaq {
28 : namespace oks {
29 :
30 : const char OksClass::class_xml_tag[] = "class";
31 : const char OksClass::name_xml_attr[] = "name";
32 : const char OksClass::description_xml_attr[] = "description";
33 : const char OksClass::is_abstract_xml_attr[] = "is-abstract";
34 : const char OksClass::superclass_xml_attr[] = "superclass";
35 :
36 : OksClass::NotifyFN OksClass::create_notify_fn;
37 : OksClass::ChangeNotifyFN OksClass::change_notify_fn;
38 : OksClass::NotifyFN OksClass::delete_notify_fn;
39 :
40 : std::string
41 0 : CannotFindSuperClass::fill(const OksClass& c, const std::string& name) noexcept
42 : {
43 0 : return std::string("cannot find superclass \'") + name + "\' of class \'" + c.get_name() + '\'';
44 : }
45 :
46 : std::string
47 0 : AttributeConversionFailed::fill(const OksAttribute& a, const OksObject* o, const std::string& reason) noexcept
48 : {
49 0 : std::ostringstream s;
50 0 : s << "failed to convert \'" << a.get_name() << "\" value of object " << o << " because:\n" + reason;
51 0 : return s.str();
52 0 : }
53 :
54 : std::string
55 0 : CannotRegisterClass::fill(const OksClass& c, const std::string& what, const std::string& reason) noexcept
56 : {
57 0 : return std::string("cannot register class \'") + c.get_name() + "\' " + what + "because:\n" + reason;
58 : }
59 :
60 : std::string
61 0 : CannotDestroyClass::fill(const OksClass& c, const std::string& reason) noexcept
62 : {
63 0 : return std::string("cannot destroy class \'") + c.get_name() + "\' because:\n" + reason;
64 : }
65 :
66 : std::string
67 0 : ObjectOperationFailed::fill(const OksClass& c,
68 : const std::string& oid,
69 : const char* op,
70 : const std::string& reason) noexcept
71 : {
72 0 : return std::string("cannot ") + op + " object \'" + oid + "\' in class \'" + c.get_name() + "\' because:\n" + reason;
73 : }
74 :
75 : std::string
76 0 : SetOperationFailed::fill(const char* op, const std::string& reason) noexcept
77 : {
78 0 : return std::string("method \'") + op + "()\' failed because:\n" + reason;
79 : }
80 :
81 0 : OksClass::OksClass(const std::string& nm, OksKernel* k, bool t)
82 0 : : p_name(nm)
83 0 : , p_super_classes(0)
84 0 : , p_attributes(0)
85 0 : , p_relationships(0)
86 0 : , p_methods(0)
87 0 : , p_abstract(false)
88 0 : , p_transient(t)
89 0 : , p_to_be_deleted(false)
90 0 : , p_all_super_classes(0)
91 0 : , p_all_sub_classes(0)
92 0 : , p_all_attributes(0)
93 0 : , p_all_relationships(0)
94 0 : , p_all_methods(0)
95 0 : , p_inheritance_hierarchy(0)
96 0 : , p_kernel(k)
97 0 : , p_instance_size(0)
98 0 : , p_data_info(0)
99 0 : , p_objects(0)
100 0 : , p_indices(0)
101 : {
102 0 : OSK_PROFILING(OksProfiler::ClassConstructor, p_kernel)
103 :
104 0 : if (p_transient == false && p_kernel) {
105 0 : oks::validate_not_empty(p_name, "class name");
106 :
107 0 : std::unique_lock lock(p_kernel->p_kernel_mutex);
108 0 : p_kernel->k_add(this);
109 0 : }
110 0 : }
111 :
112 0 : OksClass::OksClass(const std::string& nm, const std::string& d, bool a, OksKernel* k, bool t)
113 0 : : p_name(nm)
114 0 : , p_description(d)
115 0 : , p_super_classes(0)
116 0 : , p_attributes(0)
117 0 : , p_relationships(0)
118 0 : , p_methods(0)
119 0 : , p_abstract(a)
120 0 : , p_transient(t)
121 0 : , p_to_be_deleted(false)
122 0 : , p_all_super_classes(0)
123 0 : , p_all_sub_classes(0)
124 0 : , p_all_attributes(0)
125 0 : , p_all_relationships(0)
126 0 : , p_all_methods(0)
127 0 : , p_inheritance_hierarchy(0)
128 0 : , p_kernel(k)
129 0 : , p_instance_size(0)
130 0 : , p_data_info(0)
131 0 : , p_objects(0)
132 0 : , p_indices(0)
133 : {
134 0 : OSK_PROFILING(OksProfiler::ClassConstructor, p_kernel)
135 :
136 0 : if (p_transient == false && p_kernel) {
137 0 : oks::validate_not_empty(p_name, "class name");
138 :
139 0 : std::unique_lock lock(p_kernel->p_kernel_mutex);
140 0 : p_kernel->k_add(this);
141 0 : }
142 0 : }
143 :
144 0 : OksClass::OksClass(OksKernel* kernel, const std::string& name, const std::string& description, bool is_abstract)
145 0 : : p_name(name)
146 0 : , p_description(description)
147 0 : , p_super_classes(0)
148 0 : , p_attributes(0)
149 0 : , p_relationships(0)
150 0 : , p_methods(0)
151 0 : , p_abstract(is_abstract)
152 0 : , p_transient(false)
153 0 : , p_to_be_deleted(false)
154 0 : , p_all_super_classes(0)
155 0 : , p_all_sub_classes(0)
156 0 : , p_all_attributes(0)
157 0 : , p_all_relationships(0)
158 0 : , p_all_methods(0)
159 0 : , p_inheritance_hierarchy(0)
160 0 : , p_file(kernel->p_active_schema)
161 0 : , p_kernel(kernel)
162 0 : , p_instance_size(0)
163 0 : , p_data_info(0)
164 0 : , p_objects(0)
165 0 : , p_indices(0)
166 : {
167 0 : OSK_PROFILING(OksProfiler::ClassConstructor, p_kernel)
168 0 : p_kernel->p_classes[p_name.c_str()] = this;
169 0 : }
170 :
171 : void
172 0 : OksClass::destroy(OksClass* c)
173 : {
174 : // obtain write mutex, if non-transient class is registered in the oks kernel
175 :
176 0 : if (!c->p_transient && c->p_kernel) {
177 0 : std::unique_lock lock(c->p_kernel->p_kernel_mutex);
178 :
179 0 : try {
180 0 : c->p_file->lock();
181 0 : c->p_file->set_updated();
182 0 : } catch (oks::exception& ex) {
183 0 : throw oks::CannotDestroyClass(*c, ex);
184 0 : }
185 :
186 0 : delete c;
187 0 : }
188 :
189 : // destroy class without get write mutex
190 :
191 : else {
192 0 : delete c;
193 : }
194 0 : }
195 :
196 : template<class T>
197 : void
198 30008 : OksClass::destroy_list(T list)
199 : {
200 30008 : if (list) {
201 39829 : for (const auto& x : *list)
202 26065 : delete x;
203 :
204 13764 : delete list;
205 : }
206 30008 : }
207 :
208 : template<class T>
209 : void
210 15004 : OksClass::destroy_map(T map)
211 : {
212 15004 : if (map) {
213 41883 : for (const auto& x : *map)
214 34381 : delete x.second;
215 :
216 7502 : delete map;
217 : }
218 15004 : }
219 :
220 7502 : OksClass::~OksClass()
221 : {
222 7502 : OSK_PROFILING(OksProfiler::ClassDestructor, p_kernel)
223 :
224 7502 : TLOG_DEBUG(2) << "destruct " << (p_transient ? "TRANSIENT" : "NORMAL") << " class \'" << get_name() << '\'';
225 :
226 : // ~OksIndex() removes 'SELF' from OksClass and deletes 'indices' when there is no an index in it
227 7502 : while (p_indices)
228 0 : delete (*(p_indices->begin())).second;
229 :
230 7502 : destroy_map(p_objects);
231 7502 : destroy_map(p_data_info);
232 :
233 7502 : if (!p_transient && p_kernel) {
234 7502 : p_kernel->k_remove(this);
235 :
236 7502 : if (p_all_super_classes)
237 15040 : for (const auto& c : *p_all_super_classes) {
238 7538 : if (p_kernel->is_dangling(c) || c->p_to_be_deleted)
239 7538 : continue;
240 :
241 0 : c->create_sub_classes();
242 :
243 0 : if (OksClass::change_notify_fn)
244 0 : (*OksClass::change_notify_fn)(c, ChangeSubClassesList, (const void*)&p_name);
245 : }
246 :
247 7502 : if (p_all_sub_classes)
248 15040 : for (const auto& c : *p_all_sub_classes) {
249 7538 : if (p_kernel->is_dangling(c) || c->p_to_be_deleted)
250 7538 : continue;
251 :
252 0 : try {
253 0 : c->registrate_class_change(ChangeSuperClassesList, (const void*)&p_name, false);
254 0 : } catch (oks::exception& ex) {
255 0 : std::cerr << "internal OKS error: registrate_class_change() failed during \'" << get_name()
256 0 : << "\' class destruction\ncaused by: " << ex.what() << std::endl;
257 0 : }
258 : }
259 : }
260 :
261 7502 : destroy_list(p_super_classes);
262 7502 : destroy_list(p_attributes);
263 7502 : destroy_list(p_relationships);
264 7502 : destroy_list(p_methods);
265 :
266 7502 : if (!p_transient) {
267 7502 : delete p_all_super_classes;
268 7502 : delete p_all_sub_classes;
269 7502 : delete p_all_attributes;
270 7502 : delete p_all_relationships;
271 7502 : delete p_all_methods;
272 7502 : delete p_inheritance_hierarchy;
273 : }
274 7502 : }
275 :
276 : void
277 0 : OksClass::set_file(OksFile* f, bool update_owner)
278 : {
279 0 : if (p_file != f) {
280 0 : try {
281 0 : if (update_owner) {
282 0 : p_file->lock();
283 0 : p_file->set_updated();
284 : }
285 :
286 0 : f->lock();
287 0 : f->set_updated();
288 :
289 0 : p_file = f;
290 0 : } catch (oks::exception& ex) {
291 0 : throw oks::CanNotSetFile(this, 0, *f, ex);
292 0 : }
293 : }
294 0 : }
295 :
296 : bool
297 0 : OksClass::compare_without_methods(const OksClass& c) const noexcept
298 : {
299 0 : if (this == &c)
300 : return true;
301 :
302 0 : if ((p_name != c.p_name) || (p_description != c.p_description) || (p_abstract != c.p_abstract))
303 : return false;
304 :
305 0 : int l1 = (p_attributes == 0) ? 0 : p_attributes->size();
306 0 : int l2 = (c.p_attributes == 0) ? 0 : c.p_attributes->size();
307 :
308 0 : if (l1 != l2)
309 : return false;
310 :
311 0 : if (l1 > 0) {
312 0 : std::list<OksAttribute*>::const_iterator i1 = p_attributes->begin();
313 0 : std::list<OksAttribute*>::const_iterator i2 = c.p_attributes->begin();
314 :
315 0 : for (; i1 != p_attributes->end(); ++i1, ++i2)
316 0 : if (!(*(*i1) == *(*i2)))
317 0 : return false;
318 : }
319 :
320 0 : l1 = (p_relationships == 0) ? 0 : p_relationships->size();
321 0 : l2 = (c.p_relationships == 0) ? 0 : c.p_relationships->size();
322 :
323 0 : if (l1 != l2)
324 : return false;
325 :
326 0 : if (l1 > 0) {
327 0 : std::list<OksRelationship*>::const_iterator i1 = p_relationships->begin();
328 0 : std::list<OksRelationship*>::const_iterator i2 = c.p_relationships->begin();
329 :
330 0 : for (; i1 != p_relationships->end(); ++i1, ++i2)
331 0 : if (!(*(*i1) == *(*i2)))
332 0 : return false;
333 : }
334 :
335 0 : l1 = (p_super_classes == 0) ? 0 : p_super_classes->size();
336 0 : l2 = (c.p_super_classes == 0) ? 0 : c.p_super_classes->size();
337 :
338 0 : if (l1 != l2)
339 : return false;
340 :
341 0 : if (l1 > 0) {
342 0 : std::list<std::string*>::const_iterator i1 = p_super_classes->begin();
343 0 : std::list<std::string*>::const_iterator i2 = c.p_super_classes->begin();
344 :
345 0 : for (; i1 != p_super_classes->end(); ++i1, ++i2)
346 0 : if (!(*(*i1) == *(*i2)))
347 0 : return false;
348 : }
349 :
350 : return true;
351 : }
352 :
353 : bool
354 0 : OksClass::operator!=(const OksClass& c) const
355 : {
356 0 : if (this == &c)
357 : return false;
358 :
359 0 : if (compare_without_methods(c) == false)
360 : return true;
361 :
362 0 : int l1 = (p_methods == 0) ? 0 : p_methods->size();
363 0 : int l2 = (c.p_methods == 0) ? 0 : c.p_methods->size();
364 :
365 0 : if (l1 != l2)
366 : return true;
367 :
368 0 : if (l1 > 0) {
369 0 : std::list<OksMethod*>::const_iterator i1 = p_methods->begin();
370 0 : std::list<OksMethod*>::const_iterator i2 = c.p_methods->begin();
371 :
372 0 : for (; i1 != p_methods->end(); ++i1, ++i2)
373 0 : if (!(*(*i1) == *(*i2)))
374 0 : return true;
375 : }
376 :
377 : return false;
378 : }
379 :
380 : std::ostream&
381 0 : operator<<(std::ostream& s, const OksClass& c)
382 : {
383 0 : OSK_PROFILING(OksProfiler::ClassOperatorOut, c.p_kernel)
384 :
385 0 : s << "Class name: \"" << c.p_name
386 : << "\"\n"
387 : " has description: \""
388 0 : << c.p_description << "\"\n"
389 0 : << (c.p_abstract == true ? " is abstract\n" : " is not abstract\n");
390 :
391 0 : if (c.p_super_classes) {
392 0 : s << "The class has superclasses:\n";
393 0 : for (std::list<std::string*>::const_iterator i = c.p_super_classes->begin(); i != c.p_super_classes->end(); ++i) {
394 0 : s << " - " << *(*i) << std::endl;
395 : }
396 : } else
397 0 : s << "The class has no superclasses\n";
398 :
399 0 : if (c.p_attributes) {
400 0 : s << "The attributes are:\n";
401 0 : for (std::list<OksAttribute*>::const_iterator i = c.p_attributes->begin(); i != c.p_attributes->end(); ++i) {
402 0 : s << *(*i);
403 : }
404 : } else
405 0 : s << "There are no attributes\n";
406 :
407 0 : if (c.p_relationships) {
408 0 : s << "The relationships are:\n";
409 0 : for (std::list<OksRelationship*>::const_iterator i = c.p_relationships->begin(); i != c.p_relationships->end();
410 0 : ++i) {
411 0 : s << *(*i);
412 : }
413 : } else
414 0 : s << "There are no relationships\n";
415 :
416 0 : if (c.p_methods) {
417 0 : s << "The methods are:\n";
418 0 : for (std::list<OksMethod*>::const_iterator i = c.p_methods->begin(); i != c.p_methods->end(); ++i) {
419 0 : s << *(*i);
420 : }
421 : } else
422 0 : s << "There are no methods\n";
423 :
424 0 : if (c.p_objects) {
425 0 : OksObject::SMap sorted;
426 :
427 0 : s << "The objects are:\n";
428 :
429 0 : for (OksObject::Map::iterator i = c.p_objects->begin(); i != c.p_objects->end(); ++i) {
430 0 : sorted[i->first] = i->second;
431 : }
432 :
433 0 : for (OksObject::SMap::iterator i = sorted.begin(); i != sorted.end(); ++i) {
434 0 : s << *(i->second);
435 : }
436 0 : } else
437 0 : s << "There are no objects\n";
438 :
439 0 : s << "End of Class \"" << c.p_name << "\"\n";
440 :
441 0 : return s;
442 0 : }
443 :
444 : void
445 0 : OksClass::save(OksXmlOutputStream& s) const
446 : {
447 0 : try {
448 0 : s.put_raw(' ');
449 0 : s.put_start_tag(class_xml_tag, sizeof(class_xml_tag) - 1);
450 0 : s.put_attribute(name_xml_attr, sizeof(name_xml_attr) - 1, p_name.c_str());
451 :
452 : // store non-empty description only
453 0 : if (!p_description.empty())
454 0 : s.put_attribute(description_xml_attr, sizeof(description_xml_attr) - 1, p_description.c_str());
455 :
456 : // store abstract attribute only when the class is abstract
457 0 : if (p_abstract)
458 0 : s.put_attribute(is_abstract_xml_attr, sizeof(is_abstract_xml_attr) - 1, oks::xml::bool2str(p_abstract));
459 :
460 0 : s.put_raw('>');
461 0 : s.put_raw('\n');
462 :
463 0 : if (p_super_classes)
464 0 : for (const auto& i : *p_super_classes) {
465 0 : s.put_raw(' ');
466 0 : s.put_raw(' ');
467 0 : s.put_start_tag(superclass_xml_attr, sizeof(superclass_xml_attr) - 1);
468 0 : s.put_attribute(name_xml_attr, sizeof(name_xml_attr) - 1, i->c_str());
469 0 : s.put_end_tag();
470 : }
471 :
472 0 : if (p_attributes)
473 0 : for (const auto& i : *p_attributes)
474 0 : i->save(s);
475 :
476 0 : if (p_relationships)
477 0 : for (const auto& i : *p_relationships)
478 0 : i->save(s);
479 :
480 0 : if (p_methods)
481 0 : for (const auto& i : *p_methods)
482 0 : i->save(s);
483 :
484 0 : s.put_raw(' ');
485 0 : s.put_last_tag(class_xml_tag, sizeof(class_xml_tag) - 1);
486 0 : s.put_raw('\n');
487 : }
488 :
489 0 : catch (oks::exception& e) {
490 0 : throw oks::FailedSave("oks-class", p_name, e);
491 0 : }
492 :
493 0 : catch (std::exception& e) {
494 0 : throw oks::FailedSave("oks-class", p_name, e.what());
495 0 : }
496 0 : }
497 :
498 7684 : OksClass::OksClass(OksXmlInputStream& s, OksKernel* k)
499 7684 : : p_super_classes(0)
500 7684 : , p_attributes(0)
501 7684 : , p_relationships(0)
502 7684 : , p_methods(0)
503 7684 : , p_abstract(false)
504 7684 : , p_transient(false)
505 7684 : , p_to_be_deleted(false)
506 7684 : , p_all_super_classes(0)
507 7684 : , p_all_sub_classes(0)
508 7684 : , p_all_attributes(0)
509 7684 : , p_all_relationships(0)
510 7684 : , p_all_methods(0)
511 7684 : , p_inheritance_hierarchy(0)
512 7684 : , p_kernel(k)
513 7684 : , p_instance_size(0)
514 7684 : , p_data_info(0)
515 7684 : , p_objects(0)
516 7684 : , p_indices(0)
517 : {
518 :
519 : // read 'relationship' tag header
520 :
521 7684 : {
522 7684 : try {
523 7684 : const char* tag_start = s.get_tag_start();
524 :
525 7684 : if (strcmp(tag_start, class_xml_tag)) {
526 182 : if (!strcmp(tag_start, "/oks-schema")) {
527 182 : goto end_of_stream; // re-throw of exception takes too much time; go to is better
528 : }
529 0 : s.throw_unexpected_tag(tag_start, class_xml_tag);
530 : }
531 0 : } catch (oks::exception& e) {
532 0 : throw oks::FailedRead("oks-class tag", e);
533 0 : } catch (std::exception& e) {
534 0 : throw oks::FailedRead("oks-class tag", e.what());
535 0 : }
536 : }
537 :
538 : // read class attributes
539 :
540 18383 : try {
541 29264 : while (true) {
542 18383 : OksXmlAttribute attr(s);
543 :
544 : // check for close of tag
545 :
546 18383 : if (oks::cmp_str1(attr.name(), ">")) {
547 : break;
548 : }
549 :
550 : // check for known oks-class' attributes
551 :
552 10881 : else if (oks::cmp_str4(attr.name(), name_xml_attr))
553 7502 : p_name.assign(attr.value(), attr.value_len());
554 3379 : else if (oks::cmp_str11(attr.name(), description_xml_attr))
555 1772 : p_description.assign(attr.value(), attr.value_len());
556 1607 : else if (oks::cmp_str11(attr.name(), is_abstract_xml_attr))
557 1607 : p_abstract = oks::xml::str2bool(attr.value());
558 : else {
559 0 : s.throw_unexpected_tag(attr.name(), "oks-class\' attribute");
560 : }
561 10881 : }
562 0 : } catch (oks::exception& e) {
563 0 : throw oks::FailedRead("oks-class description", e);
564 0 : } catch (std::exception& e) {
565 0 : throw oks::FailedRead("oks-class description", e.what());
566 0 : }
567 :
568 7502 : try {
569 7502 : oks::validate_not_empty(p_name, "class name");
570 0 : } catch (std::exception& ex) {
571 0 : throw oks::FailedRead("oks class", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
572 0 : }
573 :
574 : // read class body
575 :
576 33567 : while (true) {
577 :
578 33567 : try {
579 :
580 33567 : const char* tag_start = s.get_tag_start();
581 :
582 : // check for closing tag and exit loop
583 :
584 33567 : if (oks::cmp_str6(tag_start, "/class")) {
585 : break;
586 : }
587 :
588 : // create superclass
589 :
590 26065 : else if (oks::cmp_str10(tag_start, superclass_xml_attr)) {
591 4509 : unsigned long scl_pos = s.get_line_no();
592 4509 : try {
593 4509 : OksXmlAttribute attr(s);
594 :
595 4509 : if (!p_super_classes)
596 4083 : p_super_classes = new std::list<std::string*>();
597 4509 : std::string* scl = new std::string(attr.value(), attr.value_len());
598 4509 : if (has_direct_super_class(*scl)) {
599 0 : std::ostringstream text;
600 0 : text << "second inclusion of super-class \"" + *scl + "\" at line " << scl_pos;
601 0 : delete scl;
602 0 : throw std::runtime_error(text.str().c_str());
603 0 : }
604 4509 : p_super_classes->push_back(scl);
605 :
606 4509 : OksXmlAttribute attr2(s);
607 0 : } catch (oks::exception& e) {
608 0 : throw oks::FailedRead(std::string("a superclass-name of class \"") + p_name + '\"', e);
609 0 : } catch (std::exception& e) {
610 0 : throw oks::FailedRead(std::string("a superclass-name of class \"") + p_name + '\"', e.what());
611 0 : }
612 : }
613 :
614 : // create attribute from stream and check attribute status
615 :
616 21556 : else if (oks::cmp_str9(tag_start, "attribute")) {
617 11955 : unsigned long attr_pos = s.get_line_no();
618 11955 : try {
619 11955 : if (!p_attributes)
620 4714 : p_attributes = new std::list<OksAttribute*>();
621 11955 : OksAttribute* a = new OksAttribute(s, this);
622 11955 : if (find_direct_attribute(a->get_name()) != nullptr) {
623 0 : std::ostringstream text;
624 0 : text << "redefinition of attribute with name \"" + a->get_name() + "\" at line " << attr_pos;
625 0 : delete a;
626 0 : throw std::runtime_error(text.str().c_str());
627 0 : }
628 11955 : p_attributes->push_back(a);
629 0 : } catch (oks::exception& e) {
630 0 : throw oks::FailedRead(std::string("an attribute of class \"") + p_name + '\"', e);
631 0 : } catch (std::exception& e) {
632 0 : throw oks::FailedRead(std::string("an attribute of class \"") + p_name + '\"', e.what());
633 0 : }
634 : }
635 :
636 : // create relationship from stream and check relationship status
637 :
638 9601 : else if (oks::cmp_str12(tag_start, "relationship")) {
639 6400 : unsigned long rel_pos = s.get_line_no();
640 6400 : try {
641 6400 : if (!p_relationships)
642 3232 : p_relationships = new std::list<OksRelationship*>();
643 6400 : OksRelationship* r = new OksRelationship(s, this);
644 6400 : if (find_direct_relationship(r->get_name()) != nullptr) {
645 0 : std::ostringstream text;
646 0 : text << "redefinition of relationship with name \"" + r->get_name() + "\" at line " << rel_pos;
647 0 : delete r;
648 0 : throw std::runtime_error(text.str().c_str());
649 0 : }
650 6400 : p_relationships->push_back(r);
651 0 : } catch (oks::exception& e) {
652 0 : throw oks::FailedRead(std::string("a relationship of class \"") + p_name + '\"', e);
653 0 : } catch (std::exception& e) {
654 0 : throw oks::FailedRead(std::string("a relationship of class \"") + p_name + '\"', e.what());
655 0 : }
656 : }
657 :
658 : // create method from stream and check method status
659 :
660 3201 : else if (oks::cmp_str6(tag_start, "method")) {
661 3201 : unsigned long method_pos = s.get_line_no();
662 3201 : try {
663 3201 : if (!p_methods)
664 1735 : p_methods = new std::list<OksMethod*>();
665 3201 : OksMethod* m = new OksMethod(s, this);
666 3201 : if (find_direct_method(m->get_name()) != nullptr) {
667 0 : std::ostringstream text;
668 0 : text << "redefinition of method with name \"" + m->get_name() + "\" at line " << method_pos;
669 0 : delete m;
670 0 : throw std::runtime_error(text.str().c_str());
671 0 : }
672 3201 : p_methods->push_back(m);
673 0 : } catch (oks::exception& e) {
674 0 : throw oks::FailedRead(std::string("a method of class \"") + p_name + '\"', e);
675 0 : } catch (std::exception& e) {
676 0 : throw oks::FailedRead(std::string("a method of class \"") + p_name + '\"', e.what());
677 0 : }
678 : }
679 :
680 : // report error if red something differnt from above
681 : // and set bad status of constructor (suppose 'name' can't be empty)
682 :
683 : else {
684 0 : s.throw_unexpected_tag(tag_start);
685 : }
686 :
687 0 : } catch (oks::FailedRead& e) {
688 0 : throw; // re-throw attribute, relationship or method exception
689 0 : } catch (oks::exception& e) {
690 0 : throw oks::FailedRead(std::string("a tag of class \"") + p_name + '\"', e);
691 0 : } catch (std::exception& e) {
692 0 : throw oks::FailedRead(std::string("a tag of class \"") + p_name + '\"', e.what());
693 0 : }
694 : }
695 :
696 7502 : return;
697 :
698 182 : end_of_stream:
699 :
700 182 : throw oks::EndOfXmlStream("oks-schema");
701 364 : }
702 :
703 : /******************************************************************************/
704 : /****************************** OKS SUPERCLASSES ******************************/
705 : /******************************************************************************/
706 :
707 : OksClass*
708 0 : OksClass::find_super_class(const std::string& nm) const noexcept
709 : {
710 0 : if (p_all_super_classes && !p_all_super_classes->empty()) {
711 0 : for (FList::const_iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
712 0 : if ((*i)->get_name() == nm)
713 0 : return *i;
714 : }
715 : }
716 :
717 : return 0;
718 : }
719 :
720 : bool
721 4509 : OksClass::has_direct_super_class(const std::string& nm) const noexcept
722 : {
723 4509 : if (p_super_classes) {
724 4944 : for (std::list<std::string*>::const_iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i)
725 435 : if (nm == *(*i))
726 0 : return true;
727 : }
728 :
729 : return false;
730 : }
731 :
732 : void
733 0 : OksClass::lock_file(const char* fname)
734 : {
735 0 : if (p_kernel) {
736 0 : try {
737 0 : p_file->lock();
738 0 : } catch (oks::exception& ex) {
739 0 : throw oks::SetOperationFailed(fname, ex);
740 0 : }
741 : }
742 0 : }
743 :
744 : void
745 0 : OksClass::set_description(const std::string& s)
746 : {
747 0 : if (p_description != s) {
748 0 : lock_file("OksClass::set_description");
749 :
750 0 : p_description = s;
751 :
752 0 : if (p_kernel) {
753 0 : p_file->set_updated();
754 0 : if (OksClass::change_notify_fn) {
755 0 : (*OksClass::change_notify_fn)(this, ChangeDescription, 0);
756 : }
757 : }
758 : }
759 0 : }
760 :
761 : void
762 0 : OksClass::set_is_abstract(bool b)
763 : {
764 0 : if (p_abstract != b) {
765 0 : lock_file("OksClass::set_is_abstract");
766 :
767 0 : p_abstract = b;
768 :
769 0 : if (p_kernel) {
770 0 : p_file->set_updated();
771 0 : if (OksClass::change_notify_fn) {
772 0 : (*OksClass::change_notify_fn)(this, ChangeIsAbstaract, 0);
773 : }
774 : }
775 : }
776 0 : }
777 :
778 : // Function to report problem with arguments of swap(...) methods
779 :
780 : static void
781 0 : check_and_report_empty_parameter(const char* fname, bool b1, bool b2)
782 : {
783 0 : if (b1) {
784 0 : throw oks::SetOperationFailed(fname, "First parameter is (null)");
785 : }
786 :
787 0 : if (b2) {
788 0 : throw oks::SetOperationFailed(fname, "Second parameter is (null)");
789 : }
790 0 : }
791 :
792 : // Function to report problem with found items of swap(...) methods
793 :
794 : static void
795 0 : check_and_report_found_items(const char* fname,
796 : const char* item_type,
797 : const std::string& item1_name,
798 : const std::string& item2_name,
799 : const std::string& class_name,
800 : bool b1,
801 : bool b2)
802 : {
803 0 : struct
804 : {
805 : bool b;
806 : const std::string* name;
807 0 : } info[] = { { b1, &item1_name }, { b2, &item2_name } };
808 :
809 0 : for (int i = 0; i < 2; ++i) {
810 0 : if (info[i].b) {
811 0 : std::string text("cannot find direct ");
812 0 : text += item_type;
813 0 : text += " \"";
814 0 : text += *info[i].name;
815 0 : text += "\" in class \"";
816 0 : text += class_name;
817 0 : text += '\"';
818 0 : throw oks::SetOperationFailed(fname, text);
819 0 : }
820 : }
821 0 : }
822 :
823 : static std::string
824 0 : add_super_class_error(const std::string& c1, const std::string& c2)
825 : {
826 0 : return (std::string("cannot add superclass \"") + c1 + "\" to class \"" + c2 + '\"');
827 : }
828 :
829 : void
830 0 : OksClass::k_add_super_class(const std::string& nm)
831 : {
832 0 : if (!p_super_classes) {
833 0 : p_super_classes = new std::list<std::string*>();
834 : }
835 :
836 0 : p_super_classes->push_back((new std::string(nm)));
837 0 : }
838 :
839 : void
840 0 : OksClass::add_super_class(const std::string& nm)
841 : {
842 0 : if (!p_super_classes) {
843 0 : p_super_classes = new std::list<std::string*>();
844 : } else {
845 0 : if (has_direct_super_class(nm)) {
846 0 : std::string text(add_super_class_error(nm, p_name));
847 0 : text += " because class \"" + p_name + "\" already has such superclass.";
848 0 : throw oks::SetOperationFailed("OksClass::add_super_class", text);
849 0 : }
850 : }
851 :
852 0 : if (nm == p_name) {
853 0 : std::string text(add_super_class_error(nm, p_name));
854 0 : text += " because names of classes are the same.";
855 0 : throw oks::SetOperationFailed("OksClass::add_super_class", text);
856 0 : }
857 :
858 0 : if (p_kernel) {
859 0 : OksClass* nmc = p_kernel->find_class(nm);
860 0 : if (nmc) {
861 0 : if (nmc->has_direct_super_class(p_name)) {
862 0 : std::string text(add_super_class_error(nm, p_name));
863 0 : text += " because class \"" + nm + "\" is already direct superclass of \"" + p_name + "\".";
864 0 : throw oks::SetOperationFailed("OksClass::add_super_class", text);
865 0 : } else if (nmc->find_super_class(p_name)) {
866 0 : std::string text(add_super_class_error(nm, p_name));
867 0 : text += " because class \"" + nm + "\" is already non-direct superclass of \"" + p_name + "\".";
868 0 : throw oks::SetOperationFailed("OksClass::add_super_class", text);
869 0 : }
870 : }
871 : }
872 :
873 0 : lock_file("OksClass::add_super_class");
874 :
875 0 : p_super_classes->push_back((new std::string(nm)));
876 :
877 0 : registrate_class_change(ChangeSuperClassesList, (const void*)&nm);
878 0 : }
879 :
880 : static std::string
881 0 : remove_super_class_error(const std::string& c1, const std::string& c2)
882 : {
883 0 : return (std::string("cannot remove superclass \"") + c1 + "\" from class \"" + c2 + '\"');
884 : }
885 :
886 : void
887 0 : OksClass::remove_super_class(const std::string& nm)
888 : {
889 0 : if (!p_super_classes) {
890 0 : std::string text(remove_super_class_error(nm, p_name));
891 0 : text += " because class \"" + p_name + "\" has no superclasses at all.";
892 0 : throw oks::SetOperationFailed("OksClass::remove_super_class", text);
893 0 : }
894 :
895 0 : for (std::list<std::string*>::iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i) {
896 0 : std::string* si(*i);
897 0 : if (nm == *si) {
898 0 : lock_file("OksClass::remove_super_class");
899 :
900 0 : p_super_classes->erase(i);
901 0 : delete si;
902 :
903 0 : if (p_super_classes->empty()) {
904 0 : delete p_super_classes;
905 0 : p_super_classes = 0;
906 : }
907 :
908 0 : registrate_class_change(ChangeSuperClassesList, (const void*)&nm);
909 :
910 0 : return;
911 : }
912 : }
913 :
914 0 : std::string text(remove_super_class_error(nm, p_name));
915 0 : text += " because class \"" + p_name + "\" has no superclass with this name.";
916 0 : throw oks::SetOperationFailed("OksClass::remove_super_class", text);
917 0 : }
918 :
919 : void
920 0 : OksClass::swap_super_classes(const std::string& c1, const std::string& c2)
921 : {
922 0 : const char* fname = "OksClass::swap_super_classes()";
923 :
924 : // if classs are equal, return success
925 :
926 0 : if (c1 == c2)
927 0 : return;
928 :
929 : // check that an class name is not empty
930 :
931 0 : check_and_report_empty_parameter(fname, c1.empty(), c2.empty());
932 :
933 : // find requested classes in the directed classs list
934 :
935 0 : std::list<std::string*>::iterator i1 = p_super_classes->end();
936 0 : std::list<std::string*>::iterator i2 = p_super_classes->end();
937 :
938 0 : for (std::list<std::string*>::iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i) {
939 0 : if (*(*i) == c1)
940 0 : i1 = i;
941 0 : else if (*(*i) == c2)
942 0 : i2 = i;
943 : }
944 :
945 : // check that the classes were found
946 :
947 0 : check_and_report_found_items("OksClass::swap_super_classes",
948 : "superclass",
949 : c1,
950 : c2,
951 0 : p_name,
952 0 : (i1 == p_super_classes->end()),
953 0 : (i2 == p_super_classes->end()));
954 :
955 : // replace the classs and make notification
956 :
957 0 : lock_file("OksClass::swap_super_classes");
958 :
959 0 : std::string* s1 = *i1;
960 0 : std::string* s2 = *i2;
961 :
962 0 : *i1 = s2;
963 0 : *i2 = s1;
964 :
965 0 : registrate_class_change(ChangeSuperClassesList, 0);
966 : }
967 :
968 : /******************************************************************************/
969 : /******************************* OKS ATTRIBUTES *******************************/
970 : /******************************************************************************/
971 :
972 : OksAttribute*
973 20585 : OksClass::find_direct_attribute(const std::string& _name) const noexcept
974 : {
975 20585 : if (p_attributes) {
976 41405 : for (std::list<OksAttribute*>::const_iterator i = p_attributes->begin(); i != p_attributes->end(); ++i)
977 24950 : if (_name == (*i)->get_name())
978 402 : return *i;
979 : }
980 :
981 : return 0;
982 : }
983 :
984 : OksAttribute*
985 8630 : OksClass::find_attribute(const std::string& _name) const noexcept
986 : {
987 8630 : if (p_all_attributes) {
988 29646 : for (std::list<OksAttribute*>::const_iterator i = p_all_attributes->begin(); i != p_all_attributes->end(); ++i)
989 21277 : if (_name == (*i)->get_name())
990 261 : return *i;
991 :
992 8369 : return 0;
993 : } else
994 0 : return find_direct_attribute(_name);
995 : }
996 :
997 : void
998 0 : OksClass::k_add(OksAttribute* attribute)
999 : {
1000 0 : if (!p_attributes) {
1001 0 : p_attributes = new std::list<OksAttribute*>();
1002 : }
1003 :
1004 0 : p_attributes->push_back(attribute);
1005 0 : attribute->p_class = this;
1006 0 : }
1007 :
1008 : void
1009 0 : OksClass::add(OksAttribute* attribute)
1010 : {
1011 0 : const char* fname = "OksClass::add(OksAttribute *)";
1012 :
1013 0 : if (!p_attributes) {
1014 0 : p_attributes = new std::list<OksAttribute*>();
1015 : } else {
1016 0 : if (find_direct_attribute(attribute->get_name()) != 0) {
1017 0 : std::ostringstream text;
1018 0 : text << "cannot add attribute \"" << attribute->get_name() << "\" to class \"" << p_name
1019 : << "\"\n"
1020 0 : "because the class already has attribute with this name.\n";
1021 0 : throw oks::SetOperationFailed(fname, text.str());
1022 0 : }
1023 : }
1024 :
1025 0 : lock_file("OksClass::add[OksAttribute]");
1026 :
1027 0 : p_attributes->push_back(attribute);
1028 0 : attribute->p_class = this;
1029 :
1030 0 : registrate_class_change(ChangeAttributesList, (const void*)attribute);
1031 0 : }
1032 :
1033 : void
1034 0 : OksClass::swap(const OksAttribute* a1, const OksAttribute* a2)
1035 : {
1036 0 : const char* fname = "OksClass::swap(const OksAttribute *, const OksAttribute *)";
1037 :
1038 : // if attributes are equal, return success
1039 :
1040 0 : if (a1 == a2)
1041 0 : return;
1042 :
1043 : // check that an attributes is not (null)
1044 :
1045 0 : check_and_report_empty_parameter(fname, (a1 == 0), (a2 == 0));
1046 :
1047 : // find requested attributes in the directed attributes list
1048 :
1049 0 : std::list<OksAttribute*>::iterator i1 = p_attributes->end();
1050 0 : std::list<OksAttribute*>::iterator i2 = p_attributes->end();
1051 :
1052 0 : for (std::list<OksAttribute*>::iterator i = p_attributes->begin(); i != p_attributes->end(); ++i) {
1053 0 : if ((*i) == a1)
1054 0 : i1 = i;
1055 0 : else if ((*i) == a2)
1056 0 : i2 = i;
1057 : }
1058 :
1059 : // check that the attributes were found
1060 :
1061 0 : check_and_report_found_items(fname,
1062 : "attribute",
1063 : a1->get_name(),
1064 : a2->get_name(),
1065 0 : p_name,
1066 0 : (i1 == p_attributes->end()),
1067 0 : (i2 == p_attributes->end()));
1068 :
1069 : // check that the file can be locked
1070 :
1071 0 : lock_file("OksClass::swap[OksAttribute]");
1072 :
1073 : // replace the attributes and make notification
1074 :
1075 0 : *i1 = const_cast<OksAttribute*>(a2);
1076 0 : *i2 = const_cast<OksAttribute*>(a1);
1077 :
1078 0 : registrate_class_change(ChangeAttributesList, 0);
1079 : }
1080 :
1081 : void
1082 0 : OksClass::remove(const OksAttribute* attribute)
1083 : {
1084 0 : const char* fname = "OksClass::remove(OksAttribute *)";
1085 :
1086 0 : if (!p_attributes) {
1087 0 : std::ostringstream text;
1088 0 : text << "cannot remove attribute \"" << attribute->get_name() << "\" from class \"" << p_name
1089 : << "\"\n"
1090 0 : "because the class has no attributes.\n";
1091 0 : throw oks::SetOperationFailed(fname, text.str());
1092 0 : }
1093 :
1094 0 : for (std::list<OksAttribute*>::iterator i = p_attributes->begin(); i != p_attributes->end(); ++i) {
1095 0 : if (attribute == *i) {
1096 0 : lock_file("OksClass::remove[OksAttribute]");
1097 :
1098 0 : p_attributes->erase(i);
1099 0 : delete const_cast<OksAttribute*>(attribute);
1100 :
1101 0 : if (p_attributes->empty()) {
1102 0 : delete p_attributes;
1103 0 : p_attributes = 0;
1104 : }
1105 :
1106 0 : registrate_class_change(ChangeAttributesList, 0);
1107 :
1108 0 : return;
1109 : }
1110 : }
1111 :
1112 0 : std::ostringstream text;
1113 0 : text << "cannot remove attribute \"" << attribute->get_name() << "\" from class \"" << p_name
1114 : << "\"\n"
1115 0 : "because the class has no such attribute with this name.\n";
1116 0 : throw oks::SetOperationFailed(fname, text.str());
1117 0 : }
1118 :
1119 : OksClass*
1120 0 : OksClass::source_class(const OksAttribute* a) const noexcept
1121 : {
1122 0 : return a->p_class;
1123 : }
1124 :
1125 : /******************************************************************************/
1126 : /***************************** OKS RELATIONSHIPS *****************************/
1127 : /******************************************************************************/
1128 :
1129 : OksRelationship*
1130 14742 : OksClass::find_direct_relationship(const std::string& _name) const noexcept
1131 : {
1132 14742 : if (p_relationships) {
1133 31224 : for (std::list<OksRelationship*>::const_iterator i = p_relationships->begin(); i != p_relationships->end(); ++i)
1134 19450 : if (_name == (*i)->get_name())
1135 8 : return *i;
1136 : }
1137 :
1138 : return 0;
1139 : }
1140 :
1141 : OksRelationship*
1142 8342 : OksClass::find_relationship(const std::string& _name) const noexcept
1143 : {
1144 8342 : if (p_all_relationships) {
1145 32278 : for (std::list<OksRelationship*>::const_iterator i = p_all_relationships->begin(); i != p_all_relationships->end();
1146 23936 : ++i)
1147 23936 : if (_name == (*i)->get_name())
1148 0 : return *i;
1149 :
1150 8342 : return 0;
1151 : } else
1152 0 : return find_direct_relationship(_name);
1153 : }
1154 :
1155 : void
1156 0 : OksClass::k_add(OksRelationship* relationship)
1157 : {
1158 0 : if (!p_relationships) {
1159 0 : p_relationships = new std::list<OksRelationship*>();
1160 : }
1161 :
1162 0 : p_relationships->push_back(relationship);
1163 0 : relationship->p_class = this;
1164 0 : }
1165 :
1166 : void
1167 0 : OksClass::add(OksRelationship* relationship)
1168 : {
1169 0 : const char* fname = "OksClass::add(OksRelationship *)";
1170 :
1171 0 : if (!p_relationships) {
1172 0 : p_relationships = new std::list<OksRelationship*>();
1173 : } else {
1174 0 : if (find_direct_relationship(relationship->get_name())) {
1175 0 : std::ostringstream text;
1176 0 : text << "cannot add relationship \"" << relationship->get_name() << "\" to class \"" << p_name
1177 : << "\"\n"
1178 0 : "because the class already has relationship with this name.\n";
1179 0 : throw oks::SetOperationFailed(fname, text.str());
1180 0 : }
1181 : }
1182 :
1183 0 : lock_file("OksClass::add[OksRelationship]");
1184 :
1185 0 : p_relationships->push_back(relationship);
1186 0 : relationship->p_class = this;
1187 :
1188 0 : registrate_class_change(ChangeRelationshipsList, (const void*)relationship);
1189 0 : }
1190 :
1191 : void
1192 0 : OksClass::remove(const OksRelationship* relationship, bool call_delete)
1193 : {
1194 0 : const char* fname = "OksClass::remove(OksRelationship *)";
1195 :
1196 0 : if (!p_relationships) {
1197 0 : std::ostringstream text;
1198 0 : text << "cannot remove relationship \"" << relationship->get_name() << "\" from class \"" << p_name
1199 : << "\"\n"
1200 0 : "because the class has no relationships.\n";
1201 0 : throw oks::SetOperationFailed(fname, text.str());
1202 0 : }
1203 :
1204 0 : for (std::list<OksRelationship*>::iterator i = p_relationships->begin(); i != p_relationships->end(); ++i) {
1205 0 : if (relationship == *i) {
1206 0 : lock_file("OksClass::remove[OksRelationship]");
1207 :
1208 0 : p_relationships->erase(i);
1209 0 : if (call_delete) {
1210 0 : delete const_cast<OksRelationship*>(relationship);
1211 : }
1212 :
1213 0 : if (p_relationships->empty()) {
1214 0 : delete p_relationships;
1215 0 : p_relationships = 0;
1216 : }
1217 :
1218 0 : registrate_class_change(ChangeRelationshipsList, 0);
1219 :
1220 0 : return;
1221 : }
1222 : }
1223 :
1224 0 : std::ostringstream text;
1225 0 : text << "cannot remove relationship \"" << relationship->get_name() << "\" from class \"" << p_name
1226 : << "\"\n"
1227 0 : "because the class has no such relationship with this name.\n";
1228 0 : throw oks::SetOperationFailed(fname, text.str());
1229 0 : }
1230 :
1231 : void
1232 0 : OksClass::swap(const OksRelationship* r1, const OksRelationship* r2)
1233 : {
1234 0 : const char* fname = "OksClass::swap(const OksRelationship *, const OksRelationship *)";
1235 :
1236 : // if relationships are equal, return success
1237 :
1238 0 : if (r1 == r2)
1239 0 : return;
1240 :
1241 : // check that an relationships is not (null)
1242 :
1243 0 : check_and_report_empty_parameter(fname, (r1 == 0), (r2 == 0));
1244 :
1245 : // find requested relationships in the directed relationships list
1246 :
1247 0 : std::list<OksRelationship*>::iterator i1 = p_relationships->end();
1248 0 : std::list<OksRelationship*>::iterator i2 = p_relationships->end();
1249 :
1250 0 : for (std::list<OksRelationship*>::iterator i = p_relationships->begin(); i != p_relationships->end(); ++i) {
1251 0 : if ((*i) == r1)
1252 0 : i1 = i;
1253 0 : else if ((*i) == r2)
1254 0 : i2 = i;
1255 : }
1256 :
1257 : // check that the relationships were found
1258 :
1259 0 : check_and_report_found_items(fname,
1260 : "relationship",
1261 : r1->get_name(),
1262 : r2->get_name(),
1263 0 : p_name,
1264 0 : (i1 == p_relationships->end()),
1265 0 : (i2 == p_relationships->end()));
1266 :
1267 : // check that the file can be locked
1268 :
1269 0 : lock_file("OksClass::swap[OksRelationship]");
1270 :
1271 : // replace the relationships and make notification
1272 :
1273 0 : *i1 = const_cast<OksRelationship*>(r2);
1274 0 : *i2 = const_cast<OksRelationship*>(r1);
1275 :
1276 0 : registrate_class_change(ChangeRelationshipsList, 0);
1277 : }
1278 :
1279 : OksClass*
1280 0 : OksClass::source_class(const OksRelationship* r) const noexcept
1281 : {
1282 0 : return r->p_class;
1283 : }
1284 :
1285 : /******************************************************************************/
1286 : /******************************** OKS METHODS ********************************/
1287 : /******************************************************************************/
1288 :
1289 : OksMethod*
1290 13909 : OksClass::find_direct_method(const std::string& _name) const noexcept
1291 : {
1292 13909 : if (p_methods) {
1293 23111 : for (std::list<OksMethod*>::const_iterator i = p_methods->begin(); i != p_methods->end(); ++i)
1294 14696 : if (_name == (*i)->get_name())
1295 1596 : return *i;
1296 : }
1297 :
1298 : return 0;
1299 : }
1300 :
1301 : OksMethod*
1302 9112 : OksClass::find_method(const std::string& _name) const noexcept
1303 : {
1304 9112 : if (p_all_methods) {
1305 26641 : for (std::list<OksMethod*>::const_iterator i = p_all_methods->begin(); i != p_all_methods->end(); ++i)
1306 18017 : if (_name == (*i)->get_name())
1307 488 : return *i;
1308 :
1309 8624 : return 0;
1310 : } else
1311 0 : return find_direct_method(_name);
1312 : }
1313 :
1314 : void
1315 0 : OksClass::add(OksMethod* method)
1316 : {
1317 0 : const char* fname = "OksClass::add(OksMethod *)";
1318 :
1319 0 : if (!p_methods) {
1320 0 : p_methods = new std::list<OksMethod*>();
1321 : } else {
1322 0 : if (find_direct_method(method->get_name())) {
1323 0 : std::ostringstream text;
1324 0 : text << "cannot add method \"" << method->get_name() << "\" to class \"" << p_name
1325 : << "\"\n"
1326 0 : "because the class already has method with this name.\n";
1327 0 : throw oks::SetOperationFailed(fname, text.str());
1328 0 : }
1329 : }
1330 :
1331 : // check that the file can be locked
1332 :
1333 0 : lock_file("OksClass::add[OksMethod]");
1334 :
1335 0 : p_methods->push_back(method);
1336 0 : method->p_class = this;
1337 :
1338 0 : registrate_class_change(ChangeMethodsList, (const void*)method);
1339 0 : }
1340 :
1341 : void
1342 0 : OksClass::remove(const OksMethod* method)
1343 : {
1344 0 : const char* fname = "OksClass::remove(OksMethod *)";
1345 :
1346 0 : if (!p_methods) {
1347 0 : std::ostringstream text;
1348 0 : text << "cannot remove method \"" << method->get_name() << "\" from class \"" << p_name
1349 : << "\"\n"
1350 0 : "because the class has no methods.\n";
1351 0 : throw oks::SetOperationFailed(fname, text.str());
1352 0 : }
1353 :
1354 0 : for (std::list<OksMethod*>::iterator i = p_methods->begin(); i != p_methods->end(); ++i) {
1355 0 : if (method == *i) {
1356 0 : lock_file("OksClass::remove[OksMethod]");
1357 :
1358 0 : p_methods->erase(i);
1359 0 : delete const_cast<OksMethod*>(method);
1360 :
1361 0 : if (p_methods->empty()) {
1362 0 : delete p_methods;
1363 0 : p_methods = 0;
1364 : }
1365 :
1366 0 : registrate_class_change(ChangeMethodsList, 0);
1367 :
1368 0 : return;
1369 : }
1370 : }
1371 :
1372 0 : std::ostringstream text;
1373 0 : text << "cannot remove method \"" << method->get_name() << "\" from class \"" << p_name
1374 : << "\"\n"
1375 0 : "because the class has no such method with this name.\n";
1376 0 : throw oks::SetOperationFailed(fname, text.str());
1377 0 : }
1378 :
1379 : void
1380 0 : OksClass::swap(const OksMethod* m1, const OksMethod* m2)
1381 : {
1382 0 : const char* fname = "OksClass::swap(const OksMethod *, const OksMethod *)";
1383 :
1384 : // if methods are equal, return success
1385 :
1386 0 : if (m1 == m2)
1387 0 : return;
1388 :
1389 : // check that an methods is not (null)
1390 :
1391 0 : check_and_report_empty_parameter(fname, (m1 == 0), (m2 == 0));
1392 :
1393 : // find requested methods in the directed methods list
1394 :
1395 0 : std::list<OksMethod*>::iterator i1 = p_methods->end();
1396 0 : std::list<OksMethod*>::iterator i2 = p_methods->end();
1397 :
1398 0 : for (std::list<OksMethod*>::iterator i = p_methods->begin(); i != p_methods->end(); ++i) {
1399 0 : if ((*i) == m1)
1400 0 : i1 = i;
1401 0 : else if ((*i) == m2)
1402 0 : i2 = i;
1403 : }
1404 :
1405 : // check that the methods were found
1406 :
1407 0 : check_and_report_found_items(
1408 0 : fname, "method", m1->get_name(), m2->get_name(), p_name, (i1 == p_methods->end()), (i2 == p_methods->end()));
1409 :
1410 : // check that the file can be locked
1411 :
1412 0 : lock_file("OksClass::swap[OksMethod]");
1413 :
1414 : // replace the methods and make notification
1415 :
1416 0 : *i1 = const_cast<OksMethod*>(m2);
1417 0 : *i2 = const_cast<OksMethod*>(m1);
1418 :
1419 0 : registrate_class_change(ChangeMethodsList, 0);
1420 : }
1421 :
1422 : OksClass*
1423 0 : OksClass::source_class(const OksMethod* m) const noexcept
1424 : {
1425 0 : return m->p_class;
1426 : }
1427 :
1428 : /******************************************************************************/
1429 : /******************************** OKS OBJECTS ********************************/
1430 : /******************************************************************************/
1431 :
1432 : size_t
1433 0 : OksClass::number_of_objects() const noexcept
1434 : {
1435 0 : return (!p_objects ? 0 : p_objects->size());
1436 : }
1437 :
1438 : //
1439 : // Creates list of class instances and instances of
1440 : // all subclasses
1441 : //
1442 :
1443 : std::list<OksObject*>*
1444 45 : OksClass::create_list_of_all_objects() const noexcept
1445 : {
1446 45 : std::list<OksObject*>* olist = 0;
1447 :
1448 : // add instances of class
1449 :
1450 45 : if (p_objects && !p_objects->empty()) {
1451 45 : olist = new std::list<OksObject*>();
1452 :
1453 215 : for (OksObject::Map::const_iterator i = p_objects->begin(); i != p_objects->end(); ++i)
1454 170 : olist->push_back((*i).second);
1455 : }
1456 :
1457 : // build iterator over subclasses
1458 :
1459 45 : if (p_all_sub_classes) {
1460 68 : for (FList::const_iterator j = p_all_sub_classes->begin(); j != p_all_sub_classes->end(); ++j) {
1461 23 : OksClass* sc = *j;
1462 :
1463 : // add instances of subclass
1464 :
1465 23 : if (sc->p_objects && !sc->p_objects->empty()) {
1466 2 : if (!olist)
1467 0 : olist = new std::list<OksObject*>();
1468 :
1469 4 : for (OksObject::Map::const_iterator i = sc->p_objects->begin(); i != sc->p_objects->end(); ++i)
1470 2 : olist->push_back((*i).second);
1471 : }
1472 : }
1473 : }
1474 :
1475 45 : return olist;
1476 : }
1477 :
1478 : OksObject*
1479 16738 : OksClass::get_object(const std::string& id) const noexcept
1480 : {
1481 16738 : std::shared_lock lock(p_mutex); // protect p_objects
1482 :
1483 16740 : if (p_objects) {
1484 16740 : OksObject::Map::const_iterator i = p_objects->find(&id);
1485 16738 : if (i != p_objects->end())
1486 7090 : return i->second;
1487 : }
1488 :
1489 : return nullptr;
1490 16738 : }
1491 :
1492 : /******************************************************************************/
1493 : /****************************** PRIVATE METHODS ******************************/
1494 : /******************************************************************************/
1495 :
1496 : void
1497 5471 : OksClass::add(OksObject* object)
1498 : {
1499 5471 : std::unique_lock lock(p_mutex); // protect p_objects
1500 :
1501 5470 : if (!p_objects->insert(std::pair<const std::string*, OksObject*>(&object->uid.object_id, object)).second) {
1502 0 : throw oks::ObjectOperationFailed(*this, object->uid.object_id, "add", "object already exists");
1503 : }
1504 5471 : }
1505 :
1506 : void
1507 0 : OksClass::remove(OksObject* object)
1508 : {
1509 0 : std::unique_lock lock(p_mutex); // protect p_objects
1510 :
1511 0 : if (!p_objects) {
1512 0 : throw oks::ObjectOperationFailed(*this, object->uid.object_id, "remove", "OKS Kernel is not inited");
1513 : }
1514 :
1515 0 : OksObject::Map::iterator i = p_objects->find(&object->uid.object_id);
1516 :
1517 0 : if (i != p_objects->end())
1518 0 : p_objects->erase(i);
1519 : else {
1520 0 : throw oks::ObjectOperationFailed(*this, object->uid.object_id, "remove", "object does not exist");
1521 : }
1522 0 : }
1523 :
1524 : inline void
1525 8505 : add_if_not_found(OksClass::FList& clist, OksClass* c)
1526 : {
1527 15359 : for (OksClass::FList::const_iterator i = clist.begin(); i != clist.end(); ++i) {
1528 6854 : if (*i == c)
1529 0 : return;
1530 : }
1531 8505 : clist.push_back(c);
1532 : }
1533 :
1534 : void
1535 16914 : OksClass::add_super_classes(FList* clist) const
1536 : {
1537 16914 : if (p_super_classes) {
1538 16489 : for (std::list<std::string*>::const_iterator i = p_super_classes->begin(); i != p_super_classes->end(); ++i) {
1539 8505 : if (OksClass* c = p_kernel->find_class(**i)) {
1540 8505 : c->add_super_classes(clist);
1541 8505 : add_if_not_found(*clist, c);
1542 : } else {
1543 0 : throw oks::CannotFindSuperClass(*this, **i);
1544 : }
1545 : }
1546 : }
1547 16914 : }
1548 :
1549 : void
1550 8409 : OksClass::create_super_classes()
1551 : {
1552 8409 : if (!p_all_super_classes)
1553 7502 : p_all_super_classes = new FList();
1554 : else
1555 907 : p_all_super_classes->clear();
1556 :
1557 8409 : add_super_classes(p_all_super_classes);
1558 :
1559 : #ifndef ERS_NO_DEBUG
1560 8409 : if (ers::debug_level() >= 5) {
1561 369 : std::ostringstream text;
1562 369 : text << "found " << p_all_super_classes->size() << " superclass(es) in class \'" << get_name() << "\':\n";
1563 369 : if (p_all_super_classes->size()) {
1564 537 : for (FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
1565 330 : text << " - class \'" << (*i)->get_name() << "\'\n";
1566 : }
1567 : }
1568 :
1569 369 : TLOG_DEBUG(5) << text.str();
1570 369 : }
1571 : #endif
1572 8409 : }
1573 :
1574 : void
1575 0 : OksClass::create_sub_classes()
1576 : {
1577 0 : if (!p_all_sub_classes)
1578 0 : p_all_sub_classes = new FList();
1579 : else
1580 0 : p_all_sub_classes->clear();
1581 :
1582 0 : if (!p_kernel->p_classes.empty()) {
1583 0 : for (Map::iterator i = p_kernel->p_classes.begin(); i != p_kernel->p_classes.end(); ++i) {
1584 0 : OksClass* c = i->second;
1585 :
1586 0 : if (const FList* scl = c->p_all_super_classes) {
1587 0 : for (FList::const_iterator j = scl->begin(); j != scl->end(); ++j) {
1588 0 : if (*j == this) {
1589 0 : p_all_sub_classes->push_back(c);
1590 : break;
1591 : }
1592 : }
1593 : }
1594 : }
1595 : }
1596 0 : }
1597 :
1598 : inline const char*
1599 0 : bool2value_type(bool v)
1600 : {
1601 0 : return (v ? "multi-value" : "single-value");
1602 : }
1603 :
1604 : // skip differency between enum and string
1605 :
1606 : inline bool
1607 0 : are_types_different(const OksAttribute* a1, const OksAttribute* a2)
1608 : {
1609 0 : static const std::string __enum_str__("enum");
1610 0 : static const std::string __string_str__("string");
1611 :
1612 0 : const std::string& s1 = a1->get_type();
1613 0 : const std::string& s2 = a2->get_type();
1614 :
1615 0 : return (
1616 0 : !((s1 == s2) || ((s1 == __enum_str__ && s2 == __string_str__) || (s1 == __string_str__ && s2 == __enum_str__))));
1617 : }
1618 :
1619 : void
1620 8409 : OksClass::create_attributes()
1621 : {
1622 8409 : if (p_attributes)
1623 17189 : for (const auto& x : *p_attributes)
1624 12305 : x->set_init_data();
1625 :
1626 8409 : if (!p_all_attributes)
1627 7502 : p_all_attributes = new std::list<OksAttribute*>();
1628 : else
1629 907 : p_all_attributes->clear();
1630 :
1631 8409 : if (p_all_super_classes) {
1632 16914 : for (FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
1633 8505 : OksClass* c(*i);
1634 8505 : if (c->p_attributes) {
1635 11818 : for (std::list<OksAttribute*>::iterator i2 = c->p_attributes->begin(); i2 != c->p_attributes->end(); ++i2) {
1636 8630 : OksAttribute* a(*i2);
1637 8630 : OksAttribute* a1 = find_direct_attribute(a->get_name());
1638 8630 : OksAttribute* a2 = find_attribute(a->get_name());
1639 8630 : if (a1 == 0 && a2 == 0) {
1640 7967 : p_all_attributes->push_back(a);
1641 663 : } else if (!p_kernel->p_silence) {
1642 0 : if (a1) {
1643 0 : TLOG_DEBUG(1) << "in class \'" << get_name() << "\' direct attribute \'" << a1->get_name()
1644 0 : << "\' overrides one coming from superclass \'" << a->p_class->get_name() << '\'';
1645 0 : if (are_types_different(a1, a)) {
1646 0 : Oks::warning_msg("OksClass::create_attributes()")
1647 0 : << " found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
1648 0 : << " type of attribute in superclass \'" << a->p_class->get_name() << "\' is \'" << a->get_type()
1649 : << "\'\n"
1650 0 : << " type of attribute in class \'" << get_name() << "\' is \'" << a1->get_type() << "\'\n";
1651 : }
1652 :
1653 0 : if (a1->get_is_multi_values() != a->get_is_multi_values()) {
1654 0 : Oks::warning_msg("OksClass::create_attributes()")
1655 0 : << " found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
1656 0 : << " attribute in superclass \'" << a->p_class->get_name() << "\' is "
1657 0 : << bool2value_type(a->get_is_multi_values()) << "\n"
1658 0 : << " attribute in class \'" << get_name() << "\' is \'" << bool2value_type(a1->get_is_multi_values())
1659 0 : << "\'\n";
1660 : }
1661 0 : } else if (a2) {
1662 0 : TLOG_DEBUG(1) << "in class \'" << get_name() << "\' attribute \'" << a2->get_name()
1663 0 : << "\' from superclass \'" << a2->p_class->get_name()
1664 0 : << "\' overrides one coming from superclass \'" << a->p_class->get_name() << '\'';
1665 0 : if (are_types_different(a2, a)) {
1666 0 : Oks::warning_msg("OksClass::create_attributes()")
1667 0 : << " found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
1668 0 : << " type of attribute in superclass \'" << a->p_class->get_name() << "\' is \'" << a->get_type()
1669 : << "\'\n"
1670 0 : << " type of attribute in superclass \'" << a2->p_class->get_name() << "\' is \'" << a2->get_type()
1671 0 : << "\'\n";
1672 : }
1673 :
1674 0 : if (a2->get_is_multi_values() != a->get_is_multi_values()) {
1675 0 : Oks::warning_msg("OksClass::create_attributes()")
1676 0 : << " found attribute \'" << a->get_name() << "\' types conflict in class \'" << get_name() << "\':\n"
1677 0 : << " attribute in superclass \'" << a->p_class->get_name() << "\' is "
1678 0 : << bool2value_type(a->get_is_multi_values()) << "\n"
1679 : << " attribute in superclass \'" << get_name() << "\' is \'"
1680 0 : << bool2value_type(a2->get_is_multi_values()) << "\'\n";
1681 : }
1682 : }
1683 : }
1684 : }
1685 : }
1686 : }
1687 : }
1688 :
1689 8409 : if (p_attributes) {
1690 17189 : for (std::list<OksAttribute*>::iterator i = p_attributes->begin(); i != p_attributes->end(); ++i) {
1691 12305 : p_all_attributes->push_back(*i);
1692 : }
1693 : }
1694 8409 : }
1695 :
1696 : inline const char*
1697 0 : card2string(OksRelationship::CardinalityConstraint cc)
1698 : {
1699 0 : return (cc == OksRelationship::One ? "one object" : "many objects");
1700 : }
1701 :
1702 : void
1703 8409 : OksClass::create_relationships()
1704 : {
1705 8409 : if (!p_all_relationships)
1706 7502 : p_all_relationships = new std::list<OksRelationship*>();
1707 : else
1708 907 : p_all_relationships->clear();
1709 :
1710 8409 : if (p_all_super_classes) {
1711 16914 : for (FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
1712 8505 : OksClass* c(*i);
1713 8505 : if (c->p_relationships) {
1714 11022 : for (std::list<OksRelationship*>::iterator i2 = c->p_relationships->begin(); i2 != c->p_relationships->end();
1715 8342 : ++i2) {
1716 8342 : OksRelationship* r = *i2;
1717 8342 : OksRelationship* r1 = find_direct_relationship(r->get_name());
1718 8342 : OksRelationship* r2 = find_relationship(r->get_name());
1719 :
1720 8342 : if (!r->p_class_type) {
1721 562 : r->p_class_type = p_kernel->find_class(r->p_rclass);
1722 : }
1723 :
1724 8342 : if (r1 == 0 && r2 == 0) {
1725 8334 : p_all_relationships->push_back(r);
1726 : } else {
1727 8 : if (r1) {
1728 8 : TLOG_DEBUG(1) << "in class \'" << get_name() << "\' direct relationship \'" << r1->get_name()
1729 8 : << "\' overrides one coming from superclass \'" << r->p_class->get_name() << '\'';
1730 8 : if (r1->get_high_cardinality_constraint() != r->get_high_cardinality_constraint()) {
1731 0 : Oks::warning_msg("OksClass::create_relationships()")
1732 0 : << " found relationship \'" << r->get_name() << "\' cardinality conflict in class \'" << get_name()
1733 : << "\':\n"
1734 0 : << " relationship in superclass \'" << r->p_class->get_name() << "\' allows "
1735 : << card2string(r->get_high_cardinality_constraint()) << "\n"
1736 : << " relationship in class \'" << get_name() << "\' allows "
1737 0 : << card2string(r1->get_high_cardinality_constraint()) << std::endl;
1738 : }
1739 0 : } else if (r2) {
1740 0 : TLOG_DEBUG(1) << "in class \'" << get_name() << "\' relationship \'" << r2->get_name()
1741 0 : << "\' from superclass \'" << r2->p_class->get_name()
1742 0 : << "\' overrides one coming from superclass \'" << r->p_class->get_name() << '\'';
1743 0 : if (r2->get_high_cardinality_constraint() != r->get_high_cardinality_constraint()) {
1744 0 : Oks::warning_msg("OksClass::create_relationships()")
1745 0 : << " found relationship \'" << r->get_name() << "\' cardinality conflict in class \'" << get_name()
1746 : << "\':\n"
1747 0 : << " relationship in superclass \'" << r->p_class->get_name() << "\' allows "
1748 : << card2string(r->get_high_cardinality_constraint()) << "\n"
1749 0 : << " relationship in superclass \'" << r2->p_class->get_name() << "\' allows "
1750 0 : << card2string(r2->get_high_cardinality_constraint()) << std::endl;
1751 : }
1752 : }
1753 : }
1754 : }
1755 : }
1756 : }
1757 : }
1758 :
1759 8409 : if (p_relationships) {
1760 9967 : for (std::list<OksRelationship*>::iterator i = p_relationships->begin(); i != p_relationships->end(); ++i) {
1761 6620 : OksRelationship* r = *i;
1762 :
1763 6620 : if (!r->p_class_type) {
1764 5838 : r->p_class_type = p_kernel->find_class(r->p_rclass);
1765 : }
1766 :
1767 6620 : p_all_relationships->push_back(r);
1768 : }
1769 : }
1770 8409 : }
1771 :
1772 : void
1773 8409 : OksClass::create_methods()
1774 : {
1775 8409 : if (!p_all_methods)
1776 7502 : p_all_methods = new std::list<OksMethod*>();
1777 : else
1778 907 : p_all_methods->clear();
1779 :
1780 8409 : if (p_all_super_classes) {
1781 16914 : for (FList::iterator i = p_all_super_classes->begin(); i != p_all_super_classes->end(); ++i) {
1782 8505 : std::list<OksMethod*>::iterator i2;
1783 8505 : if ((*i)->p_methods) {
1784 15730 : for (i2 = (*i)->p_methods->begin(); i2 != (*i)->p_methods->end(); ++i2) {
1785 10708 : if (find_direct_method((*i2)->get_name()) == 0 && find_method((*i2)->get_name()) == 0) {
1786 8624 : p_all_methods->push_back(*i2);
1787 : }
1788 : }
1789 : }
1790 : }
1791 : }
1792 :
1793 8409 : if (p_methods) {
1794 6762 : for (std::list<OksMethod*>::iterator i = p_methods->begin(); i != p_methods->end(); ++i) {
1795 4410 : p_all_methods->push_back(*i);
1796 : }
1797 : }
1798 8409 : }
1799 :
1800 : // Updates the values of the instances of the class and all their subclasses
1801 : // in case of a change of the attribute's type or multi values cardinality
1802 :
1803 : void
1804 0 : OksClass::registrate_attribute_change(OksAttribute* a)
1805 : {
1806 0 : OSK_PROFILING(OksProfiler::ClassRegistrateAttributeChange, p_kernel)
1807 :
1808 0 : FList::iterator i;
1809 0 : if (p_all_sub_classes)
1810 0 : i = p_all_sub_classes->begin();
1811 :
1812 : OksClass* c(this);
1813 :
1814 0 : do {
1815 0 : if (c->p_objects && !c->p_objects->empty()) {
1816 0 : for (OksObject::Map::const_iterator i2 = c->p_objects->begin(); i2 != c->p_objects->end(); ++i2) {
1817 0 : OksObject* o(i2->second);
1818 0 : OksData newData;
1819 0 : OksData* oldData = &o->data[((*(c->p_data_info))[a->p_name])->offset];
1820 :
1821 0 : try {
1822 0 : oldData->cvt(&newData, a);
1823 0 : oldData->Clear();
1824 0 : memcpy(static_cast<void*>(oldData), static_cast<void*>(&newData), sizeof(OksData));
1825 0 : newData.Clear2(); // Do not free !
1826 0 : } catch (oks::AttributeReadError& ex) {
1827 0 : std::ostringstream text;
1828 0 : text << "attribute \'" << a->get_name() << "\' change converting object " << o << ' ';
1829 0 : throw oks::CannotRegisterClass(*this, text.str(), ex);
1830 0 : }
1831 0 : }
1832 : }
1833 0 : } while (p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
1834 0 : }
1835 :
1836 : // Updates the values of the instances of the class and all their subclasses
1837 : // in case of a change of the relationship's class type or a cardinality
1838 :
1839 : void
1840 0 : OksClass::registrate_relationship_change(OksRelationship* r)
1841 : {
1842 0 : OSK_PROFILING(OksProfiler::ClassRegistrateRelationshipChange, p_kernel)
1843 :
1844 0 : FList::iterator i;
1845 0 : if (p_all_sub_classes)
1846 0 : i = p_all_sub_classes->begin();
1847 :
1848 : OksClass* c(this);
1849 :
1850 0 : do {
1851 0 : if (c->p_objects && !c->p_objects->empty()) {
1852 0 : for (OksObject::Map::const_iterator i2 = c->p_objects->begin(); i2 != c->p_objects->end(); ++i2) {
1853 0 : OksObject* o(i2->second);
1854 0 : OksData newData;
1855 0 : OksData* oldData = &o->data[((*(c->p_data_info))[r->p_name])->offset];
1856 :
1857 0 : oldData->ConvertTo(&newData, r);
1858 0 : oldData->Clear();
1859 0 : memcpy(static_cast<void*>(oldData), static_cast<void*>(&newData), sizeof(OksData));
1860 0 : newData.Clear2(); // Do not free !
1861 0 : }
1862 : }
1863 0 : } while (p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
1864 0 : }
1865 :
1866 : void
1867 8409 : OksClass::registrate_instances()
1868 : {
1869 8409 : OSK_PROFILING(OksProfiler::ClassRegistrateInstances, p_kernel)
1870 :
1871 8409 : OksDataInfo::Map* dInfo = new OksDataInfo::Map();
1872 :
1873 8409 : size_t dInfoLength = 0;
1874 8409 : bool thereAreChanges = false;
1875 :
1876 8409 : if (!p_all_attributes->empty()) {
1877 25952 : for (std::list<OksAttribute*>::iterator i = p_all_attributes->begin(); i != p_all_attributes->end(); ++i) {
1878 20272 : OksAttribute* a = *i;
1879 20272 : if (!thereAreChanges) {
1880 6020 : OksDataInfo::Map::const_iterator x = p_data_info->find(a->get_name());
1881 6550 : if (x == p_data_info->end() || x->second->attribute == nullptr || x->second->offset != dInfoLength ||
1882 530 : !(*(x->second->attribute) == *a)) {
1883 5490 : thereAreChanges = true;
1884 : }
1885 : }
1886 :
1887 20272 : (*dInfo)[a->get_name()] = new OksDataInfo(dInfoLength++, a);
1888 : }
1889 : }
1890 :
1891 8409 : if (!p_all_relationships->empty()) {
1892 18966 : for (std::list<OksRelationship*>::iterator i = p_all_relationships->begin(); i != p_all_relationships->end(); ++i) {
1893 14954 : OksRelationship* r = *i;
1894 14954 : if (!thereAreChanges) {
1895 1648 : OksDataInfo::Map::const_iterator x = p_data_info->find(r->get_name());
1896 1963 : if (x == p_data_info->end() || x->second->relationship == nullptr || x->second->offset != dInfoLength ||
1897 315 : !(*(x->second->relationship) == *r)) {
1898 1333 : thereAreChanges = true;
1899 : }
1900 : }
1901 :
1902 14954 : (*dInfo)[r->get_name()] = new OksDataInfo(dInfoLength++, r);
1903 : }
1904 : }
1905 :
1906 8409 : if (thereAreChanges == true) {
1907 6823 : if (p_objects && !p_objects->empty()) {
1908 0 : for (OksObject::Map::const_iterator i = p_objects->begin(); i != p_objects->end(); ++i) {
1909 0 : OksObject* o = (*i).second;
1910 0 : OksData* data = new OksData[dInfoLength];
1911 0 : size_t count = 0;
1912 :
1913 0 : if (!p_all_attributes->empty()) {
1914 0 : for (std::list<OksAttribute*>::iterator i2 = p_all_attributes->begin(); i2 != p_all_attributes->end(); ++i2) {
1915 0 : OksAttribute* a = *i2;
1916 :
1917 0 : OksDataInfo::Map::const_iterator x = p_data_info->find(a->get_name());
1918 :
1919 0 : if (x != p_data_info->end() && x->second->attribute) {
1920 0 : OksData* oldData(&o->data[x->second->offset]);
1921 :
1922 0 : if (*(x->second->attribute) == *a) {
1923 0 : memcpy(static_cast<void*>(&data[count++]), static_cast<void*>(oldData), sizeof(OksData));
1924 0 : oldData->type = OksData::unknown_type;
1925 : } else {
1926 0 : try {
1927 0 : oldData->cvt(&data[count++], a);
1928 0 : } catch (oks::AttributeReadError& ex) {
1929 0 : throw oks::AttributeConversionFailed(*a, o, ex);
1930 0 : }
1931 : }
1932 : }
1933 : }
1934 : }
1935 :
1936 0 : if (!p_all_relationships->empty()) {
1937 0 : for (std::list<OksRelationship*>::iterator i2 = p_all_relationships->begin();
1938 0 : i2 != p_all_relationships->end();
1939 0 : ++i2) {
1940 0 : OksRelationship* r = *i2;
1941 :
1942 0 : OksDataInfo::Map::const_iterator x = p_data_info->find(r->get_name());
1943 :
1944 0 : if (x != p_data_info->end() && x->second->relationship) {
1945 0 : OksData* oldData = &o->data[x->second->offset];
1946 :
1947 0 : if (*(x->second->relationship) == *r) {
1948 0 : memcpy(static_cast<void*>(&data[count++]), static_cast<void*>(oldData), sizeof(OksData));
1949 0 : oldData->type = OksData::unknown_type;
1950 : } else
1951 0 : oldData->ConvertTo(&data[count++], r);
1952 : }
1953 : }
1954 : }
1955 :
1956 0 : int n = p_instance_size;
1957 0 : while (n--)
1958 0 : o->data[n].Clear();
1959 0 : delete o->data;
1960 :
1961 0 : o->data = data;
1962 : }
1963 : }
1964 : }
1965 :
1966 8409 : if (!p_data_info->empty()) {
1967 1085 : for (OksDataInfo::Map::iterator i = p_data_info->begin(); i != p_data_info->end(); ++i) {
1968 845 : delete i->second;
1969 : }
1970 : }
1971 :
1972 8409 : delete p_data_info;
1973 :
1974 8409 : p_data_info = dInfo;
1975 8409 : p_instance_size = dInfoLength;
1976 8409 : }
1977 :
1978 : void
1979 14039 : OksClass::registrate_class(bool skip_registered)
1980 : {
1981 14039 : OSK_PROFILING(OksProfiler::ClassRegistrateClass, p_kernel)
1982 :
1983 14039 : {
1984 14039 : if (!p_data_info)
1985 7502 : p_data_info = new OksDataInfo::Map();
1986 14039 : if (!p_objects) {
1987 9109 : p_objects = new OksObject::Map((p_abstract == false) ? 1024 : 1);
1988 : }
1989 : }
1990 :
1991 14039 : if (!p_data_info->empty() && skip_registered) {
1992 5630 : TLOG_DEBUG(4) << "skip already registered " << get_name();
1993 5630 : return;
1994 : }
1995 :
1996 8409 : try {
1997 8409 : create_super_classes();
1998 8409 : create_attributes();
1999 8409 : create_relationships();
2000 8409 : create_methods();
2001 :
2002 8409 : registrate_instances();
2003 0 : } catch (oks::exception& ex) {
2004 0 : throw oks::CannotRegisterClass(*this, "", ex);
2005 0 : }
2006 14039 : }
2007 :
2008 : void
2009 0 : OksClass::registrate_class_change(ChangeType changeType, const void* parameter, bool update_file)
2010 : {
2011 0 : if (!p_kernel)
2012 0 : return;
2013 :
2014 0 : OSK_PROFILING(OksProfiler::ClassRegistrateClassChange, p_kernel)
2015 :
2016 0 : try {
2017 0 : if (update_file)
2018 0 : p_file->set_updated();
2019 :
2020 0 : FList superclasses;
2021 :
2022 0 : if (changeType == ChangeSuperClassesList && !p_all_super_classes->empty())
2023 0 : for (FList::iterator i2 = p_all_super_classes->begin(); i2 != p_all_super_classes->end(); ++i2) {
2024 0 : superclasses.push_back(*i2);
2025 : }
2026 :
2027 0 : FList::iterator i;
2028 0 : if (p_all_sub_classes)
2029 0 : i = p_all_sub_classes->begin();
2030 :
2031 : OksClass* c = this;
2032 :
2033 0 : do {
2034 0 : switch (changeType) {
2035 0 : case ChangeSuperClassesList:
2036 0 : c->create_super_classes();
2037 0 : c->create_attributes();
2038 0 : c->create_relationships();
2039 0 : c->create_methods();
2040 : break;
2041 :
2042 0 : case ChangeAttributesList:
2043 0 : c->create_attributes();
2044 : break;
2045 :
2046 0 : case ChangeRelationshipsList:
2047 0 : c->create_relationships();
2048 : break;
2049 :
2050 0 : case ChangeMethodsList:
2051 0 : c->create_methods();
2052 : break;
2053 :
2054 0 : default:
2055 0 : continue;
2056 : }
2057 :
2058 0 : if (changeType != ChangeMethodsList)
2059 0 : c->registrate_instances();
2060 0 : } while (p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
2061 :
2062 0 : if (changeType == ChangeSuperClassesList) {
2063 0 : if (!p_all_super_classes->empty())
2064 0 : for (FList::iterator i2 = p_all_super_classes->begin(); i2 != p_all_super_classes->end(); ++i2)
2065 0 : if (find(superclasses.begin(), superclasses.end(), *i2) == superclasses.end()) {
2066 0 : superclasses.push_back(*i2);
2067 : }
2068 :
2069 0 : for (FList::const_iterator i2 = superclasses.begin(); i2 != superclasses.end(); ++i2) {
2070 0 : c = *i2;
2071 :
2072 0 : if (p_kernel->is_dangling(c) || c->p_to_be_deleted)
2073 0 : continue;
2074 :
2075 0 : c->create_sub_classes();
2076 :
2077 0 : if (OksClass::change_notify_fn)
2078 0 : (*OksClass::change_notify_fn)(c, ChangeSubClassesList, 0);
2079 : }
2080 0 : superclasses.clear();
2081 : }
2082 :
2083 0 : if (OksClass::change_notify_fn) {
2084 0 : if (p_all_sub_classes)
2085 0 : i = p_all_sub_classes->begin();
2086 : c = this;
2087 :
2088 0 : do
2089 0 : (*OksClass::change_notify_fn)(c, changeType, parameter);
2090 0 : while (p_all_sub_classes && i != p_all_sub_classes->end() && (c = *(i++)));
2091 : }
2092 0 : } catch (oks::exception& ex) {
2093 0 : throw oks::CannotRegisterClass(*this, "change ", ex);
2094 0 : }
2095 0 : }
2096 :
2097 : bool
2098 14039 : OksClass::check_relationships(std::ostringstream& out, bool print_file_name) const noexcept
2099 : {
2100 14039 : bool found_problems = false;
2101 :
2102 14039 : if (const std::list<OksRelationship*>* rels = direct_relationships()) {
2103 18283 : for (auto& x : *rels) {
2104 12100 : if (x->get_class_type() == nullptr) {
2105 0 : if (found_problems == false) {
2106 0 : found_problems = true;
2107 0 : out << " * there are problems with class \"" << get_name() << '\"';
2108 0 : if (print_file_name) {
2109 0 : out << " from file \"" << get_file()->get_full_file_name() << '\"';
2110 : }
2111 0 : out << ":\n";
2112 : }
2113 :
2114 0 : out << " - class type \"" << x->get_type() << "\" of relationship \"" << x->get_name()
2115 0 : << "\" is not loaded\n";
2116 : }
2117 : }
2118 : }
2119 :
2120 14039 : return found_problems;
2121 : }
2122 :
2123 : } // namespace oks
2124 : } // namespace dunedaq
|