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
|