diff --git a/STL_Extension/doc_tex/STL_Extension_ref/Uncertain.tex b/STL_Extension/doc_tex/STL_Extension_ref/Uncertain.tex index 732dff3fd57..02c94f727c1 100644 --- a/STL_Extension/doc_tex/STL_Extension_ref/Uncertain.tex +++ b/STL_Extension/doc_tex/STL_Extension_ref/Uncertain.tex @@ -90,6 +90,9 @@ Finally, note that this class has some common points with \ccc{boost::tribool}. %% +-----------------------------------+ \ccHeading{Access Functions} + The following functions are meant to be used very rarely, they provide ways to inspect + the content of an \ccc{Uncertain} object. + % \def\ccTagRmTrailingConst{\ccFalse} \ccMethod{T inf() const;} {returns the lower bound of the range represented by~\ccVar.} @@ -97,6 +100,9 @@ Finally, note that this class has some common points with \ccc{boost::tribool}. \ccGlue\ccMethod{T sup() const;} {returns the upper bound of the range represented by~\ccVar.} + \ccGlue\ccMethod{bool is_same(Uncertain u) const;} + {returns true whether \ccVar\ and \ccc{u} are the same range (equality as sets).} + %% +-----------------------------------+ \ccHeading{Uncertainty testing and conversion} @@ -295,6 +301,26 @@ Another option is : This ensures that the first expression is not evaluated twice, and that the second is evaluated only if needed. + This behavior can also be emulated through the use of macros, but only using + non-standard features ("statement expressions", such as provided by GCC). The + macros \ccc{CGAL_AND} and \ccc{CGAL_OR} are provided that perform the lazy + evaluation of these logical operations. On compilers that do not support + statement expressions, the macros simply expand to the $\&\&$ and $||$ + operators (which will throw an exception instead of propagating the uncertainty). + +\begin{ccExampleCode} + // Logical AND + Uncertain res = CGAL_AND( p.x() == 0 , p.y() == 0 ); + + ... // Use res + + // Logical OR + Uncertain res = CGAL_OR( q.x() == 0 , q.y() == 0 ); + + ... // Use res +\end{ccExampleCode} + + %% +-----------------------------------+ \ccHeading{Overloaded operators and functions for \ccc{Uncertain} only} diff --git a/STL_Extension/include/CGAL/Uncertain.h b/STL_Extension/include/CGAL/Uncertain.h index 6b879dfa728..a15b87df170 100644 --- a/STL_Extension/include/CGAL/Uncertain.h +++ b/STL_Extension/include/CGAL/Uncertain.h @@ -111,6 +111,8 @@ public: T inf() const { return _i; } T sup() const { return _s; } + bool is_same(Uncertain u) const { return _i == u._i && _s == u._s; } + bool is_certain() const { return _i == _s; } T make_certain() const @@ -306,6 +308,23 @@ Uncertain operator&(Uncertain a, bool b) return Uncertain(a.inf() & b, a.sup() & b); } +// operator&& and operator|| are not provided because, unless their bool counterpart, +// they lack the "short-circuiting" property. +// We provide macros CGAL_AND and CGAL_OR, which attempt to emulate their behavior. +// Key things : do not evaluate expressions twice, and evaluate the right hand side +// expression only when needed. +#ifdef CGAL_CFG_NO_STATEMENT_EXPRESSIONS +# define CGAL_AND(X, Y) ((X) && (Y)) +# define CGAL_OR(X, Y) ((X) || (Y)) +#else +# define CGAL_AND(X, Y) \ + ({ CGAL::Uncertain CGAL_TMP = (X); \ + CGAL::certainly_not(CGAL_TMP) ? CGAL::make_uncertain(false) : CGAL_TMP & (Y); }) +# define CGAL_OR(X, Y) \ + ({ CGAL::Uncertain CGAL_TMP = (X); \ + CGAL::certainly(CGAL_TMP) ? CGAL::make_uncertain(true) : CGAL_TMP | (Y); }) +#endif + // Equality operators diff --git a/STL_Extension/test/STL_Extension/test_Uncertain.cpp b/STL_Extension/test/STL_Extension/test_Uncertain.cpp index d06de37fb4e..67856a45dae 100644 --- a/STL_Extension/test/STL_Extension/test_Uncertain.cpp +++ b/STL_Extension/test/STL_Extension/test_Uncertain.cpp @@ -234,6 +234,51 @@ void test_bool() bool_assert(! (false & utrue)); bool_assert(! (false & ufalse)); + bool_assert(!CGAL_AND(true, false)); + bool_assert(!CGAL_AND(false, true)); + bool_assert(CGAL_AND(true, true)); + bool_assert(!CGAL_AND(false, false)); + bool_assert(!CGAL_AND(utrue, ufalse)); + bool_assert(!CGAL_AND(ufalse, utrue)); + bool_assert(CGAL_AND(utrue, utrue)); + bool_assert(!CGAL_AND(ufalse, ufalse)); + + bool_assert(CGAL_OR(true, false)); + bool_assert(CGAL_OR(false, true)); + bool_assert(CGAL_OR(true, true)); + bool_assert(!CGAL_OR(false, false)); + bool_assert(CGAL_OR(utrue, ufalse)); + bool_assert(CGAL_OR(ufalse, utrue)); + bool_assert(CGAL_OR(utrue, utrue)); + bool_assert(!CGAL_OR(ufalse, ufalse)); + + try { + bool_assert( CGAL_AND(utrue, utrue)); + bool_assert(!CGAL_AND(ufalse, ufalse)); + bool_assert(!CGAL_AND(ufalse, utrue)); + bool_assert(!CGAL_AND(utrue, ufalse)); + bool_assert(indet.is_same(CGAL_AND(indet, indet))); + bool_assert(indet.is_same(CGAL_AND(utrue, indet))); + bool_assert(indet.is_same(CGAL_AND(indet, utrue))); + bool_assert(!CGAL_AND(ufalse, indet)); + bool_assert(!CGAL_AND(indet, ufalse)); + + bool_assert( CGAL_OR(utrue, utrue)); + bool_assert(!CGAL_OR(ufalse, ufalse)); + bool_assert( CGAL_OR(ufalse, utrue)); + bool_assert( CGAL_OR(utrue, ufalse)); + bool_assert(indet.is_same(CGAL_OR(indet, indet))); + bool_assert( CGAL_OR(utrue, indet)); + bool_assert( CGAL_OR(indet, utrue)); + bool_assert(indet.is_same(CGAL_OR(ufalse, indet))); + bool_assert(indet.is_same(CGAL_OR(indet, ufalse))); + + } catch (CGAL::Uncertain_conversion_exception) { +#ifndef CGAL_CFG_NO_STATEMENT_EXPRESSIONS + std::abort(); +#endif + } + // Test exceptions bool ok = false; try { bool b = indet; use(b); }