CDT  1.4.1
C++ library for constrained Delaunay triangulation
Loading...
Searching...
No Matches
portable_nth_element.hpp
1// This code is copied from LLVM's libc++
2// https://github.com/llvm-mirror/libcxx/blob/4dde9ccef57d50e50620408a0b7a902f0aba803e/include/algorithm
3// It is needed to provide portable nth_element on different platforms
4
5// -*- C++ -*-
6//===-------------------------- algorithm ---------------------------------===//
7//
8// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
9// See https://llvm.org/LICENSE.txt for license information.
10// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef CDT_PORTABLE_NTH_ELEMENT
15#define CDT_PORTABLE_NTH_ELEMENT
16
17#include <algorithm>
18#include <iterator>
19#ifdef CDT_CXX11_IS_SUPPORTED
20#include <type_traits>
21#else
22#include <boost/type_traits/add_lvalue_reference.hpp>
23#endif
24
25namespace CDT
26{
27namespace detail
28{
29
30// sort
31
32// stable, 2-3 compares, 0-2 swaps
33
34template <class Compare, class ForwardIterator>
35unsigned
36sort3(ForwardIterator x, ForwardIterator y, ForwardIterator z, Compare c)
37{
38 unsigned r = 0;
39 if(!c(*y, *x)) // if x <= y
40 {
41 if(!c(*z, *y)) // if y <= z
42 return r; // x <= y && y <= z
43 // x <= y && y > z
44 std::swap(*y, *z); // x <= z && y < z
45 r = 1;
46 if(c(*y, *x)) // if x > y
47 {
48 std::swap(*x, *y); // x < y && y <= z
49 r = 2;
50 }
51 return r; // x <= y && y < z
52 }
53 if(c(*z, *y)) // x > y, if y > z
54 {
55 std::swap(*x, *z); // x < y && y < z
56 r = 1;
57 return r;
58 }
59 std::swap(*x, *y); // x > y && y <= z
60 r = 1; // x < y && x <= z
61 if(c(*z, *y)) // if y > z
62 {
63 std::swap(*y, *z); // x <= y && y < z
64 r = 2;
65 }
66 return r;
67} // x <= y && y <= z
68
69// Assumes size > 0
70template <class Compare, class BirdirectionalIterator>
71void selection_sort(
72 BirdirectionalIterator first,
73 BirdirectionalIterator last,
74 Compare comp)
75{
76 BirdirectionalIterator lm1 = last;
77 for(--lm1; first != lm1; ++first)
78 {
79#ifdef CDT_CXX11_IS_SUPPORTED
80 BirdirectionalIterator i = std::min_element<
81 BirdirectionalIterator,
82 typename std::add_lvalue_reference<Compare>::type>(
83 first, last, comp);
84#else
85 BirdirectionalIterator i = std::min_element<
86 BirdirectionalIterator,
87 typename boost::add_lvalue_reference<Compare>::type>(
88 first, last, comp);
89#endif
90 if(i != first)
91 std::swap(*first, *i);
92 }
93}
94
95// nth_element
96
97template <class Compare, class RandomAccessIterator>
98void nth_element(
99 RandomAccessIterator first,
100 RandomAccessIterator nth,
101 RandomAccessIterator last,
102 Compare comp)
103{
104 // Compare is known to be a reference type
105 typedef typename std::iterator_traits<RandomAccessIterator>::difference_type
106 difference_type;
107 const difference_type limit = 7;
108 while(true)
109 {
110 restart:
111 if(nth == last)
112 return;
113 difference_type len = last - first;
114 switch(len)
115 {
116 case 0:
117 case 1:
118 return;
119 case 2:
120 if(comp(*--last, *first))
121 std::swap(*first, *last);
122 return;
123 case 3: {
124 RandomAccessIterator m = first;
125 detail::sort3<Compare>(first, ++m, --last, comp);
126 return;
127 }
128 }
129 if(len <= limit)
130 {
131 detail::selection_sort<Compare>(first, last, comp);
132 return;
133 }
134 // len > limit >= 3
135 RandomAccessIterator m = first + len / 2;
136 RandomAccessIterator lm1 = last;
137 unsigned n_swaps = detail::sort3<Compare>(first, m, --lm1, comp);
138 // *m is median
139 // partition [first, m) < *m and *m <= [m, last)
140 // (this inhibits tossing elements equivalent to m around
141 // unnecessarily)
142 RandomAccessIterator i = first;
143 RandomAccessIterator j = lm1;
144 // j points beyond range to be tested, *lm1 is known to be <= *m
145 // The search going up is known to be guarded but the search coming
146 // down isn't. Prime the downward search with a guard.
147 if(!comp(*i, *m)) // if *first == *m
148 {
149 // *first == *m, *first doesn't go in first part
150 // manually guard downward moving j against i
151 while(true)
152 {
153 if(i == --j)
154 {
155 // *first == *m, *m <= all other elements
156 // Parition instead into [first, i) == *first and
157 // *first < [i, last)
158 ++i; // first + 1
159 j = last;
160 if(!comp(*first, *--j)) // we need a guard if
161 // *first == *(last-1)
162 {
163 while(true)
164 {
165 if(i == j)
166 return; // [first, last) all equivalent
167 // elements
168 if(comp(*first, *i))
169 {
170 std::swap(*i, *j);
171 ++n_swaps;
172 ++i;
173 break;
174 }
175 ++i;
176 }
177 }
178 // [first, i) == *first and *first < [j,
179 // last) and j == last - 1
180 if(i == j)
181 return;
182 while(true)
183 {
184 while(!comp(*first, *i))
185 ++i;
186 while(comp(*first, *--j))
187 ;
188 if(i >= j)
189 break;
190 std::swap(*i, *j);
191 ++n_swaps;
192 ++i;
193 }
194 // [first, i) == *first and *first < [i,
195 // last) The first part is sorted,
196 if(nth < i)
197 return;
198 // nth_element the secod part
199 // nth_element<Compare>(i, nth, last, comp);
200 first = i;
201 goto restart;
202 }
203 if(comp(*j, *m))
204 {
205 std::swap(*i, *j);
206 ++n_swaps;
207 break; // found guard for downward moving j, now use
208 // unguarded partition
209 }
210 }
211 }
212 ++i;
213 // j points beyond range to be tested, *lm1 is known to be <= *m
214 // if not yet partitioned...
215 if(i < j)
216 {
217 // known that *(i - 1) < *m
218 while(true)
219 {
220 // m still guards upward moving i
221 while(comp(*i, *m))
222 ++i;
223 // It is now known that a guard exists for downward moving
224 // j
225 while(!comp(*--j, *m))
226 ;
227 if(i >= j)
228 break;
229 std::swap(*i, *j);
230 ++n_swaps;
231 // It is known that m != j
232 // If m just moved, follow it
233 if(m == i)
234 m = j;
235 ++i;
236 }
237 }
238 // [first, i) < *m and *m <= [i, last)
239 if(i != m && comp(*m, *i))
240 {
241 std::swap(*i, *m);
242 ++n_swaps;
243 }
244 // [first, i) < *i and *i <= [i+1, last)
245 if(nth == i)
246 return;
247 if(n_swaps == 0)
248 {
249 // We were given a perfectly partitioned sequence. Coincidence?
250 if(nth < i)
251 {
252 // Check for [first, i) already sorted
253 j = m = first;
254 while(++j != i)
255 {
256 if(comp(*j, *m))
257 // not yet sorted, so sort
258 goto not_sorted;
259 m = j;
260 }
261 // [first, i) sorted
262 return;
263 }
264 else
265 {
266 // Check for [i, last) already sorted
267 j = m = i;
268 while(++j != last)
269 {
270 if(comp(*j, *m))
271 // not yet sorted, so sort
272 goto not_sorted;
273 m = j;
274 }
275 // [i, last) sorted
276 return;
277 }
278 }
279 not_sorted:
280 // nth_element on range containing nth
281 if(nth < i)
282 {
283 // nth_element<Compare>(first, nth, i, comp);
284 last = i;
285 }
286 else
287 {
288 // nth_element<Compare>(i+1, nth, last, comp);
289 first = ++i;
290 }
291 }
292}
293
294template <class _RandomAccessIterator, class _Compare>
295inline void portable_nth_element(
296 _RandomAccessIterator first,
297 _RandomAccessIterator nth,
298 _RandomAccessIterator last,
299 _Compare comp)
300{
301#ifdef CDT_CXX11_IS_SUPPORTED
302 detail::nth_element<typename std::add_lvalue_reference<_Compare>::type>(
303 first, nth, last, comp);
304#else
305 detail::nth_element<typename boost::add_lvalue_reference<_Compare>::type>(
306 first, nth, last, comp);
307#endif
308}
309
310} // namespace detail
311} // namespace CDT
312
313#endif // CDT_PORTABLE_NTH_ELEMENT
Namespace containing triangulation functionality.