| // -*- C++ -*- |
| |
| // Copyright (C) 2007-2020 Free Software Foundation, Inc. |
| // |
| // This file is part of the GNU ISO C++ Library. This library is free |
| // software; you can redistribute it and/or modify it under the terms |
| // of the GNU General Public License as published by the Free Software |
| // Foundation; either version 3, or (at your option) any later |
| // version. |
| |
| // This library is distributed in the hope that it will be useful, but |
| // WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // General Public License for more details. |
| |
| // Under Section 7 of GPL version 3, you are granted additional |
| // permissions described in the GCC Runtime Library Exception, version |
| // 3.1, as published by the Free Software Foundation. |
| |
| // You should have received a copy of the GNU General Public License and |
| // a copy of the GCC Runtime Library Exception along with this program; |
| // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| // <http://www.gnu.org/licenses/>. |
| |
| /** |
| * @file parallel/set_operations.h |
| * @brief Parallel implementations of set operations for random-access |
| * iterators. |
| * This file is a GNU parallel extension to the Standard C++ Library. |
| */ |
| |
| // Written by Marius Elvert and Felix Bondarenko. |
| |
| #ifndef _GLIBCXX_PARALLEL_SET_OPERATIONS_H |
| #define _GLIBCXX_PARALLEL_SET_OPERATIONS_H 1 |
| |
| #include <omp.h> |
| |
| #include <parallel/settings.h> |
| #include <parallel/multiseq_selection.h> |
| |
| namespace __gnu_parallel |
| { |
| template<typename _IIter, typename _OutputIterator> |
| _OutputIterator |
| __copy_tail(std::pair<_IIter, _IIter> __b, |
| std::pair<_IIter, _IIter> __e, _OutputIterator __r) |
| { |
| if (__b.first != __e.first) |
| { |
| do |
| { |
| *__r++ = *__b.first++; |
| } |
| while (__b.first != __e.first); |
| } |
| else |
| { |
| while (__b.second != __e.second) |
| *__r++ = *__b.second++; |
| } |
| return __r; |
| } |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Compare> |
| struct __symmetric_difference_func |
| { |
| typedef std::iterator_traits<_IIter> _TraitsType; |
| typedef typename _TraitsType::difference_type _DifferenceType; |
| typedef typename std::pair<_IIter, _IIter> _IteratorPair; |
| |
| __symmetric_difference_func(_Compare __comp) : _M_comp(__comp) {} |
| |
| _Compare _M_comp; |
| |
| _OutputIterator |
| _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d, |
| _OutputIterator __r) const |
| { |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { |
| *__r = *__a; |
| ++__a; |
| ++__r; |
| } |
| else if (_M_comp(*__c, *__a)) |
| { |
| *__r = *__c; |
| ++__c; |
| ++__r; |
| } |
| else |
| { |
| ++__a; |
| ++__c; |
| } |
| } |
| return std::copy(__c, __d, std::copy(__a, __b, __r)); |
| } |
| |
| _DifferenceType |
| __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const |
| { |
| _DifferenceType __counter = 0; |
| |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { |
| ++__a; |
| ++__counter; |
| } |
| else if (_M_comp(*__c, *__a)) |
| { |
| ++__c; |
| ++__counter; |
| } |
| else |
| { |
| ++__a; |
| ++__c; |
| } |
| } |
| |
| return __counter + (__b - __a) + (__d - __c); |
| } |
| |
| _OutputIterator |
| __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const |
| { return std::copy(__c, __d, __out); } |
| |
| _OutputIterator |
| __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const |
| { return std::copy(__a, __b, __out); } |
| }; |
| |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Compare> |
| struct __difference_func |
| { |
| typedef std::iterator_traits<_IIter> _TraitsType; |
| typedef typename _TraitsType::difference_type _DifferenceType; |
| typedef typename std::pair<_IIter, _IIter> _IteratorPair; |
| |
| __difference_func(_Compare __comp) : _M_comp(__comp) {} |
| |
| _Compare _M_comp; |
| |
| _OutputIterator |
| _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d, |
| _OutputIterator __r) const |
| { |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { |
| *__r = *__a; |
| ++__a; |
| ++__r; |
| } |
| else if (_M_comp(*__c, *__a)) |
| { ++__c; } |
| else |
| { |
| ++__a; |
| ++__c; |
| } |
| } |
| return std::copy(__a, __b, __r); |
| } |
| |
| _DifferenceType |
| __count(_IIter __a, _IIter __b, |
| _IIter __c, _IIter __d) const |
| { |
| _DifferenceType __counter = 0; |
| |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { |
| ++__a; |
| ++__counter; |
| } |
| else if (_M_comp(*__c, *__a)) |
| { ++__c; } |
| else |
| { ++__a; ++__c; } |
| } |
| |
| return __counter + (__b - __a); |
| } |
| |
| _OutputIterator |
| __first_empty(_IIter, _IIter, _OutputIterator __out) const |
| { return __out; } |
| |
| _OutputIterator |
| __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const |
| { return std::copy(__a, __b, __out); } |
| }; |
| |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Compare> |
| struct __intersection_func |
| { |
| typedef std::iterator_traits<_IIter> _TraitsType; |
| typedef typename _TraitsType::difference_type _DifferenceType; |
| typedef typename std::pair<_IIter, _IIter> _IteratorPair; |
| |
| __intersection_func(_Compare __comp) : _M_comp(__comp) {} |
| |
| _Compare _M_comp; |
| |
| _OutputIterator |
| _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d, |
| _OutputIterator __r) const |
| { |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { ++__a; } |
| else if (_M_comp(*__c, *__a)) |
| { ++__c; } |
| else |
| { |
| *__r = *__a; |
| ++__a; |
| ++__c; |
| ++__r; |
| } |
| } |
| |
| return __r; |
| } |
| |
| _DifferenceType |
| __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const |
| { |
| _DifferenceType __counter = 0; |
| |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { ++__a; } |
| else if (_M_comp(*__c, *__a)) |
| { ++__c; } |
| else |
| { |
| ++__a; |
| ++__c; |
| ++__counter; |
| } |
| } |
| |
| return __counter; |
| } |
| |
| _OutputIterator |
| __first_empty(_IIter, _IIter, _OutputIterator __out) const |
| { return __out; } |
| |
| _OutputIterator |
| __second_empty(_IIter, _IIter, _OutputIterator __out) const |
| { return __out; } |
| }; |
| |
| template<class _IIter, class _OutputIterator, class _Compare> |
| struct __union_func |
| { |
| typedef typename std::iterator_traits<_IIter>::difference_type |
| _DifferenceType; |
| |
| __union_func(_Compare __comp) : _M_comp(__comp) {} |
| |
| _Compare _M_comp; |
| |
| _OutputIterator |
| _M_invoke(_IIter __a, const _IIter __b, _IIter __c, |
| const _IIter __d, _OutputIterator __r) const |
| { |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { |
| *__r = *__a; |
| ++__a; |
| } |
| else if (_M_comp(*__c, *__a)) |
| { |
| *__r = *__c; |
| ++__c; |
| } |
| else |
| { |
| *__r = *__a; |
| ++__a; |
| ++__c; |
| } |
| ++__r; |
| } |
| return std::copy(__c, __d, std::copy(__a, __b, __r)); |
| } |
| |
| _DifferenceType |
| __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const |
| { |
| _DifferenceType __counter = 0; |
| |
| while (__a != __b && __c != __d) |
| { |
| if (_M_comp(*__a, *__c)) |
| { ++__a; } |
| else if (_M_comp(*__c, *__a)) |
| { ++__c; } |
| else |
| { |
| ++__a; |
| ++__c; |
| } |
| ++__counter; |
| } |
| |
| __counter += (__b - __a); |
| __counter += (__d - __c); |
| return __counter; |
| } |
| |
| _OutputIterator |
| __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const |
| { return std::copy(__c, __d, __out); } |
| |
| _OutputIterator |
| __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const |
| { return std::copy(__a, __b, __out); } |
| }; |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Operation> |
| _OutputIterator |
| __parallel_set_operation(_IIter __begin1, _IIter __end1, |
| _IIter __begin2, _IIter __end2, |
| _OutputIterator __result, _Operation __op) |
| { |
| _GLIBCXX_CALL((__end1 - __begin1) + (__end2 - __begin2)) |
| |
| typedef std::iterator_traits<_IIter> _TraitsType; |
| typedef typename _TraitsType::difference_type _DifferenceType; |
| typedef typename std::pair<_IIter, _IIter> _IteratorPair; |
| |
| if (__begin1 == __end1) |
| return __op.__first_empty(__begin2, __end2, __result); |
| |
| if (__begin2 == __end2) |
| return __op.__second_empty(__begin1, __end1, __result); |
| |
| const _DifferenceType __size = (__end1 - __begin1) + (__end2 - __begin2); |
| |
| const _IteratorPair __sequence[2] = { std::make_pair(__begin1, __end1), |
| std::make_pair(__begin2, __end2) }; |
| _OutputIterator __return_value = __result; |
| _DifferenceType *__borders; |
| _IteratorPair *__block_begins; |
| _DifferenceType* __lengths; |
| |
| _ThreadIndex __num_threads = |
| std::min<_DifferenceType>(__get_max_threads(), |
| std::min(__end1 - __begin1, __end2 - __begin2)); |
| |
| # pragma omp parallel num_threads(__num_threads) |
| { |
| # pragma omp single |
| { |
| __num_threads = omp_get_num_threads(); |
| |
| __borders = new _DifferenceType[__num_threads + 2]; |
| __equally_split(__size, __num_threads + 1, __borders); |
| __block_begins = new _IteratorPair[__num_threads + 1]; |
| // Very __start. |
| __block_begins[0] = std::make_pair(__begin1, __begin2); |
| __lengths = new _DifferenceType[__num_threads]; |
| } //single |
| |
| _ThreadIndex __iam = omp_get_thread_num(); |
| |
| // _Result from multiseq_partition. |
| _IIter __offset[2]; |
| const _DifferenceType __rank = __borders[__iam + 1]; |
| |
| multiseq_partition(__sequence, __sequence + 2, |
| __rank, __offset, __op._M_comp); |
| |
| // allowed to read? |
| // together |
| // *(__offset[ 0 ] - 1) == *__offset[ 1 ] |
| if (__offset[ 0 ] != __begin1 && __offset[1] != __end2 |
| && !__op._M_comp(*(__offset[0] - 1), *__offset[1]) |
| && !__op._M_comp(*__offset[1], *(__offset[0] - 1))) |
| { |
| // Avoid split between globally equal elements: move one to |
| // front in first sequence. |
| --__offset[0]; |
| } |
| |
| _IteratorPair __block_end = __block_begins[__iam + 1] = |
| _IteratorPair(__offset[0], __offset[1]); |
| |
| // Make sure all threads have their block_begin result written out. |
| # pragma omp barrier |
| |
| _IteratorPair __block_begin = __block_begins[__iam]; |
| |
| // Begin working for the first block, while the others except |
| // the last start to count. |
| if (__iam == 0) |
| { |
| // The first thread can copy already. |
| __lengths[ __iam ] = |
| __op._M_invoke(__block_begin.first, __block_end.first, |
| __block_begin.second, __block_end.second, |
| __result) - __result; |
| } |
| else |
| { |
| __lengths[ __iam ] = |
| __op.__count(__block_begin.first, __block_end.first, |
| __block_begin.second, __block_end.second); |
| } |
| |
| // Make sure everyone wrote their lengths. |
| # pragma omp barrier |
| |
| _OutputIterator __r = __result; |
| |
| if (__iam == 0) |
| { |
| // Do the last block. |
| for (_ThreadIndex __i = 0; __i < __num_threads; ++__i) |
| __r += __lengths[__i]; |
| |
| __block_begin = __block_begins[__num_threads]; |
| |
| // Return the result iterator of the last block. |
| __return_value = |
| __op._M_invoke(__block_begin.first, __end1, |
| __block_begin.second, __end2, __r); |
| |
| } |
| else |
| { |
| for (_ThreadIndex __i = 0; __i < __iam; ++__i) |
| __r += __lengths[ __i ]; |
| |
| // Reset begins for copy pass. |
| __op._M_invoke(__block_begin.first, __block_end.first, |
| __block_begin.second, __block_end.second, __r); |
| } |
| } |
| return __return_value; |
| } |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Compare> |
| inline _OutputIterator |
| __parallel_set_union(_IIter __begin1, _IIter __end1, |
| _IIter __begin2, _IIter __end2, |
| _OutputIterator __result, _Compare __comp) |
| { |
| return __parallel_set_operation(__begin1, __end1, __begin2, __end2, |
| __result, |
| __union_func< _IIter, _OutputIterator, |
| _Compare>(__comp)); |
| } |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Compare> |
| inline _OutputIterator |
| __parallel_set_intersection(_IIter __begin1, _IIter __end1, |
| _IIter __begin2, _IIter __end2, |
| _OutputIterator __result, _Compare __comp) |
| { |
| return __parallel_set_operation(__begin1, __end1, __begin2, __end2, |
| __result, |
| __intersection_func<_IIter, |
| _OutputIterator, _Compare>(__comp)); |
| } |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Compare> |
| inline _OutputIterator |
| __parallel_set_difference(_IIter __begin1, _IIter __end1, |
| _IIter __begin2, _IIter __end2, |
| _OutputIterator __result, _Compare __comp) |
| { |
| return __parallel_set_operation(__begin1, __end1, __begin2, __end2, |
| __result, |
| __difference_func<_IIter, |
| _OutputIterator, _Compare>(__comp)); |
| } |
| |
| template<typename _IIter, |
| typename _OutputIterator, |
| typename _Compare> |
| inline _OutputIterator |
| __parallel_set_symmetric_difference(_IIter __begin1, _IIter __end1, |
| _IIter __begin2, _IIter __end2, |
| _OutputIterator __result, |
| _Compare __comp) |
| { |
| return __parallel_set_operation(__begin1, __end1, __begin2, __end2, |
| __result, |
| __symmetric_difference_func<_IIter, |
| _OutputIterator, _Compare>(__comp)); |
| } |
| } |
| |
| #endif /* _GLIBCXX_PARALLEL_SET_OPERATIONS_H */ |