1 // -*- C++ -*- 2 3 // Copyright (C) 2007-2013 Free Software Foundation, Inc. 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 8 // Foundation; either version 3, or (at your option) any later 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 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. 19 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/>. 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 { 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 81 { 82 while (__a != __b && __c != __d) 83 { 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 } 101 } 102 return std::copy(__c, __d, std::copy(__a, __b, __r)); 103 } 104 105 _DifferenceType 106 __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const 107 { 108 _DifferenceType __counter = 0; 109 110 while (__a != __b && __c != __d) 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 129 return __counter + (__b - __a) + (__d - __c); 130 } 131 132 _OutputIterator 133 __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const 134 { return std::copy(__c, __d, __out); } 135 136 _OutputIterator 137 __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const 138 { return std::copy(__a, __b, __out); } 139 }; 140 141 142 template<typename _IIter, 143 typename _OutputIterator, 144 typename _Compare> 145 struct __difference_func 146 { 147 typedef std::iterator_traits<_IIter> _TraitsType; 148 typedef typename _TraitsType::difference_type _DifferenceType; 149 typedef typename std::pair<_IIter, _IIter> _IteratorPair; 150 151 __difference_func(_Compare __comp) : _M_comp(__comp) {} 152 153 _Compare _M_comp; 154 155 _OutputIterator 156 _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d, 157 _OutputIterator __r) const 158 { 159 while (__a != __b && __c != __d) 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 } 177 178 _DifferenceType 179 __count(_IIter __a, _IIter __b, 180 _IIter __c, _IIter __d) const 181 { 182 _DifferenceType __counter = 0; 183 184 while (__a != __b && __c != __d) 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 } 196 197 return __counter + (__b - __a); 198 } 199 200 _OutputIterator 201 __first_empty(_IIter, _IIter, _OutputIterator __out) const 202 { return __out; } 203 204 _OutputIterator 205 __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const 206 { return std::copy(__a, __b, __out); } 207 }; 208 209 210 template<typename _IIter, 211 typename _OutputIterator, 212 typename _Compare> 213 struct __intersection_func 214 { 215 typedef std::iterator_traits<_IIter> _TraitsType; 216 typedef typename _TraitsType::difference_type _DifferenceType; 217 typedef typename std::pair<_IIter, _IIter> _IteratorPair; 218 219 __intersection_func(_Compare __comp) : _M_comp(__comp) {} 220 221 _Compare _M_comp; 222 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 } 241 242 return __r; 243 } 244 245 _DifferenceType 246 __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const 247 { 248 _DifferenceType __counter = 0; 249 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 } 263 264 return __counter; 265 } 266 267 _OutputIterator 268 __first_empty(_IIter, _IIter, _OutputIterator __out) const 269 { return __out; } 270 271 _OutputIterator 272 __second_empty(_IIter, _IIter, _OutputIterator __out) const 273 { return __out; } 274 }; 275 276 template<class _IIter, class _OutputIterator, class _Compare> 277 struct __union_func 278 { 279 typedef typename std::iterator_traits<_IIter>::difference_type 280 _DifferenceType; 281 282 __union_func(_Compare __comp) : _M_comp(__comp) {} 283 284 _Compare _M_comp; 285 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 } 312 313 _DifferenceType 314 __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const 315 { 316 _DifferenceType __counter = 0; 317 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 } 331 332 __counter += (__b - __a); 333 __counter += (__d - __c); 334 return __counter; 335 } 336 337 _OutputIterator 338 __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const 339 { return std::copy(__c, __d, __out); } 340 341 _OutputIterator 342 __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const 343 { return std::copy(__a, __b, __out); } 344 }; 345 346 template<typename _IIter, 347 typename _OutputIterator, 348 typename _Operation> 349 _OutputIterator 350 __parallel_set_operation(_IIter __begin1, _IIter __end1, 351 _IIter __begin2, _IIter __end2, 352 _OutputIterator __result, _Operation __op) 353 { 354 _GLIBCXX_CALL((__end1 - __begin1) + (__end2 - __begin2)) 355 356 typedef std::iterator_traits<_IIter> _TraitsType; 357 typedef typename _TraitsType::difference_type _DifferenceType; 358 typedef typename std::pair<_IIter, _IIter> _IteratorPair; 359 360 if (__begin1 == __end1) 361 return __op.__first_empty(__begin2, __end2, __result); 362 363 if (__begin2 == __end2) 364 return __op.__second_empty(__begin1, __end1, __result); 365 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) 380 { 381 # pragma omp single 382 { 383 __num_threads = omp_get_num_threads(); 384 385 __borders = new _DifferenceType[__num_threads + 2]; 386 __equally_split(__size, __num_threads + 1, __borders); 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 419 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. 440 # pragma omp barrier 441 442 _OutputIterator __r = __result; 443 444 if (__iam == 0) 445 { 446 // Do the last block. 447 for (_ThreadIndex __i = 0; __i < __num_threads; ++__i) 448 __r += __lengths[__i]; 449 450 __block_begin = __block_begins[__num_threads]; 451 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); 456 457 } 458 else 459 { 460 for (_ThreadIndex __i = 0; __i < __iam; ++__i) 461 __r += __lengths[ __i ]; 462 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 } 470 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 } 484 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 } 498 499 template<typename _IIter, 500 typename _OutputIterator, 501 typename _Compare> 502 inline _OutputIterator 503 __parallel_set_difference(_IIter __begin1, _IIter __end1, 504 _IIter __begin2, _IIter __end2, 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 } 512 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 } 527 } 528 529 #endif /* _GLIBCXX_PARALLEL_SET_OPERATIONS_H */ 530