// Copyright (c) 2005-2008 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; version 2.1 of the License. // See the file LICENSE.LGPL distributed with CGAL. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // // Author(s) : Sylvain Pion #ifndef CGAL_UNCERTAIN_H #define CGAL_UNCERTAIN_H #include #include #include CGAL_BEGIN_NAMESPACE namespace CGALi { // Accessory traits class to provide min and max value of a type. // Specialized for bool and CGAL's enums. template < typename T > struct Minmax_traits; template <> struct Minmax_traits { static const bool min = false; static const bool max = true; }; template <> struct Minmax_traits { static const Sign min = NEGATIVE; static const Sign max = POSITIVE; }; template <> struct Minmax_traits { static const Bounded_side min = ON_UNBOUNDED_SIDE; static const Bounded_side max = ON_BOUNDED_SIDE; }; template <> struct Minmax_traits { static const Angle min = OBTUSE; static const Angle max = ACUTE; }; } // namespace CGALi // Exception type for the automatic conversion. class Uncertain_conversion_exception : std::range_error { public: Uncertain_conversion_exception(const std::string &s) : std::range_error(s) {} ~Uncertain_conversion_exception() throw() {} }; // Encodes an interval [min;max] of values of type T. // The primary template is supposed to work for enums and bool. template < typename T > class Uncertain { T _i, _s; static unsigned failures; // Number of conversion failures. public: typedef CGAL::Uncertain_conversion_exception Uncertain_conversion_exception; typedef T value_type; Uncertain() : _i(CGALi::Minmax_traits::min), _s(CGALi::Minmax_traits::max) {} Uncertain(T t) : _i(t), _s(t) {} Uncertain(T i, T s) : _i(i), _s(s) {} Uncertain& operator=(T t) { _i = _s = t; return this; } T inf() const { return _i; } T sup() const { return _s; } bool is_certain() const { return _i == _s; } T make_certain() const { if (is_certain()) return _i; ++Uncertain::number_of_failures(); throw Uncertain_conversion_exception( "undecidable conversion of CGAL::Uncertain"); } #if 1 // Comment out in order to spot some unwanted conversions. // NB : the general conversion to bool might be too risky. // boost::tribool uses a more restricted conversion (see below). operator T() const { return make_certain(); } #else private: struct dummy { void nonnull() {}; }; typedef void (dummy::*safe_bool)(); public: operator safe_bool() const { return make_certain() ? &dummy::nonnull : 0; } #endif static unsigned & number_of_failures() { return failures; } static Uncertain indeterminate(); }; template < typename T > unsigned Uncertain::failures = 0; // Access functions // ---------------- template < typename T > inline T inf(Uncertain i) { return i.inf(); } template < typename T > inline T sup(Uncertain i) { return i.sup(); } // possibly() declarations (needed as used in the assertions) // ---------------------------------------------------------- inline bool possibly(bool b); inline bool possibly(Uncertain c); // Basic functions // --------------- #if 1 // Commenting them out allows the test-suite to spot those predicates that do not // propagate Uncertain-ty correctly. But they should probably be enabled // for now, for backward-compatibility. template < typename T > inline bool is_certain(T) { return true; } template < typename T > inline T get_certain(T t) { return t; } #endif template < typename T > inline bool is_certain(Uncertain a) { return a.is_certain(); } template < typename T > inline T get_certain(Uncertain a) { CGAL_assertion(is_certain(a)); return a.inf(); } template < typename T > inline Uncertain Uncertain::indeterminate() { return Uncertain(); } template < typename T > inline bool is_indeterminate(T) { return false; } template < typename T > inline bool is_indeterminate(Uncertain a) { return ! a.is_certain(); } // certainly/possibly // ------------------ inline bool certainly(bool b) { return b; } inline bool possibly(bool b) { return b; } inline bool certainly(Uncertain c) { if (is_certain(c)) return get_certain(c); return false; } inline bool possibly(Uncertain c) { if (is_certain(c)) return get_certain(c); return true; } // Boolean operations for Uncertain // -------------------------------------- inline Uncertain operator!(Uncertain a) { return Uncertain(!a.sup(), !a.inf()); } inline Uncertain operator|(Uncertain a, Uncertain b) { return Uncertain(a.inf() | b.inf(), a.sup() | b.sup()); } inline Uncertain operator|(bool a, Uncertain b) { return Uncertain(a | b.inf(), a | b.sup()); } inline Uncertain operator|(Uncertain a, bool b) { return Uncertain(a.inf() | b, a.sup() | b); } inline Uncertain operator&(Uncertain a, Uncertain b) { return Uncertain(a.inf() & b.inf(), a.sup() & b.sup()); } inline Uncertain operator&(bool a, Uncertain b) { return Uncertain(a & b.inf(), a & b.sup()); } inline Uncertain operator&(Uncertain a, bool b) { return Uncertain(a.inf() & b, a.sup() & b); } // Equality operators // FIXME : these are sub-optimal : // {NEGATIVE, ZERO} == {POSITIVE} returns indeterminate instead of false. template < typename T > inline Uncertain operator==(Uncertain a, Uncertain b) { if (is_indeterminate(a) || is_indeterminate(b)) return Uncertain::indeterminate(); return a.inf() == b.inf(); } template < typename T > inline Uncertain operator==(Uncertain a, T b) { if (is_indeterminate(a)) return Uncertain::indeterminate(); return a.inf() == b; } template < typename T > inline Uncertain operator==(T a, Uncertain b) { if (is_indeterminate(b)) return Uncertain::indeterminate(); return a == b.inf(); } template < typename T > inline Uncertain operator!=(Uncertain a, Uncertain b) { return ! (a == b); } template < typename T > inline Uncertain operator!=(Uncertain a, T b) { return ! (a == b); } template < typename T > inline Uncertain operator!=(T a, Uncertain b) { return ! (a == b); } // Comparison operators (useful for enums only, I guess (?) ). template < typename T > inline Uncertain operator<(Uncertain a, Uncertain b) { if (a.sup() < b.inf()) return true; if (a.inf() >= b.sup()) return false; return Uncertain::indeterminate(); } template < typename T > inline Uncertain operator<(Uncertain a, T b) { if (a.sup() < b) return true; if (a.inf() >= b) return false; return Uncertain::indeterminate(); } template < typename T > inline Uncertain operator<(T a, Uncertain b) { if (a < b.inf()) return true; if (a >= b.sup()) return false; return Uncertain::indeterminate(); } template < typename T > inline Uncertain operator>(Uncertain a, Uncertain b) { return b < a; } template < typename T > inline Uncertain operator>(Uncertain a, T b) { return b < a; } template < typename T > inline Uncertain operator>(T a, Uncertain b) { return b < a; } template < typename T > inline Uncertain operator<=(Uncertain a, Uncertain b) { return !(b < a); } template < typename T > inline Uncertain operator<=(Uncertain a, T b) { return !(b < a); } template < typename T > inline Uncertain operator<=(T a, Uncertain b) { return !(b < a); } template < typename T > inline Uncertain operator>=(Uncertain a, Uncertain b) { return !(a < b); } template < typename T > inline Uncertain operator>=(Uncertain a, T b) { return !(a < b); } template < typename T > inline Uncertain operator>=(T a, Uncertain b) { return !(a < b); } // Maker function (a la std::make_pair). template < typename T > inline Uncertain make_uncertain(T t) { return Uncertain(t); } template < typename T > inline Uncertain make_uncertain(Uncertain t) { return t; } // make_certain() : Forcing a cast to certain (possibly throwing). // This is meant to be used only in cases where we cannot easily propagate the // uncertainty, such as when used in a switch statement (code may later be // revisited to do things in a better way). template < typename T > inline T make_certain(T t) { return t; } template < typename T > inline T make_certain(Uncertain t) { return t.make_certain(); } // opposite template < typename T > // should be constrained only for enums. inline Uncertain operator-(Uncertain u) { return Uncertain(-u.sup(), -u.inf()); } // "sign" multiplication. // Should be constrained only for "sign" enums, useless for bool. template < typename T > Uncertain operator*(Uncertain a, Uncertain b) { if (a.inf() >= 0) // e>=0 { // b>=0 [a.inf()*b.inf(); a.sup()*b.sup()] // b<=0 [a.sup()*b.inf(); a.inf()*b.sup()] // b~=0 [a.sup()*b.inf(); a.sup()*b.sup()] T aa = a.inf(), bb = a.sup(); if (b.inf() < 0) { aa = bb; if (b.sup() < 0) bb = a.inf(); } return Uncertain(aa * b.inf(), bb * b.sup()); } else if (a.sup()<=0) // e<=0 { // b>=0 [a.inf()*b.sup(); a.sup()*b.inf()] // b<=0 [a.sup()*b.sup(); a.inf()*b.inf()] // b~=0 [a.inf()*b.sup(); a.inf()*b.inf()] T aa = a.sup(), bb = a.inf(); if (b.inf() < 0) { aa=bb; if (b.sup() < 0) bb=a.sup(); } return Uncertain(bb * b.sup(), aa * b.inf()); } else // 0 \in [inf();sup()] { if (b.inf()>=0) // d>=0 return Uncertain(a.inf() * b.sup(), a.sup() * b.sup()); if (b.sup()<=0) // d<=0 return Uncertain(a.sup() * b.inf(), a.inf() * b.inf()); // 0 \in d T tmp1 = a.inf() * b.sup(); T tmp2 = a.sup() * b.inf(); T tmp3 = a.inf() * b.inf(); T tmp4 = a.sup() * b.sup(); return Uncertain((std::min)(tmp1, tmp2), (std::max)(tmp3, tmp4)); } } template < typename T > inline Uncertain operator*(T a, Uncertain b) { return Uncertain(a) * b; } template < typename T > inline Uncertain operator*(Uncertain a, T b) { return a * Uncertain(b); } // enum_cast overload #ifdef CGAL_CFG_MATCHING_BUG_5 template < typename T, typename U > inline Uncertain enum_cast_bug(Uncertain u, const T*) { return Uncertain(static_cast(u.inf()), static_cast(u.sup())); } #else template < typename T, typename U > inline Uncertain enum_cast(Uncertain u) { return Uncertain(static_cast(u.inf()), static_cast(u.sup())); } #endif CGAL_END_NAMESPACE #endif // CGAL_UNCERTAIN_H