1 /* Abstract checked arithmetic functions: fall-backs.
2 Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3 Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4
5 This file is part of the Parma Polyhedra Library (PPL).
6
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23
24 #ifndef PPL_checked_inlines_hh
25 #define PPL_checked_inlines_hh 1
26
27 #include "globals_types.hh"
28 #include "meta_programming.hh"
29 #include "C_Integer.hh"
30 #include "assertions.hh"
31
32 /*! \brief
33 Performs the test <CODE>a < b</CODE> avoiding the warning about the
34 comparison being always false due to limited range of data type.
35 FIXME: we have not found a working solution. The GCC option
36 -Wno-type-limits suppresses the warning
37 */
38 #define PPL_LT_SILENT(a, b) ((a) < (b))
39 #define PPL_GT_SILENT(a, b) ((a) > (b))
40
41 namespace Parma_Polyhedra_Library {
42
43 namespace Checked {
44
45 template <typename T1, typename T2>
46 struct Safe_Conversion : public False {
47 };
48 template <typename T>
49 struct Safe_Conversion<T, T> : public True {
50 };
51
52 #define PPL_SAFE_CONVERSION(To, From) \
53 template <> struct Safe_Conversion<PPL_U(To), PPL_U(From)> \
54 : public True { }
55
56 #if PPL_CXX_PLAIN_CHAR_IS_SIGNED
57 PPL_SAFE_CONVERSION(signed short, char);
58 #endif
59 PPL_SAFE_CONVERSION(signed short, signed char);
60 #if PPL_SIZEOF_CHAR < PPL_SIZEOF_SHORT
61 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
62 PPL_SAFE_CONVERSION(signed short, char);
63 #endif
64 PPL_SAFE_CONVERSION(signed short, unsigned char);
65 #endif
66
67 #if PPL_CXX_PLAIN_CHAR_IS_SIGNED
68 PPL_SAFE_CONVERSION(signed int, char);
69 #endif
70 PPL_SAFE_CONVERSION(signed int, signed char);
71 PPL_SAFE_CONVERSION(signed int, signed short);
72 #if PPL_SIZEOF_CHAR < PPL_SIZEOF_INT
73 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
74 PPL_SAFE_CONVERSION(signed int, char);
75 #endif
76 PPL_SAFE_CONVERSION(signed int, unsigned char);
77 #endif
78 #if PPL_SIZEOF_SHORT < PPL_SIZEOF_INT
79 PPL_SAFE_CONVERSION(signed int, unsigned short);
80 #endif
81
82 #if PPL_CXX_PLAIN_CHAR_IS_SIGNED
83 PPL_SAFE_CONVERSION(signed long, char);
84 #endif
85 PPL_SAFE_CONVERSION(signed long, signed char);
86 PPL_SAFE_CONVERSION(signed long, signed short);
87 PPL_SAFE_CONVERSION(signed long, signed int);
88 #if PPL_SIZEOF_CHAR < PPL_SIZEOF_LONG
89 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
90 PPL_SAFE_CONVERSION(signed long, char);
91 #endif
92 PPL_SAFE_CONVERSION(signed long, unsigned char);
93 #endif
94 #if PPL_SIZEOF_SHORT < PPL_SIZEOF_LONG
95 PPL_SAFE_CONVERSION(signed long, unsigned short);
96 #endif
97 #if PPL_SIZEOF_INT < PPL_SIZEOF_LONG
98 PPL_SAFE_CONVERSION(signed long, unsigned int);
99 #endif
100
101 #if PPL_CXX_PLAIN_CHAR_IS_SIGNED
102 PPL_SAFE_CONVERSION(signed long long, char);
103 #endif
104 PPL_SAFE_CONVERSION(signed long long, signed char);
105 PPL_SAFE_CONVERSION(signed long long, signed short);
106 PPL_SAFE_CONVERSION(signed long long, signed int);
107 PPL_SAFE_CONVERSION(signed long long, signed long);
108 #if PPL_SIZEOF_CHAR < PPL_SIZEOF_LONG_LONG
109 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
110 PPL_SAFE_CONVERSION(signed long long, char);
111 #endif
112 PPL_SAFE_CONVERSION(signed long long, unsigned char);
113 #endif
114 #if PPL_SIZEOF_SHORT < PPL_SIZEOF_LONG_LONG
115 PPL_SAFE_CONVERSION(signed long long, unsigned short);
116 #endif
117 #if PPL_SIZEOF_INT < PPL_SIZEOF_LONG_LONG
118 PPL_SAFE_CONVERSION(signed long long, unsigned int);
119 #endif
120 #if PPL_SIZEOF_LONG < PPL_SIZEOF_LONG_LONG
121 PPL_SAFE_CONVERSION(signed long long, unsigned long);
122 #endif
123
124 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
125 PPL_SAFE_CONVERSION(unsigned short, char);
126 #endif
127 PPL_SAFE_CONVERSION(unsigned short, unsigned char);
128
129 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
130 PPL_SAFE_CONVERSION(unsigned int, char);
131 #endif
132 PPL_SAFE_CONVERSION(unsigned int, unsigned char);
133 PPL_SAFE_CONVERSION(unsigned int, unsigned short);
134
135 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
136 PPL_SAFE_CONVERSION(unsigned long, char);
137 #endif
138 PPL_SAFE_CONVERSION(unsigned long, unsigned char);
139 PPL_SAFE_CONVERSION(unsigned long, unsigned short);
140 PPL_SAFE_CONVERSION(unsigned long, unsigned int);
141
142 #if !PPL_CXX_PLAIN_CHAR_IS_SIGNED
143 PPL_SAFE_CONVERSION(unsigned long long, char);
144 #endif
145 PPL_SAFE_CONVERSION(unsigned long long, unsigned char);
146 PPL_SAFE_CONVERSION(unsigned long long, unsigned short);
147 PPL_SAFE_CONVERSION(unsigned long long, unsigned int);
148 PPL_SAFE_CONVERSION(unsigned long long, unsigned long);
149
150
151 #if PPL_SIZEOF_CHAR <= PPL_SIZEOF_FLOAT - 2
152 PPL_SAFE_CONVERSION(float, char);
153 PPL_SAFE_CONVERSION(float, signed char);
154 PPL_SAFE_CONVERSION(float, unsigned char);
155 #endif
156 #if PPL_SIZEOF_SHORT <= PPL_SIZEOF_FLOAT - 2
157 PPL_SAFE_CONVERSION(float, signed short);
158 PPL_SAFE_CONVERSION(float, unsigned short);
159 #endif
160 #if PPL_SIZEOF_INT <= PPL_SIZEOF_FLOAT - 2
161 PPL_SAFE_CONVERSION(float, signed int);
162 PPL_SAFE_CONVERSION(float, unsigned int);
163 #endif
164 #if PPL_SIZEOF_LONG <= PPL_SIZEOF_FLOAT - 2
165 PPL_SAFE_CONVERSION(float, signed long);
166 PPL_SAFE_CONVERSION(float, unsigned long);
167 #endif
168 #if PPL_SIZEOF_LONG_LONG <= PPL_SIZEOF_FLOAT - 2
169 PPL_SAFE_CONVERSION(float, signed long long);
170 PPL_SAFE_CONVERSION(float, unsigned long long);
171 #endif
172
173 #if PPL_SIZEOF_CHAR <= PPL_SIZEOF_DOUBLE - 4
174 PPL_SAFE_CONVERSION(double, char);
175 PPL_SAFE_CONVERSION(double, signed char);
176 PPL_SAFE_CONVERSION(double, unsigned char);
177 #endif
178 #if PPL_SIZEOF_SHORT <= PPL_SIZEOF_DOUBLE - 4
179 PPL_SAFE_CONVERSION(double, signed short);
180 PPL_SAFE_CONVERSION(double, unsigned short);
181 #endif
182 #if PPL_SIZEOF_INT <= PPL_SIZEOF_DOUBLE - 4
183 PPL_SAFE_CONVERSION(double, signed int);
184 PPL_SAFE_CONVERSION(double, unsigned int);
185 #endif
186 #if PPL_SIZEOF_LONG <= PPL_SIZEOF_DOUBLE - 4
187 PPL_SAFE_CONVERSION(double, signed long);
188 PPL_SAFE_CONVERSION(double, unsigned long);
189 #endif
190 #if PPL_SIZEOF_LONG_LONG <= PPL_SIZEOF_DOUBLE - 4
191 PPL_SAFE_CONVERSION(double, signed long long);
192 PPL_SAFE_CONVERSION(double, unsigned long long);
193 #endif
194 PPL_SAFE_CONVERSION(double, float);
195
196 #if PPL_SIZEOF_CHAR <= PPL_SIZEOF_LONG_DOUBLE - 4
197 PPL_SAFE_CONVERSION(long double, char);
198 PPL_SAFE_CONVERSION(long double, signed char);
199 PPL_SAFE_CONVERSION(long double, unsigned char);
200 #endif
201 #if PPL_SIZEOF_SHORT <= PPL_SIZEOF_LONG_DOUBLE - 4
202 PPL_SAFE_CONVERSION(long double, signed short);
203 PPL_SAFE_CONVERSION(long double, unsigned short);
204 #endif
205 #if PPL_SIZEOF_INT <= PPL_SIZEOF_LONG_DOUBLE - 4
206 PPL_SAFE_CONVERSION(long double, signed int);
207 PPL_SAFE_CONVERSION(long double, unsigned int);
208 #endif
209 #if PPL_SIZEOF_LONG <= PPL_SIZEOF_LONG_DOUBLE - 4
210 PPL_SAFE_CONVERSION(long double, signed long);
211 PPL_SAFE_CONVERSION(long double, unsigned long);
212 #endif
213 #if PPL_SIZEOF_LONG_LONG <= PPL_SIZEOF_LONG_DOUBLE - 4
214 PPL_SAFE_CONVERSION(long double, signed long long);
215 PPL_SAFE_CONVERSION(long double, unsigned long long);
216 #endif
217 PPL_SAFE_CONVERSION(long double, float);
218 PPL_SAFE_CONVERSION(long double, double);
219
220 PPL_SAFE_CONVERSION(mpz_class, char);
221 PPL_SAFE_CONVERSION(mpz_class, signed char);
222 PPL_SAFE_CONVERSION(mpz_class, signed short);
223 PPL_SAFE_CONVERSION(mpz_class, signed int);
224 PPL_SAFE_CONVERSION(mpz_class, signed long);
225 // GMP's API does not support signed long long.
226 PPL_SAFE_CONVERSION(mpz_class, unsigned char);
227 PPL_SAFE_CONVERSION(mpz_class, unsigned short);
228 PPL_SAFE_CONVERSION(mpz_class, unsigned int);
229 PPL_SAFE_CONVERSION(mpz_class, unsigned long);
230 // GMP's API does not support unsigned long long.
231
232 PPL_SAFE_CONVERSION(mpq_class, char);
233 PPL_SAFE_CONVERSION(mpq_class, signed char);
234 PPL_SAFE_CONVERSION(mpq_class, signed short);
235 PPL_SAFE_CONVERSION(mpq_class, signed int);
236 PPL_SAFE_CONVERSION(mpq_class, signed long);
237 // GMP's API does not support signed long long.
238 PPL_SAFE_CONVERSION(mpq_class, unsigned char);
239 PPL_SAFE_CONVERSION(mpq_class, unsigned short);
240 PPL_SAFE_CONVERSION(mpq_class, unsigned int);
241 PPL_SAFE_CONVERSION(mpq_class, unsigned long);
242 // GMP's API does not support unsigned long long.
243 PPL_SAFE_CONVERSION(mpq_class, float);
244 PPL_SAFE_CONVERSION(mpq_class, double);
245 // GMP's API does not support long double.
246
247 #undef PPL_SAFE_CONVERSION
248
249 template <typename Policy, typename Type>
PPL_FUNCTION_CLASS(construct)250 struct PPL_FUNCTION_CLASS(construct)<Policy, Policy, Type, Type> {
251 static inline Result function(Type& to, const Type& from, Rounding_Dir) {
252 new(&to) Type(from);
253 return V_EQ;
254 }
255 };
256
257 template <typename To_Policy, typename From_Policy, typename To, typename From>
PPL_FUNCTION_CLASS(construct)258 struct PPL_FUNCTION_CLASS(construct) {
259 static inline Result function(To& to, const From& from, Rounding_Dir dir) {
260 new(&to) To();
261 return assign<To_Policy, From_Policy>(to, from, dir);
262 }
263 };
264
265 template <typename To_Policy, typename To>
PPL_FUNCTION_CLASS(construct_special)266 struct PPL_FUNCTION_CLASS(construct_special) {
267 static inline Result function(To& to, Result_Class r, Rounding_Dir dir) {
268 new(&to) To();
269 return assign_special<To_Policy>(to, r, dir);
270 }
271 };
272
273 template <typename To_Policy, typename From_Policy, typename To, typename From>
274 inline Result
assign_exact(To & to,const From & from,Rounding_Dir)275 assign_exact(To& to, const From& from, Rounding_Dir) {
276 to = from;
277 return V_EQ;
278 }
279
280 template <typename To_Policy, typename From_Policy, typename Type>
281 inline typename Enable_If<Is_Same<To_Policy, From_Policy>::value, void>::type
copy_generic(Type & to,const Type & from)282 copy_generic(Type& to, const Type& from) {
283 to = from;
284 }
285
286 template <typename To_Policy, typename From_Policy, typename To, typename From>
287 inline Result
abs_generic(To & to,const From & from,Rounding_Dir dir)288 abs_generic(To& to, const From& from, Rounding_Dir dir) {
289 if (from < 0) {
290 return neg<To_Policy, From_Policy>(to, from, dir);
291 }
292 else {
293 return assign<To_Policy, From_Policy>(to, from, dir);
294 }
295 }
296
297 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
298 typename To, typename From>
299 inline void
gcd_exact_no_abs(To & to,const From & x,const From & y)300 gcd_exact_no_abs(To& to, const From& x, const From& y) {
301 To w_x = x;
302 To w_y = y;
303 To remainder;
304 while (w_y != 0) {
305 // The following is derived from the assumption that w_x % w_y
306 // is always representable. This is true for both native integers
307 // and IEC 559 floating point numbers.
308 rem<To_Policy, From1_Policy, From2_Policy>(remainder, w_x, w_y,
309 ROUND_NOT_NEEDED);
310 w_x = w_y;
311 w_y = remainder;
312 }
313 to = w_x;
314 }
315
316 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
317 typename To, typename From1, typename From2>
318 inline Result
gcd_exact(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)319 gcd_exact(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
320 gcd_exact_no_abs<To_Policy, From1_Policy, From2_Policy>(to, x, y);
321 return abs<To_Policy, To_Policy>(to, to, dir);
322 }
323
324 template <typename To1_Policy, typename To2_Policy, typename To3_Policy,
325 typename From1_Policy, typename From2_Policy,
326 typename To1, typename To2, typename To3,
327 typename From1, typename From2>
328 inline Result
gcdext_exact(To1 & to,To2 & s,To3 & t,const From1 & x,const From2 & y,Rounding_Dir dir)329 gcdext_exact(To1& to, To2& s, To3& t, const From1& x, const From2& y,
330 Rounding_Dir dir) {
331 // In case this becomes a bottleneck, we may consider using the
332 // Stehle'-Zimmermann algorithm (see R. Crandall and C. Pomerance,
333 // Prime Numbers - A Computational Perspective, Second Edition,
334 // Springer, 2005).
335 if (y == 0) {
336 if (x == 0) {
337 s = 0;
338 t = 1;
339 return V_EQ;
340 }
341 else {
342 if (x < 0) {
343 s = -1;
344 }
345 else {
346 s = 1;
347 }
348 t = 0;
349 return abs<To1_Policy, From1_Policy>(to, x, dir);
350 }
351 }
352
353 s = 1;
354 t = 0;
355 bool negative_x = x < 0;
356 bool negative_y = y < 0;
357
358 Result r;
359 r = abs<To1_Policy, From1_Policy>(to, x, dir);
360 if (r != V_EQ) {
361 return r;
362 }
363
364 From2 a_y;
365 r = abs<To1_Policy, From2_Policy>(a_y, y, dir);
366 if (r != V_EQ) {
367 return r;
368 }
369
370 // If PPL_MATCH_GMP_GCDEXT is defined then s is favored when the absolute
371 // values of the given numbers are equal. For instance if x and y
372 // are both 5 then s will be 1 and t will be 0, instead of the other
373 // way round. This is to match the behavior of GMP.
374 #define PPL_MATCH_GMP_GCDEXT 1
375 #ifdef PPL_MATCH_GMP_GCDEXT
376 if (to == a_y) {
377 goto sign_check;
378 }
379 #endif
380
381 {
382 To2 v1 = 0;
383 To3 v2 = 1;
384 To1 v3 = static_cast<To1>(a_y);
385 while (true) {
386 To1 q = to / v3;
387 // Remainder, next candidate GCD.
388 To1 t3 = to - q*v3;
389 To2 t1 = s - static_cast<To2>(q)*v1;
390 To3 t2 = t - static_cast<To3>(q)*v2;
391 s = v1;
392 t = v2;
393 to = v3;
394 if (t3 == 0) {
395 break;
396 }
397 v1 = t1;
398 v2 = t2;
399 v3 = t3;
400 }
401 }
402
403 #ifdef PPL_MATCH_GMP_GCDEXT
404 sign_check:
405 #endif
406 if (negative_x) {
407 r = neg<To2_Policy, To2_Policy>(s, s, dir);
408 if (r != V_EQ) {
409 return r;
410 }
411 }
412 if (negative_y) {
413 return neg<To3_Policy, To3_Policy>(t, t, dir);
414 }
415 return V_EQ;
416 #undef PPL_MATCH_GMP_GCDEXT
417 }
418
419 template <typename To_Policy, typename From1_Policy, typename From2_Policy,
420 typename To, typename From1, typename From2>
421 inline Result
lcm_gcd_exact(To & to,const From1 & x,const From2 & y,Rounding_Dir dir)422 lcm_gcd_exact(To& to, const From1& x, const From2& y, Rounding_Dir dir) {
423 if (x == 0 || y == 0) {
424 to = 0;
425 return V_EQ;
426 }
427 To a_x;
428 To a_y;
429 Result r;
430 r = abs<From1_Policy, From1_Policy>(a_x, x, dir);
431 if (r != V_EQ) {
432 return r;
433 }
434 r = abs<From2_Policy, From2_Policy>(a_y, y, dir);
435 if (r != V_EQ) {
436 return r;
437 }
438 To gcd;
439 gcd_exact_no_abs<To_Policy, From1_Policy, From2_Policy>(gcd, a_x, a_y);
440 // The following is derived from the assumption that a_x / gcd(a_x, a_y)
441 // is always representable. This is true for both native integers
442 // and IEC 559 floating point numbers.
443 div<To_Policy, From1_Policy, To_Policy>(to, a_x, gcd, ROUND_NOT_NEEDED);
444 return mul<To_Policy, To_Policy, From2_Policy>(to, to, a_y, dir);
445 }
446
447 template <typename Policy, typename Type>
448 inline Result_Relation
sgn_generic(const Type & x)449 sgn_generic(const Type& x) {
450 if (x > 0) {
451 return VR_GT;
452 }
453 if (x == 0) {
454 return VR_EQ;
455 }
456 return VR_LT;
457 }
458
459 template <typename T1, typename T2, typename Enable = void>
460 struct Safe_Int_Comparison : public False {
461 };
462
463 template <typename T1, typename T2>
464 struct Safe_Int_Comparison<T1, T2, typename Enable_If<(C_Integer<T1>::value && C_Integer<T2>::value)>::type>
465 : public Bool<(C_Integer<T1>::is_signed
466 ? (C_Integer<T2>::is_signed
467 || sizeof(T2) < sizeof(T1)
468 || sizeof(T2) < sizeof(int))
469 : (!C_Integer<T2>::is_signed
470 || sizeof(T1) < sizeof(T2)
471 || sizeof(T1) < sizeof(int)))> {
472 };
473
474
475 template <typename T1, typename T2>
476 inline typename Enable_If<(Safe_Int_Comparison<T1, T2>::value
477 || Safe_Conversion<T1, T2>::value
478 || Safe_Conversion<T2, T1>::value), bool>::type
lt(const T1 & x,const T2 & y)479 lt(const T1& x, const T2& y) {
480 return x < y;
481 }
482 template <typename T1, typename T2>
483 inline typename Enable_If<(Safe_Int_Comparison<T1, T2>::value
484 || Safe_Conversion<T1, T2>::value
485 || Safe_Conversion<T2, T1>::value), bool>::type
le(const T1 & x,const T2 & y)486 le(const T1& x, const T2& y) {
487 return x <= y;
488 }
489 template <typename T1, typename T2>
490 inline typename Enable_If<(Safe_Int_Comparison<T1, T2>::value
491 || Safe_Conversion<T1, T2>::value
492 || Safe_Conversion<T2, T1>::value), bool>::type
eq(const T1 & x,const T2 & y)493 eq(const T1& x, const T2& y) {
494 return x == y;
495 }
496
497 template <typename S, typename U>
498 inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
499 && C_Integer<U>::value
500 && C_Integer<S>::is_signed), bool>::type
lt(const S & x,const U & y)501 lt(const S& x, const U& y) {
502 return x < 0 || static_cast<typename C_Integer<S>::other_type>(x) < y;
503 }
504
505 template <typename U, typename S>
506 inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
507 && C_Integer<U>::value
508 && C_Integer<S>::is_signed), bool>::type
lt(const U & x,const S & y)509 lt(const U& x, const S& y) {
510 return y >= 0 && x < static_cast<typename C_Integer<S>::other_type>(y);
511 }
512
513 template <typename S, typename U>
514 inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
515 && C_Integer<U>::value
516 && C_Integer<S>::is_signed), bool>::type
le(const S & x,const U & y)517 le(const S& x, const U& y) {
518 return x < 0 || static_cast<typename C_Integer<S>::other_type>(x) <= y;
519 }
520
521 template <typename U, typename S>
522 inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
523 && C_Integer<U>::value
524 && C_Integer<S>::is_signed), bool>::type
le(const U & x,const S & y)525 le(const U& x, const S& y) {
526 return y >= 0 && x <= static_cast<typename C_Integer<S>::other_type>(y);
527 }
528
529 template <typename S, typename U>
530 inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
531 && C_Integer<U>::value
532 && C_Integer<S>::is_signed), bool>::type
eq(const S & x,const U & y)533 eq(const S& x, const U& y) {
534 return x >= 0 && static_cast<typename C_Integer<S>::other_type>(x) == y;
535 }
536
537 template <typename U, typename S>
538 inline typename Enable_If<(!Safe_Int_Comparison<S, U>::value
539 && C_Integer<U>::value
540 && C_Integer<S>::is_signed), bool>::type
eq(const U & x,const S & y)541 eq(const U& x, const S& y) {
542 return y >= 0 && x == static_cast<typename C_Integer<S>::other_type>(y);
543 }
544
545 template <typename T1, typename T2>
546 inline typename Enable_If<(!Safe_Conversion<T1, T2>::value
547 && !Safe_Conversion<T2, T1>::value
548 && (!C_Integer<T1>::value || !C_Integer<T2>::value)), bool>::type
eq(const T1 & x,const T2 & y)549 eq(const T1& x, const T2& y) {
550 PPL_DIRTY_TEMP(T1, tmp);
551 Result r = assign_r(tmp, y, ROUND_CHECK);
552 // FIXME: We can do this also without fpu inexact check using a
553 // conversion back and forth and then testing equality. We should
554 // code this in checked_float_inlines.hh, probably it's faster also
555 // if fpu supports inexact check.
556 PPL_ASSERT(r != V_LE && r != V_GE && r != V_LGE);
557 return r == V_EQ && x == tmp;
558 }
559
560 template <typename T1, typename T2>
561 inline typename Enable_If<(!Safe_Conversion<T1, T2>::value
562 && !Safe_Conversion<T2, T1>::value
563 && (!C_Integer<T1>::value || !C_Integer<T2>::value)), bool>::type
lt(const T1 & x,const T2 & y)564 lt(const T1& x, const T2& y) {
565 PPL_DIRTY_TEMP(T1, tmp);
566 Result r = assign_r(tmp, y, ROUND_UP);
567 if (!result_representable(r)) {
568 return true;
569 }
570 switch (result_relation(r)) {
571 case VR_EQ:
572 case VR_LT:
573 case VR_LE:
574 return x < tmp;
575 default:
576 return false;
577 }
578 }
579
580 template <typename T1, typename T2>
581 inline typename
582 Enable_If<(!Safe_Conversion<T1, T2>::value
583 && !Safe_Conversion<T2, T1>::value
584 && (!C_Integer<T1>::value || !C_Integer<T2>::value)), bool>::type
le(const T1 & x,const T2 & y)585 le(const T1& x, const T2& y) {
586 PPL_DIRTY_TEMP(T1, tmp);
587 Result r = assign_r(tmp, y, (ROUND_UP | ROUND_STRICT_RELATION));
588 // FIXME: We can do this also without fpu inexact check using a
589 // conversion back and forth and then testing equality. We should
590 // code this in checked_float_inlines.hh, probably it's faster also
591 // if fpu supports inexact check.
592 PPL_ASSERT(r != V_LE && r != V_GE && r != V_LGE);
593 if (!result_representable(r)) {
594 return true;
595 }
596 switch (result_relation(r)) {
597 case VR_EQ:
598 return x <= tmp;
599 case VR_LT:
600 return x < tmp;
601 case VR_LE:
602 case VR_GE:
603 case VR_LGE:
604 // See comment above.
605 PPL_UNREACHABLE;
606 return false;
607 default:
608 return false;
609 }
610 }
611
612 template <typename Policy1, typename Policy2,
613 typename Type1, typename Type2>
614 inline bool
lt_p(const Type1 & x,const Type2 & y)615 lt_p(const Type1& x, const Type2& y) {
616 return lt(x, y);
617 }
618
619 template <typename Policy1, typename Policy2,
620 typename Type1, typename Type2>
621 inline bool
le_p(const Type1 & x,const Type2 & y)622 le_p(const Type1& x, const Type2& y) {
623 return le(x, y);
624 }
625
626 template <typename Policy1, typename Policy2,
627 typename Type1, typename Type2>
628 inline bool
eq_p(const Type1 & x,const Type2 & y)629 eq_p(const Type1& x, const Type2& y) {
630 return eq(x, y);
631 }
632
633 template <typename Policy1, typename Policy2,
634 typename Type1, typename Type2>
635 inline Result_Relation
cmp_generic(const Type1 & x,const Type2 & y)636 cmp_generic(const Type1& x, const Type2& y) {
637 if (lt(y, x)) {
638 return VR_GT;
639 }
640 if (lt(x, y)) {
641 return VR_LT;
642 }
643 return VR_EQ;
644 }
645
646 template <typename Policy, typename Type>
647 inline Result
assign_nan(Type & to,Result r)648 assign_nan(Type& to, Result r) {
649 assign_special<Policy>(to, VC_NAN, ROUND_IGNORE);
650 return r;
651 }
652
653 template <typename Policy, typename Type>
654 inline Result
input_generic(Type & to,std::istream & is,Rounding_Dir dir)655 input_generic(Type& to, std::istream& is, Rounding_Dir dir) {
656 PPL_DIRTY_TEMP(mpq_class, q);
657 Result r = input_mpq(q, is);
658 Result_Class c = result_class(r);
659 switch (c) {
660 case VC_MINUS_INFINITY:
661 case VC_PLUS_INFINITY:
662 return assign_special<Policy>(to, c, dir);
663 case VC_NAN:
664 return assign_nan<Policy>(to, r);
665 default:
666 break;
667 }
668 PPL_ASSERT(r == V_EQ);
669 return assign<Policy, void>(to, q, dir);
670 }
671
672 } // namespace Checked
673
674 } // namespace Parma_Polyhedra_Library
675
676 #endif // !defined(PPL_checked_inlines_hh)
677