Sync with 5.2.0
[deliverable/titan.core.git] / compiler2 / subtypestuff.hh
CommitLineData
970ed795
EL
1///////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2000-2014 Ericsson Telecom AB
3// All rights reserved. This program and the accompanying materials
4// are made available under the terms of the Eclipse Public License v1.0
5// which accompanies this distribution, and is available at
6// http://www.eclipse.org/legal/epl-v10.html
7///////////////////////////////////////////////////////////////////////////////
8#ifndef _Subtypestuff_HH
9#define _Subtypestuff_HH
10
11#include "ttcn3/compiler.h"
12#include "vector.hh"
13#include "map.hh"
14#include "Int.hh"
15#include "Real.hh"
16#include "ustring.hh"
17#include "Setting.hh"
18#include "../common/ttcn3float.hh"
19
20namespace Ttcn {
21 class LengthRestriction;
22 class Template;
23 class ValueRange;
24 class PatternString;
25}
26
27namespace Common {
28
29class Identifier;
30class Value;
31class Type;
32
33
34enum tribool // http://en.wikipedia.org/wiki/Ternary_logic
35{
36 TFALSE = 0, // values are indexes into truth tables
37 TUNKNOWN = 1,
38 TTRUE = 2
39};
40
41extern tribool operator||(tribool a, tribool b);
42extern tribool operator&&(tribool a, tribool b);
43extern tribool operator!(tribool tb);
44extern tribool TRIBOOL(bool b);
45extern string to_string(const tribool& tb);
46
47////////////////////////////////////////////////////////////////////////////////
48
49// integer interval limit type, can be +/- infinity, in case of infinity value has no meaning
50class int_limit_t
51{
52public:
53 enum int_limit_type_t {
54 MINUS_INFINITY,
55 NUMBER,
56 PLUS_INFINITY
57 };
58 static const int_limit_t minimum;
59 static const int_limit_t maximum;
60private:
61 int_limit_type_t type;
62 int_val_t value;
63public:
64 int_limit_t(): type(NUMBER), value() {}
65 int_limit_t(int_limit_type_t p_type);
66 int_limit_t(const int_val_t& p_value): type(NUMBER), value(p_value) {}
67 bool operator<(const int_limit_t& right) const;
68 bool operator==(const int_limit_t& right) const;
69 bool is_adjacent(const int_limit_t& other) const;
70 int_val_t get_value() const;
71 int_limit_type_t get_type() const { return type; }
72 int_limit_t next() const; // upper neighbour
73 int_limit_t previous() const; // lower neighbour
74 void check_single_value() const;
75 void check_interval_start() const;
76 void check_interval_end() const;
77 string to_string() const;
78};
79
80////////////////////////////////////////////////////////////////////////////////
81
82// limit value for length/size restriction
83class size_limit_t
84{
85public:
86 enum size_limit_type_t {
87 INFINITE_SIZE
88 };
89private:
90 bool infinity;
91 size_t size;
92public:
93 static const size_limit_t minimum;
94 static const size_limit_t maximum;
95 size_limit_t() : infinity(false), size() {}
96 size_limit_t(size_limit_type_t): infinity(true), size() {}
97 size_limit_t(size_t p_size): infinity(false), size(p_size) {}
98 bool operator<(const size_limit_t& right) const;
99 bool operator==(const size_limit_t& right) const;
100 bool is_adjacent(const size_limit_t& other) const;
101 size_t get_size() const;
102 bool get_infinity() const { return infinity; }
103 size_limit_t next() const;
104 size_limit_t previous() const;
105 void check_single_value() const;
106 void check_interval_start() const;
107 void check_interval_end() const {}
108 string to_string() const;
109 int_limit_t to_int_limit() const;
110};
111
112////////////////////////////////////////////////////////////////////////////////
113
114// limit value for string range/alphabet restriction
115class char_limit_t
116{
117private:
118 short int chr;
119 static const short int max_char;
120public:
121 static bool is_valid_value(short int p_chr);
122 static const char_limit_t minimum;
123 static const char_limit_t maximum;
124 char_limit_t(): chr(0) {}
125 char_limit_t(short int p_chr);
126 bool operator<(const char_limit_t& right) const { return chr<right.chr; }
127 bool operator==(const char_limit_t& right) const { return chr==right.chr; }
128 bool is_adjacent(const char_limit_t& other) const { return (chr+1==other.chr); }
129 char get_char() const { return (char)chr; }
130 char_limit_t next() const;
131 char_limit_t previous() const;
132 void check_single_value() const {}
133 void check_interval_start() const {}
134 void check_interval_end() const {}
135 string to_string() const;
136};
137
138////////////////////////////////////////////////////////////////////////////////
139
140class universal_char_limit_t
141{
142private:
143 unsigned int code_point; // UCS-4 values [0..0x7FFFFFFF], for easy calculations
144 static const unsigned int max_code_point;
145 void check_value() const;
146public:
147 static bool is_valid_value(const ustring::universal_char& p_uchr);
148 static unsigned int uchar2codepoint(const ustring::universal_char& uchr);
149 static ustring::universal_char codepoint2uchar(unsigned int cp);
150 static const universal_char_limit_t minimum;
151 static const universal_char_limit_t maximum;
152 universal_char_limit_t(): code_point(0) {}
153 universal_char_limit_t(unsigned int p_code_point): code_point(p_code_point) { check_value(); }
154 universal_char_limit_t(const ustring::universal_char& p_chr) : code_point(uchar2codepoint(p_chr)) { check_value(); }
155 bool operator<(const universal_char_limit_t& right) const { return code_point<right.code_point; }
156 bool operator==(const universal_char_limit_t& right) const { return code_point==right.code_point; }
157 bool is_adjacent(const universal_char_limit_t& other) const { return (code_point+1==other.code_point); }
158 ustring::universal_char get_universal_char() const { return codepoint2uchar(code_point); }
159 unsigned int get_code_point() const { return code_point; }
160 universal_char_limit_t next() const;
161 universal_char_limit_t previous() const;
162 void check_single_value() const {}
163 void check_interval_start() const {}
164 void check_interval_end() const {}
165 string to_string() const;
166};
167
168////////////////////////////////////////////////////////////////////////////////
169
170class real_limit_t
171{
172public:
173 enum real_limit_type_t {
174 LOWER, // the highest value that is less than the value, for open interval's upper limit
175 EXACT, // the value itself, for closed interval limits and single values
176 UPPER // the lowest value that is more than the value, for open interval's lower limit
177 };
178 static const real_limit_t minimum;
179 static const real_limit_t maximum;
180private:
181 real_limit_type_t type;
182 ttcn3float value;
183 void check_value() const; // check for illegal values: NaN, -inf.lower and inf.upper
184public:
185 real_limit_t(): type(EXACT), value() { value = 0.0; } // avoid random illegal values
186 real_limit_t(const ttcn3float& p_value): type(EXACT), value(p_value) { check_value(); }
187 real_limit_t(const ttcn3float& p_value, real_limit_type_t p_type): type(p_type), value(p_value) { check_value(); }
188
189 bool operator<(const real_limit_t& right) const;
190 bool operator==(const real_limit_t& right) const;
191 bool is_adjacent(const real_limit_t& other) const; // two different values cannot be adjacent in a general floating point value
192 ttcn3float get_value() const { return value; }
193 real_limit_type_t get_type() const { return type; }
194 real_limit_t next() const; // upper neighbour, has same value
195 real_limit_t previous() const; // lower neighbour, has same value
196 void check_single_value() const;
197 void check_interval_start() const;
198 void check_interval_end() const;
199 string to_string() const;
200};
201
202////////////////////////////////////////////////////////////////////////////////
203
204// forward declaration
205template <typename LIMITTYPE>
206class RangeListConstraint;
207
208bool convert_int_to_size(const RangeListConstraint<int_limit_t>& int_range, RangeListConstraint<size_limit_t>& size_range);
209
210/*
211all-in-one constraint class template for xxx_limit_t types
212the xxx_limit_t classes must have the same interface for use by this class
213canonical form:
214- values must be v1 < v2 < v3 < ... < vN (xxx_limit_t::operator<() and xxx_limit_t::operator==() used)
215- there cannot be two adjacent intervals that are part of the set (determined by xxx_limit_t::is_adjacent())
216- two adjacent values must make an interval (if values[i] is adjacent to values[i+1] then intervals[i] is true)
217- empty values[] means empty set
218- full set is [minimum-maximum] interval (xxx_limit_t::minimum and xxx_limit_t::maximum are used)
219*/
220template <typename LIMITTYPE>
221class RangeListConstraint
222{
223private:
224 // used in calculating the union and intersection of two sets, _idx are indexes into the values[] vector of the operand sets
225 struct sweep_point_t
226 {
227 int a_idx; // index into the operand's values/intervals vectors or -1
228 int b_idx;
229 bool union_interval; // is this interval in the set
230 bool intersection_interval; // is this interval in the set
231 bool intersection_point; // is this point in the set
232 sweep_point_t(): a_idx(-1), b_idx(-1), union_interval(false), intersection_interval(false), intersection_point(false) {}
233 sweep_point_t(int a, int b): a_idx(a), b_idx(b), union_interval(false), intersection_interval(false), intersection_point(false) {}
234 };
235
236 dynamic_array<LIMITTYPE> values;
237 dynamic_array<bool> intervals;
238
239public:
240 // constructors
241 RangeListConstraint(): values(), intervals() {} // empty set
242 RangeListConstraint(const LIMITTYPE& l); // single value set
243 RangeListConstraint(const LIMITTYPE& l_begin, const LIMITTYPE& l_end); // value range set
244
245 tribool is_empty() const;
246 tribool is_full() const;
247 tribool is_equal(const RangeListConstraint& other) const;
248 bool is_element(const LIMITTYPE& l) const;
249
250 RangeListConstraint set_operation(const RangeListConstraint& other, bool is_union) const; // A union/intersection B -> C
251 RangeListConstraint operator+(const RangeListConstraint& other) const { return set_operation(other, true); } // union
252 RangeListConstraint operator*(const RangeListConstraint& other) const { return set_operation(other, false); } // intersection
253 RangeListConstraint operator~() const; // complement
254
255 tribool is_subset(const RangeListConstraint& other) const { return (*this*~other).is_empty(); }
256 RangeListConstraint operator-(const RangeListConstraint& other) const { return ( *this * ~other ); } // except
257
258 // will return the minimal value that is part of the interval,
259 // if the interval is empty the returned value is undefined
260 LIMITTYPE get_minimal() const;
261 LIMITTYPE get_maximal() const;
262
af710487 263 bool is_upper_limit_infinity() const;
264 bool is_lower_limit_infinity() const;
265
970ed795
EL
266 string to_string(bool add_brackets=true) const;
267
268 /** conversion from integer range to size range,
269 returns true on success, false if the integers do not fit into the size values,
270 when returning false the size_range will be set to the full set */
271 friend bool convert_int_to_size(const RangeListConstraint<int_limit_t>& int_range, RangeListConstraint<size_limit_t>& size_range);
272};
273
274template <typename LIMITTYPE>
275RangeListConstraint<LIMITTYPE>::RangeListConstraint(const LIMITTYPE& l)
276: values(), intervals()
277{
278 l.check_single_value();
279 values.add(l);
280 intervals.add(false);
281}
282
283template <typename LIMITTYPE>
284RangeListConstraint<LIMITTYPE>::RangeListConstraint(const LIMITTYPE& l_begin, const LIMITTYPE& l_end)
285: values(), intervals()
286{
287 if (l_end<l_begin) FATAL_ERROR("RangeListConstraint::RangeListConstraint(): invalid range");
288 if (l_begin==l_end) {
289 l_begin.check_single_value();
290 values.add(l_begin);
291 intervals.add(false);
292 } else {
293 l_begin.check_interval_start();
294 l_end.check_interval_end();
295 values.add(l_begin);
296 intervals.add(true);
297 values.add(l_end);
298 intervals.add(false);
299 }
300}
301
302template <typename LIMITTYPE>
303tribool RangeListConstraint<LIMITTYPE>::is_empty() const
304{
305 return TRIBOOL(values.size()==0);
306}
307
308template <typename LIMITTYPE>
309tribool RangeListConstraint<LIMITTYPE>::is_full() const
310{
311 return TRIBOOL( (values.size()==2) && (values[0]==LIMITTYPE::minimum) && (values[1]==LIMITTYPE::maximum) && (intervals[0]) );
312}
313
314template <typename LIMITTYPE>
315tribool RangeListConstraint<LIMITTYPE>::is_equal(const RangeListConstraint<LIMITTYPE>& other) const
316{
317 return TRIBOOL( (values==other.values) && (intervals==other.intervals) );
318}
319
320template <typename LIMITTYPE>
321bool RangeListConstraint<LIMITTYPE>::is_element(const LIMITTYPE& l) const
322{
323 if (values.size()==0) return false;
324 // binary search in values[]
325 size_t lower_idx = 0;
326 size_t upper_idx = values.size()-1;
327 while (upper_idx>lower_idx+1) {
328 size_t middle_idx = lower_idx + (upper_idx-lower_idx) / 2;
329 if (values[middle_idx]<l) lower_idx = middle_idx;
330 else upper_idx = middle_idx;
331 }
332 if (lower_idx==upper_idx) {
333 if (values[lower_idx]==l) return true; // every value is in the set
334 else if (values[lower_idx]<l) return intervals[lower_idx];
335 else return ( (lower_idx>0) ? intervals[lower_idx-1] : false );
336 } else {
337 if (l<values[lower_idx]) return ( (lower_idx>0) ? intervals[lower_idx-1] : false );
338 else if (l==values[lower_idx]) return true;
339 else if (l<values[upper_idx]) return intervals[upper_idx-1];
340 else if (l==values[upper_idx]) return true;
341 else return intervals[upper_idx];
342 }
343}
344
345template <typename LIMITTYPE>
346RangeListConstraint<LIMITTYPE> RangeListConstraint<LIMITTYPE>::operator~() const
347{
348 if (values.size()==0) { // if we have an empty set
349 return RangeListConstraint<LIMITTYPE>(LIMITTYPE::minimum, LIMITTYPE::maximum);
350 }
351 RangeListConstraint<LIMITTYPE> ret_val;
352 // invert intervals
353 if (!(values[0]==LIMITTYPE::minimum)) {
354 if (LIMITTYPE::minimum.is_adjacent(values[0])) {
355 ret_val.values.add(LIMITTYPE::minimum);
356 ret_val.intervals.add(false);
357 } else {
358 ret_val.values.add(LIMITTYPE::minimum);
359 ret_val.intervals.add(true);
360 ret_val.values.add(values[0].previous());
361 ret_val.intervals.add(false);
362 }
363 }
364 int last = values.size()-1;
365 for (int i=0; i<last; i++)
366 {
367 if (!intervals[i]) {
368 if (values[i].next()==values[i+1].previous()) {
369 // add one value between intervals
370 ret_val.values.add(values[i].next());
371 ret_val.intervals.add(false);
372 } else {
373 // add interval between intervals
374 ret_val.values.add(values[i].next());
375 ret_val.intervals.add(true);
376 ret_val.values.add(values[i+1].previous());
377 ret_val.intervals.add(false);
378 }
379 }
380 }
381 if (!(values[last]==LIMITTYPE::maximum)) {
382 if (values[last].is_adjacent(LIMITTYPE::maximum)) {
383 ret_val.values.add(LIMITTYPE::maximum);
384 ret_val.intervals.add(false);
385 } else {
386 ret_val.values.add(values[last].next());
387 ret_val.intervals.add(true);
388 ret_val.values.add(LIMITTYPE::maximum);
389 ret_val.intervals.add(false);
390 }
391 }
392 return ret_val;
393}
394
395template <typename LIMITTYPE>
396RangeListConstraint<LIMITTYPE> RangeListConstraint<LIMITTYPE>::set_operation(const RangeListConstraint<LIMITTYPE>& other, bool is_union) const
397{
398 // special case: one or both are empty sets
399 if (values.size()==0) return is_union ? other : *this;
400 if (other.values.size()==0) return is_union ? *this : other;
401
402 // calculate the sweep points
403 dynamic_array<sweep_point_t> sweep_points;
404 sweep_point_t spi(0,0);
405 while ( (spi.a_idx<(int)values.size()) || (spi.b_idx<(int)other.values.size()) )
406 {
407 if (spi.a_idx>=(int)values.size()) {
408 sweep_points.add(sweep_point_t(-1,spi.b_idx));
409 spi.b_idx++;
410 } else if (spi.b_idx>=(int)other.values.size()) {
411 sweep_points.add(sweep_point_t(spi.a_idx, -1));
412 spi.a_idx++;
413 } else { // both are within the vector, get smaller or get both if equal
414 if (values[spi.a_idx]<other.values[spi.b_idx]) {
415 sweep_points.add(sweep_point_t(spi.a_idx, -1));
416 spi.a_idx++;
417 } else if (values[spi.a_idx]==other.values[spi.b_idx]) {
418 sweep_points.add(spi);
419 spi.a_idx++;
420 spi.b_idx++;
421 } else {
422 sweep_points.add(sweep_point_t(-1,spi.b_idx));
423 spi.b_idx++;
424 }
425 }
426 }
427
428 // sweep (iterate) through both vectors
429 bool in_a = false; // we are already in an interval of A
430 bool in_b = false;
431 for (int i=0; i<(int)sweep_points.size(); i++)
432 {
433 // set bools for A interval
434 bool a_interval = in_a;
435 bool a_point = false;
436 if (sweep_points[i].a_idx!=-1) { // we are at a value in A
437 a_point = true;
438 if (intervals[sweep_points[i].a_idx]) { // this is a starting point of an interval in A
439 a_interval = true;
440 if (in_a) FATAL_ERROR("RangeListConstraint::set_operation(): invalid double interval");
441 in_a = true;
442 } else { // this point ends an interval of A
443 a_interval = false;
444 in_a = false;
445 }
446 }
447 // set bools for B interval
448 bool b_interval = in_b;
449 bool b_point = false;
450 if (sweep_points[i].b_idx!=-1) { // we are at a value in B
451 b_point = true;
452 if (other.intervals[sweep_points[i].b_idx]) { // this is a starting point of an interval in B
453 b_interval = true;
454 if (in_b) FATAL_ERROR("RangeListConstraint::set_operation(): invalid double interval");
455 in_b = true;
456 } else { // this point ends an interval of B
457 b_interval = false;
458 in_b = false;
459 }
460 }
461 // set the booleans of the union and intersection sets
462 sweep_points[i].union_interval = a_interval || b_interval;
463 sweep_points[i].intersection_point = (a_point || in_a) && (b_point || in_b);
464 sweep_points[i].intersection_interval = a_interval && b_interval;
465 }
466
467 // canonicalization of ret_val
468 if (is_union) {
469 // connect adjacent limit points with interval: [i,i+1] becomes interval
470 for (int i=1; i<(int)sweep_points.size(); i++)
471 {
472 LIMITTYPE first, second;
473 if (sweep_points[i-1].a_idx!=-1) {
474 first = values[sweep_points[i-1].a_idx];
475 } else {
476 if (sweep_points[i-1].b_idx!=-1) first = other.values[sweep_points[i-1].b_idx];
477 else FATAL_ERROR("RangeListConstraint::set_operation()");
478 }
479 if (sweep_points[i].a_idx!=-1) {
480 second = values[sweep_points[i].a_idx];
481 } else {
482 if (sweep_points[i].b_idx!=-1) second = other.values[sweep_points[i].b_idx];
483 else FATAL_ERROR("RangeListConstraint::set_operation()");
484 }
485 if (first.is_adjacent(second)) {
486 sweep_points[i-1].union_interval = true;
487 sweep_points[i-1].intersection_interval = sweep_points[i-1].intersection_point && sweep_points[i].intersection_point;
488 }
489 }
490 }
491 // two adjacent intervals shall be united into one
492 RangeListConstraint<LIMITTYPE> ret_val;
493 for (int i=0; i<(int)sweep_points.size(); i++)
494 {
495 if (is_union) {
496 if ( (i>0) && sweep_points[i-1].union_interval && sweep_points[i].union_interval) {
497 // drop this point, it's in a double interval
498 } else {
499 LIMITTYPE l;
500 if (sweep_points[i].a_idx!=-1) {
501 l = values[sweep_points[i].a_idx];
502 } else {
503 if (sweep_points[i].b_idx!=-1) l = other.values[sweep_points[i].b_idx];
504 else FATAL_ERROR("RangeListConstraint::set_operation()");
505 }
506 ret_val.values.add(l);
507 ret_val.intervals.add(sweep_points[i].union_interval);
508 }
509 } else {
510 if (sweep_points[i].intersection_point) {
511 if ( (i>0) && sweep_points[i-1].intersection_interval && sweep_points[i].intersection_interval) {
512 // drop this point, it's in a double interval
513 } else {
514 LIMITTYPE l;
515 if (sweep_points[i].a_idx!=-1) {
516 l = values[sweep_points[i].a_idx];
517 } else {
518 if (sweep_points[i].b_idx!=-1) l = other.values[sweep_points[i].b_idx];
519 else FATAL_ERROR("RangeListConstraint::set_operation()");
520 }
521 ret_val.values.add(l);
522 ret_val.intervals.add(sweep_points[i].intersection_interval);
523 }
524 }
525 }
526 }
527 return ret_val;
528}
529
530template <typename LIMITTYPE>
531LIMITTYPE RangeListConstraint<LIMITTYPE>::get_minimal() const
532{
533 if (values.size()<1) return LIMITTYPE();
534 return values[0];
535}
536
537template <typename LIMITTYPE>
538LIMITTYPE RangeListConstraint<LIMITTYPE>::get_maximal() const
539{
540 if (values.size()<1) return LIMITTYPE();
541 return values[values.size()-1];
542}
543
af710487 544template <typename LIMITTYPE>
545bool RangeListConstraint<LIMITTYPE>::is_upper_limit_infinity () const
546{
547 if (0 == values.size()) return false;
548 return LIMITTYPE::maximum == values[values.size()-1];
549}
550
551template <typename LIMITTYPE>
552bool RangeListConstraint<LIMITTYPE>::is_lower_limit_infinity () const
553{
554 if (0 == values.size()) return false;
555 return LIMITTYPE::minimum == values[0];
556}
557
970ed795
EL
558template <typename LIMITTYPE>
559string RangeListConstraint<LIMITTYPE>::to_string(bool add_brackets) const
560{
561 string ret_val;
562 if (add_brackets) ret_val += '(';
563 int last = values.size()-1;
564 for (int i=0; i<=last; i++)
565 {
566 ret_val += values[i].to_string();
567 if (intervals[i]) ret_val += "..";
568 else if (i<last) ret_val += ',';
569 }
570 if (add_brackets) ret_val += ')';
571 return ret_val;
572}
573
574////////////////////////////////////////////////////////////////////////////////
575
576typedef RangeListConstraint<int_limit_t> IntegerRangeListConstraint; // for integer type
577typedef RangeListConstraint<size_limit_t> SizeRangeListConstraint; // for length constraints
578typedef RangeListConstraint<char_limit_t> CharRangeListConstraint; // for char/bit/hex/octet strings
579typedef RangeListConstraint<universal_char_limit_t> UniversalCharRangeListConstraint; // for universal charstring
580
581////////////////////////////////////////////////////////////////////////////////
582
583// RangeListConstraint with added NaN value (NaN is unordered so it cannot be a limit value)
584// this is canonical only if two different Real values are never considered to be adjacent
585// which means that in theory for two different Real values there are always infinite number of Real values that are between them
586class RealRangeListConstraint
587{
588private:
589 bool has_nan;
590 RangeListConstraint<real_limit_t> rlc;
591public:
592 // constructors
593 RealRangeListConstraint(bool p_has_nan = false): has_nan(p_has_nan), rlc() {} // empty set or NaN
594 RealRangeListConstraint(const real_limit_t& rl): has_nan(false), rlc(rl) {} // single value set (cannot be lower or upper, must be exact value)
595 RealRangeListConstraint(const real_limit_t& rl_begin, const real_limit_t& rl_end): has_nan(false), rlc(rl_begin,rl_end) {} // range set
596
597 tribool is_empty() const { return ( rlc.is_empty() && TRIBOOL(!has_nan) ); }
598 tribool is_full() const { return ( rlc.is_full() && TRIBOOL(has_nan) ); }
599 tribool is_equal(const RealRangeListConstraint& other) const { return ( rlc.is_equal(other.rlc) && TRIBOOL(has_nan==other.has_nan) ); }
600 bool is_element(const ttcn3float& r) const;
601
602 // A union/intersection B -> C
603 RealRangeListConstraint set_operation(const RealRangeListConstraint& other, bool is_union) const;
604
605 RealRangeListConstraint operator+(const RealRangeListConstraint& other) const { return set_operation(other, true); } // union
606 RealRangeListConstraint operator*(const RealRangeListConstraint& other) const { return set_operation(other, false); } // intersection
607 RealRangeListConstraint operator~() const; // complement
608
609 tribool is_subset(const RealRangeListConstraint& other) const { return (*this*~other).is_empty(); }
610 RealRangeListConstraint operator-(const RealRangeListConstraint& other) const { return ( *this * ~other ); } // except
611
612 tribool is_range_empty() const { return rlc.is_empty(); }
613 real_limit_t get_minimal() const { return rlc.get_minimal(); }
614 real_limit_t get_maximal() const { return rlc.get_maximal(); }
615
616 string to_string() const;
af710487 617 bool is_upper_limit_infinity() const;
618 bool is_lower_limit_infinity() const;
970ed795
EL
619};
620
621////////////////////////////////////////////////////////////////////////////////
622
623class BooleanListConstraint
624{
625private:
626 // every value selects a different bit, if the bit is set to 1 then the associated value is element of the set
627 enum boolean_constraint_t {
628 // 0x00 is empty set
629 BC_FALSE = 0x01,
630 BC_TRUE = 0x02,
631 BC_ALL = 0x03 // all values, full set
632 };
633 unsigned char values;
634
635public:
636 // constructors
637 BooleanListConstraint(): values(0) {} // empty set
638 BooleanListConstraint(bool b): values(b ? BC_TRUE:BC_FALSE) {} // single value set
639
640 tribool is_empty() const { return TRIBOOL(values==0); }
641 tribool is_full() const { return TRIBOOL(values==BC_ALL); }
642 tribool is_equal(const BooleanListConstraint& other) const { return TRIBOOL(values==other.values); }
643 bool is_element(bool b) const { return b ? (values&BC_TRUE) : (values&BC_FALSE); }
644
645 BooleanListConstraint operator+(const BooleanListConstraint& other) const { BooleanListConstraint rv; rv.values = values | other.values; return rv; }
646 BooleanListConstraint operator*(const BooleanListConstraint& other) const { BooleanListConstraint rv; rv.values = values & other.values; return rv; }
647 BooleanListConstraint operator~() const { BooleanListConstraint rv; rv.values = values ^ BC_ALL; return rv; }
648
649 tribool is_subset(const BooleanListConstraint& other) const { return (*this*~other).is_empty(); }
650
651 BooleanListConstraint operator-(const BooleanListConstraint& other) const { return ( *this * ~other ); }
652
653 string to_string() const;
654};
655
656////////////////////////////////////////////////////////////////////////////////
657
658class VerdicttypeListConstraint
659{
660public:
661 enum verdicttype_constraint_t { // every value selects a different bit, if the bit is set to 1 then the associated value is element of the set
662 // 0x00 is empty set
663 VC_NONE = 0x01,
664 VC_PASS = 0x02,
665 VC_INCONC = 0x04,
666 VC_FAIL = 0x08,
667 VC_ERROR = 0x10,
668 VC_ALL = 0x1F // all values, full set
669 };
670
671private:
672 unsigned char values;
673
674public:
675 // constructors
676 VerdicttypeListConstraint(): values(0) {} // empty set
677 VerdicttypeListConstraint(verdicttype_constraint_t vtc): values(vtc) {} // single value set
678
679 tribool is_empty() const { return TRIBOOL(values==0); }
680 tribool is_full() const { return TRIBOOL(values==VC_ALL); }
681 tribool is_equal(const VerdicttypeListConstraint& other) const { return TRIBOOL(values==other.values); }
682 bool is_element(verdicttype_constraint_t vtc) const { return vtc&values; }
683
684 VerdicttypeListConstraint operator+(const VerdicttypeListConstraint& other) const { VerdicttypeListConstraint rv; rv.values = values | other.values; return rv; }
685 VerdicttypeListConstraint operator*(const VerdicttypeListConstraint& other) const { VerdicttypeListConstraint rv; rv.values = values & other.values; return rv; }
686 VerdicttypeListConstraint operator~() const { VerdicttypeListConstraint rv; rv.values = values ^ VC_ALL; return rv; }
687
688 tribool is_subset(const VerdicttypeListConstraint& other) const { return (*this*~other).is_empty(); }
689
690 VerdicttypeListConstraint operator-(const VerdicttypeListConstraint& other) const { return ( *this * ~other ); }
691
692 string to_string() const;
693};
694
695////////////////////////////////////////////////////////////////////////////////
696
697// size and value list constraint for bitstring, hexstring and octetstring
698// in the compiler octetstring is a special hexstring where 1 octet = 2 hex.chars
699// not_values is needed because the operation complement/except
700// not_values must always be inside size_constraint set, has_values must be outside of size_constraint set
701// canonical form can be obtained by simplifying value list constraints into size constraints
702// and by converting not_values information into the other two sets if number of not values is >= [number of all values for L] / 2
703// for length(L) there must be exactly N^L number of values that have length=L, where an element can have N different values
704// where N = 2^BITCNT, BITCNT is the number of bits needed to store one element, works for BITCNT=1,4,8
705// for octetstrings one octet element is 2 chars long, for others one element is one char, real size of string = elem.size()/ELEMSIZE
706template<unsigned char BITCNT, unsigned short ELEMSIZE>
707class StringSizeAndValueListConstraint
708{
709private:
710 SizeRangeListConstraint size_constraint;
711 map<string,void> has_values, not_values;
712 void clean_up();
713 void copy_content(const StringSizeAndValueListConstraint& other);
714 void canonicalize(map<string,void>& values, map<string,void>& other_values, bool if_values);
715 void canonicalize();
716public:
717 // constructors
718 StringSizeAndValueListConstraint() {} // empty set
719 StringSizeAndValueListConstraint(const string& s); // single value set
720 StringSizeAndValueListConstraint(const size_limit_t& sl): size_constraint(sl) {} // single size value set
721 StringSizeAndValueListConstraint(const size_limit_t& rl_begin, const size_limit_t& rl_end): size_constraint(rl_begin,rl_end) {} // size range set
722 StringSizeAndValueListConstraint(const SizeRangeListConstraint& p_size_constraint): size_constraint(p_size_constraint) {}
723 StringSizeAndValueListConstraint(const StringSizeAndValueListConstraint& other) { copy_content(other); }
724 StringSizeAndValueListConstraint& operator=(const StringSizeAndValueListConstraint& other) { clean_up(); copy_content(other); return *this; }
725 ~StringSizeAndValueListConstraint() { clean_up(); }
726
727 tribool is_empty() const { return ( size_constraint.is_empty() && TRIBOOL(has_values.size()==0) ); }
728 tribool is_full() const { return ( size_constraint.is_full() && TRIBOOL(not_values.size()==0) ); }
729 tribool is_equal(const StringSizeAndValueListConstraint& other) const;
730 bool is_element(const string& s) const;
731
732 StringSizeAndValueListConstraint set_operation(const StringSizeAndValueListConstraint& other, bool is_union) const;
733
734 StringSizeAndValueListConstraint operator+(const StringSizeAndValueListConstraint& other) const { return set_operation(other, true); } // union
735 StringSizeAndValueListConstraint operator*(const StringSizeAndValueListConstraint& other) const { return set_operation(other, false); } // intersection
736 StringSizeAndValueListConstraint operator~() const; // complement
737
738 tribool is_subset(const StringSizeAndValueListConstraint& other) const { return (*this*~other).is_empty(); }
739 StringSizeAndValueListConstraint operator-(const StringSizeAndValueListConstraint& other) const { return ( *this * ~other ); } // except
740
741 tribool get_size_limit(bool is_upper, size_limit_t& limit) const;
742
743 string to_string() const;
744};
745
746template<unsigned char BITCNT, unsigned short ELEMSIZE>
747tribool StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::get_size_limit(bool is_upper, size_limit_t& limit) const
748{
749 if (size_constraint.is_empty()==TTRUE) return TFALSE;
750 limit = is_upper ? size_constraint.get_maximal() : size_constraint.get_minimal();
751 return TTRUE;
752}
753
754template<unsigned char BITCNT, unsigned short ELEMSIZE>
755void StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::clean_up()
756{
757 size_constraint = SizeRangeListConstraint();
758 has_values.clear();
759 not_values.clear();
760}
761
762template<unsigned char BITCNT, unsigned short ELEMSIZE>
763void StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::copy_content(const StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>& other)
764{
765 size_constraint = other.size_constraint;
766 for (size_t i=0; i<other.has_values.size(); i++) has_values.add(other.has_values.get_nth_key(i),NULL);
767 for (size_t i=0; i<other.not_values.size(); i++) not_values.add(other.not_values.get_nth_key(i),NULL);
768}
769
770template<unsigned char BITCNT, unsigned short ELEMSIZE>
771StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::StringSizeAndValueListConstraint(const string& s)
772{
773 if (s.size() % ELEMSIZE != 0) FATAL_ERROR("StringSizeAndValueListConstraint::StringSizeAndValueListConstraint()");
774 if (BITCNT==1) {
775 for (size_t i=0; i<s.size(); i++)
776 if ( (s[i]!='0') && (s[i]!='1') ) FATAL_ERROR("StringSizeAndValueListConstraint::StringSizeAndValueListConstraint()");
777 } else if ( (BITCNT==4) || (BITCNT==8) ) {
778 for (size_t i=0; i<s.size(); i++)
779 if ( !((s[i]>='0')&&(s[i]<='9')) && !((s[i]>='A')&&(s[i]<='F')) )
780 FATAL_ERROR("StringSizeAndValueListConstraint::StringSizeAndValueListConstraint()");
781 } else {
782 FATAL_ERROR("StringSizeAndValueListConstraint::StringSizeAndValueListConstraint()");
783 }
784 has_values.add(s,NULL);
785}
786
787template<unsigned char BITCNT, unsigned short ELEMSIZE>
788void StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::canonicalize(map<string,void>& values, map<string,void>& other_values, bool if_values)
789{
790 map<size_t,size_t> values_lengths; // length -> number of values
791 for (size_t i=0; i<values.size(); i++) {
792 size_t value_size = values.get_nth_key(i).size()/ELEMSIZE;
793 if (values_lengths.has_key(value_size)) (*values_lengths[value_size])++;
794 else values_lengths.add(value_size,new size_t(1));
795 }
796
797 for (size_t i=0; i<values_lengths.size(); i++) {
798 // calculate the number of all possible values
799 size_t size = values_lengths.get_nth_key(i); // length of string
800 size_t count = *(values_lengths.get_nth_elem(i)); // number of strings with this length
801 size_t all_values_count = ~((size_t)0); // fake infinity
802 if (BITCNT*size<sizeof(size_t)*8) all_values_count = ( ((size_t)1) << (BITCNT*size) );
803 if (count==all_values_count) {
804 // delete all values which have this size
805 for (size_t hv_idx=0; hv_idx<values.size(); hv_idx++) {
806 if ((values.get_nth_key(hv_idx).size()/ELEMSIZE)==size) {
807 values.erase(values.get_nth_key(hv_idx));
808 hv_idx--;
809 }
810 }
811 // add/remove a single value size constraint with this size
812 if (if_values) size_constraint = size_constraint + SizeRangeListConstraint(size_limit_t(size));
813 else size_constraint = size_constraint - SizeRangeListConstraint(size_limit_t(size));
814 } else
815 if ( (!if_values && (count>=all_values_count/2)) || (if_values && (count>all_values_count/2)) ) {
816 // add to other_values the complement of these values on the set with this size
817 for (size_t act_value=0; act_value<all_values_count; act_value++) {
818 string str; // for each value of act_value there is corresponding string value str
819 for (size_t elem_idx=0; elem_idx<size; elem_idx++) { // for every element
820 size_t ei = ( ( act_value >> (elem_idx*BITCNT) ) & ( (1<<BITCNT) - 1 ) );
821 if (BITCNT==1) {
822 str += '0' + (char)ei;
823 } else if (BITCNT==4) {
824 str += (ei<10) ? ('0' + (char)ei) : ('A' + ((char)ei-10));
825 } else if (BITCNT==8) {
826 char c = ei & 0x0F;
827 str += (c<10) ? ('0' + c) : ('A' + (c-10));
828 c = (ei >> (BITCNT/ELEMSIZE)) & 0x0F;
829 str += (c<10) ? ('0' + c) : ('A' + (c-10));
830 } else {
831 FATAL_ERROR("StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::canonicalize()");
832 }
833 }
834 // if str is not element of values then add to other_values
835 if (!values.has_key(str)) other_values.add(str,NULL);
836 }
837 // delete all values which have this size
838 for (size_t hv_idx=0; hv_idx<values.size(); hv_idx++) {
839 if ((values.get_nth_key(hv_idx).size()/ELEMSIZE)==size) {
840 values.erase(values.get_nth_key(hv_idx));
841 hv_idx--;
842 }
843 }
844 // add/remove a single value size constraint with this size
845 if (if_values) size_constraint = size_constraint + SizeRangeListConstraint(size_limit_t(size));
846 else size_constraint = size_constraint - SizeRangeListConstraint(size_limit_t(size));
847 }
848 }
849 // clean up
850 for (size_t i=0; i<values_lengths.size(); i++) delete (values_lengths.get_nth_elem(i));
851 values_lengths.clear();
852}
853
854template<unsigned char BITCNT, unsigned short ELEMSIZE>
855void StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::canonicalize()
856{
857 canonicalize(has_values, not_values, true);
858 canonicalize(not_values, has_values, false);
859}
860
861template<unsigned char BITCNT, unsigned short ELEMSIZE>
862tribool StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::is_equal(const StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>& other) const
863{
864 if (size_constraint.is_equal(other.size_constraint)==TFALSE) return TFALSE;
865 if (has_values.size()!=other.has_values.size()) return TFALSE;
866 if (not_values.size()!=other.not_values.size()) return TFALSE;
867 for (size_t i=0; i<has_values.size(); i++) if (has_values.get_nth_key(i)!=other.has_values.get_nth_key(i)) return TFALSE;
868 for (size_t i=0; i<not_values.size(); i++) if (not_values.get_nth_key(i)!=other.not_values.get_nth_key(i)) return TFALSE;
869 return TTRUE;
870}
871
872template<unsigned char BITCNT, unsigned short ELEMSIZE>
873bool StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::is_element(const string& s) const
874{
875 return ( ( size_constraint.is_element(s.size()/ELEMSIZE) && !not_values.has_key(s) ) || has_values.has_key(s) );
876}
877
878// representation of two sets: [Si+Vi-Ni] where Si=size_constraint, Vi=has_values, Ni=not_values
879// UNION: [S1+V1-N1] + [S2+V2-N2] = ... = [(S1+S2)+(V1+V2)-((~S1*N2)+(N1*~S2)+(N1*N2))]
880// INTERSECTION: [S1+V1-N1] * [S2+V2-N2] = ... = [(S1*S2)+((S1*V2-N1)+(S2*V1-N2)+(V1*V2))-(N1+N2)]
881template<unsigned char BITCNT, unsigned short ELEMSIZE>
882StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>
883 StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::
884 set_operation(const StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>& other, bool is_union) const
885{
886 StringSizeAndValueListConstraint<BITCNT,ELEMSIZE> ret_val;
887 ret_val.size_constraint = size_constraint.set_operation(other.size_constraint, is_union);
888 if (is_union) {
889 // V1+V2 (union of has_values)
890 for (size_t i=0; i<has_values.size(); i++) ret_val.has_values.add(has_values.get_nth_key(i),NULL);
891 for (size_t i=0; i<other.has_values.size(); i++) {
892 const string& str = other.has_values.get_nth_key(i);
893 if (!ret_val.has_values.has_key(str)) ret_val.has_values.add(str,NULL);
894 }
895 // N1*N2 (intersection of not_values)
896 for (size_t i=0; i<not_values.size(); i++) {
897 const string& str = not_values.get_nth_key(i);
898 if (other.not_values.has_key(str)) ret_val.not_values.add(str,NULL);
899 }
900 // ~S1*N2
901 for (size_t i=0; i<other.not_values.size(); i++) {
902 const string& str = other.not_values.get_nth_key(i);
903 if (!size_constraint.is_element(size_limit_t(str.size()/ELEMSIZE)) &&
904 !ret_val.not_values.has_key(str)) ret_val.not_values.add(str,NULL);
905 }
906 // N1*~S2
907 for (size_t i=0; i<not_values.size(); i++) {
908 const string& str = not_values.get_nth_key(i);
909 if (!other.size_constraint.is_element(size_limit_t(str.size()/ELEMSIZE)) &&
910 !ret_val.not_values.has_key(str)) ret_val.not_values.add(str,NULL);
911 }
912 } else { // intersection
913 // V1*V2 (intersection of has_values)
914 for (size_t i=0; i<has_values.size(); i++) {
915 const string& str = has_values.get_nth_key(i);
916 if (other.has_values.has_key(str)) ret_val.has_values.add(str,NULL);
917 }
918 // S2*V1-N2
919 for (size_t i=0; i<has_values.size(); i++) {
920 const string& str = has_values.get_nth_key(i);
921 if (other.size_constraint.is_element(size_limit_t(str.size()/ELEMSIZE)) &&
922 !other.not_values.has_key(str) &&
923 !ret_val.has_values.has_key(str)) ret_val.has_values.add(str,NULL);
924 }
925 // S1*V2-N1
926 for (size_t i=0; i<other.has_values.size(); i++) {
927 const string& str = other.has_values.get_nth_key(i);
928 if (size_constraint.is_element(size_limit_t(str.size()/ELEMSIZE)) &&
929 !not_values.has_key(str) &&
930 !ret_val.has_values.has_key(str)) ret_val.has_values.add(str,NULL);
931 }
932 // N1+N2 (union of not_values)
933 for (size_t i=0; i<not_values.size(); i++) ret_val.not_values.add(not_values.get_nth_key(i),NULL);
934 for (size_t i=0; i<other.not_values.size(); i++) {
935 const string& str = other.not_values.get_nth_key(i);
936 if (!ret_val.not_values.has_key(str)) ret_val.not_values.add(str,NULL);
937 }
938 }
939 {
940 // drop ret_val.has_values that are elements of ret_val.not_values too, drop from ret_val.not_values too
941 for (size_t i=0; i<ret_val.not_values.size(); i++) {
942 string str = ret_val.not_values.get_nth_key(i);
943 if (ret_val.has_values.has_key(str)) {
944 ret_val.has_values.erase(str);
945 ret_val.not_values.erase(str);
946 i--;
947 }
948 }
949 // drop ret_val.has_values elements that are elements of the ret_val.size_constraint set
950 for (size_t i=0; i<ret_val.has_values.size(); i++) {
951 string str = ret_val.has_values.get_nth_key(i);
952 if (ret_val.size_constraint.is_element(size_limit_t(str.size()/ELEMSIZE))) {
953 ret_val.has_values.erase(str);
954 i--;
955 }
956 }
957 // drop ret_val.not_values elements that are not elements of the ret_val.size_constraint set
958 for (size_t i=0; i<ret_val.not_values.size(); i++) {
959 string str = ret_val.not_values.get_nth_key(i);
960 if (!ret_val.size_constraint.is_element(size_limit_t(str.size()/ELEMSIZE))) {
961 ret_val.not_values.erase(str);
962 i--;
963 }
964 }
965 }
966 ret_val.canonicalize();
967 return ret_val;
968}
969
970template<unsigned char BITCNT, unsigned short ELEMSIZE>
971StringSizeAndValueListConstraint<BITCNT,ELEMSIZE> StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::operator~() const
972{
973 StringSizeAndValueListConstraint<BITCNT,ELEMSIZE> ret_val;
974 ret_val.size_constraint = ~size_constraint;
975 for (size_t i=0; i<has_values.size(); i++) ret_val.not_values.add(has_values.get_nth_key(i),NULL);
976 for (size_t i=0; i<not_values.size(); i++) ret_val.has_values.add(not_values.get_nth_key(i),NULL);
977 ret_val.canonicalize();
978 return ret_val;
979}
980
981template<unsigned char BITCNT, unsigned short ELEMSIZE>
982string StringSizeAndValueListConstraint<BITCNT,ELEMSIZE>::to_string() const
983{
984 string ret_val;
985 if (has_values.size()>0) {
986 ret_val += '(';
987 for (size_t i=0; i<has_values.size(); i++) {
988 if (i>0) ret_val += ',';
989 ret_val += '\'';
990 ret_val += has_values.get_nth_key(i);
991 ret_val += '\'';
992 if (BITCNT==1) ret_val += 'B';
993 else if (BITCNT==4) ret_val += 'H';
994 else if (BITCNT==8) ret_val += 'O';
995 }
996 ret_val += ')';
997 }
998 // size constraint
999 if (size_constraint.is_empty()!=TTRUE) {
1000 if (has_values.size()>0) ret_val += " union ";
1001 ret_val += "length";
1002 ret_val += size_constraint.to_string();
1003 }
1004 // except not_values
1005 if (not_values.size()>0) {
1006 ret_val += " except (";
1007 for (size_t i=0; i<not_values.size(); i++) {
1008 if (i>0) ret_val += ',';
1009 ret_val += '\'';
1010 ret_val += not_values.get_nth_key(i);
1011 ret_val += '\'';
1012 if (BITCNT==1) ret_val += 'B';
1013 else if (BITCNT==4) ret_val += 'H';
1014 else if (BITCNT==8) ret_val += 'O';
1015 }
1016 ret_val += ')';
1017 }
1018 return ret_val;
1019}
1020
1021typedef StringSizeAndValueListConstraint<1,1> BitstringConstraint;
1022typedef StringSizeAndValueListConstraint<4,1> HexstringConstraint;
1023typedef StringSizeAndValueListConstraint<8,2> OctetstringConstraint; // one char is half octet
1024
1025////////////////////////////////////////////////////////////////////////////////
1026
1027class StringPatternConstraint
1028{
1029private:
1030 Ttcn::PatternString* pattern; // not owned
1031public:
1032 // constructors
1033 StringPatternConstraint() : pattern(0) {} // empty set
1034 StringPatternConstraint(Ttcn::PatternString* p): pattern(p) {}
1035
1036 tribool is_empty() const { return TUNKNOWN; }
1037 tribool is_full() const { return TUNKNOWN; }
1038 tribool is_equal(const StringPatternConstraint&) const { return TUNKNOWN; }
1039
1040 tribool match(const string& str) const;
1041 tribool match(const ustring&) const { return TUNKNOWN; } // TODO
1042
1043 StringPatternConstraint set_operation(const StringPatternConstraint&, bool) const { FATAL_ERROR("StringPatternConstraint::set_operation(): not implemented"); }
1044
1045 StringPatternConstraint operator+(const StringPatternConstraint& other) const { return set_operation(other, true); } // union
1046 StringPatternConstraint operator*(const StringPatternConstraint& other) const { return set_operation(other, false); } // intersection
1047 StringPatternConstraint operator~() const { FATAL_ERROR("StringPatternConstraint::operator~(): not implemented"); }
1048
1049 tribool is_subset(const StringPatternConstraint&) const { return TUNKNOWN; }
1050 StringPatternConstraint operator-(const StringPatternConstraint& other) const { return ( *this * ~other ); } // except
1051
1052 string to_string() const;
1053};
1054
1055////////////////////////////////////////////////////////////////////////////////
1056
1057template <class STRINGTYPE>
1058class StringValueConstraint
1059{
1060private:
1061 map<STRINGTYPE,void> values;
1062 void clean_up();
1063 void copy_content(const StringValueConstraint& other);
1064public:
1065 // constructors
1066 StringValueConstraint() {} // empty set
1067 StringValueConstraint(const STRINGTYPE& s) { values.add(s,NULL); } // single value set
1068
1069 StringValueConstraint(const StringValueConstraint& other) { copy_content(other); }
1070 StringValueConstraint& operator=(const StringValueConstraint& other) { clean_up(); copy_content(other); return *this; }
1071 ~StringValueConstraint() { clean_up(); }
1072
1073 tribool is_empty() const { return TRIBOOL(values.size()==0); }
1074 tribool is_full() const { return TFALSE; }
1075 tribool is_equal(const StringValueConstraint& other) const;
1076 bool is_element(const STRINGTYPE& s) const { return values.has_key(s); }
1077
1078 StringValueConstraint set_operation(const StringValueConstraint& other, bool is_union) const;
1079
1080 StringValueConstraint operator+(const StringValueConstraint& other) const { return set_operation(other, true); } // union
1081 StringValueConstraint operator*(const StringValueConstraint& other) const { return set_operation(other, false); } // intersection
1082
1083 tribool is_subset(const StringValueConstraint& other) const { return (*this-other).is_empty(); }
1084 StringValueConstraint operator-(const StringValueConstraint& other) const; // except
1085
1086 // remove strings that are or are not elements of the set defined by the XXX_constraint object,
1087 // using the XXX_constraint.is_element() member function
1088 void remove(const SizeRangeListConstraint& size_constraint, bool if_element);
1089 template <class CHARLIMITTYPE> void remove(const RangeListConstraint<CHARLIMITTYPE>& alphabet_constraint, bool if_element);
1090 void remove(const StringPatternConstraint& pattern_constraint, bool if_element);
1091
1092 string to_string() const;
1093};
1094
1095template <class STRINGTYPE>
1096void StringValueConstraint<STRINGTYPE>::clean_up()
1097{
1098 values.clear();
1099}
1100
1101template <class STRINGTYPE>
1102void StringValueConstraint<STRINGTYPE>::copy_content(const StringValueConstraint<STRINGTYPE>& other)
1103{
1104 for (size_t i=0; i<other.values.size(); i++) values.add(other.values.get_nth_key(i),NULL);
1105}
1106
1107template <class STRINGTYPE>
1108tribool StringValueConstraint<STRINGTYPE>::is_equal(const StringValueConstraint<STRINGTYPE>& other) const
1109{
1110 if (values.size()!=other.values.size()) return TFALSE;
1111 for (size_t i=0; i<values.size(); i++) {
1112 if (values.get_nth_key(i)!=other.values.get_nth_key(i)) return TFALSE;
1113 }
1114 return TTRUE;
1115}
1116
1117template <class STRINGTYPE>
1118StringValueConstraint<STRINGTYPE> StringValueConstraint<STRINGTYPE>::set_operation
1119 (const StringValueConstraint<STRINGTYPE>& other, bool is_union) const
1120{
1121 StringValueConstraint<STRINGTYPE> ret_val;
1122 if (is_union) {
1123 for (size_t i=0; i<values.size(); i++) ret_val.values.add(values.get_nth_key(i), NULL);
1124 for (size_t i=0; i<other.values.size(); i++) {
1125 const STRINGTYPE& str = other.values.get_nth_key(i);
1126 if (!ret_val.values.has_key(str)) ret_val.values.add(str, NULL);
1127 }
1128 } else {
1129 for (size_t i=0; i<values.size(); i++) {
1130 const STRINGTYPE& str = values.get_nth_key(i);
1131 if (other.values.has_key(str)) ret_val.values.add(str, NULL);
1132 }
1133 }
1134 return ret_val;
1135}
1136
1137template <class STRINGTYPE>
1138StringValueConstraint<STRINGTYPE> StringValueConstraint<STRINGTYPE>::operator-(const StringValueConstraint<STRINGTYPE>& other) const
1139{
1140 StringValueConstraint<STRINGTYPE> ret_val;
1141 for (size_t i=0; i<values.size(); i++) {
1142 const STRINGTYPE& str = values.get_nth_key(i);
1143 if (!other.values.has_key(str)) ret_val.values.add(str, NULL);
1144 }
1145 return ret_val;
1146}
1147
1148template <class STRINGTYPE>
1149void StringValueConstraint<STRINGTYPE>::remove(const SizeRangeListConstraint& size_constraint, bool if_element)
1150{
1151 for (size_t i=0; i<values.size(); i++) {
1152 STRINGTYPE str = values.get_nth_key(i);
1153 if (size_constraint.is_element(size_limit_t(str.size()))==if_element) {
1154 values.erase(str);
1155 i--;
1156 }
1157 }
1158}
1159
1160template <class STRINGTYPE>
1161template <class CHARLIMITTYPE>
1162void StringValueConstraint<STRINGTYPE>::remove(const RangeListConstraint<CHARLIMITTYPE>& alphabet_constraint, bool if_element)
1163{
1164 for (size_t i=0; i<values.size(); i++) {
1165 STRINGTYPE str = values.get_nth_key(i);
1166 bool all_chars_are_elements = true;
1167 for (size_t chr_idx=0; chr_idx<str.size(); chr_idx++)
1168 {
1169 if (!alphabet_constraint.is_element(CHARLIMITTYPE(str[chr_idx]))) {
1170 all_chars_are_elements = false;
1171 break;
1172 }
1173 }
1174 if (all_chars_are_elements==if_element) {
1175 values.erase(str);
1176 i--;
1177 }
1178 }
1179}
1180
1181template <class STRINGTYPE>
1182void StringValueConstraint<STRINGTYPE>::remove(const StringPatternConstraint& pattern_constraint, bool if_element)
1183{
1184 for (size_t i=0; i<values.size(); i++) {
1185 STRINGTYPE str = values.get_nth_key(i);
1186 switch (pattern_constraint.match(str)) {
1187 case TFALSE:
1188 if (!if_element) { values.erase(str); i--; }
1189 break;
1190 case TUNKNOWN:
1191 break;
1192 case TTRUE:
1193 if (if_element) { values.erase(str); i--; }
1194 break;
1195 default:
1196 FATAL_ERROR("StringValueConstraint::remove(StringPatternConstraint)");
1197 }
1198 }
1199}
1200
1201template <class STRINGTYPE>
1202string StringValueConstraint<STRINGTYPE>::to_string() const
1203{
1204 string ret_val;
1205 ret_val += '(';
1206 for (size_t i=0; i<values.size(); i++) {
1207 if (i>0) ret_val += ',';
1208 STRINGTYPE str = values.get_nth_key(i);
1209 ret_val += str.get_stringRepr();
1210 }
1211 ret_val += ')';
1212 return ret_val;
1213}
1214
1215////////////////////////////////////////////////////////////////////////////////
1216
1217// contains a tree of subtype constraints
1218template <class STRINGTYPE, class CHARLIMITTYPE>
1219class StringSubtypeTreeElement
1220{
1221public:
1222 enum elementtype_t {
1223 ET_NONE, // empty set
1224 ET_ALL, // all values of the root type, no subtype constraint was given, other data members have no meaning
1225 ET_CONSTRAINT, // constraint value
1226 ET_INTERSECTION, // A intersection B
1227 ET_UNION, // A union B
1228 ET_EXCEPT // A except B
1229 };
1230 enum constrainttype_t {
1231 CT_SIZE,
1232 CT_ALPHABET,
1233 CT_VALUES,
1234 CT_PATTERN
1235 };
1236private:
1237 elementtype_t elementtype;
1238 union {
1239 struct { // operation (ET_INTERSECTION, ET_UNION, ET_EXCEPT)
1240 StringSubtypeTreeElement* a; // owned
1241 StringSubtypeTreeElement* b; // owned
1242 } op;
1243 struct { // constraint
1244 constrainttype_t constrainttype;
1245 union { // constraint objects are owned
1246 SizeRangeListConstraint* s; // size/length constraint type
1247 struct {
1248 RangeListConstraint<CHARLIMITTYPE>* c; // range/alphabet constraint type
1249 bool char_context; // this constraint can be either in char or string context
1250 // char context is constraining a single char,
1251 // string context is constraining a string
1252 // this bool value affects evaluation
1253 // in char context only range,all,none and operation
1254 // constructors can be called, operations must always evaluate
1255 // to range, all or none
1256 } a;
1257 StringValueConstraint<STRINGTYPE>* v; // value set constraint
1258 StringPatternConstraint* p; // pattern constraint
1259 };
1260 } cs;
1261 } u;
1262 void clean_up();
1263 void copy_content(const StringSubtypeTreeElement& other); // *this must be empty
1264 void set_to_operand(bool operand_a);
1265 void simplify(); // convert to ET_NONE or ET_ALL if possible
1266 void evaluate(); // tries to evaluate a tree to a single constraint, works recursively for the whole tree
1267public:
1268 StringSubtypeTreeElement(): elementtype(ET_NONE) {}
1269 StringSubtypeTreeElement(elementtype_t p_elementtype, StringSubtypeTreeElement* p_a, StringSubtypeTreeElement* p_b);
1270 StringSubtypeTreeElement(const SizeRangeListConstraint& p_s);
1271 StringSubtypeTreeElement(const RangeListConstraint<CHARLIMITTYPE>& p_a, bool p_char_context);
1272 StringSubtypeTreeElement(const StringValueConstraint<STRINGTYPE>& p_v);
1273 StringSubtypeTreeElement(const StringPatternConstraint& p_p);
1274
1275 StringSubtypeTreeElement(const StringSubtypeTreeElement& p) { copy_content(p); }
1276 StringSubtypeTreeElement& operator=(const StringSubtypeTreeElement& other) { clean_up(); copy_content(other); return *this; }
1277 ~StringSubtypeTreeElement() { clean_up(); }
1278
1279 tribool is_empty() const;
1280 tribool is_full() const;
1281 tribool is_equal(const StringSubtypeTreeElement* other) const;
1282 bool is_element(const STRINGTYPE& s) const;
1283 tribool is_subset(const StringSubtypeTreeElement* other) const;
1284
1285 bool is_single_constraint() const { return ( (elementtype==ET_CONSTRAINT) || (elementtype==ET_NONE) || (elementtype==ET_ALL) ); }
1286 void set_none() { clean_up(); elementtype = ET_NONE; }
1287 void set_all() { clean_up(); elementtype = ET_ALL; }
1288
1289 /** return value:
1290 TFALSE: limit does not exist (empty set or values, ...)
1291 TUNKNOWN: limit cannot be determined
1292 TTRUE: limit was set to the proper value */
1293 tribool get_alphabet_limit(bool is_upper, CHARLIMITTYPE& limit) const;
1294 tribool get_size_limit(bool is_upper, size_limit_t& limit) const;
1295
1296 bool is_valid_range() const;
1297 void set_char_context(bool p_char_context);
1298
1299 string to_string() const;
1300};
1301
1302template <class STRINGTYPE, class CHARLIMITTYPE>
1303StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::StringSubtypeTreeElement(elementtype_t p_elementtype, StringSubtypeTreeElement* p_a, StringSubtypeTreeElement* p_b)
1304: elementtype(p_elementtype)
1305{
1306 switch (elementtype) {
1307 case ET_INTERSECTION:
1308 case ET_UNION:
1309 case ET_EXCEPT:
1310 break;
1311 default:
1312 FATAL_ERROR("StringSubtypeTreeElement::StringSubtypeTreeElement()");
1313 }
1314 u.op.a = p_a;
1315 u.op.b = p_b;
1316 evaluate();
1317}
1318
1319
1320template <class STRINGTYPE, class CHARLIMITTYPE>
1321tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::
1322 get_alphabet_limit(bool is_upper, CHARLIMITTYPE& limit) const
1323{
1324 switch (elementtype) {
1325 case ET_NONE:
1326 return TFALSE;
1327 case ET_ALL:
1328 limit = is_upper ? CHARLIMITTYPE::maximum : CHARLIMITTYPE::minimum;
1329 return TTRUE;
1330 case ET_CONSTRAINT:
1331 switch (u.cs.constrainttype) {
1332 case CT_SIZE:
1333 limit = is_upper ? CHARLIMITTYPE::maximum : CHARLIMITTYPE::minimum;
1334 return TTRUE;
1335 case CT_ALPHABET:
1336 if (u.cs.a.c->is_empty()==TTRUE) return TFALSE;
1337 limit = is_upper ? u.cs.a.c->get_maximal() : u.cs.a.c->get_minimal();
1338 return TTRUE;
1339 case CT_VALUES:
1340 return TFALSE;
1341 case CT_PATTERN:
1342 return TUNKNOWN;
1343 default:
1344 FATAL_ERROR("StringSubtypeTreeElement::get_alphabet_limit()");
1345 }
1346 case ET_INTERSECTION: {
1347 CHARLIMITTYPE la, lb;
1348 tribool tb = u.op.a->get_alphabet_limit(is_upper, la) && u.op.b->get_alphabet_limit(is_upper, lb);
1349 if (tb==TTRUE) {
1350 limit = ((lb<la) ^ !is_upper) ? lb : la;
1351 }
1352 return tb;
1353 }
1354 case ET_UNION:
1355 case ET_EXCEPT:
1356 return TUNKNOWN;
1357 default:
1358 FATAL_ERROR("StringSubtypeTreeElement::get_alphabet_limit()");
1359 }
1360 return TUNKNOWN;
1361}
1362
1363template <class STRINGTYPE, class CHARLIMITTYPE>
1364tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::
1365 get_size_limit(bool is_upper, size_limit_t& limit) const
1366{
1367 switch (elementtype) {
1368 case ET_NONE:
1369 return TFALSE;
1370 case ET_ALL:
1371 limit = is_upper ? size_limit_t::maximum : size_limit_t::minimum;
1372 return TTRUE;
1373 case ET_CONSTRAINT:
1374 switch (u.cs.constrainttype) {
1375 case CT_SIZE:
1376 if (u.cs.s->is_empty()==TTRUE) return TFALSE;
1377 limit = is_upper ? u.cs.s->get_maximal() : u.cs.s->get_minimal();
1378 return TTRUE;
1379 case CT_ALPHABET:
1380 limit = is_upper ? size_limit_t::maximum : size_limit_t::minimum;
1381 return TTRUE;
1382 case CT_VALUES:
1383 return TFALSE;
1384 case CT_PATTERN:
1385 return TUNKNOWN;
1386 default:
1387 FATAL_ERROR("StringSubtypeTreeElement::get_size_limit()");
1388 }
1389 case ET_INTERSECTION: {
1390 size_limit_t la, lb;
1391 tribool tb = u.op.a->get_size_limit(is_upper, la) && u.op.b->get_size_limit(is_upper, lb);
1392 if (tb==TTRUE) {
1393 limit = ((lb<la) ^ !is_upper) ? lb : la;
1394 }
1395 return tb;
1396 }
1397 case ET_UNION:
1398 case ET_EXCEPT:
1399 return TUNKNOWN;
1400 default:
1401 FATAL_ERROR("StringSubtypeTreeElement::get_size_limit()");
1402 }
1403 return TUNKNOWN;
1404}
1405
1406template <class STRINGTYPE, class CHARLIMITTYPE>
1407bool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_valid_range() const
1408{
1409 switch (elementtype) {
1410 case ET_NONE:
1411 case ET_ALL:
1412 return true;
1413 case ET_CONSTRAINT:
1414 switch (u.cs.constrainttype) {
1415 case CT_SIZE:
1416 // must be SIZE(1)
1417 return (u.cs.s->is_equal(SizeRangeListConstraint(size_limit_t(1)))==TTRUE);
1418 case CT_ALPHABET:
1419 return true;
1420 case CT_VALUES:
1421 case CT_PATTERN:
1422 return false;
1423 default:
1424 FATAL_ERROR("StringSubtypeTreeElement::is_valid_range()");
1425 }
1426 case ET_INTERSECTION:
1427 case ET_UNION:
1428 case ET_EXCEPT:
1429 return ( u.op.a->is_valid_range() && u.op.b->is_valid_range() );
1430 default:
1431 FATAL_ERROR("StringSubtypeTreeElement::is_valid_range()");
1432 }
1433 return false;
1434}
1435
1436template <class STRINGTYPE, class CHARLIMITTYPE>
1437void StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::set_char_context(bool p_char_context)
1438{
1439 switch (elementtype) {
1440 case ET_NONE:
1441 case ET_ALL:
1442 break;
1443 case ET_CONSTRAINT:
1444 u.cs.a.char_context = p_char_context;
1445 switch (u.cs.constrainttype) {
1446 case CT_SIZE:
1447 if (p_char_context) set_all(); // false -> true
1448 else FATAL_ERROR("StringSubtypeTreeElement::set_char_context()");
1449 case CT_ALPHABET:
1450 break;
1451 default:
1452 FATAL_ERROR("StringSubtypeTreeElement::set_char_context()");
1453 }
1454 break;
1455 case ET_INTERSECTION:
1456 case ET_UNION:
1457 case ET_EXCEPT:
1458 u.op.a->set_char_context(p_char_context);
1459 u.op.b->set_char_context(p_char_context);
1460 break;
1461 default:
1462 FATAL_ERROR("StringSubtypeTreeElement::set_char_context()");
1463 }
1464}
1465
1466template <class STRINGTYPE, class CHARLIMITTYPE>
1467StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::StringSubtypeTreeElement
1468 (const SizeRangeListConstraint& p_s):
1469 elementtype(ET_CONSTRAINT)
1470{
1471 u.cs.constrainttype = CT_SIZE;
1472 u.cs.s = new SizeRangeListConstraint(p_s);
1473 simplify();
1474}
1475
1476template <class STRINGTYPE, class CHARLIMITTYPE>
1477StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::StringSubtypeTreeElement
1478 (const RangeListConstraint<CHARLIMITTYPE>& p_a, bool p_char_context):
1479 elementtype(ET_CONSTRAINT)
1480{
1481 u.cs.constrainttype = CT_ALPHABET;
1482 u.cs.a.c = new RangeListConstraint<CHARLIMITTYPE>(p_a);
1483 u.cs.a.char_context = p_char_context;
1484 simplify();
1485}
1486
1487template <class STRINGTYPE, class CHARLIMITTYPE>
1488StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::StringSubtypeTreeElement
1489 (const StringValueConstraint<STRINGTYPE>& p_v):
1490 elementtype(ET_CONSTRAINT)
1491{
1492 u.cs.constrainttype = CT_VALUES;
1493 u.cs.v = new StringValueConstraint<STRINGTYPE>(p_v);
1494 simplify();
1495}
1496
1497template <class STRINGTYPE, class CHARLIMITTYPE>
1498StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::StringSubtypeTreeElement
1499 (const StringPatternConstraint& p_p):
1500 elementtype(ET_CONSTRAINT)
1501{
1502 u.cs.constrainttype = CT_PATTERN;
1503 u.cs.p = new StringPatternConstraint(p_p);
1504 simplify();
1505}
1506
1507template <class STRINGTYPE, class CHARLIMITTYPE>
1508void StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::clean_up()
1509{
1510 switch (elementtype) {
1511 case ET_NONE:
1512 case ET_ALL:
1513 break;
1514 case ET_CONSTRAINT:
1515 switch (u.cs.constrainttype) {
1516 case CT_SIZE: delete u.cs.s; break;
1517 case CT_ALPHABET: delete u.cs.a.c; break;
1518 case CT_VALUES: delete u.cs.v; break;
1519 case CT_PATTERN: delete u.cs.p; break;
1520 default: FATAL_ERROR("StringSubtypeTreeElement::clean_up()");
1521 }
1522 break;
1523 case ET_INTERSECTION:
1524 case ET_UNION:
1525 case ET_EXCEPT:
1526 delete u.op.a;
1527 delete u.op.b;
1528 break;
1529 default:
1530 FATAL_ERROR("StringSubtypeTreeElement::clean_up()");
1531 }
1532}
1533
1534template <class STRINGTYPE, class CHARLIMITTYPE>
1535void StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::copy_content(const StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>& other)
1536{
1537 elementtype = other.elementtype;
1538 switch (elementtype) {
1539 case ET_NONE:
1540 case ET_ALL:
1541 break;
1542 case ET_CONSTRAINT:
1543 u.cs.constrainttype = other.u.cs.constrainttype;
1544 switch (u.cs.constrainttype) {
1545 case CT_SIZE: u.cs.s = new SizeRangeListConstraint(*(other.u.cs.s)); break;
1546 case CT_ALPHABET:
1547 u.cs.a.c = new RangeListConstraint<CHARLIMITTYPE>(*(other.u.cs.a.c));
1548 u.cs.a.char_context = other.u.cs.a.char_context;
1549 break;
1550 case CT_VALUES: u.cs.v = new StringValueConstraint<STRINGTYPE>(*(other.u.cs.v)); break;
1551 case CT_PATTERN: u.cs.p = new StringPatternConstraint(*(other.u.cs.p)); break;
1552 default: FATAL_ERROR("StringSubtypeTreeElement::copy_content()");
1553 }
1554 break;
1555 case ET_INTERSECTION:
1556 case ET_UNION:
1557 case ET_EXCEPT:
1558 u.op.a = new StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>(*(other.u.op.a));
1559 u.op.b = new StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>(*(other.u.op.b));
1560 break;
1561 default:
1562 FATAL_ERROR("StringSubtypeTreeElement::copy_content()");
1563 }
1564}
1565
1566template <class STRINGTYPE, class CHARLIMITTYPE>
1567void StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::set_to_operand(bool operand_a)
1568{
1569 switch (elementtype) {
1570 case ET_INTERSECTION:
1571 case ET_UNION:
1572 case ET_EXCEPT:
1573 break;
1574 default:
1575 FATAL_ERROR("StringSubtypeTreeElement::copy_operand()");
1576 }
1577 StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>* op;
1578 if (operand_a) {
1579 delete u.op.b;
1580 op = u.op.a;
1581 } else {
1582 delete u.op.a;
1583 op = u.op.b;
1584 }
1585 // steal the content of op into myself
1586 elementtype = op->elementtype;
1587 switch (elementtype) {
1588 case ET_NONE:
1589 case ET_ALL:
1590 break;
1591 case ET_CONSTRAINT:
1592 u.cs.constrainttype = op->u.cs.constrainttype;
1593 switch (u.cs.constrainttype) {
1594 case CT_SIZE: u.cs.s = op->u.cs.s; break;
1595 case CT_ALPHABET:
1596 u.cs.a.c = op->u.cs.a.c;
1597 u.cs.a.char_context = op->u.cs.a.char_context;
1598 break;
1599 case CT_VALUES: u.cs.v = op->u.cs.v; break;
1600 case CT_PATTERN: u.cs.p = op->u.cs.p; break;
1601 default: FATAL_ERROR("StringSubtypeTreeElement::copy_operand()");
1602 }
1603 break;
1604 case ET_INTERSECTION:
1605 case ET_UNION:
1606 case ET_EXCEPT:
1607 u.op.a = op->u.op.a;
1608 u.op.b = op->u.op.b;
1609 break;
1610 default:
1611 FATAL_ERROR("StringSubtypeTreeElement::copy_operand()");
1612 }
1613 // delete the empty op
1614 op->elementtype = ET_NONE;
1615 delete op;
1616}
1617
1618template <class STRINGTYPE, class CHARLIMITTYPE>
1619void StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::simplify()
1620{
1621 switch (elementtype) {
1622 case ET_NONE:
1623 case ET_ALL:
1624 break;
1625 case ET_CONSTRAINT:
1626 switch (u.cs.constrainttype) {
1627 case CT_SIZE:
1628 if (u.cs.s->is_empty()==TTRUE) { set_none(); return; }
1629 if (u.cs.s->is_full()==TTRUE) { set_all(); return; }
1630 break;
1631 case CT_ALPHABET:
1632 if (u.cs.a.c->is_empty()==TTRUE) { set_none(); return; }
1633 if (u.cs.a.c->is_full()==TTRUE) { set_all(); return; }
1634 break;
1635 case CT_VALUES:
1636 if (u.cs.v->is_empty()==TTRUE) { set_none(); return; }
1637 if (u.cs.v->is_full()==TTRUE) { set_all(); return; }
1638 break;
1639 case CT_PATTERN:
1640 if (u.cs.p->is_empty()==TTRUE) { set_none(); return; }
1641 if (u.cs.p->is_full()==TTRUE) { set_all(); return; }
1642 break;
1643 default: FATAL_ERROR("StringSubtypeTreeElement::simplify()");
1644 }
1645 break;
1646 case ET_INTERSECTION:
1647 case ET_UNION:
1648 case ET_EXCEPT:
1649 break;
1650 default:
1651 FATAL_ERROR("StringSubtypeTreeElement::simplify()");
1652 }
1653}
1654
1655template <class STRINGTYPE, class CHARLIMITTYPE>
1656tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_empty() const
1657{
1658 switch (elementtype) {
1659 case ET_NONE:
1660 return TTRUE;
1661 case ET_ALL:
1662 return TFALSE;
1663 case ET_CONSTRAINT:
1664 switch (u.cs.constrainttype) {
1665 case CT_SIZE: return u.cs.s->is_empty();
1666 case CT_ALPHABET: return ( u.cs.a.char_context ? u.cs.a.c->is_empty() : TFALSE );
1667 case CT_VALUES: return u.cs.v->is_empty();
1668 case CT_PATTERN: return u.cs.p->is_empty();
1669 default: FATAL_ERROR("StringSubtypeTreeElement::is_empty()");
1670 }
1671 case ET_INTERSECTION:
1672 return ( u.op.a->is_empty() || u.op.b->is_empty() );
1673 case ET_UNION:
1674 return ( u.op.a->is_empty() && u.op.b->is_empty() );
1675 case ET_EXCEPT: {
1676 tribool a_empty = u.op.a->is_empty();
1677 return ( (a_empty!=TFALSE) ? a_empty :
1678 ( (u.op.b->is_empty()==TTRUE) ? TFALSE : TUNKNOWN ) );
1679 }
1680 default:
1681 FATAL_ERROR("StringSubtypeTreeElement::is_empty()");
1682 }
1683 return TUNKNOWN;
1684}
1685
1686template <class STRINGTYPE, class CHARLIMITTYPE>
1687tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_full() const
1688{
1689 switch (elementtype) {
1690 case ET_NONE:
1691 return TFALSE;
1692 case ET_ALL:
1693 return TTRUE;
1694 case ET_CONSTRAINT:
1695 switch (u.cs.constrainttype) {
1696 case CT_SIZE: return u.cs.s->is_full();
1697 case CT_ALPHABET: return u.cs.a.c->is_full();
1698 case CT_VALUES: return u.cs.v->is_full();
1699 case CT_PATTERN: return u.cs.p->is_full();
1700 default: FATAL_ERROR("StringSubtypeTreeElement::is_full()");
1701 }
1702 case ET_INTERSECTION:
1703 return ( u.op.a->is_full() && u.op.b->is_full() );
1704 case ET_UNION:
1705 return ( u.op.a->is_full() || u.op.b->is_full() );
1706 case ET_EXCEPT:
1707 return ( u.op.a->is_full() && u.op.b->is_empty() );
1708 default:
1709 FATAL_ERROR("StringSubtypeTreeElement::is_full()");
1710 }
1711 return TUNKNOWN;
1712}
1713
1714template <class STRINGTYPE, class CHARLIMITTYPE>
1715tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_equal(const StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>* other) const
1716{
1717 if (elementtype!=other->elementtype) return TUNKNOWN;
1718 switch (elementtype) {
1719 case ET_NONE:
1720 case ET_ALL:
1721 return TTRUE;
1722 case ET_CONSTRAINT:
1723 if (u.cs.constrainttype!=other->u.cs.constrainttype) return TUNKNOWN;
1724 switch (u.cs.constrainttype) {
1725 case CT_SIZE: return u.cs.s->is_equal(*(other->u.cs.s));
1726 case CT_ALPHABET: return u.cs.a->is_equal(*(other->u.cs.a));
1727 case CT_VALUES: return u.cs.v->is_equal(*(other->u.cs.v));
1728 case CT_PATTERN: return u.cs.p->is_equal(*(other->u.cs.p));
1729 default: FATAL_ERROR("StringSubtypeTreeElement::is_equal()");
1730 }
1731 case ET_INTERSECTION:
1732 case ET_UNION:
1733 case ET_EXCEPT:
1734 return TUNKNOWN;
1735 default:
1736 FATAL_ERROR("StringSubtypeTreeElement::is_equal()");
1737 }
1738 return TUNKNOWN;
1739}
1740
1741template <class STRINGTYPE, class CHARLIMITTYPE>
1742bool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_element(const STRINGTYPE& s) const
1743{
1744 switch (elementtype) {
1745 case ET_NONE:
1746 return false;
1747 case ET_ALL:
1748 return true;
1749 case ET_CONSTRAINT:
1750 switch (u.cs.constrainttype) {
1751 case CT_SIZE: return u.cs.s->is_element(size_limit_t(s.size()));
1752 case CT_ALPHABET: {
1753 for (size_t i=0; i<s.size(); i++) {
1754 CHARLIMITTYPE cl(s[i]);
1755 if (!u.cs.a.c->is_element(cl)) return false;
1756 }
1757 return true;
1758 }
1759 case CT_VALUES: return u.cs.v->is_element(s);
1760 case CT_PATTERN: {
1761 switch (u.cs.p->match(s)) {
1762 case TFALSE: return false;
1763 case TUNKNOWN: return true; // don't know if it matches
1764 case TTRUE: return true;
1765 default: FATAL_ERROR("StringSubtypeTreeElement::is_element()");
1766 }
1767 }
1768 default: FATAL_ERROR("StringSubtypeTreeElement::is_element()");
1769 }
1770 case ET_INTERSECTION:
1771 return ( u.op.a->is_element(s) && u.op.b->is_element(s) );
1772 case ET_UNION:
1773 return ( u.op.a->is_element(s) || u.op.b->is_element(s) );
1774 case ET_EXCEPT:
1775 return ( u.op.a->is_element(s) && !u.op.b->is_element(s) );
1776 default:
1777 FATAL_ERROR("StringSubtypeTreeElement::is_element()");
1778 }
1779 return TUNKNOWN;
1780}
1781
1782// if the constraints are ortogonal (e.g. size and alphabet) or just different then return TUNKNOWN
1783// in case of ortogonal constraints we should return TFALSE (if other is not full set)
1784// but it seems that the standard wants to ignore such trivial cases, example:
1785// length(1..4) is_subset ('a'..'z') shall not report an error
1786template <class STRINGTYPE, class CHARLIMITTYPE>
1787tribool StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::is_subset(const StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>* other) const
1788{
1789 switch (elementtype) {
1790 case ET_NONE:
1791 return TTRUE;
1792 case ET_ALL:
1793 if (other->elementtype==ET_ALL) return TTRUE;
1794 else return TUNKNOWN;
1795 case ET_CONSTRAINT:
1796 if (elementtype!=other->elementtype) return TUNKNOWN;
1797 if (u.cs.constrainttype!=other->u.cs.constrainttype) return TUNKNOWN;
1798 switch (u.cs.constrainttype) {
1799 case CT_SIZE: return u.cs.s->is_subset(*(other->u.cs.s));
1800 case CT_ALPHABET: return u.cs.a.c->is_subset(*(other->u.cs.a.c));
1801 case CT_VALUES: return u.cs.v->is_subset(*(other->u.cs.v));
1802 case CT_PATTERN: return u.cs.p->is_subset(*(other->u.cs.p));
1803 default: FATAL_ERROR("StringSubtypeTreeElement::is_subset()");
1804 }
1805 case ET_INTERSECTION:
1806 case ET_UNION:
1807 case ET_EXCEPT:
1808 return TUNKNOWN;
1809 default:
1810 FATAL_ERROR("StringSubtypeTreeElement::is_subset()");
1811 }
1812 return TUNKNOWN;
1813}
1814
1815template <class STRINGTYPE, class CHARLIMITTYPE>
1816void StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::evaluate()
1817{
1818 switch (elementtype) {
1819 case ET_NONE:
1820 case ET_ALL:
1821 case ET_CONSTRAINT:
1822 // these are the simplest forms, others are reduced to these in ideal case
1823 return;
1824 case ET_INTERSECTION:
1825 case ET_UNION:
1826 case ET_EXCEPT:
1827 break;
1828 default:
1829 FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
1830 }
1831
1832 // recursive evaluation
1833 u.op.a->evaluate();
1834 u.op.b->evaluate();
1835
1836 // special case where the construct looks like this:
1837 // 1. ( A + B ) + C
1838 // 2. A + ( B + C )
1839 // 3. (A+B) + (C+D)
1840 // can be union or intersection, try to exchange constraint to have same type of constraints as operands,
1841 // constraint types: tree, ....
1842 // if succeeded then evaluate the new construct
1843 // TODO...
1844
1845 // special simple cases when one side is ET_ALL or ET_NONE but the other can be a tree
1846 if ( (u.op.a->elementtype==ET_NONE) || (u.op.b->elementtype==ET_NONE) ) {
1847 if (elementtype==ET_INTERSECTION) { set_none(); return; }
1848 if (elementtype==ET_UNION) {
1849 // the result is the other set
1850 set_to_operand(u.op.b->elementtype==ET_NONE);
1851 return;
1852 }
1853 }
1854 if ( (u.op.b->elementtype==ET_NONE) && (elementtype==ET_EXCEPT) ) {
1855 set_to_operand(true);
1856 return;
1857 }
1858 if ( (u.op.a->elementtype==ET_ALL) || (u.op.b->elementtype==ET_ALL) ) {
1859 if (elementtype==ET_INTERSECTION) {
1860 // the result is the other set
1861 set_to_operand(u.op.b->elementtype==ET_ALL);
1862 return;
1863 }
1864 if (elementtype==ET_UNION) { set_all(); return; }
1865 }
1866 if ( (u.op.b->elementtype==ET_ALL) && (elementtype==ET_EXCEPT) ) { set_none(); return; }
1867
1868 // both operands must be single constraints (ALL,NONE,CONSTRAINT),
1869 // after this point trees will not be further simplified
1870 if (!u.op.a->is_single_constraint() || !u.op.b->is_single_constraint()) return;
1871
1872 // special case: ALL - some constraint type that can be complemented
1873 if ( (u.op.a->elementtype==ET_ALL) && (elementtype==ET_EXCEPT) && (u.op.b->elementtype==ET_CONSTRAINT) ) {
1874 switch (u.op.b->u.cs.constrainttype) {
1875 case CT_SIZE: {
1876 SizeRangeListConstraint* rvs = new SizeRangeListConstraint(~*(u.op.b->u.cs.s));
1877 clean_up();
1878 elementtype = ET_CONSTRAINT;
1879 u.cs.constrainttype = CT_SIZE;
1880 u.cs.s = rvs;
1881 simplify();
1882 } return;
1883 case CT_ALPHABET: {
1884 if (u.cs.a.char_context) {
1885 RangeListConstraint<CHARLIMITTYPE>* rva = new RangeListConstraint<CHARLIMITTYPE>(~*(u.op.b->u.cs.a.c));
1886 clean_up();
1887 elementtype = ET_CONSTRAINT;
1888 u.cs.constrainttype = CT_ALPHABET;
1889 u.cs.a.c = rva;
1890 u.cs.a.char_context = true;
1891 simplify();
1892 }
1893 } return;
1894 default:
1895 break;
1896 }
1897 }
1898
1899 // special case: when one operand is CT_VALUES then is_element() can be called for the values
1900 // and drop values or drop the other operand set or both depending on the operation
1901 StringValueConstraint<STRINGTYPE>* svc = NULL;
1902 bool first_is_svc = false;
1903 if ( (u.op.a->elementtype==ET_CONSTRAINT) && (u.op.a->u.cs.constrainttype==CT_VALUES) ) {
1904 svc = u.op.a->u.cs.v;
1905 first_is_svc = true;
1906 } else if ( (u.op.b->elementtype==ET_CONSTRAINT) && (u.op.b->u.cs.constrainttype==CT_VALUES) ) {
1907 svc = u.op.b->u.cs.v;
1908 first_is_svc = false; // it's the second
1909 }
1910 if (svc!=NULL) { // if one or both operands are CT_VALUES
1911 switch (elementtype) {
1912 case ET_INTERSECTION: {
1913 switch (first_is_svc ? u.op.b->u.cs.constrainttype : u.op.a->u.cs.constrainttype) {
1914 case CT_SIZE:
1915 svc->remove(*(first_is_svc ? u.op.b->u.cs.s : u.op.a->u.cs.s), false);
1916 break;
1917 case CT_ALPHABET:
1918 svc->remove(*(first_is_svc ? u.op.b->u.cs.a.c : u.op.a->u.cs.a.c), false);
1919 break;
1920 case CT_PATTERN:
1921 svc->remove(*(first_is_svc ? u.op.b->u.cs.p : u.op.a->u.cs.p), false);
1922 break;
1923 default:
1924 break;
1925 }
1926 // drop the other operand, keep the values as constraint of this object
1927 StringValueConstraint<STRINGTYPE>* keep_svc = new StringValueConstraint<STRINGTYPE>(*svc);
1928 clean_up();
1929 elementtype = ET_CONSTRAINT;
1930 u.cs.constrainttype = CT_VALUES;
1931 u.cs.v = keep_svc;
1932 simplify();
1933 return;
1934 }
1935 case ET_UNION: {
1936 switch (first_is_svc ? u.op.b->u.cs.constrainttype : u.op.a->u.cs.constrainttype) {
1937 case CT_SIZE:
1938 svc->remove(*(first_is_svc ? u.op.b->u.cs.s : u.op.a->u.cs.s), true);
1939 break;
1940 case CT_ALPHABET:
1941 svc->remove(*(first_is_svc ? u.op.b->u.cs.a.c : u.op.a->u.cs.a.c), true);
1942 break;
1943 case CT_PATTERN:
1944 svc->remove(*(first_is_svc ? u.op.b->u.cs.p : u.op.a->u.cs.p), true);
1945 break;
1946 default:
1947 break;
1948 }
1949 // if all values were dropped then drop the empty values operand
1950 if (svc->is_empty()==TTRUE) {
1951 set_to_operand(!first_is_svc);
1952 return;
1953 }
1954 } break;
1955 case ET_EXCEPT: {
1956 if (first_is_svc) { // the second operand is u.op.b->u.cs.X where X can be length/alphabet/pattern constraint
1957 switch (u.op.b->u.cs.constrainttype) {
1958 case CT_SIZE:
1959 svc->remove(*(u.op.b->u.cs.s), true);
1960 break;
1961 case CT_ALPHABET:
1962 svc->remove(*(u.op.b->u.cs.a.c), true);
1963 break;
1964 case CT_PATTERN:
1965 svc->remove(*(u.op.b->u.cs.p), true);
1966 break;
1967 default:
1968 break;
1969 }
1970 // drop the other operand, keep the values as constraint of this object
1971 StringValueConstraint<STRINGTYPE>* keep_svc = new StringValueConstraint<STRINGTYPE>(*svc);
1972 clean_up();
1973 elementtype = ET_CONSTRAINT;
1974 u.cs.constrainttype = CT_VALUES;
1975 u.cs.v = keep_svc;
1976 simplify();
1977 return;
1978 }
1979 } break;
1980 default:
1981 FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
1982 }
1983 }
1984
1985 // operands of same types can be evaluated to one constraint using their
1986 // set arithmetic member functions
1987 // alphabet constraint in string context:
1988 // FROM(A) UNION FROM(B) =/= FROM(A UNION B)
1989 // ALL - FROM(A) =/= FROM(ALL - A)
1990 // FROM(A) INTERSECTION FROM(B) == FROM (A INTERSECTION B)
1991 if (u.op.a->elementtype==u.op.b->elementtype) {
1992 switch (u.op.a->elementtype) {
1993 case ET_ALL:
1994 if (elementtype==ET_EXCEPT) set_none();
1995 else set_all();
1996 return;
1997 case ET_NONE:
1998 set_none();
1999 return;
2000 case ET_CONSTRAINT:
2001 if (u.op.a->u.cs.constrainttype==u.op.b->u.cs.constrainttype) {
2002 switch (u.op.a->u.cs.constrainttype) {
2003 case CT_SIZE: {
2004 SizeRangeListConstraint* rvs = new SizeRangeListConstraint;
2005 switch (elementtype) {
2006 case ET_INTERSECTION:
2007 *rvs = *(u.op.a->u.cs.s) * *(u.op.b->u.cs.s);
2008 break;
2009 case ET_UNION:
2010 *rvs = *(u.op.a->u.cs.s) + *(u.op.b->u.cs.s);
2011 break;
2012 case ET_EXCEPT:
2013 *rvs = *(u.op.a->u.cs.s) - *(u.op.b->u.cs.s);
2014 break;
2015 default:
2016 FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
2017 }
2018 clean_up();
2019 elementtype = ET_CONSTRAINT;
2020 u.cs.constrainttype = CT_SIZE;
2021 u.cs.s = rvs;
2022 } break;
2023 case CT_ALPHABET: {
2024 bool char_ctx = u.op.a->u.cs.a.char_context;
2025 if (u.op.b->u.cs.a.char_context!=char_ctx) FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
2026 if (char_ctx || (elementtype==ET_INTERSECTION)) {
2027 RangeListConstraint<CHARLIMITTYPE>* rva = new RangeListConstraint<CHARLIMITTYPE>;
2028 switch (elementtype) {
2029 case ET_INTERSECTION:
2030 *rva = *(u.op.a->u.cs.a.c) * *(u.op.b->u.cs.a.c);
2031 break;
2032 case ET_UNION:
2033 *rva = *(u.op.a->u.cs.a.c) + *(u.op.b->u.cs.a.c);
2034 break;
2035 case ET_EXCEPT:
2036 *rva = *(u.op.a->u.cs.a.c) - *(u.op.b->u.cs.a.c);
2037 break;
2038 default:
2039 FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
2040 }
2041 clean_up();
2042 elementtype = ET_CONSTRAINT;
2043 u.cs.constrainttype = CT_ALPHABET;
2044 u.cs.a.c = rva;
2045 u.cs.a.char_context = char_ctx;
2046 }
2047 } break;
2048 case CT_VALUES: {
2049 StringValueConstraint<STRINGTYPE>* rvv = new StringValueConstraint<STRINGTYPE>;
2050 switch (elementtype) {
2051 case ET_INTERSECTION:
2052 *rvv = *(u.op.a->u.cs.v) * *(u.op.b->u.cs.v);
2053 break;
2054 case ET_UNION:
2055 *rvv = *(u.op.a->u.cs.v) + *(u.op.b->u.cs.v);
2056 break;
2057 case ET_EXCEPT:
2058 *rvv = *(u.op.a->u.cs.v) - *(u.op.b->u.cs.v);
2059 break;
2060 default:
2061 FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
2062 }
2063 clean_up();
2064 elementtype = ET_CONSTRAINT;
2065 u.cs.constrainttype = CT_VALUES;
2066 u.cs.v = rvv;
2067 } break;
2068 case CT_PATTERN:
2069 return; // OH SHI-
2070 default:
2071 FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
2072 }
2073 }
2074 break;
2075 default:
2076 FATAL_ERROR("StringSubtypeTreeElement::evaluate()");
2077 }
2078 }
2079 simplify();
2080}
2081
2082template <class STRINGTYPE, class CHARLIMITTYPE>
2083string StringSubtypeTreeElement<STRINGTYPE,CHARLIMITTYPE>::to_string() const
2084{
2085 string ret_val;
2086 bool print_operation = false;
2087 string op_str;
2088 switch (elementtype) {
2089 case ET_NONE:
2090 break;
2091 case ET_ALL:
2092 ret_val += "ALL";
2093 break;
2094 case ET_CONSTRAINT:
2095 switch (u.cs.constrainttype) {
2096 case CT_SIZE:
2097 ret_val += "length";
2098 ret_val += u.cs.s->to_string();
2099 break;
2100 case CT_ALPHABET:
2101 ret_val += u.cs.a.char_context ? "range" : "from";
2102 ret_val += u.cs.a.c->to_string();
2103 break;
2104 case CT_VALUES:
2105 ret_val += u.cs.v->to_string();
2106 break;
2107 case CT_PATTERN:
2108 ret_val += u.cs.p->to_string();
2109 break;
2110 default:
2111 FATAL_ERROR("StringSubtypeTreeElement::to_string()");
2112 }
2113 break;
2114 case ET_INTERSECTION:
2115 op_str = "intersection";
2116 print_operation = true;
2117 break;
2118 case ET_UNION:
2119 op_str = "union";
2120 print_operation = true;
2121 break;
2122 case ET_EXCEPT:
2123 op_str = "except";
2124 print_operation = true;
2125 break;
2126 default:
2127 FATAL_ERROR("StringSubtypeTreeElement::to_string()");
2128 }
2129 if (print_operation) {
2130 ret_val += '(';
2131 ret_val += u.op.a->to_string();
2132 ret_val += ' ';
2133 ret_val += op_str;
2134 ret_val += ' ';
2135 ret_val += u.op.b->to_string();
2136 ret_val += ')';
2137 }
2138 return ret_val;
2139}
2140
2141typedef StringSubtypeTreeElement<string,char_limit_t> CharstringSubtypeTreeElement;
2142typedef StringSubtypeTreeElement<ustring,universal_char_limit_t> UniversalCharstringSubtypeTreeElement;
2143
2144////////////////////////////////////////////////////////////////////////////////
2145// constraint classes for structured types
2146
2147// used by ValueListConstraint and RecofConstraint classes
2148// only operator==() is used, since most value types do not have operator<()
2149// when used in RecofConstraint it will use Value::get_nof_comps()
2150class ValueList
2151{
2152private:
2153 vector<Value> values; // values are not owned
2154 void clean_up();
2155 void copy_content(const ValueList& other);
2156public:
2157 ValueList() : values() {} // empty set
2158 ValueList(Value* v) : values() { values.add(v); }
2159
2160 ValueList(const ValueList& other) : values() { copy_content(other); }
2161 ValueList& operator=(const ValueList& other) { clean_up(); copy_content(other); return *this; }
2162 ~ValueList() { clean_up(); }
2163
2164 tribool is_empty() const { return TRIBOOL(values.size()==0); }
2165 tribool is_full() const { return TUNKNOWN; } // it's unknown how many possible values we have
2166 tribool is_equal(const ValueList& other) const;
2167 bool is_element(Value* v) const;
2168
2169 // remove all elements whose size is (not) element of the given length set
2170 // works only if the type of values is correct (the get_nof_comps() doesn't end in FATAL_ERROR)
2171 void remove(const SizeRangeListConstraint& size_constraint, bool if_element);
2172
2173 ValueList set_operation(const ValueList& other, bool is_union) const;
2174
2175 ValueList operator+(const ValueList& other) const { return set_operation(other, true); } // union
2176 ValueList operator*(const ValueList& other) const { return set_operation(other, false); } // intersection
2177 ValueList operator-(const ValueList& other) const; // except
2178
2179 tribool is_subset(const ValueList& other) const { return (*this-other).is_empty(); }
2180
2181 string to_string() const;
2182};
2183
2184// can be a ValueList or (ALL-ValueList), used for subtypes of structured types, enumerated and objid
2185class ValueListConstraint
2186{
2187private:
2188 bool complemented;
2189 ValueList values;
2190public:
2191 ValueListConstraint(): complemented(false), values() {} // empty set
2192 ValueListConstraint(Value* v): complemented(false), values(v) {} // single element set
2193 ValueListConstraint(bool p_complemented): complemented(p_complemented), values() {} // empty of full set
2194
2195 tribool is_empty() const;
2196 tribool is_full() const;
2197 tribool is_equal(const ValueListConstraint& other) const;
2198 bool is_element(Value* v) const;
2199
2200 ValueListConstraint operator+(const ValueListConstraint& other) const; // union
2201 ValueListConstraint operator*(const ValueListConstraint& other) const; // intersection
2202 ValueListConstraint operator~() const; // complement
2203
2204 inline tribool is_subset(const ValueListConstraint& other) const
2205 { return (*this*~other).is_empty(); }
2206 inline ValueListConstraint operator-(const ValueListConstraint& other) const
2207 { return ( *this * ~other ); } // except
2208
2209 string to_string() const;
2210};
2211
2212// length and value list constraints for record/set of types
2213class RecofConstraint
2214{
2215private:
2216 SizeRangeListConstraint size_constraint;
2217 ValueList has_values, not_values;
2218public:
2219 // constructors
2220 RecofConstraint(): size_constraint(), has_values(), not_values() {} // empty set
2221 RecofConstraint(Value* v): size_constraint(), has_values(v), not_values() {} // single value set
2222 RecofConstraint(const size_limit_t& sl): size_constraint(sl), has_values(), not_values() {} // single size value set
2223 RecofConstraint(const size_limit_t& rl_begin, const size_limit_t& rl_end)
2224 : size_constraint(rl_begin,rl_end), has_values(), not_values() {} // size range set
2225 RecofConstraint(const SizeRangeListConstraint& p_size_constraint)
2226 : size_constraint(p_size_constraint), has_values(), not_values() {}
2227
2228 tribool is_empty() const;
2229 tribool is_full() const;
2230 tribool is_equal(const RecofConstraint& other) const;
2231 bool is_element(Value* v) const;
2232
2233 RecofConstraint set_operation(const RecofConstraint& other, bool is_union) const;
2234
2235 inline RecofConstraint operator+(const RecofConstraint& other) const { return set_operation(other, true); } // union
2236 inline RecofConstraint operator*(const RecofConstraint& other) const { return set_operation(other, false); } // intersection
2237 RecofConstraint operator~() const; // complement
2238
2239 inline tribool is_subset(const RecofConstraint& other) const { return (*this*~other).is_empty(); }
2240 inline RecofConstraint operator-(const RecofConstraint& other) const { return ( *this * ~other ); } // except
2241
2242 tribool get_size_limit(bool is_upper, size_limit_t& limit) const;
2243
2244 string to_string() const;
2245};
2246
2247
2248}// namespace Common
2249
2250#endif // #ifndef _Subtypestuff_HH
This page took 0.120921 seconds and 5 git commands to generate.