]>
Commit | Line | Data |
---|---|---|
c2ba9709 JS |
1 | // -*- C++ -*- |
2 | ||
7adcbafe | 3 | // Copyright (C) 2007-2022 Free Software Foundation, Inc. |
c2ba9709 JS |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the terms | |
7 | // of the GNU General Public License as published by the Free Software | |
748086b7 | 8 | // Foundation; either version 3, or (at your option) any later |
c2ba9709 JS |
9 | // version. |
10 | ||
11 | // This library is distributed in the hope that it will be useful, but | |
12 | // WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | ||
748086b7 JJ |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
c2ba9709 | 19 | |
748086b7 JJ |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
c2ba9709 JS |
24 | |
25 | /** | |
26 | * @file parallel/set_operations.h | |
27 | * @brief Parallel implementations of set operations for random-access | |
28 | * iterators. | |
29 | * This file is a GNU parallel extension to the Standard C++ Library. | |
30 | */ | |
31 | ||
32 | // Written by Marius Elvert and Felix Bondarenko. | |
33 | ||
34 | #ifndef _GLIBCXX_PARALLEL_SET_OPERATIONS_H | |
35 | #define _GLIBCXX_PARALLEL_SET_OPERATIONS_H 1 | |
36 | ||
37 | #include <omp.h> | |
38 | ||
39 | #include <parallel/settings.h> | |
40 | #include <parallel/multiseq_selection.h> | |
41 | ||
42 | namespace __gnu_parallel | |
43 | { | |
77d16198 PC |
44 | template<typename _IIter, typename _OutputIterator> |
45 | _OutputIterator | |
46 | __copy_tail(std::pair<_IIter, _IIter> __b, | |
47 | std::pair<_IIter, _IIter> __e, _OutputIterator __r) | |
48 | { | |
49 | if (__b.first != __e.first) | |
50 | { | |
51 | do | |
52 | { | |
53 | *__r++ = *__b.first++; | |
54 | } | |
55 | while (__b.first != __e.first); | |
56 | } | |
57 | else | |
58 | { | |
59 | while (__b.second != __e.second) | |
60 | *__r++ = *__b.second++; | |
61 | } | |
62 | return __r; | |
63 | } | |
64 | ||
65 | template<typename _IIter, | |
66 | typename _OutputIterator, | |
67 | typename _Compare> | |
68 | struct __symmetric_difference_func | |
69 | { | |
70 | typedef std::iterator_traits<_IIter> _TraitsType; | |
71 | typedef typename _TraitsType::difference_type _DifferenceType; | |
72 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
73 | ||
74 | __symmetric_difference_func(_Compare __comp) : _M_comp(__comp) {} | |
75 | ||
76 | _Compare _M_comp; | |
77 | ||
78 | _OutputIterator | |
79 | _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d, | |
80 | _OutputIterator __r) const | |
c2ba9709 | 81 | { |
77d16198 | 82 | while (__a != __b && __c != __d) |
e683ee2a | 83 | { |
77d16198 PC |
84 | if (_M_comp(*__a, *__c)) |
85 | { | |
86 | *__r = *__a; | |
87 | ++__a; | |
88 | ++__r; | |
89 | } | |
90 | else if (_M_comp(*__c, *__a)) | |
91 | { | |
92 | *__r = *__c; | |
93 | ++__c; | |
94 | ++__r; | |
95 | } | |
96 | else | |
97 | { | |
98 | ++__a; | |
99 | ++__c; | |
100 | } | |
e683ee2a | 101 | } |
77d16198 | 102 | return std::copy(__c, __d, std::copy(__a, __b, __r)); |
c2ba9709 | 103 | } |
77d16198 PC |
104 | |
105 | _DifferenceType | |
6e687a9a | 106 | __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const |
c2ba9709 | 107 | { |
77d16198 PC |
108 | _DifferenceType __counter = 0; |
109 | ||
6e687a9a | 110 | while (__a != __b && __c != __d) |
77d16198 PC |
111 | { |
112 | if (_M_comp(*__a, *__c)) | |
113 | { | |
114 | ++__a; | |
115 | ++__counter; | |
116 | } | |
117 | else if (_M_comp(*__c, *__a)) | |
118 | { | |
119 | ++__c; | |
120 | ++__counter; | |
121 | } | |
122 | else | |
123 | { | |
124 | ++__a; | |
125 | ++__c; | |
126 | } | |
127 | } | |
128 | ||
6e687a9a | 129 | return __counter + (__b - __a) + (__d - __c); |
c2ba9709 | 130 | } |
c2ba9709 | 131 | |
77d16198 | 132 | _OutputIterator |
6e687a9a RW |
133 | __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const |
134 | { return std::copy(__c, __d, __out); } | |
c2ba9709 | 135 | |
77d16198 PC |
136 | _OutputIterator |
137 | __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const | |
138 | { return std::copy(__a, __b, __out); } | |
139 | }; | |
c2ba9709 | 140 | |
c2ba9709 | 141 | |
77d16198 PC |
142 | template<typename _IIter, |
143 | typename _OutputIterator, | |
144 | typename _Compare> | |
145 | struct __difference_func | |
c2ba9709 | 146 | { |
77d16198 PC |
147 | typedef std::iterator_traits<_IIter> _TraitsType; |
148 | typedef typename _TraitsType::difference_type _DifferenceType; | |
149 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
c2ba9709 | 150 | |
77d16198 | 151 | __difference_func(_Compare __comp) : _M_comp(__comp) {} |
c2ba9709 | 152 | |
77d16198 | 153 | _Compare _M_comp; |
c2ba9709 | 154 | |
77d16198 | 155 | _OutputIterator |
6e687a9a | 156 | _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d, |
77d16198 PC |
157 | _OutputIterator __r) const |
158 | { | |
6e687a9a | 159 | while (__a != __b && __c != __d) |
77d16198 PC |
160 | { |
161 | if (_M_comp(*__a, *__c)) | |
162 | { | |
163 | *__r = *__a; | |
164 | ++__a; | |
165 | ++__r; | |
166 | } | |
167 | else if (_M_comp(*__c, *__a)) | |
168 | { ++__c; } | |
169 | else | |
170 | { | |
171 | ++__a; | |
172 | ++__c; | |
173 | } | |
174 | } | |
175 | return std::copy(__a, __b, __r); | |
176 | } | |
c2ba9709 | 177 | |
77d16198 PC |
178 | _DifferenceType |
179 | __count(_IIter __a, _IIter __b, | |
6e687a9a | 180 | _IIter __c, _IIter __d) const |
77d16198 PC |
181 | { |
182 | _DifferenceType __counter = 0; | |
c2ba9709 | 183 | |
6e687a9a | 184 | while (__a != __b && __c != __d) |
77d16198 PC |
185 | { |
186 | if (_M_comp(*__a, *__c)) | |
187 | { | |
188 | ++__a; | |
189 | ++__counter; | |
190 | } | |
191 | else if (_M_comp(*__c, *__a)) | |
192 | { ++__c; } | |
193 | else | |
194 | { ++__a; ++__c; } | |
195 | } | |
c2ba9709 | 196 | |
77d16198 PC |
197 | return __counter + (__b - __a); |
198 | } | |
c2ba9709 | 199 | |
77d16198 PC |
200 | _OutputIterator |
201 | __first_empty(_IIter, _IIter, _OutputIterator __out) const | |
202 | { return __out; } | |
c2ba9709 | 203 | |
77d16198 PC |
204 | _OutputIterator |
205 | __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const | |
206 | { return std::copy(__a, __b, __out); } | |
207 | }; | |
c2ba9709 | 208 | |
c2ba9709 | 209 | |
77d16198 PC |
210 | template<typename _IIter, |
211 | typename _OutputIterator, | |
212 | typename _Compare> | |
213 | struct __intersection_func | |
c2ba9709 | 214 | { |
77d16198 PC |
215 | typedef std::iterator_traits<_IIter> _TraitsType; |
216 | typedef typename _TraitsType::difference_type _DifferenceType; | |
217 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
c2ba9709 | 218 | |
77d16198 | 219 | __intersection_func(_Compare __comp) : _M_comp(__comp) {} |
c2ba9709 | 220 | |
77d16198 | 221 | _Compare _M_comp; |
c2ba9709 | 222 | |
77d16198 PC |
223 | _OutputIterator |
224 | _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d, | |
225 | _OutputIterator __r) const | |
226 | { | |
227 | while (__a != __b && __c != __d) | |
228 | { | |
229 | if (_M_comp(*__a, *__c)) | |
230 | { ++__a; } | |
231 | else if (_M_comp(*__c, *__a)) | |
232 | { ++__c; } | |
233 | else | |
234 | { | |
235 | *__r = *__a; | |
236 | ++__a; | |
237 | ++__c; | |
238 | ++__r; | |
239 | } | |
240 | } | |
c2ba9709 | 241 | |
77d16198 PC |
242 | return __r; |
243 | } | |
c2ba9709 | 244 | |
77d16198 PC |
245 | _DifferenceType |
246 | __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const | |
247 | { | |
248 | _DifferenceType __counter = 0; | |
c2ba9709 | 249 | |
77d16198 PC |
250 | while (__a != __b && __c != __d) |
251 | { | |
252 | if (_M_comp(*__a, *__c)) | |
253 | { ++__a; } | |
254 | else if (_M_comp(*__c, *__a)) | |
255 | { ++__c; } | |
256 | else | |
257 | { | |
258 | ++__a; | |
259 | ++__c; | |
260 | ++__counter; | |
261 | } | |
262 | } | |
c2ba9709 | 263 | |
77d16198 PC |
264 | return __counter; |
265 | } | |
c2ba9709 | 266 | |
77d16198 PC |
267 | _OutputIterator |
268 | __first_empty(_IIter, _IIter, _OutputIterator __out) const | |
269 | { return __out; } | |
c2ba9709 | 270 | |
77d16198 PC |
271 | _OutputIterator |
272 | __second_empty(_IIter, _IIter, _OutputIterator __out) const | |
273 | { return __out; } | |
274 | }; | |
c2ba9709 | 275 | |
77d16198 PC |
276 | template<class _IIter, class _OutputIterator, class _Compare> |
277 | struct __union_func | |
c2ba9709 | 278 | { |
77d16198 PC |
279 | typedef typename std::iterator_traits<_IIter>::difference_type |
280 | _DifferenceType; | |
c2ba9709 | 281 | |
77d16198 | 282 | __union_func(_Compare __comp) : _M_comp(__comp) {} |
c2ba9709 | 283 | |
77d16198 | 284 | _Compare _M_comp; |
c2ba9709 | 285 | |
77d16198 PC |
286 | _OutputIterator |
287 | _M_invoke(_IIter __a, const _IIter __b, _IIter __c, | |
288 | const _IIter __d, _OutputIterator __r) const | |
289 | { | |
290 | while (__a != __b && __c != __d) | |
291 | { | |
292 | if (_M_comp(*__a, *__c)) | |
293 | { | |
294 | *__r = *__a; | |
295 | ++__a; | |
296 | } | |
297 | else if (_M_comp(*__c, *__a)) | |
298 | { | |
299 | *__r = *__c; | |
300 | ++__c; | |
301 | } | |
302 | else | |
303 | { | |
304 | *__r = *__a; | |
305 | ++__a; | |
306 | ++__c; | |
307 | } | |
308 | ++__r; | |
309 | } | |
310 | return std::copy(__c, __d, std::copy(__a, __b, __r)); | |
311 | } | |
c2ba9709 | 312 | |
77d16198 PC |
313 | _DifferenceType |
314 | __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const | |
315 | { | |
316 | _DifferenceType __counter = 0; | |
c2ba9709 | 317 | |
77d16198 PC |
318 | while (__a != __b && __c != __d) |
319 | { | |
320 | if (_M_comp(*__a, *__c)) | |
321 | { ++__a; } | |
322 | else if (_M_comp(*__c, *__a)) | |
323 | { ++__c; } | |
324 | else | |
325 | { | |
326 | ++__a; | |
327 | ++__c; | |
328 | } | |
329 | ++__counter; | |
330 | } | |
c2ba9709 | 331 | |
77d16198 PC |
332 | __counter += (__b - __a); |
333 | __counter += (__d - __c); | |
334 | return __counter; | |
335 | } | |
c2ba9709 | 336 | |
77d16198 PC |
337 | _OutputIterator |
338 | __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const | |
339 | { return std::copy(__c, __d, __out); } | |
c2ba9709 | 340 | |
77d16198 PC |
341 | _OutputIterator |
342 | __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const | |
343 | { return std::copy(__a, __b, __out); } | |
344 | }; | |
c2ba9709 | 345 | |
77d16198 PC |
346 | template<typename _IIter, |
347 | typename _OutputIterator, | |
2d9ca17b | 348 | typename _Operation> |
1acba85b | 349 | _OutputIterator |
77d16198 PC |
350 | __parallel_set_operation(_IIter __begin1, _IIter __end1, |
351 | _IIter __begin2, _IIter __end2, | |
2d9ca17b | 352 | _OutputIterator __result, _Operation __op) |
c2ba9709 | 353 | { |
77d16198 | 354 | _GLIBCXX_CALL((__end1 - __begin1) + (__end2 - __begin2)) |
c2ba9709 | 355 | |
77d16198 PC |
356 | typedef std::iterator_traits<_IIter> _TraitsType; |
357 | typedef typename _TraitsType::difference_type _DifferenceType; | |
358 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
c2ba9709 | 359 | |
77d16198 PC |
360 | if (__begin1 == __end1) |
361 | return __op.__first_empty(__begin2, __end2, __result); | |
c2ba9709 | 362 | |
77d16198 PC |
363 | if (__begin2 == __end2) |
364 | return __op.__second_empty(__begin1, __end1, __result); | |
c2ba9709 | 365 | |
77d16198 PC |
366 | const _DifferenceType __size = (__end1 - __begin1) + (__end2 - __begin2); |
367 | ||
368 | const _IteratorPair __sequence[2] = { std::make_pair(__begin1, __end1), | |
369 | std::make_pair(__begin2, __end2) }; | |
370 | _OutputIterator __return_value = __result; | |
371 | _DifferenceType *__borders; | |
372 | _IteratorPair *__block_begins; | |
373 | _DifferenceType* __lengths; | |
374 | ||
375 | _ThreadIndex __num_threads = | |
376 | std::min<_DifferenceType>(__get_max_threads(), | |
377 | std::min(__end1 - __begin1, __end2 - __begin2)); | |
378 | ||
379 | # pragma omp parallel num_threads(__num_threads) | |
e683ee2a JS |
380 | { |
381 | # pragma omp single | |
77d16198 PC |
382 | { |
383 | __num_threads = omp_get_num_threads(); | |
384 | ||
385 | __borders = new _DifferenceType[__num_threads + 2]; | |
6b77089f | 386 | __equally_split(__size, __num_threads + 1, __borders); |
77d16198 PC |
387 | __block_begins = new _IteratorPair[__num_threads + 1]; |
388 | // Very __start. | |
389 | __block_begins[0] = std::make_pair(__begin1, __begin2); | |
390 | __lengths = new _DifferenceType[__num_threads]; | |
391 | } //single | |
392 | ||
393 | _ThreadIndex __iam = omp_get_thread_num(); | |
394 | ||
395 | // _Result from multiseq_partition. | |
396 | _IIter __offset[2]; | |
397 | const _DifferenceType __rank = __borders[__iam + 1]; | |
398 | ||
399 | multiseq_partition(__sequence, __sequence + 2, | |
400 | __rank, __offset, __op._M_comp); | |
401 | ||
402 | // allowed to read? | |
403 | // together | |
404 | // *(__offset[ 0 ] - 1) == *__offset[ 1 ] | |
405 | if (__offset[ 0 ] != __begin1 && __offset[1] != __end2 | |
406 | && !__op._M_comp(*(__offset[0] - 1), *__offset[1]) | |
407 | && !__op._M_comp(*__offset[1], *(__offset[0] - 1))) | |
408 | { | |
409 | // Avoid split between globally equal elements: move one to | |
410 | // front in first sequence. | |
411 | --__offset[0]; | |
412 | } | |
413 | ||
414 | _IteratorPair __block_end = __block_begins[__iam + 1] = | |
415 | _IteratorPair(__offset[0], __offset[1]); | |
416 | ||
417 | // Make sure all threads have their block_begin result written out. | |
418 | # pragma omp barrier | |
e683ee2a | 419 | |
77d16198 PC |
420 | _IteratorPair __block_begin = __block_begins[__iam]; |
421 | ||
422 | // Begin working for the first block, while the others except | |
423 | // the last start to count. | |
424 | if (__iam == 0) | |
425 | { | |
426 | // The first thread can copy already. | |
427 | __lengths[ __iam ] = | |
428 | __op._M_invoke(__block_begin.first, __block_end.first, | |
429 | __block_begin.second, __block_end.second, | |
430 | __result) - __result; | |
431 | } | |
432 | else | |
433 | { | |
434 | __lengths[ __iam ] = | |
435 | __op.__count(__block_begin.first, __block_end.first, | |
436 | __block_begin.second, __block_end.second); | |
437 | } | |
438 | ||
439 | // Make sure everyone wrote their lengths. | |
e683ee2a JS |
440 | # pragma omp barrier |
441 | ||
77d16198 | 442 | _OutputIterator __r = __result; |
e683ee2a | 443 | |
77d16198 PC |
444 | if (__iam == 0) |
445 | { | |
446 | // Do the last block. | |
8b0c13a8 | 447 | for (_ThreadIndex __i = 0; __i < __num_threads; ++__i) |
77d16198 | 448 | __r += __lengths[__i]; |
e683ee2a | 449 | |
77d16198 | 450 | __block_begin = __block_begins[__num_threads]; |
e683ee2a | 451 | |
77d16198 PC |
452 | // Return the result iterator of the last block. |
453 | __return_value = | |
454 | __op._M_invoke(__block_begin.first, __end1, | |
455 | __block_begin.second, __end2, __r); | |
e683ee2a | 456 | |
77d16198 PC |
457 | } |
458 | else | |
459 | { | |
8b0c13a8 | 460 | for (_ThreadIndex __i = 0; __i < __iam; ++__i) |
77d16198 | 461 | __r += __lengths[ __i ]; |
e683ee2a | 462 | |
77d16198 PC |
463 | // Reset begins for copy pass. |
464 | __op._M_invoke(__block_begin.first, __block_end.first, | |
465 | __block_begin.second, __block_end.second, __r); | |
466 | } | |
467 | } | |
468 | return __return_value; | |
469 | } | |
e683ee2a | 470 | |
77d16198 PC |
471 | template<typename _IIter, |
472 | typename _OutputIterator, | |
473 | typename _Compare> | |
474 | inline _OutputIterator | |
475 | __parallel_set_union(_IIter __begin1, _IIter __end1, | |
476 | _IIter __begin2, _IIter __end2, | |
477 | _OutputIterator __result, _Compare __comp) | |
478 | { | |
479 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, | |
480 | __result, | |
481 | __union_func< _IIter, _OutputIterator, | |
482 | _Compare>(__comp)); | |
483 | } | |
e683ee2a | 484 | |
77d16198 PC |
485 | template<typename _IIter, |
486 | typename _OutputIterator, | |
487 | typename _Compare> | |
488 | inline _OutputIterator | |
489 | __parallel_set_intersection(_IIter __begin1, _IIter __end1, | |
490 | _IIter __begin2, _IIter __end2, | |
491 | _OutputIterator __result, _Compare __comp) | |
492 | { | |
493 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, | |
494 | __result, | |
495 | __intersection_func<_IIter, | |
496 | _OutputIterator, _Compare>(__comp)); | |
497 | } | |
e683ee2a | 498 | |
77d16198 PC |
499 | template<typename _IIter, |
500 | typename _OutputIterator, | |
501 | typename _Compare> | |
502 | inline _OutputIterator | |
503 | __parallel_set_difference(_IIter __begin1, _IIter __end1, | |
15ac3c72 | 504 | _IIter __begin2, _IIter __end2, |
77d16198 PC |
505 | _OutputIterator __result, _Compare __comp) |
506 | { | |
507 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, | |
508 | __result, | |
509 | __difference_func<_IIter, | |
510 | _OutputIterator, _Compare>(__comp)); | |
511 | } | |
c2ba9709 | 512 | |
77d16198 PC |
513 | template<typename _IIter, |
514 | typename _OutputIterator, | |
515 | typename _Compare> | |
516 | inline _OutputIterator | |
517 | __parallel_set_symmetric_difference(_IIter __begin1, _IIter __end1, | |
518 | _IIter __begin2, _IIter __end2, | |
519 | _OutputIterator __result, | |
520 | _Compare __comp) | |
521 | { | |
522 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, | |
523 | __result, | |
524 | __symmetric_difference_func<_IIter, | |
525 | _OutputIterator, _Compare>(__comp)); | |
526 | } | |
c2ba9709 JS |
527 | } |
528 | ||
cbcd1e45 | 529 | #endif /* _GLIBCXX_PARALLEL_SET_OPERATIONS_H */ |