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