svf-tools 1.0.682 → 1.0.683

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.682",
3
+ "version": "1.0.683",
4
4
  "description": "* <b>[TypeClone](https://github.com/SVF-tools/SVF/wiki/TypeClone) published in our [ECOOP paper](https://yuleisui.github.io/publications/ecoop20.pdf) is now available in SVF </b> * <b>SVF now uses a single script for its build. Just type [`source ./build.sh`](https://github.com/SVF-tools/SVF/blob/master/build.sh) in your terminal, that's it!</b> * <b>SVF now supports LLVM-10.0.0! </b> * <b>We thank [bsauce](https://github.com/bsauce) for writing a user manual of SVF ([link1](https://www.jianshu.com/p/068a08ec749c) and [link2](https://www.jianshu.com/p/777c30d4240e)) in Chinese </b> * <b>SVF now supports LLVM-9.0.0 (Thank [Byoungyoung Lee](https://github.com/SVF-tools/SVF/issues/142) for his help!). </b> * <b>SVF now supports a set of [field-sensitive pointer analyses](https://yuleisui.github.io/publications/sas2019a.pdf). </b> * <b>[Use SVF as an external lib](https://github.com/SVF-tools/SVF/wiki/Using-SVF-as-a-lib-in-your-own-tool) for your own project (Contributed by [Hongxu Chen](https://github.com/HongxuChen)). </b> * <b>SVF now supports LLVM-7.0.0. </b> * <b>SVF now supports Docker. [Try SVF in Docker](https://github.com/SVF-tools/SVF/wiki/Try-SVF-in-Docker)! </b> * <b>SVF now supports [LLVM-6.0.0](https://github.com/svf-tools/SVF/pull/38) (Contributed by [Jack Anthony](https://github.com/jackanth)). </b> * <b>SVF now supports [LLVM-4.0.0](https://github.com/svf-tools/SVF/pull/23) (Contributed by Jared Carlson. Thank [Jared](https://github.com/jcarlson23) and [Will](https://github.com/dtzWill) for their in-depth [discussions](https://github.com/svf-tools/SVF/pull/18) about updating SVF!) </b> * <b>SVF now supports analysis for C++ programs.</b> <br />",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,353 @@
