LCOV - code coverage report
Current view: top level - oks/src - class.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 27.4 % 1193 327
Test Date: 2026-10-11 15:05:20 Functions: 36.9 % 84 31

            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
        

Generated by: LCOV version 2.0-1