GCC Code Coverage Report


Directory: ./
File: lib/geogram/numerics/PCK.h
Date: 2026-09-07 02:36:43
Exec Total Coverage
Lines: 32 37 86.5%
Functions: 6 7 85.7%
Branches: 17 38 44.7%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40 #ifndef GEOGRAM_NUMERICS_PCK
41 #define GEOGRAM_NUMERICS_PCK
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/numeric.h>
45 #include <geogram/basic/logger.h>
46 #include <functional>
47 #include <algorithm>
48 #include <atomic>
49
50 /**
51 * \file geogram/numerics/PCK.h
52 * \brief Utilities to write geometric predicates (Predicate Construction Kit).
53 */
54
55 // Uncomment to get full reporting on predicate statistics
56 // (but has a non-negligible impact on performance)
57 // For instance, Early Universe Reconstruction with 2M points:
58 // with PCK_STATS: 6'36 without PCK_STATS: 3'38
59
60 // #define PCK_STATS
61
62 namespace GEO {
63
64 namespace PCK {
65
66 /**
67 * \brief Logs statistics for predicates. The statistics are
68 * displayed on exit if the command line flag "sys:statistics"
69 * is set. It is used as follows in a predicate:
70 * \code
71 * void my_predicate(...) {
72 * static PCK::PredicateStats stats("my_predicate");
73 * my_predicate.log_invoke();
74 * // Filter
75 * {
76 * Sign s = ...;
77 * if(s != ZERO) {
78 * return s;
79 * }
80 * }
81 * // Exact
82 * {
83 * stats.log_exact();
84 * Sign s = ...;
85 * if(s != ZERO) {
86 * return s;
87 * }
88 * }
89 * // SOS
90 * {
91 * stats.log_SOS();
92 * ...
93 * }
94 * }
95 * \endcode
96 */
97
98 #ifdef PCK_STATS
99 class GEOGRAM_API PredicateStats {
100 public:
101 PredicateStats(const char* name);
102 void log_invoke() {
103 ++invoke_count_;
104 }
105 void log_exact() {
106 ++exact_count_;
107 }
108 void log_SOS() {
109 ++SOS_count_;
110 }
111 void show_stats();
112 static void show_all_stats();
113 private:
114 static PredicateStats* first_;
115 PredicateStats* next_;
116 const char* name_;
117 std::atomic<Numeric::int64> invoke_count_;
118 std::atomic<Numeric::int64> exact_count_;
119 std::atomic<Numeric::int64> SOS_count_;
120 };
121 #else
122 class PredicateStats {
123 public:
124 2695 PredicateStats(const char* name) {
125 2695 geo_argused(name);
126 2695 }
127 96723114 void log_invoke() {
128 96723114 }
129 8468814 void log_exact() {
130 8468814 }
131 656376 void log_SOS() {
132 656376 }
133 static void show_all_stats() {
134 Logger::out("Stats") << "Compiled without PCK_STAT (no stats)"
135 << std::endl;
136 }
137 };
138 #endif
139
140
141 /**
142 * \brief Shorthand for writing lambdas for symbolic perturbations
143 * \see SOS()
144 */
145 #define SOS_result(x) [&]()->Sign { return Sign(x); }
146
147 /**
148 * \brief template for writing symbolic perturbation in predicates
149 * \param[in] compare a comparator for sorting the points
150 * \param[in] p1 , p2 , p3 , p4 the four points
151 * \param[in] sos_p1 , sos_p2 , sos_p3 , sos_p4 the four lambdas that
152 * compute the symbolic perturbation associated with each point, and
153 * that return the sign of the perturbed predicate. There is a
154 * SOS_result() macro to help writing these lambdas.
155 * \details How to use/example:
156 * \code
157 * ... beginning of predicate, filter did not hit and exact value
158 * is zero ..
159 *
160 * return SOS(
161 * vec2HgLexicoCompare<exact_nt>(),
162 * p0, SOS_result( det3_111_sign(p1,p2,p3)),
163 * p1, SOS_result(-det3_111_sign(p0,p2,p3)),
164 * p2, SOS_result( det3_111_sign(p0,p1,p3)),
165 * p3, SOS_result(-det3_111_sign(p0,p1,p2))
166 * );
167 * \endcode
168 */
169 template <
170 class POINT, class COMPARE,
171 class FUNC1, class FUNC2, class FUNC3, class FUNC4
172 12696 > inline Sign SOS(
173 COMPARE compare,
174 const POINT& p1, FUNC1 sos_p1,
175 const POINT& p2, FUNC2 sos_p2,
176 const POINT& p3, FUNC3 sos_p3,
177 const POINT& p4, FUNC4 sos_p4
178 ) {
179 static constexpr int N = 4;
180 12696 Sign result = ZERO;
181 12696 const POINT* p[N] = {&p1, &p2, &p3, &p4};
182
1/2
✓ Branch 1 taken 12696 times.
✗ Branch 2 not taken.
12696 std::sort(
183 p, p+N,
184 84303 [compare](const POINT* A, const POINT* B)->bool{
185 84303 return compare(*A,*B);
186 }
187 );
188
1/2
✓ Branch 0 taken 12696 times.
✗ Branch 1 not taken.
12696 for(int i=0; i<N; ++i) {
189
2/2
✓ Branch 0 taken 5660 times.
✓ Branch 1 taken 7036 times.
12696 if(p[i] == &p1) {
190
1/2
✓ Branch 1 taken 5660 times.
✗ Branch 2 not taken.
5660 result = sos_p1();
191
1/2
✓ Branch 0 taken 5660 times.
✗ Branch 1 not taken.
5660 if(result != ZERO) {
192 5660 return result;
193 }
194 }
195
2/2
✓ Branch 0 taken 2252 times.
✓ Branch 1 taken 4784 times.
7036 if(p[i] == &p2) {
196
1/2
✓ Branch 1 taken 2252 times.
✗ Branch 2 not taken.
2252 result = sos_p2();
197
1/2
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
2252 if(result != ZERO) {
198 2252 return result;
199 }
200 }
201
2/2
✓ Branch 0 taken 3422 times.
✓ Branch 1 taken 1362 times.
4784 if(p[i] == &p3) {
202
1/2
✓ Branch 1 taken 3422 times.
✗ Branch 2 not taken.
3422 result = sos_p3();
203
1/2
✓ Branch 0 taken 3422 times.
✗ Branch 1 not taken.
3422 if(result != ZERO) {
204 3422 return result;
205 }
206 }
207
1/2
✓ Branch 0 taken 1362 times.
✗ Branch 1 not taken.
1362 if(p[i] == &p4) {
208
1/2
✓ Branch 1 taken 1362 times.
✗ Branch 2 not taken.
1362 result = sos_p4();
209
1/2
✓ Branch 0 taken 1362 times.
✗ Branch 1 not taken.
1362 if(result != ZERO) {
210 1362 return result;
211 }
212 }
213 }
214 geo_assert_not_reached;
215 }
216
217 }
218 }
219
220 #endif
221