]>
Commit | Line | Data |
---|---|---|
c2ba9709 JS |
1 | // -*- C++ -*- |
2 | ||
748086b7 | 3 | // Copyright (C) 2007, 2008, 2009 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 | { | |
1acba85b JS |
44 | template<typename _IIter, typename _OutputIterator> |
45 | _OutputIterator | |
46 | copy_tail(std::pair<_IIter, _IIter> __b, | |
47 | std::pair<_IIter, _IIter> __e, _OutputIterator __r) | |
c2ba9709 | 48 | { |
1acba85b | 49 | if (__b.first != __e.first) |
c2ba9709 | 50 | { |
e683ee2a JS |
51 | do |
52 | { | |
1acba85b | 53 | *__r++ = *__b.first++; |
e683ee2a | 54 | } |
1acba85b | 55 | while (__b.first != __e.first); |
c2ba9709 JS |
56 | } |
57 | else | |
58 | { | |
1acba85b JS |
59 | while (__b.second != __e.second) |
60 | *__r++ = *__b.second++; | |
c2ba9709 | 61 | } |
1acba85b | 62 | return __r; |
c2ba9709 JS |
63 | } |
64 | ||
1acba85b JS |
65 | template<typename _IIter, |
66 | typename _OutputIterator, | |
67 | typename _Compare> | |
c2ba9709 JS |
68 | struct symmetric_difference_func |
69 | { | |
1acba85b JS |
70 | typedef std::iterator_traits<_IIter> _TraitsType; |
71 | typedef typename _TraitsType::difference_type _DifferenceType; | |
72 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
c2ba9709 | 73 | |
54384f7f | 74 | symmetric_difference_func(_Compare __comp) : _M_comp(__comp) {} |
c2ba9709 | 75 | |
54384f7f | 76 | _Compare _M_comp; |
c2ba9709 | 77 | |
1acba85b JS |
78 | _OutputIterator |
79 | _M_invoke(_IIter __a, _IIter __b, | |
80 | _IIter __c, _IIter d, | |
81 | _OutputIterator __r) const | |
c2ba9709 | 82 | { |
1acba85b | 83 | while (__a != __b && __c != d) |
e683ee2a | 84 | { |
54384f7f | 85 | if (_M_comp(*__a, *__c)) |
e683ee2a | 86 | { |
1acba85b JS |
87 | *__r = *__a; |
88 | ++__a; | |
89 | ++__r; | |
e683ee2a | 90 | } |
54384f7f | 91 | else if (_M_comp(*__c, *__a)) |
e683ee2a | 92 | { |
1acba85b JS |
93 | *__r = *__c; |
94 | ++__c; | |
95 | ++__r; | |
e683ee2a JS |
96 | } |
97 | else | |
98 | { | |
1acba85b JS |
99 | ++__a; |
100 | ++__c; | |
e683ee2a JS |
101 | } |
102 | } | |
1acba85b | 103 | return std::copy(__c, d, std::copy(__a, __b, __r)); |
c2ba9709 JS |
104 | } |
105 | ||
1acba85b JS |
106 | _DifferenceType |
107 | __count(_IIter __a, _IIter __b, | |
108 | _IIter __c, _IIter d) const | |
c2ba9709 | 109 | { |
1acba85b | 110 | _DifferenceType __counter = 0; |
c2ba9709 | 111 | |
1acba85b | 112 | while (__a != __b && __c != d) |
e683ee2a | 113 | { |
54384f7f | 114 | if (_M_comp(*__a, *__c)) |
e683ee2a | 115 | { |
1acba85b JS |
116 | ++__a; |
117 | ++__counter; | |
e683ee2a | 118 | } |
54384f7f | 119 | else if (_M_comp(*__c, *__a)) |
e683ee2a | 120 | { |
1acba85b JS |
121 | ++__c; |
122 | ++__counter; | |
e683ee2a JS |
123 | } |
124 | else | |
125 | { | |
1acba85b JS |
126 | ++__a; |
127 | ++__c; | |
e683ee2a JS |
128 | } |
129 | } | |
c2ba9709 | 130 | |
1acba85b | 131 | return __counter + (__b - __a) + (d - __c); |
c2ba9709 JS |
132 | } |
133 | ||
1acba85b JS |
134 | _OutputIterator |
135 | __first_empty(_IIter __c, _IIter d, _OutputIterator __out) const | |
136 | { return std::copy(__c, d, __out); } | |
c2ba9709 | 137 | |
1acba85b JS |
138 | _OutputIterator |
139 | __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const | |
140 | { return std::copy(__a, __b, __out); } | |
c2ba9709 JS |
141 | }; |
142 | ||
143 | ||
1acba85b JS |
144 | template<typename _IIter, |
145 | typename _OutputIterator, | |
146 | typename _Compare> | |
147 | struct __difference_func | |
c2ba9709 | 148 | { |
1acba85b JS |
149 | typedef std::iterator_traits<_IIter> _TraitsType; |
150 | typedef typename _TraitsType::difference_type _DifferenceType; | |
151 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
c2ba9709 | 152 | |
54384f7f | 153 | __difference_func(_Compare __comp) : _M_comp(__comp) {} |
c2ba9709 | 154 | |
54384f7f | 155 | _Compare _M_comp; |
c2ba9709 | 156 | |
1acba85b JS |
157 | _OutputIterator |
158 | _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter d, | |
159 | _OutputIterator __r) const | |
c2ba9709 | 160 | { |
1acba85b | 161 | while (__a != __b && __c != d) |
e683ee2a | 162 | { |
54384f7f | 163 | if (_M_comp(*__a, *__c)) |
e683ee2a | 164 | { |
1acba85b JS |
165 | *__r = *__a; |
166 | ++__a; | |
167 | ++__r; | |
e683ee2a | 168 | } |
54384f7f | 169 | else if (_M_comp(*__c, *__a)) |
1acba85b | 170 | { ++__c; } |
e683ee2a JS |
171 | else |
172 | { | |
1acba85b JS |
173 | ++__a; |
174 | ++__c; | |
e683ee2a JS |
175 | } |
176 | } | |
1acba85b | 177 | return std::copy(__a, __b, __r); |
c2ba9709 JS |
178 | } |
179 | ||
1acba85b JS |
180 | _DifferenceType |
181 | __count(_IIter __a, _IIter __b, | |
182 | _IIter __c, _IIter d) const | |
c2ba9709 | 183 | { |
1acba85b | 184 | _DifferenceType __counter = 0; |
c2ba9709 | 185 | |
1acba85b | 186 | while (__a != __b && __c != d) |
e683ee2a | 187 | { |
54384f7f | 188 | if (_M_comp(*__a, *__c)) |
e683ee2a | 189 | { |
1acba85b JS |
190 | ++__a; |
191 | ++__counter; | |
e683ee2a | 192 | } |
54384f7f | 193 | else if (_M_comp(*__c, *__a)) |
1acba85b | 194 | { ++__c; } |
e683ee2a | 195 | else |
1acba85b | 196 | { ++__a; ++__c; } |
e683ee2a | 197 | } |
c2ba9709 | 198 | |
1acba85b | 199 | return __counter + (__b - __a); |
c2ba9709 JS |
200 | } |
201 | ||
1acba85b JS |
202 | inline _OutputIterator |
203 | __first_empty(_IIter __c, _IIter d, _OutputIterator __out) const | |
204 | { return __out; } | |
c2ba9709 | 205 | |
1acba85b JS |
206 | inline _OutputIterator |
207 | __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const | |
208 | { return std::copy(__a, __b, __out); } | |
c2ba9709 JS |
209 | }; |
210 | ||
211 | ||
1acba85b JS |
212 | template<typename _IIter, |
213 | typename _OutputIterator, | |
214 | typename _Compare> | |
215 | struct __intersection_func | |
c2ba9709 | 216 | { |
1acba85b JS |
217 | typedef std::iterator_traits<_IIter> _TraitsType; |
218 | typedef typename _TraitsType::difference_type _DifferenceType; | |
219 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
c2ba9709 | 220 | |
54384f7f | 221 | __intersection_func(_Compare __comp) : _M_comp(__comp) {} |
c2ba9709 | 222 | |
54384f7f | 223 | _Compare _M_comp; |
c2ba9709 | 224 | |
1acba85b JS |
225 | _OutputIterator |
226 | _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter d, | |
227 | _OutputIterator __r) const | |
c2ba9709 | 228 | { |
1acba85b | 229 | while (__a != __b && __c != d) |
e683ee2a | 230 | { |
54384f7f | 231 | if (_M_comp(*__a, *__c)) |
1acba85b | 232 | { ++__a; } |
54384f7f | 233 | else if (_M_comp(*__c, *__a)) |
1acba85b | 234 | { ++__c; } |
e683ee2a JS |
235 | else |
236 | { | |
1acba85b JS |
237 | *__r = *__a; |
238 | ++__a; | |
239 | ++__c; | |
240 | ++__r; | |
e683ee2a JS |
241 | } |
242 | } | |
c2ba9709 | 243 | |
1acba85b | 244 | return __r; |
c2ba9709 JS |
245 | } |
246 | ||
1acba85b JS |
247 | _DifferenceType |
248 | __count(_IIter __a, _IIter __b, | |
249 | _IIter __c, _IIter d) const | |
c2ba9709 | 250 | { |
1acba85b | 251 | _DifferenceType __counter = 0; |
c2ba9709 | 252 | |
1acba85b | 253 | while (__a != __b && __c != d) |
e683ee2a | 254 | { |
54384f7f | 255 | if (_M_comp(*__a, *__c)) |
1acba85b | 256 | { ++__a; } |
54384f7f | 257 | else if (_M_comp(*__c, *__a)) |
1acba85b | 258 | { ++__c; } |
e683ee2a JS |
259 | else |
260 | { | |
1acba85b JS |
261 | ++__a; |
262 | ++__c; | |
263 | ++__counter; | |
e683ee2a JS |
264 | } |
265 | } | |
c2ba9709 | 266 | |
1acba85b | 267 | return __counter; |
c2ba9709 JS |
268 | } |
269 | ||
1acba85b JS |
270 | inline _OutputIterator |
271 | __first_empty(_IIter __c, _IIter d, _OutputIterator __out) const | |
272 | { return __out; } | |
c2ba9709 | 273 | |
1acba85b JS |
274 | inline _OutputIterator |
275 | __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const | |
276 | { return __out; } | |
c2ba9709 JS |
277 | }; |
278 | ||
1acba85b JS |
279 | template<class _IIter, class _OutputIterator, class _Compare> |
280 | struct __union_func | |
c2ba9709 | 281 | { |
1acba85b JS |
282 | typedef typename std::iterator_traits<_IIter>::difference_type |
283 | _DifferenceType; | |
c2ba9709 | 284 | |
54384f7f | 285 | __union_func(_Compare __comp) : _M_comp(__comp) {} |
c2ba9709 | 286 | |
54384f7f | 287 | _Compare _M_comp; |
c2ba9709 | 288 | |
1acba85b JS |
289 | _OutputIterator |
290 | _M_invoke(_IIter __a, const _IIter __b, _IIter __c, | |
291 | const _IIter d, _OutputIterator __r) const | |
c2ba9709 | 292 | { |
1acba85b | 293 | while (__a != __b && __c != d) |
e683ee2a | 294 | { |
54384f7f | 295 | if (_M_comp(*__a, *__c)) |
e683ee2a | 296 | { |
1acba85b JS |
297 | *__r = *__a; |
298 | ++__a; | |
e683ee2a | 299 | } |
54384f7f | 300 | else if (_M_comp(*__c, *__a)) |
e683ee2a | 301 | { |
1acba85b JS |
302 | *__r = *__c; |
303 | ++__c; | |
e683ee2a JS |
304 | } |
305 | else | |
306 | { | |
1acba85b JS |
307 | *__r = *__a; |
308 | ++__a; | |
309 | ++__c; | |
e683ee2a | 310 | } |
1acba85b | 311 | ++__r; |
e683ee2a | 312 | } |
1acba85b | 313 | return std::copy(__c, d, std::copy(__a, __b, __r)); |
c2ba9709 JS |
314 | } |
315 | ||
1acba85b JS |
316 | _DifferenceType |
317 | __count(_IIter __a, _IIter __b, | |
318 | _IIter __c, _IIter d) const | |
c2ba9709 | 319 | { |
1acba85b | 320 | _DifferenceType __counter = 0; |
c2ba9709 | 321 | |
1acba85b | 322 | while (__a != __b && __c != d) |
e683ee2a | 323 | { |
54384f7f | 324 | if (_M_comp(*__a, *__c)) |
1acba85b | 325 | { ++__a; } |
54384f7f | 326 | else if (_M_comp(*__c, *__a)) |
1acba85b | 327 | { ++__c; } |
e683ee2a JS |
328 | else |
329 | { | |
1acba85b JS |
330 | ++__a; |
331 | ++__c; | |
e683ee2a | 332 | } |
1acba85b | 333 | ++__counter; |
e683ee2a | 334 | } |
c2ba9709 | 335 | |
1acba85b JS |
336 | __counter += (__b - __a); |
337 | __counter += (d - __c); | |
338 | return __counter; | |
c2ba9709 JS |
339 | } |
340 | ||
1acba85b JS |
341 | inline _OutputIterator |
342 | __first_empty(_IIter __c, _IIter d, _OutputIterator __out) const | |
343 | { return std::copy(__c, d, __out); } | |
c2ba9709 | 344 | |
1acba85b JS |
345 | inline _OutputIterator |
346 | __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const | |
347 | { return std::copy(__a, __b, __out); } | |
c2ba9709 JS |
348 | }; |
349 | ||
1acba85b JS |
350 | template<typename _IIter, |
351 | typename _OutputIterator, | |
5817ff8e | 352 | typename Operation> |
1acba85b JS |
353 | _OutputIterator |
354 | __parallel_set_operation(_IIter __begin1, _IIter __end1, | |
355 | _IIter __begin2, _IIter __end2, | |
356 | _OutputIterator __result, Operation __op) | |
c2ba9709 | 357 | { |
1acba85b | 358 | _GLIBCXX_CALL((__end1 - __begin1) + (__end2 - __begin2)) |
c2ba9709 | 359 | |
1acba85b JS |
360 | typedef std::iterator_traits<_IIter> _TraitsType; |
361 | typedef typename _TraitsType::difference_type _DifferenceType; | |
362 | typedef typename std::pair<_IIter, _IIter> _IteratorPair; | |
c2ba9709 | 363 | |
1acba85b JS |
364 | if (__begin1 == __end1) |
365 | return __op.__first_empty(__begin2, __end2, __result); | |
c2ba9709 | 366 | |
1acba85b JS |
367 | if (__begin2 == __end2) |
368 | return __op.__second_empty(__begin1, __end1, __result); | |
c2ba9709 | 369 | |
1acba85b | 370 | const _DifferenceType size = (__end1 - __begin1) + (__end2 - __begin2); |
c2ba9709 | 371 | |
1acba85b JS |
372 | const _IteratorPair __sequence[ 2 ] = |
373 | { std::make_pair(__begin1, __end1), std::make_pair(__begin2, __end2) } ; | |
374 | _OutputIterator return_value = __result; | |
375 | _DifferenceType *__borders; | |
376 | _IteratorPair *__block_begins; | |
377 | _DifferenceType* __lengths; | |
c2ba9709 | 378 | |
1acba85b JS |
379 | _ThreadIndex __num_threads = |
380 | std::min<_DifferenceType>(__get_max_threads(), | |
381 | std::min(__end1 - __begin1, __end2 - __begin2)); | |
e683ee2a | 382 | |
1acba85b | 383 | # pragma omp parallel num_threads(__num_threads) |
e683ee2a JS |
384 | { |
385 | # pragma omp single | |
386 | { | |
1acba85b JS |
387 | __num_threads = omp_get_num_threads(); |
388 | ||
389 | __borders = new _DifferenceType[__num_threads + 2]; | |
390 | equally_split(size, __num_threads + 1, __borders); | |
391 | __block_begins = new _IteratorPair[__num_threads + 1]; | |
392 | // Very __start. | |
393 | __block_begins[0] = std::make_pair(__begin1, __begin2); | |
394 | __lengths = new _DifferenceType[__num_threads]; | |
e683ee2a JS |
395 | } //single |
396 | ||
1acba85b | 397 | _ThreadIndex __iam = omp_get_thread_num(); |
e683ee2a | 398 | |
1acba85b JS |
399 | // _Result from multiseq_partition. |
400 | _IIter __offset[2]; | |
401 | const _DifferenceType __rank = __borders[__iam + 1]; | |
e683ee2a | 402 | |
54384f7f | 403 | multiseq_partition(__sequence, __sequence + 2, __rank, __offset, __op._M_comp); |
e683ee2a JS |
404 | |
405 | // allowed to read? | |
406 | // together | |
1acba85b JS |
407 | // *(__offset[ 0 ] - 1) == *__offset[ 1 ] |
408 | if (__offset[ 0 ] != __begin1 && __offset[ 1 ] != __end2 | |
54384f7f JS |
409 | && !__op._M_comp(*(__offset[ 0 ] - 1), *__offset[ 1 ]) |
410 | && !__op._M_comp(*__offset[ 1 ], *(__offset[ 0 ] - 1))) | |
e683ee2a JS |
411 | { |
412 | // Avoid split between globally equal elements: move one to | |
413 | // front in first sequence. | |
1acba85b | 414 | --__offset[ 0 ]; |
e683ee2a JS |
415 | } |
416 | ||
1acba85b JS |
417 | _IteratorPair block_end = __block_begins[ __iam + 1 ] = |
418 | _IteratorPair(__offset[ 0 ], __offset[ 1 ]); | |
e683ee2a JS |
419 | |
420 | // Make sure all threads have their block_begin result written out. | |
421 | # pragma omp barrier | |
422 | ||
1acba85b | 423 | _IteratorPair __block_begin = __block_begins[ __iam ]; |
e683ee2a JS |
424 | |
425 | // Begin working for the first block, while the others except | |
426 | // the last start to count. | |
1acba85b | 427 | if (__iam == 0) |
e683ee2a JS |
428 | { |
429 | // The first thread can copy already. | |
1acba85b JS |
430 | __lengths[ __iam ] = __op._M_invoke(__block_begin.first, block_end.first, |
431 | __block_begin.second, block_end.second, | |
432 | __result) | |
433 | - __result; | |
e683ee2a JS |
434 | } |
435 | else | |
436 | { | |
1acba85b JS |
437 | __lengths[ __iam ] = __op.__count(__block_begin.first, block_end.first, |
438 | __block_begin.second, block_end.second); | |
e683ee2a JS |
439 | } |
440 | ||
441 | // Make sure everyone wrote their lengths. | |
442 | # pragma omp barrier | |
443 | ||
1acba85b | 444 | _OutputIterator __r = __result; |
e683ee2a | 445 | |
1acba85b | 446 | if (__iam == 0) |
e683ee2a JS |
447 | { |
448 | // Do the last block. | |
1acba85b JS |
449 | for (int __i = 0; __i < __num_threads; ++__i) |
450 | __r += __lengths[__i]; | |
e683ee2a | 451 | |
1acba85b | 452 | __block_begin = __block_begins[__num_threads]; |
e683ee2a JS |
453 | |
454 | // Return the result iterator of the last block. | |
1acba85b JS |
455 | return_value = __op._M_invoke( |
456 | __block_begin.first, __end1, __block_begin.second, __end2, __r); | |
e683ee2a JS |
457 | |
458 | } | |
459 | else | |
460 | { | |
1acba85b JS |
461 | for (int __i = 0; __i < __iam; ++__i) |
462 | __r += __lengths[ __i ]; | |
e683ee2a JS |
463 | |
464 | // Reset begins for copy pass. | |
1acba85b JS |
465 | __op._M_invoke(__block_begin.first, block_end.first, |
466 | __block_begin.second, block_end.second, __r); | |
e683ee2a JS |
467 | } |
468 | } | |
c2ba9709 JS |
469 | return return_value; |
470 | } | |
471 | ||
472 | ||
1acba85b JS |
473 | template<typename _IIter, |
474 | typename _OutputIterator, | |
475 | typename _Compare> | |
476 | inline _OutputIterator | |
477 | __parallel_set_union(_IIter __begin1, _IIter __end1, | |
478 | _IIter __begin2, _IIter __end2, | |
54384f7f | 479 | _OutputIterator __result, _Compare _M_comp) |
c2ba9709 | 480 | { |
1acba85b | 481 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, __result, |
54384f7f | 482 | __union_func< _IIter, _OutputIterator, _Compare>(_M_comp)); |
c2ba9709 JS |
483 | } |
484 | ||
1acba85b JS |
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, | |
54384f7f | 491 | _OutputIterator __result, _Compare _M_comp) |
c2ba9709 | 492 | { |
1acba85b | 493 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, __result, |
54384f7f | 494 | __intersection_func<_IIter, _OutputIterator, _Compare>(_M_comp)); |
c2ba9709 JS |
495 | } |
496 | ||
1acba85b JS |
497 | template<typename _IIter, |
498 | typename _OutputIterator, | |
499 | typename _Compare> | |
500 | inline _OutputIterator | |
501 | __parallel_set_difference(_IIter __begin1, _IIter __end1, | |
502 | _IIter __begin2, _IIter __end2, | |
54384f7f | 503 | _OutputIterator __result, _Compare _M_comp) |
c2ba9709 | 504 | { |
1acba85b | 505 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, __result, |
54384f7f | 506 | __difference_func<_IIter, _OutputIterator, _Compare>(_M_comp)); |
c2ba9709 JS |
507 | } |
508 | ||
1acba85b JS |
509 | template<typename _IIter, |
510 | typename _OutputIterator, | |
511 | typename _Compare> | |
512 | inline _OutputIterator | |
513 | __parallel_set_symmetric_difference(_IIter __begin1, _IIter __end1, | |
514 | _IIter __begin2, _IIter __end2, | |
54384f7f | 515 | _OutputIterator __result, _Compare _M_comp) |
c2ba9709 | 516 | { |
1acba85b JS |
517 | return __parallel_set_operation(__begin1, __end1, __begin2, __end2, __result, |
518 | symmetric_difference_func<_IIter, _OutputIterator, _Compare> | |
54384f7f | 519 | (_M_comp)); |
c2ba9709 JS |
520 | } |
521 | ||
522 | } | |
523 | ||
cbcd1e45 | 524 | #endif /* _GLIBCXX_PARALLEL_SET_OPERATIONS_H */ |