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

Generated by: LCOV version 2.0-1