LCOV - code coverage report
Current view: top level - oks/src - attribute.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 34.1 % 469 160
Test Date: 2025-12-21 13:07:08 Functions: 37.8 % 37 14

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

Generated by: LCOV version 2.0-1