GCC Code Coverage Report


Directory: ./
File: lib/geogram/basic/algorithm.h
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 19 25 76.0%
Functions: 9 12 75.0%
Branches: 18 20 90.0%

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_BASIC_ALGORITHM
41 #define GEOGRAM_BASIC_ALGORITHM
42
43 #include <geogram/basic/common.h>
44 #include <geogram/basic/numeric.h>
45 #include <algorithm>
46 #include <random>
47
48 #ifdef GEO_PARALLEL_STL
49 #include <execution>
50 #endif
51
52 /**
53 * \file geogram/basic/algorithm.h
54 * \brief Wrappers around parallel implementation of STL
55 */
56
57 namespace GEO {
58
59 /**
60 * \brief Checks whether parallel algorithms are used.
61 * \details Some algorithms such as sort() can be used
62 * in parallel or sequential mode. Behavior is toggled
63 * by the "algo:parallel" environment variable.
64 * \param[in] size optional size of structure to be processed.
65 * If smaller than threshold, then sequential algorithms are
66 * used.
67 * \retval true if parallel algorithms are used.
68 * \retval false if sequential algorithms are used.
69 */
70 bool GEOGRAM_API uses_parallel_algorithm(size_t size=0);
71
72 /**
73 * \brief Sorts elements in parallel
74 * \details Sorts elements in the iterator range [\p begin..\p end) using
75 * a parallel version of the standard \c std::sort() algorithm (if
76 * possible). The elements are compared using operator<().
77 * Whether to use the parallel or the standard version of the std::sort()
78 * algorithm is controlled by the "algo:parallel" environment property.
79 * \param[in] begin first element to sort
80 * \param[in] end one position past the last element to sort
81 * \tparam ITERATOR the type of the iterator
82 * \see uses_parallel_algorithm()
83 */
84 template <typename ITERATOR>
85 inline void sort(
86 const ITERATOR& begin, const ITERATOR& end
87 ) {
88 #ifdef GEO_PARALLEL_STL
89 if(uses_parallel_algorithm(size_t(end - begin))) {
90 std::sort(std::execution::par, begin, end);
91 } else
92 #endif
93 {
94 std::sort(begin, end);
95 }
96 }
97
98 /**
99 * \brief Sorts elements in parallel
100 * \details Sorts elements in the iterator range [\p begin..\p end) using
101 * a parallel version of the standard \c std::sort() algorithm (if
102 * possible). The elements are compared using comparator \p cmp.
103 * Comparator \p cmp must implement an operator() with the following
104 * signature:
105 * \code
106 * bool operator(T a, T b) const;
107 * \endcode
108 * Whether to use the parallel or the standard version of the std::sort()
109 * algorithm is controlled by the "algo:parallel" environment property.
110 * \param[in] begin first element to sort
111 * \param[in] end one position past the last element to sort
112 * \param[in] cmp comparison object.
113 * \tparam ITERATOR the type of the iterator
114 * \tparam CMP the type of the comparator
115 * \see uses_parallel_algorithm()
116 */
117 template <typename ITERATOR, typename CMP>
118 669 inline void sort(
119 const ITERATOR& begin, const ITERATOR& end, const CMP& cmp
120 ) {
121 #ifdef GEO_PARALLEL_STL
122
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 540 times.
669 if(uses_parallel_algorithm(size_t(end - begin))) {
123 std::sort(std::execution::par, begin, end, cmp);
124 } else
125 #endif
126 {
127 651 std::sort(begin, end, cmp);
128 }
129 669 }
130
131
132 /**
133 * \brief Sorts a vector and suppresses all duplicated elements.
134 * \param[in,out] v the vector
135 */
136 template <typename VECTOR> inline void sort_unique(VECTOR& v) {
137 std::sort(v.begin(), v.end());
138 // Note that std::unique leaves a 'queue' of duplicated elements
139 // at the end of the vector, and returns an iterator that
140 // indicates where to stop.
141 v.erase(
142 std::unique(v.begin(), v.end()), v.end()
143 );
144 }
145
146 /**
147 * \brief Specialized sort routine for 3 elements.
148 * \details std::sort is slower than specialized sort on small sequences
149 * of elements.
150 * \param[in] items a random access iterator iterator to the first element.
151 */
152 template <typename ITERATOR> inline void sort_3(ITERATOR items) {
153
2/2
✓ Branch 0 taken 3735356 times.
✓ Branch 1 taken 2212169 times.
5947525 if (items[0]> items[1]) {
154 std::swap(items[0], items[1]);
155 }
156
2/2
✓ Branch 0 taken 4193744 times.
✓ Branch 1 taken 1753781 times.
5947525 if (items[1]> items[2]) {
157 std::swap(items[1], items[2]);
158 }
159
2/2
✓ Branch 0 taken 2653143 times.
✓ Branch 1 taken 3294382 times.
5947525 if (items[0]> items[1]) {
160 std::swap(items[0], items[1]);
161 }
162 }
163
164 /**
165 * \brief Specialized sort routine for 4 elements.
166 * \details std::sort is slower than specialized sort on small sequences
167 * of elements.
168 * \param[in] items a random access iterator iterator to the first element.
169 */
170 1921462 template <typename ITERATOR> inline void sort_4(ITERATOR items) {
171
2/2
✓ Branch 0 taken 920969 times.
✓ Branch 1 taken 39762 times.
1921462 if (items[1] < items[0]) {
172 std::swap(items[0], items[1]);
173 }
174
2/2
✓ Branch 0 taken 400207 times.
✓ Branch 1 taken 560524 times.
1921462 if (items[3] < items[2]) {
175 std::swap(items[2], items[3]);
176 }
177
2/2
✓ Branch 0 taken 320493 times.
✓ Branch 1 taken 640238 times.
1921462 if (items[2] < items[0]) {
178 std::swap(items[0], items[2]);
179 std::swap(items[1], items[3]);
180 }
181
2/2
✓ Branch 0 taken 818429 times.
✓ Branch 1 taken 142302 times.
1921462 if (items[2] < items[1]) {
182 std::swap(items[1], items[2]);
183 }
184
2/2
✓ Branch 0 taken 408098 times.
✓ Branch 1 taken 552633 times.
1921462 if (items[3] < items[2]) {
185 std::swap(items[2], items[3]);
186 }
187 1921462 }
188
189 /**
190 * \brief Applies a random permutation to a sequence
191 * \details A drop-in replacement of std::random_shuffle(),
192 * that is deprecated since c++17
193 * \param[in] begin , end first position and one item past last
194 * position of the sequence to be randomly permuted
195 */
196 template <typename ITERATOR>
197 56 inline void random_shuffle(const ITERATOR& begin, const ITERATOR& end) {
198 56 Numeric::int32 seed = Numeric::random_int32();
199 56 std::mt19937 urng{Numeric::uint32(seed)};
200 56 std::shuffle(begin, end, urng);
201 56 }
202
203 }
204
205 #endif
206