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

Generated by: LCOV version 2.0-1