LCOV - code coverage report
Current view: top level - oks/src - method.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 17.6 % 244 43
Test Date: 2025-12-21 13:07:08 Functions: 15.0 % 20 3

            Line data    Source code
       1              : #define _OksBuildDll_
       2              : 
       3              : #include "oks/method.hpp"
       4              : #include "oks/xml.hpp"
       5              : #include "oks/class.hpp"
       6              : #include "oks/cstring.hpp"
       7              : 
       8              : #include <stdexcept>
       9              : #include <sstream>
      10              : 
      11              : namespace dunedaq {
      12              : namespace oks {
      13              : 
      14              : const char OksMethodImplementation::method_impl_xml_tag[] = "method-implementation";
      15              : const char OksMethodImplementation::language_xml_attr[]   = "language";
      16              : const char OksMethodImplementation::prototype_xml_attr[]  = "prototype";
      17              : const char OksMethodImplementation::body_xml_attr[]       = "body";
      18              : 
      19              : const char OksMethod::method_xml_tag[]                    = "method";
      20              : const char OksMethod::name_xml_attr[]                     = "name";
      21              : const char OksMethod::description_xml_attr[]              = "description";
      22              : 
      23              : 
      24            0 : OksMethodImplementation::OksMethodImplementation(const std::string& language, const std::string& prototype, const std::string& body, OksMethod * p) :
      25            0 :  p_language  (language),
      26            0 :  p_prototype (prototype),
      27            0 :  p_body      (body),
      28            0 :  p_method    (p)
      29              : {
      30            0 :   oks::validate_not_empty(p_language, "method implementation language");
      31            0 :   oks::validate_not_empty(p_prototype, "method implementation prototype");
      32            0 : }
      33              : 
      34              : bool
      35            0 : OksMethodImplementation::operator==(const class OksMethodImplementation &i) const
      36              : {
      37            0 :   return (
      38            0 :     ( this == &i ) ||
      39            0 :     ( p_language == i.p_language && p_prototype == i.p_prototype && p_body == i.p_body )
      40            0 :   );
      41              : }
      42              : 
      43              : std::ostream&
      44            0 : operator<<(std::ostream& s, const OksMethodImplementation& i)
      45              : {
      46            0 :   s << "  Method implementation:\n"
      47            0 :        "    language:  \"" << i.get_language()  << "\"\n"
      48            0 :        "    prototype: \"" << i.get_prototype() << "\"\n"
      49            0 :        "    body:      \"" << i.get_body()      << "\"\n";
      50              : 
      51            0 :   return s;
      52              : }
      53              : 
      54              : 
      55              : void
      56            0 : OksMethodImplementation::save(OksXmlOutputStream& s) const
      57              : {
      58            0 :   s.put("   ");
      59              : 
      60            0 :   s.put_start_tag(method_impl_xml_tag, sizeof(method_impl_xml_tag)-1);
      61              : 
      62            0 :   s.put_attribute( language_xml_attr,  sizeof(language_xml_attr)-1,  get_language().c_str()  );
      63            0 :   s.put_attribute( prototype_xml_attr, sizeof(prototype_xml_attr)-1, get_prototype().c_str() );
      64            0 :   s.put_attribute( body_xml_attr,      sizeof(body_xml_attr)-1,      get_body().c_str()      );
      65              : 
      66            0 :   s.put_end_tag();
      67            0 : }
      68              : 
      69              : 
      70         2639 : OksMethodImplementation::OksMethodImplementation(OksXmlInputStream& s, OksMethod * parent) :
      71         2639 :  p_method (parent)
      72              : {
      73        10556 :   try {
      74        18473 :     while(true) {
      75        10556 :       OksXmlAttribute attr(s);
      76              : 
      77              :         // check for close of tag
      78              : 
      79        10556 :       if(oks::cmp_str1(attr.name(), "/")) { break; }
      80              : 
      81              :         // check for known oks-method-implementation' attributes
      82              : 
      83         7917 :       else if( oks::cmp_str8(attr.name(), language_xml_attr)  ) p_language.assign(attr.value(), attr.value_len());
      84         5278 :       else if( oks::cmp_str9(attr.name(), prototype_xml_attr) ) p_prototype.assign(attr.value(), attr.value_len());
      85         2639 :       else if( oks::cmp_str4(attr.name(), body_xml_attr)      ) p_body.assign(attr.value(), attr.value_len());
      86              :       else {
      87            0 :         s.throw_unexpected_attribute(attr.name());
      88              :       }
      89         7917 :     }
      90              :   }
      91            0 :   catch(oks::exception & e) {
      92            0 :     throw oks::FailedRead("xml method implementation", e);
      93            0 :   }
      94            0 :   catch (std::exception & e) {
      95            0 :     throw oks::FailedRead("xml method implementation", e.what());
      96            0 :   }
      97              : 
      98         2639 :   try {
      99         2639 :     oks::validate_not_empty(p_language, "method implementation language");
     100         2639 :     oks::validate_not_empty(p_prototype, "method implementation prototype");
     101              :   }
     102            0 :   catch(std::exception& ex) {
     103            0 :     throw oks::FailedRead("oks method implementation", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
     104            0 :   }
     105         2639 : }
     106              : 
     107              : 
     108            0 : OksMethod::OksMethod(const std::string& nm, OksClass * p) :
     109            0 :   p_class               (p),
     110            0 :   p_name                (nm),
     111            0 :   p_implementations     (nullptr)
     112              : {
     113            0 :   try {
     114            0 :     oks::validate_not_empty(p_name, "method name");
     115              :   }
     116            0 :   catch(std::exception& ex) {
     117            0 :     Oks::error_msg("OksMethod::OksMethod()") << ex.what() << std::endl;
     118            0 :   }
     119            0 : }
     120              : 
     121            0 : OksMethod::OksMethod(const std::string& nm, const std::string& desc, OksClass * p) :
     122            0 :   p_class               (p),
     123            0 :   p_name                (nm),
     124            0 :   p_description         (desc),
     125            0 :   p_implementations     (nullptr)
     126              : {
     127            0 :   oks::validate_not_empty(p_name, "method name");
     128            0 : }
     129              : 
     130         2396 : OksMethod::~OksMethod()
     131              : {
     132         2396 :   if(p_implementations) {
     133         5035 :     while(!p_implementations->empty()) {
     134         2639 :       OksMethodImplementation * i = p_implementations->front();
     135         2639 :       p_implementations->pop_front();
     136         2639 :       delete i;
     137              :     }
     138              : 
     139         2396 :     delete p_implementations;
     140              :   }
     141         2396 : }
     142              : 
     143              : 
     144              : bool
     145            0 : OksMethod::operator==(const class OksMethod &m) const
     146              : {
     147              :     // check if compare with self
     148              : 
     149            0 :   if(this == &m) return true;
     150              : 
     151              : 
     152              :     // check if attributes are different
     153              : 
     154            0 :   if(p_name != m.p_name || p_description != m.p_description) return false;
     155              : 
     156              : 
     157              :     // check if methods have no implementations
     158              : 
     159            0 :   if(p_implementations == 0 && m.p_implementations == 0) return true;
     160              : 
     161              : 
     162              :     // check if only one method has implementation
     163              : 
     164            0 :   if(p_implementations == 0 || m.p_implementations == 0) return false;
     165              : 
     166              : 
     167              :     // check if numbers of implementations are different
     168              : 
     169            0 :   if(p_implementations->size() != m.p_implementations->size()) return false;
     170              : 
     171              : 
     172              :     // check implementations
     173              : 
     174            0 :   std::list<OksMethodImplementation *>::const_iterator i1 = p_implementations->begin();
     175            0 :   std::list<OksMethodImplementation *>::const_iterator i2 = m.p_implementations->begin();
     176              :   
     177            0 :   for(;i1 != p_implementations->end(); ++i1, ++i2) {
     178            0 :     if( !(*(*i1) == *(*i2)) ) return false;
     179              :   }
     180              :   
     181              :   return true;
     182              : }
     183              : 
     184              : std::ostream&
     185            0 : operator<<(std::ostream& s, const OksMethod& m)
     186              : {
     187            0 :   s << "Method name: \"" << m.p_name << "\"\n"
     188            0 :        " description: \"" << m.p_description << "\"\n";
     189              :         
     190            0 :   if(m.p_implementations) {
     191            0 :     s << " implementations:\n";
     192              : 
     193            0 :     for(std::list<OksMethodImplementation *>::const_iterator i = m.p_implementations->begin(); i != m.p_implementations->end(); ++i)
     194            0 :       s << *(*i);
     195              :   }
     196              :   else
     197            0 :     s << " there are no implementation(s)\n";
     198              : 
     199            0 :   return s;
     200              : }
     201              : 
     202              : 
     203              : void
     204            0 : OksMethod::save(OksXmlOutputStream& s) const
     205              : {
     206            0 :   s.put_raw(' ');
     207            0 :   s.put_raw(' ');
     208              : 
     209            0 :   s.put_start_tag(method_xml_tag, sizeof(method_xml_tag)-1);
     210              :   
     211            0 :   s.put_attribute(name_xml_attr, sizeof(name_xml_attr)-1, p_name.c_str());
     212            0 :   s.put_attribute(description_xml_attr, sizeof(description_xml_attr)-1, p_description.c_str());
     213              : 
     214            0 :   s.put_raw('>');
     215            0 :   s.put_raw('\n');
     216              : 
     217            0 :   if(p_implementations) {
     218            0 :     for(std::list<OksMethodImplementation *>::iterator i = p_implementations->begin(); i != p_implementations->end(); ++i)
     219            0 :       (*i)->save(s);
     220              :   }
     221              : 
     222            0 :   s.put_raw(' ');
     223            0 :   s.put_raw(' ');
     224              : 
     225            0 :   s.put_last_tag(method_xml_tag, sizeof(method_xml_tag)-1);
     226            0 : }
     227              : 
     228              : 
     229         2396 : OksMethod::OksMethod(OksXmlInputStream& s, OksClass * parent) :
     230         2396 :  p_class           (parent),
     231         2396 :  p_implementations (0)
     232              : {
     233         7188 :   try {
     234        11980 :     while(true) {
     235         7188 :       OksXmlAttribute attr(s);
     236              : 
     237              :         // check for close of tag
     238              : 
     239         7188 :       if(oks::cmp_str1(attr.name(), ">")) { break; }
     240              : 
     241              :         // check for known oks-relationship' attributes
     242              : 
     243         4792 :       else if(oks::cmp_str4(attr.name(), name_xml_attr)) p_name.assign(attr.value(), attr.value_len());
     244         2396 :       else if(oks::cmp_str11(attr.name(), description_xml_attr)) p_description.assign(attr.value(), attr.value_len());
     245              :       else {
     246            0 :         s.throw_unexpected_attribute(attr.name());
     247              :       }
     248         4792 :     }
     249              :   }
     250            0 :   catch(oks::exception & e) {
     251            0 :     throw oks::FailedRead("xml method", e);
     252            0 :   }
     253            0 :   catch (std::exception & e) {
     254            0 :     throw oks::FailedRead("xml method", e.what());
     255            0 :   }
     256              : 
     257              :     // check validity of read values
     258              : 
     259         2396 :   try {
     260         2396 :     oks::validate_not_empty(p_name, "method name");
     261              :   }
     262            0 :   catch(std::exception& ex) {
     263            0 :     throw oks::FailedRead("oks method", oks::BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
     264            0 :   }
     265              : 
     266              : 
     267              :     // read 'body' and 'method-actions'
     268              : 
     269         5035 :   {
     270         7674 :     while(true) try {
     271         5035 :       const char * tag_start = s.get_tag_start();
     272              : 
     273         5035 :       if(oks::cmp_str7(tag_start, "/method")) { break; }
     274              : 
     275         2639 :       else if(!strcmp(tag_start, "method-implementation")) {
     276         2639 :         if(!p_implementations) p_implementations = new std::list<OksMethodImplementation *>();
     277         2639 :         p_implementations->push_back(new OksMethodImplementation(s, this));
     278              :       }
     279              : 
     280              :       else {
     281            0 :         std::ostringstream text;
     282            0 :         text << "Unexpected tag \'" << tag_start << "\' inside method \'" << p_name << "\'\n";
     283            0 :         throw std::runtime_error( text.str().c_str() );
     284            0 :       }
     285              : 
     286              :     }
     287            0 :     catch (oks::exception & e) {
     288            0 :       throw oks::FailedRead("method tag", e);
     289            0 :     }
     290            0 :     catch (std::exception & e) {
     291            0 :       throw oks::FailedRead("method tag", e.what());
     292         2639 :     }
     293              :   }
     294         2396 : }
     295              : 
     296              : 
     297              : void
     298            0 : OksMethod::set_name(const std::string& new_name)
     299              : {
     300              :     // ignore when name is the same
     301              : 
     302            0 :   if(p_name == new_name) return;
     303              : 
     304              : 
     305              :     // additional checks are required,
     306              :     // if the method already belongs to some class
     307              : 
     308            0 :   if(p_class) {
     309              : 
     310              :       // check allowed length for attribute name
     311              : 
     312            0 :     try {
     313            0 :       oks::validate_not_empty(new_name, "name");
     314              :     }
     315            0 :     catch(std::exception& ex) {
     316            0 :       throw oks::SetOperationFailed("OksMethod::set_name", ex.what());
     317            0 :     }
     318              : 
     319              : 
     320              :       // having a direct method with the same name is an error
     321              : 
     322            0 :     if(p_class->find_direct_method(new_name) != 0) {
     323            0 :       std::ostringstream text;
     324            0 :       text << "Class \"" << p_class->get_name() << "\" already has direct method \"" << new_name << '\"';
     325            0 :       throw oks::SetOperationFailed("OksMethod::set_name", text.str());
     326            0 :     }
     327              : 
     328              : 
     329              :       // check that it is possible to lock the file
     330              : 
     331            0 :     p_class->lock_file("OksMethod::set_name");
     332              : 
     333              : 
     334              :       // probably a non-direct method already exists
     335              : 
     336            0 :     OksMethod * m = p_class->find_method(new_name);
     337              : 
     338              : 
     339              :       // change the name
     340              : 
     341            0 :     p_name = new_name;
     342              : 
     343              : 
     344              :       // registrate the change
     345              : 
     346            0 :     p_class->registrate_class_change(OksClass::ChangeMethodsList, (const void *)m);
     347              :   }
     348              :   else {
     349            0 :     p_name = new_name;
     350              :   }
     351              : }
     352              : 
     353              : OksMethodImplementation *
     354            0 : OksMethod::find_implementation(const std::string& language) const
     355              : {
     356            0 :   if(p_implementations) {
     357            0 :     for(std::list<OksMethodImplementation *>::iterator i = p_implementations->begin(); i != p_implementations->end(); ++i)
     358            0 :       if(language == (*i)->get_language()) return *i;
     359              :   }
     360              : 
     361              :   return 0;
     362              : }
     363              : 
     364              : void
     365            0 : OksMethod::add_implementation(const std::string& language, const std::string& prototype, const std::string& body)
     366              : {
     367            0 :   if(find_implementation(language)) {
     368            0 :     std::ostringstream text;
     369            0 :     text << "Cannot add implementation on language \"" << language << "\" since it already exists.";
     370            0 :     throw oks::SetOperationFailed("OksMethod::add_implementation", text.str());
     371            0 :   }
     372              : 
     373            0 :   if(p_class) p_class->lock_file("OksMethod::add_implementation");
     374              : 
     375            0 :   if(!p_implementations) {
     376            0 :     p_implementations = new std::list<OksMethodImplementation *>();
     377              :   }
     378              : 
     379            0 :   OksMethodImplementation * i = new OksMethodImplementation(language, prototype, body);
     380              : 
     381            0 :   p_implementations->push_back(i);
     382            0 :   i->p_method = this;
     383              : 
     384            0 :   if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
     385            0 : }
     386              : 
     387              : void
     388            0 : OksMethod::remove_implementation(const std::string& language)
     389              : {
     390            0 :   OksMethodImplementation * i = find_implementation(language);
     391              : 
     392            0 :   if(i == 0) {
     393            0 :     std::ostringstream text;
     394            0 :     text << "Cannot remove implementation on language \"" << language << "\" since it does not exist.";
     395            0 :     throw oks::SetOperationFailed("OksMethod::remove_implementation", text.str());
     396            0 :   }
     397              : 
     398            0 :   if(p_class) p_class->lock_file("OksMethod::remove_implementation");
     399              : 
     400            0 :   p_implementations->remove(i);
     401              : 
     402            0 :   if(p_implementations->empty()) {
     403            0 :     delete p_implementations;
     404            0 :     p_implementations = 0;
     405              :   }
     406              : 
     407            0 :   if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
     408            0 : }
     409              : 
     410              : 
     411              : void
     412            0 : OksMethod::set_description(const std::string& desc)
     413              : {
     414            0 :   if(p_description != desc) {
     415            0 :     if(p_class) p_class->lock_file("OksMethod::set_description");
     416              : 
     417            0 :     p_description = desc;
     418              : 
     419            0 :     if(p_class) p_class->registrate_class_change(OksClass::ChangeMethodDescription, (const void *)this);
     420              :   }
     421            0 : }
     422              : 
     423              : void
     424            0 : OksMethodImplementation::set_language(const std::string& s)
     425              : {
     426            0 :   if(p_language != s) {
     427            0 :     if(p_method) {
     428            0 :       if(p_method->find_implementation(s) != 0) {
     429            0 :         std::ostringstream text;
     430            0 :         text << "cannot rename \"" << p_method->p_name << "\" method implementation to language \"" << s << "\" "
     431            0 :              "since the method already has implementation with such language.";
     432            0 :         throw oks::SetOperationFailed("OksMethodImplementation::set_language", text.str());
     433            0 :       }
     434              : 
     435            0 :       try {
     436            0 :         oks::validate_not_empty(s, "language");
     437              :       }
     438            0 :       catch(std::exception& ex) {
     439            0 :         throw oks::SetOperationFailed("OksMethodImplementation::set_language", ex.what());
     440            0 :       }
     441              : 
     442            0 :       if(p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_language");
     443              :     }
     444              : 
     445            0 :     p_language = s;
     446              : 
     447            0 :     if(p_method && p_method->p_class) {
     448            0 :       p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
     449              :     }
     450              :   }
     451            0 : }
     452              : 
     453              : void
     454            0 : OksMethodImplementation::set_prototype(const std::string& s)
     455              : {
     456            0 :   if(p_prototype != s) {
     457            0 :     try {
     458            0 :       oks::validate_not_empty(s, "prototype");
     459              :     }
     460            0 :     catch(std::exception& ex) {
     461            0 :       throw oks::SetOperationFailed("OksMethodImplementation::set_prototype", ex.what());
     462            0 :     }
     463              : 
     464            0 :     if(p_method && p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_prototype");
     465              : 
     466            0 :     p_prototype = s;
     467              : 
     468            0 :     if(p_method && p_method->p_class) {
     469            0 :       p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
     470              :     }
     471              :   }
     472            0 : }
     473              : 
     474              : void
     475            0 : OksMethodImplementation::set_body(const std::string& s)
     476              : {
     477            0 :   if(p_body != s) {
     478            0 :     if(p_method && p_method->p_class) p_method->p_class->lock_file("OksMethodImplementation::set_body");
     479              : 
     480            0 :     p_body = s;
     481              : 
     482            0 :     if(p_method && p_method->p_class) {
     483            0 :       p_method->p_class->registrate_class_change(OksClass::ChangeMethodImplementation, (const void *)this);
     484              :     }
     485              :   }
     486            0 : }
     487              : 
     488              : } // namespace oks
     489              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1