1
+ //===- AddressValue.h ----Address Value Sets-------------------------//
2
+ //
3
+ // SVF: Static Value-Flow Analysis
4
+ //
5
+ // Copyright (C) <2013-2022> <Yulei Sui>
6
+ //
7
+
8
+ // This program is free software: you can redistribute it and/or modify
9
+ // it under the terms of the GNU Affero General Public License as published by
10
+ // the Free Software Foundation, either version 3 of the License, or
11
+ // (at your option) any later version.
12
+
13
+ // This program is distributed in the hope that it will be useful,
14
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ // GNU Affero General Public License for more details.
17
+
18
+ // You should have received a copy of the GNU Affero General Public License
19
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ //
21
+ //===----------------------------------------------------------------------===//
22
+ /*
23
+ * BoundedZ3Expr.h
24
+ *
25
+ * Created on: Mar 20, 2023
26
+ * Author: Xiao Cheng
27
+ *
28
+ */
29
+
30
+ #ifndef SVF_BOUNDEDZ3EXPR_H
31
+ #define SVF_BOUNDEDZ3EXPR_H
32
+
33
+ #include "Util/Z3Expr.h"
34
+
35
+ namespace SVF
36
+ {
37
+
38
+ /*!
39
+ * Atom Z3 expr for unlimited precision integers
40
+ */
41
+ class BoundedZ3Expr : public Z3Expr
42
+ {
43
+
44
+ public:
45
+ BoundedZ3Expr() = default;
46
+
47
+ BoundedZ3Expr(const Z3Expr &z3Expr) : Z3Expr(z3Expr) {}
48
+
49
+ BoundedZ3Expr(const z3::expr &e) : Z3Expr(e) {}
50
+
51
+ BoundedZ3Expr(s32_t i) : Z3Expr(i) {}
52
+
53
+ BoundedZ3Expr(int64_t i) : Z3Expr(getContext().int_val(i)) {}
54
+
55
+ BoundedZ3Expr(const BoundedZ3Expr &z3Expr) : Z3Expr(z3Expr) {}
56
+
57
+
58
+ inline BoundedZ3Expr &operator=(const BoundedZ3Expr &rhs)
59
+ {
60
+ Z3Expr::operator=(rhs);
61
+ return *this;
62
+ }
63
+
64
+ BoundedZ3Expr(BoundedZ3Expr &&z3Expr) : Z3Expr(z3Expr) {}
65
+
66
+
67
+ inline BoundedZ3Expr &operator=(BoundedZ3Expr &&rhs)
68
+ {
69
+ Z3Expr::operator=(rhs);
70
+ return *this;
71
+ }
72
+
73
+ bool is_plus_infinite() const
74
+ {
75
+ return eq(*this, getContext().int_const("+oo"));
76
+ }
77
+
78
+ bool is_minus_infinite() const
79
+ {
80
+ return eq(*this, getContext().int_const("-oo"));
81
+ }
82
+
83
+ bool is_infinite() const
84
+ {
85
+ return is_plus_infinite() || is_minus_infinite();
86
+ }
87
+
88
+ void set_plus_infinite()
89
+ {
90
+ *this = plus_infinity();
91
+ }
92
+
93
+ void set_minus_infinite()
94
+ {
95
+ *this = minus_infinity();
96
+ }
97
+
98
+ static BoundedZ3Expr plus_infinity()
99
+ {
100
+ return getContext().int_const("+oo");
101
+ }
102
+
103
+ static BoundedZ3Expr minus_infinity()
104
+ {
105
+ return getContext().int_const("-oo");
106
+ }
107
+
108
+ static z3::context &getContext()
109
+ {
110
+ return Z3Expr::getContext();
111
+ }
112
+
113
+ bool is_zero() const
114
+ {
115
+ return getExpr().is_numeral() && getExpr().get_numeral_int64() == 0;
116
+ }
117
+
118
+ static bool isZero(const BoundedZ3Expr &expr)
119
+ {
120
+ return expr.is_numeral() && expr.get_numeral_int64() == 0;
121
+ }
122
+
123
+ BoundedZ3Expr equal(const BoundedZ3Expr &rhs) const
124
+ {
125
+ return getExpr() == rhs.getExpr();
126
+ }
127
+
128
+ BoundedZ3Expr leq(const BoundedZ3Expr &rhs) const
129
+ {
130
+ return getExpr() <= rhs.getExpr();
131
+ }
132
+
133
+ BoundedZ3Expr geq(const BoundedZ3Expr &rhs) const
134
+ {
135
+ return getExpr() >= rhs.getExpr();
136
+ }
137
+
138
+ /// Reload operator
139
+ //{%
140
+ friend BoundedZ3Expr operator==(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
141
+ {
142
+ return lhs.equal(rhs);
143
+ }
144
+
145
+ friend BoundedZ3Expr operator!=(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
146
+ {
147
+ return !lhs.equal(rhs);
148
+ }
149
+
150
+ friend BoundedZ3Expr operator>(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
151
+ {
152
+ return !lhs.leq(rhs);
153
+ }
154
+
155
+ friend BoundedZ3Expr operator<(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
156
+ {
157
+ return !lhs.geq(rhs);
158
+ }
159
+
160
+ friend BoundedZ3Expr operator<=(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
161
+ {
162
+ return lhs.leq(rhs);
163
+ }
164
+
165
+ friend BoundedZ3Expr operator>=(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
166
+ {
167
+ return lhs.geq(rhs);
168
+ }
169
+
170
+ friend BoundedZ3Expr operator+(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
171
+ {
172
+ if (!lhs.is_infinite() && !rhs.is_infinite())
173
+ return lhs.getExpr() + rhs.getExpr();
174
+ else if (!lhs.is_infinite() && rhs.is_infinite())
175
+ return rhs;
176
+ else if (lhs.is_infinite() && !rhs.is_infinite())
177
+ return lhs;
178
+ else if (eq(lhs, rhs))
179
+ return lhs;
180
+ else
181
+ assert(false && "undefined operation +oo + -oo");
182
+ }
183
+
184
+ friend BoundedZ3Expr operator-(const BoundedZ3Expr &lhs)
185
+ {
186
+ return -lhs.getExpr();
187
+ }
188
+
189
+ friend BoundedZ3Expr operator-(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
190
+ {
191
+ if (!lhs.is_infinite() && !rhs.is_infinite())
192
+ return lhs.getExpr() - rhs.getExpr();
193
+ else if (!lhs.is_infinite() && rhs.is_infinite())
194
+ return -rhs;
195
+ else if (lhs.is_infinite() && !rhs.is_infinite())
196
+ return lhs;
197
+ else if (!eq(lhs, rhs))
198
+ return lhs;
199
+ else
200
+ assert(false && "undefined operation +oo - +oo");
201
+ }
202
+
203
+ friend BoundedZ3Expr operator*(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
204
+ {
205
+ if (lhs.is_zero() || rhs.is_zero()) return 0;
206
+ else if (lhs.is_infinite() && rhs.is_infinite())
207
+ return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
208
+ else if (lhs.is_infinite())
209
+ return ite(rhs.getExpr() > 0, lhs, -lhs);
210
+ else if (rhs.is_infinite())
211
+ return ite(lhs.getExpr() > 0, rhs, -rhs);
212
+ else
213
+ return lhs.getExpr() * rhs.getExpr();
214
+ }
215
+
216
+ friend BoundedZ3Expr operator/(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
217
+ {
218
+ if (rhs.is_zero()) assert(false && "divide by zero");
219
+ else if (!lhs.is_infinite() && !rhs.is_infinite())
220
+ return lhs.getExpr() / rhs.getExpr();
221
+ else if (!lhs.is_infinite() && rhs.is_infinite())
222
+ return 0;
223
+ else if (lhs.is_infinite() && !rhs.is_infinite())
224
+ return ite(rhs.getExpr() > 0, lhs, -lhs);
225
+ else
226
+ // TODO: +oo/-oo L'Hôpital's rule?
227
+ return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
228
+
229
+ }
230
+
231
+ friend BoundedZ3Expr operator%(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
232
+ {
233
+ if (rhs.is_zero()) assert(false && "divide by zero");
234
+ else if (!lhs.is_infinite() && !rhs.is_infinite())
235
+ return lhs.getExpr() % rhs.getExpr();
236
+ else if (!lhs.is_infinite() && rhs.is_infinite())
237
+ return 0;
238
+ // TODO: not sure
239
+ else if (lhs.is_infinite() && !rhs.is_infinite())
240
+ return ite(rhs.getExpr() > 0, lhs, -lhs);
241
+ else
242
+ // TODO: +oo/-oo L'Hôpital's rule?
243
+ return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
244
+ }
245
+
246
+ friend BoundedZ3Expr operator^(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
247
+ {
248
+ return bv2int(int2bv(64, lhs.getExpr()) ^ int2bv(64, rhs.getExpr()), true);
249
+ }
250
+
251
+ friend BoundedZ3Expr operator&(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
252
+ {
253
+ return bv2int(int2bv(64, lhs.getExpr()) & int2bv(64, rhs.getExpr()), true);
254
+ }
255
+
256
+ friend BoundedZ3Expr operator|(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
257
+ {
258
+ return bv2int(int2bv(64, lhs.getExpr()) | int2bv(64, rhs.getExpr()), true);
259
+ }
260
+
261
+ friend BoundedZ3Expr ashr(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
262
+ {
263
+ if (lhs.is_zero())
264
+ return lhs;
265
+ else if (lhs.is_infinite())
266
+ return lhs;
267
+ else if (rhs.is_infinite())
268
+ return ite(lhs.getExpr() >= 0, BoundedZ3Expr(0), BoundedZ3Expr(-1));
269
+ else
270
+ return ashr(lhs.getExpr(), rhs.getExpr());
271
+ }
272
+
273
+ friend BoundedZ3Expr shl(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
274
+ {
275
+ if (lhs.is_zero())
276
+ return lhs;
277
+ else if (lhs.is_infinite())
278
+ return lhs;
279
+ else if (rhs.is_infinite())
280
+ return ite(lhs.getExpr() >= 0, plus_infinity(), minus_infinity());
281
+ else
282
+ return shl(lhs.getExpr(), rhs.getExpr());
283
+ }
284
+
285
+ friend BoundedZ3Expr lshr(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
286
+ {
287
+ return lshr(lhs.getExpr(), rhs.getExpr());
288
+ }
289
+
290
+ friend BoundedZ3Expr int2bv(u32_t n, const BoundedZ3Expr &e)
291
+ {
292
+ return int2bv(n, e.getExpr());
293
+ }
294
+
295
+ friend BoundedZ3Expr bv2int(const BoundedZ3Expr &e, bool isSigned)
296
+ {
297
+ return bv2int(e.getExpr(), isSigned);
298
+ }
299
+
300
+ friend BoundedZ3Expr operator&&(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
301
+ {
302
+ return lhs.getExpr() && rhs.getExpr();
303
+ }
304
+
305
+ friend BoundedZ3Expr operator||(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
306
+ {
307
+ return lhs.getExpr() || rhs.getExpr();
308
+ }
309
+
310
+ friend BoundedZ3Expr operator!(const BoundedZ3Expr &lhs)
311
+ {
312
+ return !lhs.getExpr();
313
+ }
314
+
315
+ friend BoundedZ3Expr ite(const BoundedZ3Expr &cond, const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
316
+ {
317
+ return ite(cond.getExpr(), lhs.getExpr(), rhs.getExpr());
318
+ }
319
+
320
+ friend std::ostream &operator<<(std::ostream &out, const BoundedZ3Expr &expr)
321
+ {
322
+ out << expr.getExpr();
323
+ return out;
324
+ }
325
+
326
+ friend bool eq(const BoundedZ3Expr &lhs, const BoundedZ3Expr &rhs)
327
+ {
328
+ return eq(lhs.getExpr(), rhs.getExpr());
329
+ }
330
+
331
+ inline BoundedZ3Expr simplify() const
332
+ {
333
+ return getExpr().simplify();
334
+ }
335
+
336
+ inline bool is_true() const
337
+ {
338
+ return getExpr().is_true();
339
+ }
340
+ //%}
341
+ }; // end class ConZ3Expr
342
+ } // end namespace SVF
343
+
344
+ /// Specialise hash for ConZ3Expr
345
+ template<>
346
+ struct std::hash<SVF::BoundedZ3Expr>
347
+ {
348
+ size_t operator()(const SVF::BoundedZ3Expr &z3Expr) const
349
+ {
350
+ return z3Expr.hash();
351
+ }
352
+ };
353
+ #endif //SVF_BOUNDEDZ3EXPR_H
@@ -82,7 +82,7 @@ public:
82
82
  /// Create the IntervalValue [-oo, +oo]
83
83
  static IntervalValue top()
84
84
  {
85
- return IntervalValue(INT_MIN, INT_MAX);
85
+ return IntervalValue(minus_infinity(), plus_infinity());
86
86
  }
87
87
 
88
88
  /// Create the bottom IntervalValue
@@ -92,37 +92,41 @@ public:
92
92
  }
93
93
 
94
94
  /// Create default IntervalValue
95
- explicit IntervalValue() : AbstractValue(AbstractValue::IntervalK), _lb(INT_MIN), _ub(INT_MAX) {}
95
+ explicit IntervalValue() : AbstractValue(AbstractValue::IntervalK), _lb(minus_infinity()), _ub(plus_infinity()) {}
96
96
 
97
97
  /// Create the IntervalValue [n, n]
98
- explicit IntervalValue(double n) : AbstractValue(AbstractValue::IntervalK), _lb(n), _ub(n) {}
98
+ explicit IntervalValue(int64_t n) : AbstractValue(AbstractValue::IntervalK), _lb(n), _ub(n) {}
99
99
 
100
- explicit IntervalValue(s32_t n) : IntervalValue((double) n) {}
100
+ explicit IntervalValue(s32_t n) : IntervalValue((int64_t) n) {}
101
101
 
102
- explicit IntervalValue(u32_t n) : IntervalValue((double) n) {}
102
+ explicit IntervalValue(u32_t n) : IntervalValue((int64_t) n) {}
103
+
104
+ explicit IntervalValue(double n) : IntervalValue((int64_t) n) {}
105
+
106
+ explicit IntervalValue(NumericLiteral n) : IntervalValue(n, n) {}
103
107
 
104
108
  /// Create the IntervalValue [lb, ub]
105
109
  explicit IntervalValue(NumericLiteral lb, NumericLiteral ub) : AbstractValue(AbstractValue::IntervalK),
106
110
  _lb(std::move(lb)), _ub(std::move(ub)) {}
107
111
 
108
- explicit IntervalValue(double lb, double ub) : IntervalValue(NumericLiteral(lb), NumericLiteral(ub)) {}
112
+ explicit IntervalValue(int64_t lb, int64_t ub) : IntervalValue(NumericLiteral(lb), NumericLiteral(ub)) {}
109
113
 
110
- explicit IntervalValue(s32_t lb, s32_t ub) : IntervalValue((double) lb, (double) ub) {}
114
+ explicit IntervalValue(double lb, double ub) : IntervalValue(NumericLiteral((int64_t) lb), NumericLiteral((int64_t) ub)) {}
111
115
 
112
- explicit IntervalValue(u32_t lb, u32_t ub) : IntervalValue((double) lb, (double) ub) {}
116
+ explicit IntervalValue(s32_t lb, s32_t ub) : IntervalValue((int64_t) lb, (int64_t) ub) {}
113
117
 
114
- explicit IntervalValue(s64_t lb, s64_t ub) : IntervalValue((double) lb, (double) ub) {}
118
+ explicit IntervalValue(u32_t lb, u32_t ub) : IntervalValue((int64_t) lb, (int64_t) ub) {}
115
119
 
116
- explicit IntervalValue(u64_t lb, u64_t ub) : IntervalValue((double) lb, (double) ub) {}
120
+ explicit IntervalValue(u64_t lb, u64_t ub) : IntervalValue((int64_t) lb, (int64_t) ub) {}
117
121
 
118
122
  /// Copy constructor
119
123
  IntervalValue(const IntervalValue &) = default;
120
124
 
121
125
  /// Move constructor
122
- IntervalValue(IntervalValue &&) noexcept = default;
126
+ IntervalValue(IntervalValue &&) = default;
123
127
 
124
128
  /// Copy assignment operator
125
- IntervalValue &operator=(const IntervalValue &a) noexcept = default;
129
+ IntervalValue &operator=(const IntervalValue &a) = default;
126
130
 
127
131
  /// Move assignment operator
128
132
  IntervalValue &operator=(IntervalValue &&) = default;
@@ -256,7 +260,7 @@ public:
256
260
  }
257
261
 
258
262
  /// Return
259
- double getNumeral() const
263
+ int64_t getNumeral() const
260
264
  {
261
265
  assert(is_numeral() && "this IntervalValue is not numeral");
262
266
  return _lb.getNumeral();
@@ -419,7 +423,7 @@ public:
419
423
  /// Return true if the IntervalValue contains n
420
424
  bool contains(int n) const
421
425
  {
422
- return this->_lb.getNumeral() <= n && this->_ub.getNumeral() >= n;
426
+ return this->_lb.leq(n) && this->_ub.geq(n);
423
427
  }
424
428
 
425
429
  void dump(std::ostream &o) const
@@ -436,7 +440,7 @@ public:
436
440
 
437
441
  std::string toString() const
438
442
  {
439
- return "[" + std::to_string(lb().getNumeral()) + ", " + std::to_string(ub().getNumeral()) + "]";
443
+ return "[" + lb().to_string() + ", " + ub().to_string() + "]";
440
444
  }
441
445
 
442
446
  }; // end class IntervalValue
@@ -491,8 +495,9 @@ inline IntervalValue operator*(const IntervalValue &lhs,
491
495
  NumericLiteral lu = lhs.lb() * rhs.ub();
492
496
  NumericLiteral ul = lhs.ub() * rhs.lb();
493
497
  NumericLiteral uu = lhs.ub() * rhs.ub();
494
- return IntervalValue(std::min({ll.getNumeral(), lu.getNumeral(), ul.getNumeral(), uu.getNumeral()}),
495
- std::max({ll.getNumeral(), lu.getNumeral(), ul.getNumeral(), uu.getNumeral()}));
498
+ std::vector<NumericLiteral> vec{ll, lu, ul, uu};
499
+ return IntervalValue(NumericLiteral::min(vec),
500
+ NumericLiteral::max(vec));
496
501
  }
497
502
  }
498
503
 
@@ -515,8 +520,10 @@ inline IntervalValue operator/(const IntervalValue &lhs,
515
520
  NumericLiteral lu = lhs.lb() / rhs.ub();
516
521
  NumericLiteral ul = lhs.ub() / rhs.lb();
517
522
  NumericLiteral uu = lhs.ub() / rhs.ub();
518
- return IntervalValue(std::min({ll.getNumeral(), lu.getNumeral(), ul.getNumeral(), uu.getNumeral()}),
519
- std::max({ll.getNumeral(), lu.getNumeral(), ul.getNumeral(), uu.getNumeral()}));
523
+ std::vector<NumericLiteral> vec{ll, lu, ul, uu};
524
+
525
+ return IntervalValue(NumericLiteral::min(vec),
526
+ NumericLiteral::max(vec));
520
527
  }
521
528
  }
522
529
 
@@ -538,9 +545,9 @@ inline IntervalValue operator%(const IntervalValue &lhs,
538
545
  }
539
546
  else
540
547
  {
541
- double n_ub = std::max(std::abs(lhs.lb().getNumeral()), std::abs(lhs.ub().getNumeral()));
542
- double d_ub = std::max(std::abs(rhs.lb().getNumeral()), std::abs(rhs.ub().getNumeral())) - 1;
543
- double ub = std::min(n_ub, d_ub);
548
+ NumericLiteral n_ub = max(abs(lhs.lb()), abs(lhs.ub()));
549
+ NumericLiteral d_ub = max(abs(rhs.lb()), rhs.ub() - 1);
550
+ NumericLiteral ub = min(n_ub, d_ub);
544
551
 
545
552
  if (lhs.lb().getNumeral() < 0)
546
553
  {
@@ -550,12 +557,12 @@ inline IntervalValue operator%(const IntervalValue &lhs,
550
557
  }
551
558
  else
552
559
  {
553
- return IntervalValue(-ub, double(0));
560
+ return IntervalValue(-ub, 0);
554
561
  }
555
562
  }
556
563
  else
557
564
  {
558
- return IntervalValue(double(0), ub);
565
+ return IntervalValue(0, ub);
559
566
  }
560
567
  }
561
568
  }
@@ -580,12 +587,12 @@ inline IntervalValue operator>(const IntervalValue &lhs, const IntervalValue &rh
580
587
  else
581
588
  {
582
589
  // lhs[3,4] rhs[1,2]
583
- if (lhs.lb().getNumeral() > rhs.ub().getNumeral())
590
+ if (!lhs.lb().leq(rhs.ub()))
584
591
  {
585
592
  return IntervalValue(1, 1);
586
593
  // lhs[1,2] rhs[3,4]
587
594
  }
588
- else if (lhs.ub().getNumeral() < rhs.lb().getNumeral())
595
+ else if (lhs.ub().geq(rhs.lb()))
589
596
  {
590
597
  return IntervalValue(0, 0);
591
598
  }
@@ -618,12 +625,12 @@ inline IntervalValue operator<(const IntervalValue &lhs, const IntervalValue &rh
618
625
  else
619
626
  {
620
627
  // lhs [1,2] rhs [3,4]
621
- if (lhs.ub().getNumeral() < rhs.lb().getNumeral())
628
+ if (!lhs.ub().geq(rhs.lb()))
622
629
  {
623
630
  return IntervalValue(1, 1);
624
631
  // lhs [3,4] rhs [1,2]
625
632
  }
626
- else if (lhs.lb().getNumeral() > rhs.ub().getNumeral())
633
+ else if (!lhs.lb().leq(rhs.ub()))
627
634
  {
628
635
  return IntervalValue(0, 0);
629
636
  // lhs [1,3] rhs [2,4]
@@ -657,12 +664,12 @@ inline IntervalValue operator>=(const IntervalValue &lhs, const IntervalValue &r
657
664
  else
658
665
  {
659
666
  // lhs [2,3] rhs [1,2]
660
- if (lhs.lb().getNumeral() >= rhs.ub().getNumeral())
667
+ if (lhs.lb().geq(rhs.ub()))
661
668
  {
662
669
  return IntervalValue(1, 1);
663
670
  // lhs [1,2] rhs[3,4]
664
671
  }
665
- else if (lhs.ub().getNumeral() < rhs.lb().getNumeral())
672
+ else if (!lhs.ub().geq(rhs.lb()))
666
673
  {
667
674
  return IntervalValue(0, 0);
668
675
  // lhs [1,3] rhs [2,4]
@@ -696,12 +703,12 @@ inline IntervalValue operator<=(const IntervalValue &lhs, const IntervalValue &r
696
703
  else
697
704
  {
698
705
  // lhs [1,2] rhs [2,3]
699
- if (lhs.ub().getNumeral() <= rhs.lb().getNumeral())
706
+ if (lhs.ub().leq(rhs.lb()))
700
707
  {
701
708
  return IntervalValue(1, 1);
702
709
  // lhs [3,4] rhs[1,2]
703
710
  }
704
- else if (lhs.lb().getNumeral() > rhs.ub().getNumeral())
711
+ else if (!lhs.lb().leq(rhs.ub()))
705
712
  {
706
713
  return IntervalValue(0, 0);
707
714
  // lhs [1,3] rhs [2,4]
@@ -765,8 +772,9 @@ inline IntervalValue operator>>(const IntervalValue &lhs, const IntervalValue &r
765
772
  NumericLiteral lu = lhs.lb() >> shift.ub();
766
773
  NumericLiteral ul = lhs.ub() >> shift.lb();
767
774
  NumericLiteral uu = lhs.ub() >> shift.ub();
768
- return IntervalValue(std::min({ll.getNumeral(), lu.getNumeral(), ul.getNumeral(), uu.getNumeral()}),
769
- std::max({ll.getNumeral(), lu.getNumeral(), ul.getNumeral(), uu.getNumeral()}));
775
+ std::vector<NumericLiteral> vec{ll, lu, ul, uu};
776
+ return IntervalValue(NumericLiteral::min(vec),
777
+ NumericLiteral::max(vec));
770
778
  }
771
779
  }
772
780
  }
@@ -778,19 +786,19 @@ inline IntervalValue operator&(const IntervalValue &lhs, const IntervalValue &rh
778
786
  return IntervalValue::bottom();
779
787
  else if (lhs.is_numeral() && rhs.is_numeral())
780
788
  {
781
- return IntervalValue((s32_t)lhs.getNumeral() & (s32_t)rhs.getNumeral());
789
+ return IntervalValue(lhs.lb() & rhs.lb());
782
790
  }
783
791
  else if (lhs.lb().getNumeral() >= 0 && rhs.lb().getNumeral() >= 0)
784
792
  {
785
- return IntervalValue(0.0, std::min(lhs.ub().getNumeral(), rhs.ub().getNumeral()));
793
+ return IntervalValue((int64_t) 0, min(lhs.ub(), rhs.ub()));
786
794
  }
787
795
  else if (lhs.lb().getNumeral() >= 0)
788
796
  {
789
- return IntervalValue(0.0, lhs.ub().getNumeral());
797
+ return IntervalValue((int64_t) 0, lhs.ub());
790
798
  }
791
799
  else if (rhs.lb().getNumeral() >= 0)
792
800
  {
793
- return IntervalValue(0.0, rhs.ub().getNumeral());
801
+ return IntervalValue((int64_t) 0, rhs.ub());
794
802
  }
795
803
  else
796
804
  {
@@ -813,13 +821,13 @@ inline IntervalValue operator|(const IntervalValue &lhs, const IntervalValue &rh
813
821
  if (lhs.isBottom() || rhs.isBottom())
814
822
  return IntervalValue::bottom();
815
823
  else if (lhs.is_numeral() && rhs.is_numeral())
816
- return IntervalValue((s32_t)lhs.getNumeral() | (s32_t)rhs.getNumeral());
824
+ return IntervalValue(lhs.lb() | rhs.lb());
817
825
  else if (lhs.lb().getNumeral() >= 0 && !lhs.ub().is_infinity() &&
818
826
  rhs.lb().getNumeral() >= 0 && !rhs.ub().is_infinity())
819
827
  {
820
- double m = std::max(lhs.ub().getNumeral(), rhs.ub().getNumeral());
821
- double ub = next_power_of_2(s64_t(m+1));
822
- return IntervalValue(0.0, ub);
828
+ int64_t m = std::max(lhs.ub().getNumeral(), rhs.ub().getNumeral());
829
+ int64_t ub = next_power_of_2(s64_t(m+1));
830
+ return IntervalValue((int64_t) 0, (int64_t) ub);
823
831
  }
824
832
  else
825
833
  {
@@ -842,13 +850,13 @@ inline IntervalValue operator^(const IntervalValue &lhs, const IntervalValue &rh
842
850
  if (lhs.isBottom() || rhs.isBottom())
843
851
  return IntervalValue::bottom();
844
852
  else if (lhs.is_numeral() && rhs.is_numeral())
845
- return IntervalValue((s32_t)lhs.getNumeral() ^ (s32_t)rhs.getNumeral());
853
+ return IntervalValue(lhs.lb() ^ rhs.lb());
846
854
  else if (lhs.lb().getNumeral() >= 0 && !lhs.ub().is_infinity() &&
847
855
  rhs.lb().getNumeral() >= 0 && !rhs.ub().is_infinity())
848
856
  {
849
- double m = std::max(lhs.ub().getNumeral(), rhs.ub().getNumeral());
850
- double ub = next_power_of_2(s64_t(m+1));
851
- return IntervalValue(0.0, ub);
857
+ int64_t m = std::max(lhs.ub().getNumeral(), rhs.ub().getNumeral());
858
+ int64_t ub = next_power_of_2(s64_t(m+1));
859
+ return IntervalValue((int64_t) 0, (int64_t) ub);
852
860
  }
853
861
  else
854
862
  {
@@ -30,70 +30,78 @@
30
30
  #ifndef Z3_EXAMPLE_Number_H
31
31
  #define Z3_EXAMPLE_Number_H
32
32
 
33
+ #include <utility>
34
+
33
35
  #include "SVFIR/SVFType.h"
36
+ #include "AbstractExecution/BoundedZ3Expr.h"
34
37
 
35
38
  namespace SVF
36
39
  {
37
40
  class NumericLiteral
38
41
  {
39
42
  private:
40
- double _n;
43
+ BoundedZ3Expr _n;
41
44
 
42
45
  public:
43
46
  /// Default constructor
44
47
  NumericLiteral() = delete;
45
48
 
46
- /// Create a new NumericLiteral from double
47
- NumericLiteral(double n) : _n(n) {}
48
-
49
49
  /// Create a new NumericLiteral from s32_t
50
- NumericLiteral(s32_t n) : _n(n) {}
51
50
 
52
- /// Create a new NumericLiteral from s64_t
53
- NumericLiteral(s64_t n) : _n(n) {}
51
+ NumericLiteral(const Z3Expr &z3Expr) : _n(z3Expr) {}
52
+
53
+ NumericLiteral(const z3::expr &e) : _n(e) {}
54
54
 
55
- /// Create a new NumericLiteral from u32_t
56
- NumericLiteral(u32_t n) : _n(n) {}
55
+ NumericLiteral(s32_t i) : _n(i) {}
57
56
 
58
- /// Create a new NumericLiteral from u64_t
59
- NumericLiteral(u64_t n) : _n(n) {}
57
+ NumericLiteral(int64_t i) : _n(i) {}
58
+
59
+ NumericLiteral(BoundedZ3Expr z3Expr) : _n(std::move(z3Expr)) {}
60
60
 
61
61
  virtual ~NumericLiteral() = default;
62
62
 
63
63
  /// Copy Constructor
64
- NumericLiteral(const NumericLiteral &) noexcept = default;
64
+ NumericLiteral(const NumericLiteral &) = default;
65
65
 
66
66
  /// Move Constructor
67
- NumericLiteral(NumericLiteral &&) noexcept = default;
67
+ NumericLiteral(NumericLiteral &&) = default;
68
68
 
69
69
  /// Operator = , another Copy Constructor
70
- inline NumericLiteral &operator=(const NumericLiteral &) noexcept = default;
70
+ inline NumericLiteral &operator=(const NumericLiteral &) = default;
71
71
 
72
72
  /// Operator = , another Move Constructor
73
- inline NumericLiteral &operator=(NumericLiteral &&) noexcept = default;
73
+ inline NumericLiteral &operator=(NumericLiteral &&) = default;
74
+
75
+ static NumericLiteral plus_infinity()
76
+ {
77
+ return BoundedZ3Expr::plus_infinity();
78
+ }
74
79
 
75
- /// Get minus infinity -oo
76
80
  static NumericLiteral minus_infinity()
77
81
  {
78
- return NumericLiteral(INT_MIN);
82
+ return BoundedZ3Expr::minus_infinity();
79
83
  }
80
84
 
81
- /// Get plus infinity +oo
82
- static NumericLiteral plus_infinity()
85
+ static z3::context &getContext()
83
86
  {
84
- return NumericLiteral(INT_MAX);
87
+ return BoundedZ3Expr::getContext();
88
+ }
89
+
90
+ const std::string to_string() const
91
+ {
92
+ return _n.to_string();
85
93
  }
86
94
 
87
95
  /// Check if this is minus infinity
88
96
  inline bool is_minus_infinity() const
89
97
  {
90
- return _n == INT_MIN;
98
+ return _n.is_minus_infinite();
91
99
  }
92
100
 
93
101
  /// Check if this is plus infinity
94
102
  inline bool is_plus_infinity() const
95
103
  {
96
- return _n == INT_MAX;
104
+ return _n.is_plus_infinite();
97
105
  }
98
106
 
99
107
  /// Check if this is infinity (either of plus/minus)
@@ -105,13 +113,34 @@ public:
105
113
  /// Check if this is zero
106
114
  inline bool is_zero() const
107
115
  {
108
- return _n == 0;
116
+ return _n.is_zero();
109
117
  }
110
118
 
111
119
  /// Return Numeral
112
- inline double getNumeral() const
120
+ inline int64_t getNumeral() const
113
121
  {
114
- return _n;
122
+ if (_n.is_numeral())
123
+ {
124
+ int64_t i;
125
+ if(_n.getExpr().is_numeral_i64(i))
126
+ return _n.get_numeral_int64();
127
+ else
128
+ {
129
+ return leq(0) ? INT64_MIN : INT64_MAX;
130
+ }
131
+ }
132
+ if (is_minus_infinity())
133
+ {
134
+ return INT64_MIN;
135
+ }
136
+ else if (is_plus_infinity())
137
+ {
138
+ return INT64_MAX;
139
+ }
140
+ else
141
+ {
142
+ assert(false && "other literal?");
143
+ }
115
144
  }
116
145
 
117
146
  /// Check two object is equal
@@ -134,7 +163,13 @@ public:
134
163
  return rhs.is_plus_infinity();
135
164
  }
136
165
  }
137
- return _n <= rhs._n;
166
+ if(is_infinity() && rhs.is_infinity())
167
+ {
168
+ if(is_minus_infinity()) return true;
169
+ else return rhs.is_plus_infinity();
170
+ }
171
+ else
172
+ return _n.leq(rhs._n).simplify().is_true();
138
173
  }
139
174
 
140
175
  // Greater than or equal
@@ -151,7 +186,13 @@ public:
151
186
  return rhs.is_minus_infinity();
152
187
  }
153
188
  }
154
- return _n >= rhs._n;
189
+ if(is_infinity() && rhs.is_infinity())
190
+ {
191
+ if(is_plus_infinity()) return true;
192
+ else return rhs.is_minus_infinity();
193
+ }
194
+ else
195
+ return _n.geq(rhs._n).simplify().is_true();
155
196
  }
156
197
 
157
198
 
@@ -159,38 +200,38 @@ public:
159
200
  //{%
160
201
  friend NumericLiteral operator==(const NumericLiteral &lhs, const NumericLiteral &rhs)
161
202
  {
162
- return eq(lhs, rhs);
203
+ return eq(lhs, rhs) ? 1 : 0;
163
204
  }
164
205
 
165
206
  friend NumericLiteral operator!=(const NumericLiteral &lhs, const NumericLiteral &rhs)
166
207
  {
167
- return !eq(lhs, rhs);
208
+ return !eq(lhs, rhs) ? 1 : 0;
168
209
  }
169
210
 
170
211
  friend NumericLiteral operator>(const NumericLiteral &lhs, const NumericLiteral &rhs)
171
212
  {
172
- return !lhs.leq(rhs);
213
+ return (!lhs.leq(rhs)) ? 1 : 0;
173
214
  }
174
215
 
175
216
  friend NumericLiteral operator<(const NumericLiteral &lhs, const NumericLiteral &rhs)
176
217
  {
177
- return !lhs.geq(rhs);
218
+ return (!lhs.geq(rhs)) ? 1 : 0;
178
219
  }
179
220
 
180
221
  friend NumericLiteral operator<=(const NumericLiteral &lhs, const NumericLiteral &rhs)
181
222
  {
182
- return lhs.leq(rhs);
223
+ return lhs.leq(rhs) ? 1 : 0;
183
224
  }
184
225
 
185
226
  friend NumericLiteral operator>=(const NumericLiteral &lhs, const NumericLiteral &rhs)
186
227
  {
187
- return lhs.geq(rhs);
228
+ return lhs.geq(rhs) ? 1 : 0;
188
229
  }
189
230
 
190
- friend NumericLiteral operator+(const NumericLiteral& lhs, const NumericLiteral& rhs)
231
+ friend NumericLiteral operator+(const NumericLiteral &lhs, const NumericLiteral &rhs)
191
232
  {
192
233
  if (!lhs.is_infinity() && !rhs.is_infinity())
193
- return lhs.getNumeral() + rhs.getNumeral();
234
+ return (lhs._n + rhs._n).simplify();
194
235
  else if (!lhs.is_infinity() && rhs.is_infinity())
195
236
  return rhs;
196
237
  else if (lhs.is_infinity() && !rhs.is_infinity())
@@ -207,7 +248,7 @@ public:
207
248
  friend NumericLiteral operator-(const NumericLiteral &lhs, const NumericLiteral &rhs)
208
249
  {
209
250
  if (!lhs.is_infinity() && !rhs.is_infinity())
210
- return lhs.getNumeral() - rhs.getNumeral();
251
+ return (lhs._n - rhs._n).simplify();
211
252
  else if (!lhs.is_infinity() && rhs.is_infinity())
212
253
  return -rhs;
213
254
  else if (lhs.is_infinity() && !rhs.is_infinity())
@@ -228,11 +269,11 @@ public:
228
269
  else if (lhs.is_infinity() && rhs.is_infinity())
229
270
  return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
230
271
  else if (lhs.is_infinity())
231
- return rhs.getNumeral() > 0 ? lhs : -lhs;
272
+ return !rhs.leq(0) ? lhs : -lhs;
232
273
  else if (rhs.is_infinity())
233
- return lhs.getNumeral() > 0 ? rhs : -rhs;
274
+ return !lhs.leq(0) ? rhs : -rhs;
234
275
  else
235
- return lhs.getNumeral() * rhs.getNumeral();
276
+ return (lhs._n * rhs._n).simplify();
236
277
  }
237
278
 
238
279
  friend NumericLiteral operator/(const NumericLiteral &lhs, const NumericLiteral &rhs)
@@ -244,11 +285,11 @@ public:
244
285
  abort();
245
286
  }
246
287
  else if (!lhs.is_infinity() && !rhs.is_infinity())
247
- return lhs.getNumeral() / rhs.getNumeral();
288
+ return (lhs._n / rhs._n).simplify();
248
289
  else if (!lhs.is_infinity() && rhs.is_infinity())
249
290
  return 0;
250
291
  else if (lhs.is_infinity() && !rhs.is_infinity())
251
- return rhs.getNumeral() > 0 ? lhs : -lhs;
292
+ return !rhs.leq(0) ? lhs : -lhs;
252
293
  else
253
294
  // TODO: +oo/-oo L'Hôpital's rule?
254
295
  return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
@@ -262,12 +303,12 @@ public:
262
303
  abort();
263
304
  }
264
305
  else if (!lhs.is_infinity() && !rhs.is_infinity())
265
- return (s32_t) lhs.getNumeral() % (s32_t) rhs.getNumeral();
306
+ return (lhs._n % rhs._n).simplify();
266
307
  else if (!lhs.is_infinity() && rhs.is_infinity())
267
308
  return 0;
268
309
  // TODO: not sure
269
310
  else if (lhs.is_infinity() && !rhs.is_infinity())
270
- return rhs.getNumeral() > 0 ? lhs : -lhs;
311
+ return !rhs.leq(0) ? lhs : -lhs;
271
312
  else
272
313
  // TODO: +oo/-oo L'Hôpital's rule?
273
314
  return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
@@ -276,17 +317,17 @@ public:
276
317
  // TODO: logic operation for infinity?
277
318
  friend NumericLiteral operator^(const NumericLiteral &lhs, const NumericLiteral &rhs)
278
319
  {
279
- return (s32_t) lhs.getNumeral() ^ (s32_t) rhs.getNumeral();
320
+ return (lhs._n ^ rhs._n).simplify();
280
321
  }
281
322
 
282
323
  friend NumericLiteral operator&(const NumericLiteral &lhs, const NumericLiteral &rhs)
283
324
  {
284
- return (s32_t) lhs.getNumeral() & (s32_t) rhs.getNumeral();
325
+ return (lhs._n & rhs._n).simplify();
285
326
  }
286
327
 
287
328
  friend NumericLiteral operator|(const NumericLiteral &lhs, const NumericLiteral &rhs)
288
329
  {
289
- return (s32_t) lhs.getNumeral() | (s32_t) rhs.getNumeral();
330
+ return (lhs._n | rhs._n).simplify();
290
331
  }
291
332
 
292
333
  friend NumericLiteral operator>>(const NumericLiteral &lhs, const NumericLiteral &rhs)
@@ -297,7 +338,7 @@ public:
297
338
  else if (lhs.is_infinity())
298
339
  return lhs;
299
340
  else if (rhs.is_infinity())
300
- return lhs._n >= 0 ? 0 : -1;
341
+ return lhs.geq(0) ? 0 : -1;
301
342
  else
302
343
  return (s32_t) lhs.getNumeral() >> (s32_t) rhs.getNumeral();
303
344
  }
@@ -310,35 +351,44 @@ public:
310
351
  else if (lhs.is_infinity())
311
352
  return lhs;
312
353
  else if (rhs.is_infinity())
313
- return lhs._n >= 0 ? plus_infinity() : minus_infinity();
354
+ return lhs.geq(0) ? plus_infinity() : minus_infinity();
314
355
  else
315
356
  return (s32_t) lhs.getNumeral() << (s32_t) rhs.getNumeral();
316
357
  }
317
358
 
318
359
  friend NumericLiteral operator&&(const NumericLiteral &lhs, const NumericLiteral &rhs)
319
360
  {
320
- return lhs.getNumeral() && rhs.getNumeral();
361
+ return (lhs._n && rhs._n).simplify();
321
362
  }
322
363
 
323
364
  friend NumericLiteral operator||(const NumericLiteral &lhs, const NumericLiteral &rhs)
324
365
  {
325
- return lhs.getNumeral() || rhs.getNumeral();
366
+ return (lhs._n || rhs._n).simplify();
326
367
  }
327
368
 
328
369
  friend NumericLiteral operator!(const NumericLiteral &lhs)
329
370
  {
330
- return !lhs.getNumeral();
371
+ return (!lhs._n).simplify();
331
372
  }
332
373
 
333
374
  friend NumericLiteral operator-(const NumericLiteral &lhs)
334
375
  {
335
- return -lhs.getNumeral();
376
+ if (lhs.is_plus_infinity())
377
+ {
378
+ return minus_infinity();
379
+ }
380
+ else if (lhs.is_minus_infinity())
381
+ {
382
+ return plus_infinity();
383
+ }
384
+ else
385
+ return (-lhs._n).simplify();
336
386
  }
337
387
 
338
388
  /// Return ite? lhs : rhs
339
389
  friend NumericLiteral ite(const NumericLiteral &cond, const NumericLiteral &lhs, const NumericLiteral &rhs)
340
390
  {
341
- return cond.getNumeral() ? lhs.getNumeral() : rhs.getNumeral();
391
+ return ite(cond._n, lhs._n, rhs._n).simplify();
342
392
  }
343
393
 
344
394
  friend std::ostream &operator<<(std::ostream &out, const NumericLiteral &expr)
@@ -348,29 +398,34 @@ public:
348
398
  else if (expr.is_minus_infinity())
349
399
  out << "-INF";
350
400
  else
351
- out << std::to_string(expr.getNumeral());
401
+ out << expr._n;
352
402
  return out;
353
403
  }
354
404
 
355
405
  friend bool eq(const NumericLiteral &lhs, const NumericLiteral &rhs)
356
406
  {
357
- return lhs._n == rhs._n;
407
+ return eq(lhs._n, rhs._n);
358
408
  }
359
409
 
360
410
  friend NumericLiteral min(const NumericLiteral &lhs, const NumericLiteral &rhs)
361
411
  {
362
- return std::min(lhs.getNumeral(), rhs.getNumeral());
412
+ return lhs.leq(rhs) ? lhs : rhs;
363
413
  }
364
414
 
365
415
  friend NumericLiteral max(const NumericLiteral &lhs, const NumericLiteral &rhs)
366
416
  {
367
- return std::max(lhs.getNumeral(), rhs.getNumeral());
417
+ return lhs.leq(rhs) ? rhs : lhs;
418
+ }
419
+
420
+ friend NumericLiteral abs(const NumericLiteral &lhs)
421
+ {
422
+ return lhs.leq(0) ? -lhs : lhs;
368
423
  }
369
424
 
370
425
  // TODO: how to use initializer_list as argument?
371
- friend NumericLiteral min(std::initializer_list<NumericLiteral> _l)
426
+ static NumericLiteral min(std::vector<NumericLiteral>& _l)
372
427
  {
373
- NumericLiteral ret(INT_MAX);
428
+ NumericLiteral ret(plus_infinity());
374
429
  for (const auto &it: _l)
375
430
  {
376
431
  if (it.is_minus_infinity())
@@ -383,9 +438,9 @@ public:
383
438
  return ret;
384
439
  }
385
440
 
386
- friend NumericLiteral max(std::initializer_list<NumericLiteral> _l)
441
+ static NumericLiteral max(std::vector<NumericLiteral>& _l)
387
442
  {
388
- NumericLiteral ret(INT_MIN);
443
+ NumericLiteral ret(minus_infinity());
389
444
  for (const auto &it: _l)
390
445
  {
391
446
  if (it.is_plus_infinity())
@@ -401,6 +456,6 @@ public:
401
456
  //%}
402
457
 
403
458
 
404
- }; // end class IntervalDouble
459
+ }; // end class NumericLiteral
405
460
  } // end namespace SVF
406
461
  #endif //Z3_EXAMPLE_Number_H