1// -*- C++ -*-
2
3// Copyright (C) 2007-2020 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
42namespace __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