ESBMC
Efficient SMT-based Context-Bounded Model Checker
Loading...
Searching...
No Matches
interval_template.h
Go to the documentation of this file.
1#ifndef CPROVER_ANALYSES_INTERVAL_TEMPLATE_H
2#define CPROVER_ANALYSES_INTERVAL_TEMPLATE_H
3
4#include <algorithm>
5#include <iosfwd>
8#include <sstream>
10#include <optional>
18template <class T>
20{
21public:
22 virtual ~interval_templatet() = default;
23
24 interval_templatet() = default;
25
26 explicit interval_templatet(const type2tc &)
27 {
28 }
29
30 explicit interval_templatet(const T &x) : lower(x), upper(x)
31 {
32 }
33
34 interval_templatet(const T &l, const T &u) : lower(l), upper(u)
35 {
36 }
37
39 std::optional<T> lower, upper;
42 T get_lower() const
43 {
44 return get(false);
45 }
46
47 T get_upper() const
48 {
49 return get(true);
50 }
51
52 T adjust(const T &v) const
53 {
54 // This is just an id function
55 return v;
56 }
57
58 virtual void set(bool is_upper, const T &b)
59 {
60 if (is_upper)
61 upper = b;
62 else
63 lower = b;
64 }
65
66 virtual T get(bool is_upper) const
67 {
68 return is_upper ? *upper : *lower;
69 }
70
71 void set_upper(const T &b)
72 {
73 set(true, b);
74 }
75 void set_lower(const T &b)
76 {
77 set(false, b);
78 }
79
80 void dump() const
81 {
82 std::ostringstream oss;
83
84 if (is_bottom())
85 oss << "EMPTY";
86 else
87 {
88 if (lower)
89
90 oss << "[" << get_lower();
91 else
92 oss << "(-inf";
93
94 oss << ",";
95 if (upper)
96 oss << get_upper() << "]";
97 else
98 oss << "+inf)";
99 }
100 log_status("{}", oss.str());
101 }
102
103 virtual bool is_le_than(const T &a, const T &b) const
104 {
105 return a <= b;
106 }
107
112 virtual bool empty() const
113 {
114 return lower && upper && *lower > *upper;
115 }
116
117 bool is_bottom() const // equivalent to 'false'
118 {
119 return empty();
120 }
121
122 virtual bool is_top() const // equivalent to 'true'
123 {
124 return !lower && !upper;
125 }
126
128 bool singleton() const
129 {
130 return upper && lower && *lower == *upper;
131 }
132
133 // constraints
134 virtual void make_le_than(const T &v) // add upper bound
135 {
136 auto value = adjust(v);
137 if (upper)
138 {
139 if (is_le_than(value, get_upper()))
141 }
142 else
143 {
145 }
146 }
147
148 virtual bool contains(const T &e) const
149 {
150 if (is_top())
151 return true;
152
153 if (lower && e < get_lower())
154 return false;
155
156 if (upper && e > get_upper())
157 return false;
158
159 return true;
160 }
161
162 // Sound version (considering over approximations)
164 {
165 // [lower, upper] <= [v.lower,v.upper] <==> [lower, min(upper,v.upper)] <=
166 // [max(lower, v.lower), v.upper]
167
168 if (upper || v.upper)
169 upper = upper && v.upper ? std::min(*upper, *v.upper)
170 : upper ? *upper
171 : *v.upper;
172 if (lower || v.lower)
173 v.lower = lower && v.lower ? std::max(*lower, *v.lower)
174 : lower ? *lower
175 : *v.lower;
176 }
177
178 virtual void make_ge_than(const T &v) // add lower bound
179 {
180 auto value = adjust(v);
181 if (lower)
182 {
183 if (is_le_than(get_lower(), value))
185 }
186 else
187 {
189 }
190 }
191
194 {
196 }
197
200 {
202 }
203
205 {
206 if (i.lower)
207 {
208 if (lower)
209 {
210 lower = std::max(*lower, *i.lower);
211 }
212 else
213 {
214 lower = *i.lower;
215 }
216 }
217
218 if (i.upper)
219 {
220 if (upper)
221 {
222 upper = std::min(*upper, *i.upper);
223 }
224 else
225 {
226 upper = *i.upper;
227 }
228 }
229 }
230
231 // Wether *this \subseteq other
233 {
234 if ((!lower && other.lower) || (!upper && other.upper))
235 return false;
236 if (other.lower && *lower < *other.lower)
237 return false;
238 if (other.upper && *upper > *other.upper)
239 return false;
240
241 return true;
242 }
243
245 {
246 if (i.lower && lower)
247 lower = std::min(*lower, *i.lower);
248 else if (!i.lower)
249 lower.reset();
250
251 if (i.upper && upper)
252 upper = std::max(*upper, *i.upper);
253 else if (!i.upper)
254 upper.reset();
255 }
256
257 /* INTERVAL ARITHMETICS
258 *
259 * Following Chapter 32 of Principles of Abstract Interpretation.
260 *
261 * ADD/SUB
262 * [x0, x1] + empty <==> empty + [x0, x1] <==> [x0, x1] - empty <==> empty +
263 * [x0, x1] <==> empty [x0, x1] + [y0, y1] <==> [x0+y0, x1+y1] [x0, x1] - [y0,
264 * y1] <==> [x0-y1, x1-y0]
265 * -[x0, x1] <==> [-x1, -x0]
266 * -infinity + infinity <==> -infinity
267 * -infinity + c <==> -infinity
268 * infinity + infinity = infinity
269 *
270 * MULT
271 * [x0, x1] * empty <==> empty * [x0, x1] <==> empty
272 * [x0, x1] * [y0, y1] <==> [min(x0*y0, x0*y1, x1*y0, x1*y1), max(x0*y0,
273 * x0*y1, x1*y0, x1*y1)]
274 *
275 * DIV
276 * [1, 1] / [x0, x1] <==> {
277 * (x1 < 0) || (0 < x0) => [1/x1, 1/x0]
278 * otherwise (e.g. 1/0) => [-infinity, infinity]
279 * }
280 * [x0, x1] / [y0, y1] <==> [x0, x1] * [[1,1] / [y0, y1]]
281 *
282 *
283 */
286 {
287 // [a_0, a_1] + [b_0, b_1] = [a_0+b_0, a_1 + b_1]
288 auto result = rhs.empty() ? rhs : lhs;
289 if (result.empty())
290 return result;
291
292 if (!lhs.lower || !rhs.lower)
293 result.lower.reset();
294 else
295 result.lower = *lhs.lower + *rhs.lower;
296
297 if (!lhs.upper || !rhs.upper)
298 result.upper.reset();
299 else
300 result.upper = *lhs.upper + *rhs.upper;
301
302 return result;
303 }
304
306 {
307 // -[a_0, a_1] = [-a_1, -a_0]
308 auto result = lhs;
309 if (!lhs.upper)
310 result.lower.reset();
311 else
312 {
313 result.lower = -(*lhs.upper);
314 }
315
316 if (!lhs.lower)
317 {
318 result.upper.reset();
319 }
320 else
321 {
322 result.upper = -(*lhs.lower);
323 }
324 return result;
325 }
326
329 {
330 // [a_0, a_1] - [b_0, b_1] = [a_0-b_1, a_1 - b_0]
331 auto result = rhs.empty() ? rhs : lhs;
332 if (result.empty())
333 return result;
334
335 if (!lhs.lower || !rhs.upper)
336 result.lower.reset();
337 else
338 result.lower = *lhs.lower - *rhs.upper;
339
340 if (!lhs.upper || !rhs.lower)
341 result.upper.reset();
342 else
343 result.upper = *lhs.upper - *rhs.lower;
344
345 return result;
346 }
347
350 {
351 // [a_0, a_1] * [b_0, b_1] = [min(a_0*b_0, a_0*b_1, a_1*b_0, a_1*b_1),
352 // max(a_0*b_0, a_0*b_1, a_1*b_0, a_1*b_1)]
354 if (rhs.empty() || lhs.empty())
355 return rhs.empty() ? rhs : lhs;
356
357 // Let's deal with infinities first
358 if (!lhs.lower || !rhs.lower || !lhs.upper || !rhs.upper)
359 return result;
360
361 // Initialize with a0 * b0
362 auto a0_b0 = *lhs.lower * *rhs.lower;
363 result.lower = a0_b0;
364 result.upper = a0_b0;
365
366 auto update_value = [&result](T value) {
367 result.lower = std::min(value, *result.lower);
368 result.upper = std::max(value, *result.upper);
369 };
370
371 update_value(*lhs.lower * *rhs.upper); // a0 * b1
372 update_value(*lhs.upper * *rhs.lower); // a1 * b0
373 update_value(*lhs.upper * *rhs.upper); // a1 * b1
374
375 return result;
376 }
377
380 {
381 /* Note, some works suggests doing a multiplication as [a0, a_1] * ([1,1] /
382 * [b_0, b_1]) However, our implementation is not a symbolic computation;
383 * thus the arithmetic is not associative. For example, [-6, 10] / 2 which
384 * is [-3, 5] cannot be computed through the [-6, 10] * [1/2, 1/2] because
385 * 1/2 will result in 0.
386 */
387 if (rhs.empty() || lhs.empty())
388 return rhs.empty() ? rhs : lhs;
389
391
392 // A divisor range containing 0 also contains the divisors giving the
393 // largest quotients (±1, or arbitrarily small reals), not just its ends.
394 if (
395 !lhs.lower || !rhs.lower || !lhs.upper || !rhs.upper ||
396 rhs.contains(T(0)))
397 return result;
398
399 // Initialize with a0 * b0
400 T a0_b0 = *lhs.lower / *rhs.lower;
401 result.lower = a0_b0;
402 result.upper = a0_b0;
403
404 auto update_value = [&result](T value) {
405 result.lower = std::min(value, *result.lower);
406 result.upper = std::max(value, *result.upper);
407 };
408
409 update_value(*lhs.lower / *rhs.upper); // a0 / b1
410 update_value(*lhs.upper / *rhs.lower); // a1 / b0
411 update_value(*lhs.upper / *rhs.upper); // a1 / b1
412
413 return result;
414 }
415
418 const interval_templatet<T> &true_value,
419 const interval_templatet<T> &false_value)
420 {
421 if (!cond.contains(0))
422 return true_value;
423
424 if (cond.singleton())
425 return false_value;
426
427 interval_templatet<T> result = true_value;
428 result.join(false_value);
429 return result;
430 }
431
434 static bool is_representable(const type2tc &)
435 {
436 return true;
437 }
438
441 {
442 log_debug("interval", "No support for typecasting");
444 return result;
445 }
446
449 {
450 log_debug("interval", "No support for mod");
452 return result;
453 }
454
456 const interval_templatet<T> &,
457 const interval_templatet<T> &) const
458 {
459 log_debug("interval", "No support for bitand");
461 return result;
462 }
463
466 {
467 return lhs.interval_bitand(lhs, rhs);
468 }
469
471 const interval_templatet<T> &,
472 const interval_templatet<T> &) const
473 {
474 log_debug("interval", "No support for bitor");
476 return result;
477 }
478
481 {
482 return lhs.interval_bitor(lhs, rhs);
483 }
484
486 const interval_templatet<T> &,
487 const interval_templatet<T> &) const
488 {
489 log_debug("interval", "No support for bitxor");
491 return result;
492 }
493
496 {
497 return lhs.interval_bitxor(lhs, rhs);
498 }
499
501 const interval_templatet<T> &,
502 const interval_templatet<T> &) const
503 {
504 log_debug("interval", "No support for lshr");
506 return result;
507 }
508
510 const interval_templatet<T> &lhs,
511 const interval_templatet<T> &rhs)
512 {
513 return lhs.interval_logical_right_shift(lhs, rhs);
514 }
515
517 const interval_templatet<T> &,
518 const interval_templatet<T> &) const
519 {
520 log_debug("interval", "No support for shl");
522 return result;
523 }
524
527 {
528 return lhs.interval_left_shift(lhs, rhs);
529 }
530
532 const interval_templatet<T> &,
533 const interval_templatet<T> &) const
534 {
535 log_debug("interval", "No support for ashr");
537 return result;
538 }
539
541 const interval_templatet<T> &lhs,
542 const interval_templatet<T> &rhs)
543 {
544 return lhs.interval_arithmetic_right_shift(lhs, rhs);
545 }
546
548 bitnot([[maybe_unused]] const interval_templatet<T> &w)
549 {
551 return result;
552 }
553
556 {
558 result.set_lower(0);
559 result.set_upper(1);
560
561 // If the intervals are singletons and equal then it's always true
562 if (
563 lhs.singleton() && rhs.singleton() && lhs.get_lower() == rhs.get_lower())
564 {
565 result.set_lower(1);
566 return result;
567 }
568
569 // If the intervals don't intersect, then they are always empty
570 auto lhs_cpy = lhs;
571 lhs_cpy.intersect_with(rhs);
572 if (lhs_cpy.empty())
573 result.set_upper(0);
574
575 return result;
576 }
577
579 {
581 if (!i.contains(0))
582 {
583 // i is always true, return false
584 result.set_lower(0);
585 result.set_upper(0);
586 }
587 else if (i.singleton())
588 {
589 // i is always false, return true
590 result.set_lower(1);
591 result.set_upper(1);
592 }
593 else
594 {
595 // i is a maybe
596 result.set_lower(0);
597 result.set_upper(1);
598 }
599 return result;
600 }
601
604 {
605 return invert_bool(equality(lhs, rhs));
606 }
607
610 {
612 result.set_lower(0);
613 result.set_upper(1);
614
615 // MAX LHS < MIN RHS => TRUE
616 if (lhs.upper && rhs.lower && lhs.get_upper() < rhs.get_lower())
617 {
618 result.set_lower(1);
619 return result;
620 }
621
622 // MIN LHS >= MAX RHS => FALSE
623 if (lhs.lower && rhs.upper && lhs.get_lower() >= rhs.get_upper())
624 {
625 result.set_upper(0);
626 return result;
627 }
628
629 assert(!result.singleton() && !result.is_bottom());
630 return result;
631 }
632
634 const interval_templatet<T> &lhs,
635 const interval_templatet<T> &rhs)
636 {
638 result.set_lower(0);
639 result.set_upper(1);
640
641 // MAX LHS <= MIN RHS => TRUE
642 if (lhs.upper && rhs.lower && lhs.get_upper() <= rhs.get_lower())
643 {
644 result.set_lower(1);
645 return result;
646 }
647
648 // MIN LHS > MAX RHS => FALSE
649 if (lhs.lower && rhs.upper && lhs.get_lower() > rhs.get_upper())
650 {
651 result.set_upper(0);
652 return result;
653 }
654
655 assert(!result.singleton() && !result.is_bottom());
656 return result;
657 }
658
660 const interval_templatet<T> &lhs,
661 const interval_templatet<T> &rhs)
662 {
663 // a >= b <==> b <= a
664 return less_than_equal(rhs, lhs);
665 }
666
668 const interval_templatet<T> &lhs,
669 const interval_templatet<T> &rhs)
670 {
671 // a > b <==> b < a
672 return less_than(rhs, lhs);
673 }
674
677 bool inline has_changed(const interval_templatet<T> &i)
678 {
679 if (empty())
680 return false;
681
682 if ((lower != i.lower) || (upper != i.upper))
683 return true;
684
685 return false;
686 }
687
690 {
691 // [-infinity, 0]
692 make_le_than(0);
693 }
694
701 static void
703 {
713 interval_templatet<T> intersection_operand;
714 intersection_operand.make_lower_interval();
715 bool changed;
716 do
717 {
718 changed = false;
719 auto tmp_a = a;
720 auto tmp_b = b;
721 auto y = (a - b);
722 y.intersect_with(intersection_operand);
723
724 a.intersect_with(tmp_b + y);
725 b.intersect_with(tmp_a - y);
726
727 changed = a.has_changed(tmp_a) || b.has_changed(tmp_b);
728 } while (changed);
729 }
730};
731
732template <class T>
734{
735 if (a.upper && b.lower && *a.upper <= *b.lower)
736 return tvt(true);
737 if (a.lower && b.upper && *a.lower > *b.upper)
738 return tvt(false);
739
740 return tvt(tvt::TV_UNKNOWN);
741}
742
743template <class T>
745{
746 return b <= a;
747}
748
749template <class T>
751{
752 return !(a >= b);
753}
754
755template <class T>
757{
758 return !(a <= b);
759}
760
761template <class T>
763{
764 if (a.lower.has_value() != b.lower.has_value())
765 return false;
766 if (a.upper.has_value() != b.upper.has_value())
767 return false;
768
769 if (a.lower && *a.lower != *b.lower)
770 return false;
771 if (a.upper && *a.upper != *b.upper)
772 return false;
773
774 return true;
775}
776
777template <class T>
779{
780 return !(a == b);
781}
782
783template <class T>
785{
787 i.upper = u;
788 return i;
789}
790
791template <class T>
793{
795 i.lower = l;
796 return i;
797}
798
799template <class T>
800std::ostream &operator<<(std::ostream &out, const interval_templatet<T> &i)
801{
802 if (i.lower)
803 out << '[' << *i.lower;
804 else
805 out << ")-INF";
806
807 out << ',';
808
809 if (i.upper)
810 out << *i.upper << ']';
811 else
812 out << "+INF(";
813
814 return out;
815}
816#endif // CPROVER_ANALYSES_INTERVAL_TEMPLATE_H
This class is used to store intervals in the form of lower <= upper.
Definition interval_template.h:20
friend interval_templatet< T > operator&(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:465
static interval_templatet< T > equality(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:555
static interval_templatet< T > bitnot(const interval_templatet< T > &w)
Definition interval_template.h:548
virtual bool is_top() const
Definition interval_template.h:122
interval_templatet(const type2tc &)
Definition interval_template.h:26
friend interval_templatet< T > operator%(const interval_templatet< T > &, const interval_templatet< T > &)
Definition interval_template.h:448
void dump() const
Definition interval_template.h:80
friend interval_templatet< T > operator/(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:379
T adjust(const T &v) const
Definition interval_template.h:52
static interval_templatet< T > greater_than(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:667
T get_lower() const
Definition interval_template.h:42
friend interval_templatet< T > operator|(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:480
static interval_templatet< T > cast(const interval_templatet< T > &, const type2tc &)
Definition interval_template.h:440
interval_templatet(const T &x)
Definition interval_template.h:30
void set_lower(const T &b)
Definition interval_template.h:75
friend interval_templatet< T > operator-(const interval_templatet< T > &lhs)
Definition interval_template.h:305
void set_upper(const T &b)
Definition interval_template.h:71
static interval_templatet< T > greater_than_equal(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:659
interval_templatet< T > interval_bitor(const interval_templatet< T > &, const interval_templatet< T > &) const
Definition interval_template.h:470
void join(const interval_templatet< T > &i)
Union or disjunction.
Definition interval_template.h:193
static interval_templatet< T > less_than(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:609
interval_templatet< T > interval_left_shift(const interval_templatet< T > &, const interval_templatet< T > &) const
Definition interval_template.h:516
interval_templatet< T > interval_arithmetic_right_shift(const interval_templatet< T > &, const interval_templatet< T > &) const
Definition interval_template.h:531
static interval_templatet< T > invert_bool(const interval_templatet< T > &i)
Definition interval_template.h:578
virtual void make_le_than(const T &v)
Definition interval_template.h:134
void make_sound_le(interval_templatet< T > &v)
Definition interval_template.h:163
static void contract_interval_le(interval_templatet< T > &a, interval_templatet< T > &b)
Computer the contraction of "a" and "b" under a <= b.
Definition interval_template.h:702
static interval_templatet< T > not_equal(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:603
interval_templatet< T > interval_bitxor(const interval_templatet< T > &, const interval_templatet< T > &) const
Definition interval_template.h:485
bool has_changed(const interval_templatet< T > &i)
This is just to check if a value has changed.
Definition interval_template.h:677
virtual void set(bool is_upper, const T &b)
Definition interval_template.h:58
void meet(const interval_templatet< T > &i)
Intersection or conjunction.
Definition interval_template.h:199
void make_lower_interval()
Generates an interval of the form (-infinity, 0].
Definition interval_template.h:689
static interval_templatet< T > arithmetic_right_shift(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:540
virtual void approx_union_with(const interval_templatet &i)
Definition interval_template.h:244
bool is_bottom() const
Definition interval_template.h:117
interval_templatet(const T &l, const T &u)
Definition interval_template.h:34
virtual ~interval_templatet()=default
static interval_templatet< T > left_shift(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:526
bool is_subseteq(const interval_templatet &other) const
Definition interval_template.h:232
interval_templatet< T > interval_logical_right_shift(const interval_templatet< T > &, const interval_templatet< T > &) const
Definition interval_template.h:500
friend interval_templatet< T > operator*(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:349
std::optional< BigInt > upper
Definition interval_template.h:39
static interval_templatet< T > logical_right_shift(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:509
static interval_templatet< T > less_than_equal(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:633
virtual T get(bool is_upper) const
Definition interval_template.h:66
virtual bool contains(const T &e) const
Definition interval_template.h:148
void intersect_with(const interval_templatet &i)
Definition interval_template.h:204
virtual bool empty() const
Checks whether there are values that satisfy the the interval.
Definition interval_template.h:112
friend interval_templatet< T > operator+(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:285
T get_upper() const
Definition interval_template.h:47
bool singleton() const
There is only one value that satisfies.
Definition interval_template.h:128
interval_templatet()=default
static bool is_representable(const type2tc &)
Whether an interval can be built for a value of type t; when it cannot, expressions over such values ...
Definition interval_template.h:434
friend interval_templatet< T > operator-(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:328
type2tc type
Definition interval_template.h:41
std::optional< BigInt > lower
Definition interval_template.h:39
interval_templatet< T > interval_bitand(const interval_templatet< T > &, const interval_templatet< T > &) const
Definition interval_template.h:455
virtual void make_ge_than(const T &v)
Definition interval_template.h:178
friend interval_templatet< T > operator^(const interval_templatet< T > &lhs, const interval_templatet< T > &rhs)
Definition interval_template.h:495
virtual bool is_le_than(const T &a, const T &b) const
Definition interval_template.h:103
static interval_templatet< T > ternary_if(const interval_templatet< T > &cond, const interval_templatet< T > &true_value, const interval_templatet< T > &false_value)
Definition interval_template.h:416
Definition threeval.h:10
@ TV_UNKNOWN
Definition threeval.h:15
Definition toml.hpp:1531
@ other
Definition converter_compare.cpp:887
pthread_cond_t cond
Definition cuda.h:50
#define T
Definition exp2f.c:24
interval_templatet< T > lower_interval(const T &l)
Definition interval_template.h:792
tvt operator<=(const interval_templatet< T > &a, const interval_templatet< T > &b)
Definition interval_template.h:733
tvt operator>(const interval_templatet< T > &a, const interval_templatet< T > &b)
Definition interval_template.h:756
std::ostream & operator<<(std::ostream &out, const interval_templatet< T > &i)
Definition interval_template.h:800
bool operator==(const interval_templatet< T > &a, const interval_templatet< T > &b)
Definition interval_template.h:762
interval_templatet< T > upper_interval(const T &u)
Definition interval_template.h:784
bool operator!=(const interval_templatet< T > &a, const interval_templatet< T > &b)
Definition interval_template.h:778
tvt operator<(const interval_templatet< T > &a, const interval_templatet< T > &b)
Definition interval_template.h:750
tvt operator>=(const interval_templatet< T > &a, const interval_templatet< T > &b)
Definition interval_template.h:744
irep_container< type2t > type2tc
Definition irep2.h:430
#define log_debug(mod, fmt,...)
Definition message.h:104
#define log_status(fmt,...)
Definition message.h:101
const T & max(const T &left, const T &right)
Definition min_max.h:10
const T & min(const T &left, const T &right)
Definition min_max.h:19