LCOV - code coverage report
Current view: top level - oks/src - attribute.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 34.2 % 468 160
Test Date: 2026-07-12 15:23:06 Functions: 37.8 % 37 14

            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/attribute.hpp"
       9              : #include "oks/xml.hpp"
      10              : #include "oks/class.hpp"
      11              : #include "oks/kernel.hpp"
      12              : #include "oks/object.hpp"
      13              : #include "oks/cstring.hpp"
      14              : 
      15              : #include "logging/Logging.hpp"
      16              : 
      17              : #include <sstream>
      18              : #include <stdexcept>
      19              : 
      20              : #include <string.h>
      21              : 
      22              : namespace dunedaq {
      23              : namespace oks {
      24              : 
      25              : 
      26              : const char * OksAttribute::bool_type    = "bool";
      27              : const char * OksAttribute::s8_int_type  = "s8";
      28              : const char * OksAttribute::u8_int_type  = "u8";
      29              : const char * OksAttribute::s16_int_type = "s16";
      30              : const char * OksAttribute::u16_int_type = "u16";
      31              : const char * OksAttribute::s32_int_type = "s32";
      32              : const char * OksAttribute::u32_int_type = "u32";
      33              : const char * OksAttribute::s64_int_type = "s64";
      34              : const char * OksAttribute::u64_int_type = "u64";
      35              : const char * OksAttribute::float_type   = "float";
      36              : const char * OksAttribute::double_type  = "double";
      37              : const char * OksAttribute::date_type    = "date";
      38              : const char * OksAttribute::time_type    = "time";
      39              : const char * OksAttribute::string_type  = "string";
      40              : const char * OksAttribute::uid_type     = "uid";
      41              : const char * OksAttribute::enum_type    = "enum";
      42              : const char * OksAttribute::class_type   = "class";
      43              : 
      44              : const char OksAttribute::attribute_xml_tag[]       = "attribute";
      45              : const char OksAttribute::name_xml_attr[]           = "name";
      46              : const char OksAttribute::description_xml_attr[]    = "description";
      47              : const char OksAttribute::type_xml_attr[]           = "type";
      48              : const char OksAttribute::range_xml_attr[]          = "range";
      49              : const char OksAttribute::format_xml_attr[]         = "format";
      50              : const char OksAttribute::is_multi_value_xml_attr[] = "is-multi-value";
      51              : const char OksAttribute::init_value_xml_attr[]     = "init-value";
      52              : const char OksAttribute::is_not_null_xml_attr[]    = "is-not-null";
      53              : const char OksAttribute::ordered_xml_attr[]        = "ordered";
      54              : 
      55              : 
      56              : OksAttribute::Format
      57           45 : OksAttribute::str2format(const char * s) noexcept
      58              : {
      59           45 :   return (
      60           45 :     cmp_str3(s, "dec") ? Dec :
      61           45 :     cmp_str3(s, "hex") ? Hex :
      62              :     Oct
      63           45 :   );
      64              : }
      65              : 
      66              : const char *
      67            0 : OksAttribute::format2str(Format f) noexcept
      68              : {
      69            0 :   return (
      70              :     f == Dec ? "dec" :
      71              :     f == Hex ? "hex" :
      72              :     "oct"
      73            0 :   );
      74              : }
      75              : 
      76              : bool
      77        17327 : OksAttribute::is_integer() const noexcept
      78              : {
      79        17327 :   return (p_data_type >= OksData::s8_int_type && p_data_type <= OksData::u64_int_type);
      80              : }
      81              : 
      82              : bool
      83            0 : OksAttribute::is_number() const noexcept
      84              : {
      85            0 :   return (p_data_type >= OksData::s8_int_type && p_data_type <= OksData::bool_type);
      86              : }
      87              : 
      88              : void
      89        10227 : OksAttribute::init_enum()
      90              : {
      91        10227 :   if (p_data_type == OksData::enum_type)
      92              :     {
      93          794 :       if (p_enumerators)
      94              :         {
      95            0 :           p_enumerators->clear();
      96              :         }
      97              :       else
      98              :         {
      99          794 :           p_enumerators = new std::vector<std::string>();
     100              :         }
     101              : 
     102          794 :       Oks::Tokenizer t(p_range, ",");
     103          794 :       std::string token;
     104              : 
     105         4388 :       while (t.next(token))
     106              :         {
     107         2800 :           p_enumerators->push_back(token);
     108              :         }
     109              : 
     110          794 :       if (p_enumerators->empty())
     111              :         {
     112            0 :           std::ostringstream text;
     113            0 :           text << "range of enumeration attribute \"" << p_name << "\" is empty";
     114            0 :           throw std::runtime_error(text.str().c_str());
     115            0 :         }
     116          794 :     }
     117        10227 : }
     118              : 
     119              : void
     120        10227 : OksAttribute::init_range()
     121              : {
     122        10227 :   clean_range();
     123              : 
     124        10227 :   if (p_range.empty() == false)
     125              :     {
     126          974 :       p_range_obj = new OksRange(p_range, this);
     127          974 :       if (p_range_obj->is_empty())
     128              :         {
     129            0 :           clean_range();
     130              :         }
     131              :     }
     132        10227 : }
     133              : 
     134              : 
     135              : int
     136            0 : OksAttribute::get_enum_index(const char * s, size_t length) const noexcept
     137              : {
     138            0 :   if (p_data_type == OksData::enum_type)
     139              :     {
     140            0 :       for (int i = 0; i < (int) p_enumerators->size(); ++i)
     141              :         {
     142            0 :           const std::string * x = &((*p_enumerators)[i]);
     143            0 :           if (x->length() == length)
     144              :             {
     145            0 :               if (memcmp(s, x->data(), length) == 0)
     146              :                 {
     147              :                   return i;
     148              :                 }
     149              :             }
     150              :         }
     151              : 
     152              :       return (-1);
     153              :     }
     154              : 
     155              :   return (-2);
     156              : }
     157              : 
     158              : const std::string *
     159         5058 : OksAttribute::get_enum_value(const char * s, size_t length) const
     160              : {
     161         5058 :   if (p_data_type == OksData::enum_type)
     162              :     {
     163        14853 :       for (unsigned int i = 0; i < p_enumerators->size(); ++i)
     164              :         {
     165        14853 :           const std::string * x = &((*p_enumerators)[i]);
     166        14853 :           if (x->length() == length)
     167              :             {
     168         6646 :               if (memcmp(s, x->data(), length) == 0)
     169              :                 {
     170         5058 :                   return x;
     171              :                 }
     172              :             }
     173              :         }
     174              : 
     175            0 :       std::ostringstream text;
     176            0 :       text << "value \'" << s << "\' is out of range \'" << get_range() << '\'';
     177            0 :       throw std::runtime_error(text.str().c_str());
     178            0 :     }
     179              : 
     180            0 :   throw std::runtime_error("attribute is not enumeration");
     181              : }
     182              : 
     183              : uint16_t
     184            0 : OksAttribute::get_enum_value(const OksData& d) const noexcept
     185              : {
     186            0 :   const std::string * p_enumerators_first(&((*p_enumerators)[0]));
     187            0 :   return (d.data.ENUMERATION - p_enumerators_first);
     188              : }
     189              : 
     190              : void
     191        10227 : validate_init2range(const OksAttribute * a)
     192              : {
     193        10227 :   if (!a->get_range().empty() && a->get_data_type() != OksData::class_type)
     194              :     {
     195          974 :       try
     196              :         {
     197          974 :           OksData d;
     198          974 :           d.set_init_value(a, false);
     199          974 :           d.check_range(a);
     200          974 :         }
     201            0 :       catch (std::exception& ex)
     202              :         {
     203            0 :           std::ostringstream text;
     204            0 :           text << "failed to set initial value \'" << a->get_init_value() << "\' of attribute \'" << a->get_name() << "\':\n" << ex.what();
     205            0 :           throw std::runtime_error(text.str().c_str());
     206            0 :         }
     207              :     }
     208        10227 : }
     209              : 
     210              : 
     211            0 : OksAttribute::OksAttribute(const std::string& nm, OksClass * p) :
     212            0 :   p_name           (nm),
     213            0 :   p_data_type      (OksData::string_type),
     214            0 :   p_multi_values   (false),
     215            0 :   p_no_null        (false),
     216            0 :   p_format         (OksAttribute::Dec),
     217            0 :   p_class          (p),
     218            0 :   p_enumerators    (nullptr),
     219            0 :   p_range_obj      (nullptr),
     220            0 :   p_ordered        (false)
     221              : 
     222              : {
     223            0 :   validate_not_empty(p_name, "attribute name");
     224            0 : }
     225              : 
     226              : 
     227            0 : OksAttribute::OksAttribute(const std::string& nm, const std::string& t, bool is_mv,
     228              :                            const std::string& r, const std::string& init_v, const std::string& ds,
     229            0 :                            bool no_null, Format f, OksClass * p) :
     230            0 :   p_name           (nm),
     231            0 :   p_range          (r),
     232            0 :   p_data_type      (get_data_type(t)),
     233            0 :   p_multi_values   (is_mv),
     234            0 :   p_no_null        (no_null),
     235            0 :   p_init_value     (init_v),
     236            0 :   p_format         (f),
     237            0 :   p_description    (ds),
     238            0 :   p_class          (p),
     239            0 :   p_enumerators    (nullptr),
     240            0 :   p_range_obj      (nullptr),
     241            0 :   p_ordered        (false)
     242              : {
     243            0 :   set_type(t, true);
     244            0 :   validate_not_empty(p_name, "attribute name");
     245            0 :   init_enum();
     246            0 :   init_range();
     247              :   // cannot call set_init_data() because of the CLASS data type, since other class may not be known yet;
     248              :   // initialize the init_data in the register_all_classes() call
     249            0 : }
     250              : 
     251              : bool
     252          530 : OksAttribute::operator==(const class OksAttribute &a) const
     253              : {
     254          530 :   return (
     255          530 :     ( this == &a ) ||
     256              :     (
     257            0 :       ( p_name == a.p_name ) &&
     258            0 :       ( p_range == a.p_range ) &&
     259            0 :       ( p_data_type == a.p_data_type ) &&
     260            0 :       ( p_multi_values == a.p_multi_values ) &&
     261            0 :       ( p_init_value == a.p_init_value ) &&
     262            0 :       ( p_description == a.p_description ) &&
     263            0 :       ( p_no_null == a.p_no_null ) &&
     264            0 :       ( p_ordered == a.p_ordered )
     265              :    )
     266          530 :   );
     267              : }
     268              : 
     269              : std::ostream&
     270            0 : operator<<(std::ostream& s, const OksAttribute& a)
     271              : {
     272            0 :   s << "Attribute name: \"" << a.p_name << "\"\n"
     273            0 :        " type: \"" << a.get_type() << "\"\n"
     274            0 :        " range: \"" << a.p_range << "\"\n";
     275              : 
     276            0 :   if(a.is_integer()) {
     277            0 :     s << " format: \"" << OksAttribute::format2str(a.p_format) << "\"\n";
     278              :   }
     279              : 
     280            0 :   if(a.p_multi_values == true) {
     281            0 :     s << " is \'multi values\'\n";
     282              :   }
     283              :   else {
     284            0 :     s << " is \'single value\'\n";
     285              :   }
     286              : 
     287            0 :   s << " initial value: \"" << a.p_init_value << "\"\n"
     288            0 :        " has description: \"" << a.p_description << "\"\n"
     289            0 :     << (a.p_no_null == true ? " can not be null\n" : " can be null\n")
     290            0 :     << " is " << (a.p_ordered == true ? "ordered" : "unordered") << std::endl;
     291              : 
     292            0 :   return s;
     293              : }
     294              : 
     295              : 
     296              : void
     297            0 : OksAttribute::save(OksXmlOutputStream& s) const
     298              : {
     299            0 :   if (p_data_type == OksData::class_type && p_init_value.empty() && p_multi_values == false)
     300              :     {
     301            0 :       std::ostringstream text;
     302            0 :       text << "single-value attribute \"" << p_name << "\" is of \"class_type\" and has empty init value";
     303            0 :       throw std::runtime_error(text.str().c_str());
     304            0 :     }
     305              : 
     306            0 :   validate_init2range(this);
     307              : 
     308            0 :   s.put("  ");
     309            0 :   s.put_start_tag(attribute_xml_tag, sizeof(attribute_xml_tag) - 1);
     310              : 
     311            0 :   s.put_attribute(name_xml_attr, sizeof(name_xml_attr) - 1, p_name.c_str());
     312              : 
     313            0 :   if (!p_description.empty())
     314            0 :     s.put_attribute(description_xml_attr, sizeof(description_xml_attr) - 1, p_description.c_str());
     315              : 
     316            0 :   s.put_attribute(type_xml_attr, sizeof(type_xml_attr) - 1, get_type().c_str());
     317              : 
     318            0 :   if (!p_range.empty())
     319            0 :     s.put_attribute(range_xml_attr, sizeof(range_xml_attr) - 1, p_range.c_str());
     320              : 
     321            0 :   if (is_integer() && p_format != OksAttribute::Dec)
     322            0 :     s.put_attribute(format_xml_attr, sizeof(format_xml_attr) - 1, format2str(p_format));
     323              : 
     324            0 :   if (p_multi_values)
     325            0 :     s.put_attribute(is_multi_value_xml_attr, sizeof(is_multi_value_xml_attr) - 1, xml::bool2str(p_multi_values));
     326              : 
     327            0 :   if (!p_init_value.empty())
     328            0 :     s.put_attribute(init_value_xml_attr, sizeof(init_value_xml_attr) - 1, p_init_value.c_str());
     329              : 
     330            0 :   if (p_no_null)
     331            0 :     s.put_attribute(is_not_null_xml_attr, sizeof(is_not_null_xml_attr) - 1, xml::bool2str(p_no_null));
     332              : 
     333            0 :   if (p_ordered)
     334            0 :     s.put_attribute(ordered_xml_attr, sizeof(ordered_xml_attr) - 1, xml::bool2str(p_ordered));
     335              : 
     336            0 :   s.put_end_tag();
     337            0 : }
     338              : 
     339              : 
     340        10227 : OksAttribute::OksAttribute(OksXmlInputStream& s, OksClass *parent) :
     341        10227 :   p_data_type      (OksData::unknown_type),
     342        10227 :   p_multi_values   (false),
     343        10227 :   p_no_null        (false),
     344        10227 :   p_format         (OksAttribute::Dec),
     345        10227 :   p_class          (parent),
     346        10227 :   p_enumerators    (nullptr),
     347        10227 :   p_range_obj      (nullptr),
     348        10227 :   p_ordered        (false)
     349              : {
     350              :   // read attributes of OksAttribute from xml
     351              : 
     352        51765 :   try
     353              :     {
     354        93303 :       while (true)
     355              :         {
     356        51765 :           OksXmlAttribute attr(s);
     357              : 
     358              :           // check for close of tag
     359              : 
     360        51765 :           if (cmp_str1(attr.name(), "/"))
     361              :             {
     362              :               break;
     363              :             }
     364              : 
     365              :           // check for known oks-attribute' attributes
     366              : 
     367        41538 :           else if (cmp_str4(attr.name(), name_xml_attr))
     368        10227 :             p_name.assign(attr.value(), attr.value_len());
     369        31311 :           else if (cmp_str11(attr.name(), description_xml_attr))
     370         5837 :             p_description.assign(attr.value(), attr.value_len());
     371        25474 :           else if (cmp_str4(attr.name(), type_xml_attr))
     372              :             {
     373        10227 :               __set_data_type(attr.value(), attr.value_len());
     374        10227 :               if (p_data_type == OksData::unknown_type)
     375              :                 {
     376            0 :                   throw BadFileData(std::string("Value \'") + attr.value() + "\' is not a valid attribute type", s.get_line_no(), s.get_line_pos());
     377              :                 }
     378              :             }
     379        15247 :           else if (cmp_str5(attr.name(), range_xml_attr))
     380          974 :             p_range.assign(attr.value(), attr.value_len());
     381        14273 :           else if (cmp_str6(attr.name(), format_xml_attr))
     382           45 :             p_format = str2format(attr.value());
     383        14228 :           else if (cmp_str14(attr.name(), is_multi_value_xml_attr))
     384          839 :             p_multi_values = xml::str2bool(attr.value());
     385        13389 :           else if (cmp_str10(attr.name(), init_value_xml_attr))
     386         6584 :             p_init_value.assign(attr.value(), attr.value_len());
     387         6805 :           else if (cmp_str11(attr.name(), is_not_null_xml_attr))
     388         6805 :             p_no_null = xml::str2bool(attr.value());
     389            0 :           else if (cmp_str7(attr.name(), ordered_xml_attr))
     390            0 :             p_ordered = xml::str2bool(attr.value());
     391            0 :           else if (!strcmp(attr.name(), "multi-value-implementation"))
     392            0 :             s.error_msg("OksAttribute::OksAttribute(OksXmlInputStream&)") << "Obsolete oks-attribute\'s attribute \'" << attr.name() << "\'\n";
     393              :           else
     394            0 :             s.throw_unexpected_attribute(attr.name());
     395        41538 :         }
     396              :     }
     397            0 :   catch (exception & e)
     398              :     {
     399            0 :       throw FailedRead("xml attribute", e);
     400            0 :     }
     401            0 :   catch (std::exception & e)
     402              :     {
     403            0 :       throw FailedRead("xml attribute", e.what());
     404            0 :     }
     405              : 
     406              :   // check validity of read values
     407              : 
     408        10227 :   if (p_data_type == OksData::unknown_type)
     409              :     {
     410            0 :       throw FailedRead("oks attribute", BadFileData("attribute type is not set", s.get_line_no(), s.get_line_pos()));
     411              :     }
     412              : 
     413        10227 :   try
     414              :     {
     415        10227 :       validate_not_empty(p_name, "attribute name");
     416        10227 :       init_enum();
     417        10227 :       init_range();
     418              :     }
     419            0 :   catch (std::exception& ex)
     420              :     {
     421            0 :       throw FailedRead("oks attribute", BadFileData(ex.what(), s.get_line_no(), s.get_line_pos()));
     422            0 :     }
     423              : 
     424        10227 :   if (p_init_value.empty())
     425              :     {
     426         3643 :       if (p_data_type == OksData::class_type && p_multi_values == false)
     427              :         {
     428            0 :           std::ostringstream text;
     429            0 :           text << "single-value attribute \"" << p_name << "\" is of \"class_type\" and has empty init value";
     430            0 :           throw FailedRead("oks attribute", BadFileData(text.str(), s.get_line_no(), s.get_line_pos()));
     431            0 :         }
     432              :     }
     433              :   else
     434              :     {
     435         6584 :       if (p_data_type == OksData::date_type || p_data_type == OksData::time_type)
     436              :         {
     437            0 :           try
     438              :             {
     439            0 :               OksData _d;
     440            0 :               if (p_multi_values)
     441              :                 {
     442            0 :                   _d.SetValues(p_init_value.c_str(), this);
     443              :                 }
     444              :               else
     445              :                 {
     446            0 :                   _d.type = p_data_type;
     447            0 :                   _d.SetValue(p_init_value.c_str(), 0);
     448              :                 }
     449            0 :             }
     450            0 :           catch (exception& ex)
     451              :             {
     452            0 :               std::ostringstream text;
     453            0 :               text << "attribute \"" << p_name << "\" has bad init value:\n" << ex.what();
     454            0 :               throw FailedRead("oks attribute", BadFileData(text.str(), s.get_line_no(), s.get_line_pos()));
     455            0 :             }
     456              :         }
     457              :     }
     458              : 
     459        10227 :   try
     460              :     {
     461        10227 :       validate_init2range(this);
     462              :     }
     463            0 :   catch (std::exception& ex)
     464              :     {
     465            0 :       std::ostringstream text;
     466            0 :       text << "attribute \"" << p_name << "\" has mismatch between init value and range:\n" << ex.what();
     467            0 :       throw FailedRead("oks attribute", BadFileData(text.str(), s.get_line_no(), s.get_line_pos()));
     468            0 :     }
     469              : 
     470              : //  set_init_data();
     471        10227 : }
     472              : 
     473              : 
     474              : OksData::Type
     475            0 : OksAttribute::get_data_type(const std::string& t) noexcept
     476              : {
     477            0 :   return get_data_type(t.c_str(), t.size());
     478              : }
     479              : 
     480              : 
     481              : OksData::Type
     482        19625 : OksAttribute::get_data_type(const char * t, size_t len) noexcept
     483              : {
     484        19625 :   switch(len) {
     485         7450 :     case 3:
     486         7450 :       if     ( cmp_str3n  (t, uid_type)     ) return OksData::uid2_type;     // "uid"
     487         7450 :       else if( cmp_str3n  (t, u32_int_type) ) return OksData::u32_int_type;  // "u32"
     488         1573 :       else if( cmp_str3n  (t, s32_int_type) ) return OksData::s32_int_type;  // "s32"
     489         1152 :       else if( cmp_str3n  (t, u16_int_type) ) return OksData::u16_int_type;  // "u16"
     490          256 :       else if( cmp_str3n  (t, s16_int_type) ) return OksData::s16_int_type;  // "s16"
     491          168 :       else if( cmp_str3n  (t, s64_int_type) ) return OksData::s64_int_type;  // "s64"
     492          130 :       else if( cmp_str3n  (t, u64_int_type) ) return OksData::u64_int_type;  // "u64"
     493              :       break;
     494              : 
     495         8551 :     case 6:
     496         8551 :       if(      cmp_str6n  (t, string_type)  ) return OksData::string_type;   // "string"
     497           15 :       else if( cmp_str6n  (t, double_type)  ) return OksData::double_type;   // "double"
     498              :       break;
     499              : 
     500         2967 :     case 4:
     501         2967 :       if(      cmp_str4n (t, bool_type)     ) return OksData::bool_type;    // "bool"
     502         1525 :       else if( cmp_str4n (t, enum_type)     ) return OksData::enum_type;    // "enum"
     503            0 :       else if( cmp_str4n (t, date_type)     ) return OksData::date_type;    // "date"
     504            0 :       else if( cmp_str4n (t, time_type)     ) return OksData::time_type;    // "time"
     505              :       break;
     506              : 
     507          387 :     case 5:
     508          387 :       if(      cmp_str5n  (t, float_type)   ) return OksData::float_type;   // "float"
     509          264 :       else if( cmp_str5n  (t, class_type)   ) return OksData::class_type;   // "class"
     510              :       break;
     511              : 
     512          270 :     case 2:
     513          270 :       if(      cmp_str2n  (t, s8_int_type)  ) return OksData::s8_int_type;  // "s8"
     514          270 :       else if( cmp_str2n  (t, u8_int_type)  ) return OksData::u8_int_type;  // "u8"
     515              :       break;
     516              :   }
     517              : 
     518              :   return OksData::unknown_type;
     519              : }
     520              : 
     521              : 
     522              : const std::string&
     523            0 : OksAttribute::get_type() const throw()
     524              : {
     525            0 :   static std::string __types [] = {
     526              :     "unknown",     // unknown_type = 0
     527              :     "s8",          // s8_int_type  = 1
     528              :     "u8",          // u8_int_type  = 2
     529              :     "s16",         // s16_int_type = 3,
     530              :     "u16",         // u16_int_type = 4,
     531              :     "s32",         // s32_int_type = 5,
     532              :     "u32",         // u32_int_type = 6,
     533              :     "s64",         // s64_int_type = 7,
     534              :     "u64",         // u64_int_type = 8,
     535              :     "float",       // float_type   = 9,
     536              :     "double",      // double_type  = 10,
     537              :     "bool",        // bool_type    = 11,
     538              :     "class",       // class_type   = 12,
     539              :     "object",      // object_type  = 13,
     540              :     "date",        // date_type    = 14,
     541              :     "time",        // time_type    = 15,
     542              :     "string",      // string_type  = 16,
     543              :     "list",        // list_type    = 17,
     544              :     "uid",         // uid_type     = 18,
     545              :     "uid2",        // uid2_type    = 19,
     546              :     "enum"         // enum_type    = 20
     547            0 :   };
     548              : 
     549            0 :   return __types[(int)p_data_type];
     550              : }
     551              : 
     552              : 
     553              : void
     554            0 : OksAttribute::set_type(const std::string& t, bool skip_init)
     555              : {
     556            0 :   OksData::Type p_dt = get_data_type(t);
     557              : 
     558            0 :   if (p_dt == OksData::unknown_type)
     559              :     {
     560            0 :       std::ostringstream text;
     561            0 :       text << "the type \'" << t << "\' is not valid";
     562            0 :       throw SetOperationFailed("OksAttribute::set_type", text.str());
     563            0 :     }
     564              : 
     565            0 :   if (p_data_type == p_dt)
     566              :     return;
     567              : 
     568            0 :   if (p_class)
     569            0 :     p_class->lock_file("OksAttribute::set_type");
     570              : 
     571            0 :   p_data_type = p_dt;
     572              : 
     573            0 :   if (skip_init == false)
     574              :     {
     575            0 :       try
     576              :         {
     577            0 :           init_enum();
     578            0 :           init_range();
     579              :         }
     580            0 :       catch (std::exception& ex)
     581              :         {
     582            0 :           throw SetOperationFailed("OksAttribute::set_type", ex.what());
     583            0 :         }
     584              :     }
     585              : 
     586            0 :   if (p_class)
     587              :     {
     588            0 :       p_class->registrate_attribute_change(this);
     589            0 :       p_class->registrate_class_change(OksClass::ChangeAttributeType, (const void *) this);
     590              :     }
     591              : }
     592              : 
     593              : void
     594            0 : OksAttribute::set_name(const std::string& new_name)
     595              : {
     596              :   // ignore when name is the same
     597              : 
     598            0 :   if (p_name == new_name)
     599              :     return;
     600              : 
     601              :   // additional checks are required,
     602              :   // if the attribute already belongs to some class
     603              : 
     604            0 :   if (p_class)
     605              :     {
     606              :       // check allowed length for attribute name
     607              : 
     608            0 :       try
     609              :         {
     610            0 :           validate_not_empty(new_name, "name");
     611              :         }
     612            0 :       catch (std::exception& ex)
     613              :         {
     614            0 :           throw SetOperationFailed("OksAttribute::set_name", ex.what());
     615            0 :         }
     616              : 
     617              :       // having a direct attribute with the same name is an error
     618              : 
     619            0 :       if (p_class->find_direct_attribute(new_name) != 0)
     620              :         {
     621            0 :           std::ostringstream text;
     622            0 :           text << "Class \"" << p_class->get_name() << "\" already has direct attribute \"" << new_name << '\"';
     623            0 :           throw SetOperationFailed("OksAttribute::set_name", text.str());
     624            0 :         }
     625              : 
     626              :       // check that the file can be updated
     627              : 
     628            0 :       p_class->lock_file("OksAttribute::set_name");
     629              : 
     630              :       // probably a non-direct attribute already exists
     631              : 
     632            0 :       OksAttribute * a = p_class->find_attribute(new_name);
     633              : 
     634              :       // change the name
     635              : 
     636            0 :       p_name = new_name;
     637              : 
     638              :       // registrate the change
     639              : 
     640            0 :       p_class->registrate_class_change(OksClass::ChangeAttributesList, (const void *) a);
     641              :     }
     642              :   else
     643              :     {
     644            0 :       p_name = new_name;
     645              :     }
     646              : }
     647              : 
     648              : void
     649            0 : OksAttribute::set_is_multi_values(bool is_mv)
     650              : {
     651            0 :   if (p_multi_values != is_mv)
     652              :     {
     653            0 :       if (p_class)
     654            0 :         p_class->lock_file("OksAttribute::set_is_multi_values");
     655              : 
     656            0 :       p_multi_values = is_mv;
     657              : 
     658            0 :       if (p_class)
     659              :         {
     660            0 :           p_class->registrate_class_change(OksClass::ChangeAttributeMultiValueCardinality, (const void *) this);
     661            0 :           p_class->registrate_attribute_change(this);
     662              :         }
     663              :     }
     664            0 : }
     665              : 
     666              : void
     667            0 : OksAttribute::set_init_value(const std::string& init_v)
     668              : {
     669            0 :   if (p_init_value != init_v)
     670              :     {
     671            0 :       std::string old_value = p_init_value;
     672              : 
     673            0 :       if (p_class)
     674            0 :         p_class->lock_file("OksAttribute::set_init_value");
     675              : 
     676            0 :       p_init_value = init_v;
     677              : 
     678            0 :       try
     679              :         {
     680            0 :           validate_init2range(this);
     681              :         }
     682            0 :       catch (...)
     683              :         {
     684            0 :           p_init_value = old_value;
     685            0 :           throw;
     686            0 :         }
     687              : 
     688            0 :       if (p_class)
     689            0 :         p_class->registrate_class_change(OksClass::ChangeAttributeInitValue, (const void *) this);
     690            0 :     }
     691            0 : }
     692              : 
     693              : void
     694            0 : OksAttribute::set_description(const std::string& ds)
     695              : {
     696            0 :   if (p_description != ds)
     697              :     {
     698            0 :       if (p_class)
     699            0 :         p_class->lock_file("OksAttribute::set_description");
     700              : 
     701            0 :       p_description = ds;
     702              : 
     703            0 :       if (p_class)
     704            0 :         p_class->registrate_class_change(OksClass::ChangeAttributeDescription, (const void *) this);
     705              :     }
     706            0 : }
     707              : 
     708              : 
     709              : void
     710            0 : OksAttribute::set_is_no_null(bool no_null)
     711              : {
     712            0 :   if (p_no_null != no_null)
     713              :     {
     714            0 :       if (p_class)
     715            0 :         p_class->lock_file("OksAttribute::set_is_no_null");
     716              : 
     717            0 :       p_no_null = no_null;
     718              : 
     719            0 :       if (p_class)
     720            0 :         p_class->registrate_class_change(OksClass::ChangeAttributeIsNoNull, (const void *) this);
     721              :     }
     722            0 : }
     723              : 
     724              : void
     725            0 : OksAttribute::set_format(Format f)
     726              : {
     727            0 :   if (f != p_format)
     728              :     {
     729            0 :       if (p_class)
     730            0 :         p_class->lock_file("OksAttribute::set_format");
     731              : 
     732            0 :       p_format = f;
     733              : 
     734            0 :       if (p_class)
     735            0 :         p_class->registrate_class_change(OksClass::ChangeAttributeFormat, (const void *) this);
     736              :     }
     737            0 : }
     738              : 
     739              : void
     740            0 : OksAttribute::set_range(const std::string& s)
     741              : {
     742            0 :   if (s != p_range)
     743              :     {
     744            0 :       std::string old_value = p_range;
     745              : 
     746            0 :       if (p_class)
     747            0 :         p_class->lock_file("OksAttribute::set_range");
     748              : 
     749            0 :       p_range.erase();
     750            0 :       int count = 0;
     751            0 :       Oks::Tokenizer t(s, ", \t");
     752            0 :       std::string token;
     753              : 
     754            0 :       while (t.next(token))
     755              :         {
     756            0 :           if (count++ != 0)
     757              :             {
     758            0 :               p_range += ',';
     759              :             }
     760              : 
     761            0 :           p_range += token;
     762              :         }
     763              : 
     764            0 :       if (count != 0)
     765              :         {
     766            0 :           if (p_data_type == OksData::bool_type)
     767              :             {
     768            0 :               p_range.erase();
     769            0 :               throw SetOperationFailed("OksAttribute::set_range", "boolean type can't have user-defined range!");
     770              :             }
     771              :         }
     772              : 
     773            0 :       try
     774              :         {
     775            0 :           init_enum();
     776            0 :           init_range();
     777            0 :           validate_init2range(this);
     778              :         }
     779            0 :       catch (std::exception& ex)
     780              :         {
     781            0 :           p_range = old_value;
     782              : 
     783            0 :           try
     784              :             {
     785            0 :               init_enum();
     786              :             }
     787            0 :           catch (...)
     788              :             {
     789            0 :               ;
     790            0 :             }
     791              : 
     792            0 :           try
     793              :             {
     794            0 :               init_range();
     795              :             }
     796            0 :           catch (...)
     797              :             {
     798            0 :               ;
     799            0 :             }
     800              : 
     801            0 :           throw SetOperationFailed("OksAttribute::set_range", ex.what());
     802            0 :         }
     803              : 
     804            0 :       if (p_class)
     805            0 :         p_class->registrate_class_change(OksClass::ChangeAttributeRange, (const void *) this);
     806            0 :     }
     807            0 : }
     808              : 
     809              : bool
     810            0 : OksAttribute::find_token(const char * token, const char * range) noexcept
     811              : {
     812            0 :   const char * p;
     813              : 
     814            0 :   if (token && (p = strstr(range, token)) != 0)
     815              :     {
     816            0 :       int len = strlen(token);
     817              : 
     818            0 :       do
     819              :         {
     820            0 :           if (((p != range) && (p[-1] != ',')) || ((p[len] != ',') && (p[len] != '\0')))
     821              :             {
     822            0 :               p = strstr(p + 1, token);
     823              :             }
     824              :           else
     825              :             {
     826              :               return true;
     827              :             }
     828              : 
     829              :         }
     830            0 :       while (p != 0);
     831              :     }
     832              : 
     833              :   return false;
     834              : }
     835              : 
     836              : inline bool
     837         6059 : is_star(const std::string& s)
     838              : {
     839         6059 :   return (s.size() == 1 && s[0] == '*');
     840              : }
     841              : 
     842              : 
     843              : void
     844          974 : OksRange::reset(const std::string& range, OksAttribute * a)
     845              : {
     846          974 :   clear();
     847              : 
     848          974 :   if (a->get_data_type() != OksData::string_type)
     849              :     {
     850          947 :       if (!range.empty())
     851              :         {
     852          947 :           Oks::Tokenizer t(range, ",");
     853          947 :           std::string token, token1, token2;
     854              : 
     855         4847 :           while (t.next(token))
     856              :             {
     857         2953 :               if (is_star(token))
     858              :                 {
     859            0 :                   TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' allows any value";
     860            0 :                   clear();
     861            0 :                   return;
     862              :                 }
     863              : 
     864         2953 :               static const char __dot_dot_str[] = "..";
     865         2953 :               std::string::size_type p = token.find(__dot_dot_str, 0, (sizeof(__dot_dot_str) - 1));
     866              : 
     867         2953 :               bool pi; // if true, then it is plus infinity, i.e. x..*
     868              : 
     869         2953 :               if (p != std::string::npos)
     870              :                 {
     871          153 :                   token1.assign(token, 0, p);
     872          153 :                   token2.assign(token, p + 2, std::string::npos);
     873          153 :                   pi = (is_star(token2));
     874              :                 }
     875              :               else
     876              :                 {
     877         2800 :                   token1.assign(token);
     878         2800 :                   token2.clear();
     879         2800 :                   pi = false;
     880              :                 }
     881              : 
     882         2953 :               bool mi = (is_star(token1));    // if true, then it is minus infinity, i.e. *..x
     883              : 
     884         2953 :               if (mi && pi)
     885              :                 {
     886            0 :                   TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' allows any value";
     887            0 :                   clear();
     888            0 :                   return;
     889              :                 }
     890              : 
     891         2953 :               OksData d1, d2;
     892              : 
     893         2953 :               if (!mi)
     894              :                 {
     895         2953 :                   d1.type = a->get_data_type();
     896         2953 :                   d1.ReadFrom(token1, a);
     897              :                 }
     898              : 
     899         2953 :               if (token2.empty())
     900              :                 {
     901         2800 :                   TLOG_DEBUG(2) <<  "token \'" << token << "\' of \'" << range << "\' defines equality condition";
     902         2800 :                   m_equal.emplace_back(d1);
     903              :                 }
     904              :               else
     905              :                 {
     906          153 :                   if (!pi)
     907              :                     {
     908          153 :                       d2.type = a->get_data_type();
     909          153 :                       d2.ReadFrom(token2, a);
     910              :                     }
     911              : 
     912          153 :                   if (mi)
     913              :                     {
     914            0 :                       TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' defines smaller condition";
     915            0 :                       m_less.emplace_back(d2);
     916              :                     }
     917          153 :                   else if (pi)
     918              :                     {
     919            0 :                       TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' defines greater condition";
     920            0 :                       m_great.emplace_back(d1);
     921              :                     }
     922              :                   else
     923              :                     {
     924          153 :                       TLOG_DEBUG(2) << "token \'" << token << "\' of \'" << range << "\' defines interval condition";
     925          153 :                       m_interval.emplace_back(d1, d2);
     926              :                     }
     927              :                 }
     928         2953 :             }
     929          947 :         }
     930              :     }
     931              :   else
     932              :     {
     933           27 :       try
     934              :         {
     935           27 :           m_like.emplace_back(range);
     936              :         }
     937            0 :       catch (std::exception& ex)
     938              :         {
     939            0 :           throw BadReqExp(range, ex.what());
     940            0 :         }
     941              :     }
     942              : }
     943              : 
     944              : bool
     945         1790 : OksRange::validate(const OksData& d) const
     946              : {
     947         1790 :   for (const auto& x : m_less)
     948              :     {
     949            0 :       if (d <= x)
     950            0 :         return true;
     951              :     }
     952              : 
     953         1790 :   for (const auto& x : m_great)
     954              :     {
     955            0 :       if (d >= x)
     956            0 :         return true;
     957              :     }
     958              : 
     959         3050 :   for (const auto& x : m_equal)
     960              :     {
     961         2777 :       if (d == x)
     962         1517 :         return true;
     963              :     }
     964              : 
     965          273 :   for (const auto& x : m_interval)
     966              :     {
     967          237 :       if (d >= x.first && d <= x.second)
     968          237 :         return true;
     969              :     }
     970              : 
     971           36 :   for (const auto& x : m_like)
     972              :     {
     973           36 :       if (OksKernel::get_skip_string_range())
     974           36 :         return true;
     975              : 
     976           36 :       if (boost::regex_match(d.str(),x))
     977              :         return true;
     978              :     }
     979              : 
     980            0 :   return false;
     981              : }
     982              : 
     983              : } // namespace oks
     984              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1