(root)/
gcc-13.2.0/
libstdc++-v3/
include/
parallel/
set_operations.h
       1  // -*- C++ -*-
       2  
       3  // Copyright (C) 2007-2023 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 */