You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

530 lines
14KB

  1. // -*- C++ -*-
  2. // Copyright (C) 2007-2020 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the terms
  6. // of the GNU General Public License as published by the Free Software
  7. // Foundation; either version 3, or (at your option) any later
  8. // version.
  9. // This library is distributed in the hope that it will be useful, but
  10. // WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. // General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /**
  21. * @file parallel/set_operations.h
  22. * @brief Parallel implementations of set operations for random-access
  23. * iterators.
  24. * This file is a GNU parallel extension to the Standard C++ Library.
  25. */
  26. // Written by Marius Elvert and Felix Bondarenko.
  27. #ifndef _GLIBCXX_PARALLEL_SET_OPERATIONS_H
  28. #define _GLIBCXX_PARALLEL_SET_OPERATIONS_H 1
  29. #include <omp.h>
  30. #include <parallel/settings.h>
  31. #include <parallel/multiseq_selection.h>
  32. namespace __gnu_parallel
  33. {
  34. template<typename _IIter, typename _OutputIterator>
  35. _OutputIterator
  36. __copy_tail(std::pair<_IIter, _IIter> __b,
  37. std::pair<_IIter, _IIter> __e, _OutputIterator __r)
  38. {
  39. if (__b.first != __e.first)
  40. {
  41. do
  42. {
  43. *__r++ = *__b.first++;
  44. }
  45. while (__b.first != __e.first);
  46. }
  47. else
  48. {
  49. while (__b.second != __e.second)
  50. *__r++ = *__b.second++;
  51. }
  52. return __r;
  53. }
  54. template<typename _IIter,
  55. typename _OutputIterator,
  56. typename _Compare>
  57. struct __symmetric_difference_func
  58. {
  59. typedef std::iterator_traits<_IIter> _TraitsType;
  60. typedef typename _TraitsType::difference_type _DifferenceType;
  61. typedef typename std::pair<_IIter, _IIter> _IteratorPair;
  62. __symmetric_difference_func(_Compare __comp) : _M_comp(__comp) {}
  63. _Compare _M_comp;
  64. _OutputIterator
  65. _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d,
  66. _OutputIterator __r) const
  67. {
  68. while (__a != __b && __c != __d)
  69. {
  70. if (_M_comp(*__a, *__c))
  71. {
  72. *__r = *__a;
  73. ++__a;
  74. ++__r;
  75. }
  76. else if (_M_comp(*__c, *__a))
  77. {
  78. *__r = *__c;
  79. ++__c;
  80. ++__r;
  81. }
  82. else
  83. {
  84. ++__a;
  85. ++__c;
  86. }
  87. }
  88. return std::copy(__c, __d, std::copy(__a, __b, __r));
  89. }
  90. _DifferenceType
  91. __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const
  92. {
  93. _DifferenceType __counter = 0;
  94. while (__a != __b && __c != __d)
  95. {
  96. if (_M_comp(*__a, *__c))
  97. {
  98. ++__a;
  99. ++__counter;
  100. }
  101. else if (_M_comp(*__c, *__a))
  102. {
  103. ++__c;
  104. ++__counter;
  105. }
  106. else
  107. {
  108. ++__a;
  109. ++__c;
  110. }
  111. }
  112. return __counter + (__b - __a) + (__d - __c);
  113. }
  114. _OutputIterator
  115. __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const
  116. { return std::copy(__c, __d, __out); }
  117. _OutputIterator
  118. __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const
  119. { return std::copy(__a, __b, __out); }
  120. };
  121. template<typename _IIter,
  122. typename _OutputIterator,
  123. typename _Compare>
  124. struct __difference_func
  125. {
  126. typedef std::iterator_traits<_IIter> _TraitsType;
  127. typedef typename _TraitsType::difference_type _DifferenceType;
  128. typedef typename std::pair<_IIter, _IIter> _IteratorPair;
  129. __difference_func(_Compare __comp) : _M_comp(__comp) {}
  130. _Compare _M_comp;
  131. _OutputIterator
  132. _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d,
  133. _OutputIterator __r) const
  134. {
  135. while (__a != __b && __c != __d)
  136. {
  137. if (_M_comp(*__a, *__c))
  138. {
  139. *__r = *__a;
  140. ++__a;
  141. ++__r;
  142. }
  143. else if (_M_comp(*__c, *__a))
  144. { ++__c; }
  145. else
  146. {
  147. ++__a;
  148. ++__c;
  149. }
  150. }
  151. return std::copy(__a, __b, __r);
  152. }
  153. _DifferenceType
  154. __count(_IIter __a, _IIter __b,
  155. _IIter __c, _IIter __d) const
  156. {
  157. _DifferenceType __counter = 0;
  158. while (__a != __b && __c != __d)
  159. {
  160. if (_M_comp(*__a, *__c))
  161. {
  162. ++__a;
  163. ++__counter;
  164. }
  165. else if (_M_comp(*__c, *__a))
  166. { ++__c; }
  167. else
  168. { ++__a; ++__c; }
  169. }
  170. return __counter + (__b - __a);
  171. }
  172. _OutputIterator
  173. __first_empty(_IIter, _IIter, _OutputIterator __out) const
  174. { return __out; }
  175. _OutputIterator
  176. __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const
  177. { return std::copy(__a, __b, __out); }
  178. };
  179. template<typename _IIter,
  180. typename _OutputIterator,
  181. typename _Compare>
  182. struct __intersection_func
  183. {
  184. typedef std::iterator_traits<_IIter> _TraitsType;
  185. typedef typename _TraitsType::difference_type _DifferenceType;
  186. typedef typename std::pair<_IIter, _IIter> _IteratorPair;
  187. __intersection_func(_Compare __comp) : _M_comp(__comp) {}
  188. _Compare _M_comp;
  189. _OutputIterator
  190. _M_invoke(_IIter __a, _IIter __b, _IIter __c, _IIter __d,
  191. _OutputIterator __r) const
  192. {
  193. while (__a != __b && __c != __d)
  194. {
  195. if (_M_comp(*__a, *__c))
  196. { ++__a; }
  197. else if (_M_comp(*__c, *__a))
  198. { ++__c; }
  199. else
  200. {
  201. *__r = *__a;
  202. ++__a;
  203. ++__c;
  204. ++__r;
  205. }
  206. }
  207. return __r;
  208. }
  209. _DifferenceType
  210. __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const
  211. {
  212. _DifferenceType __counter = 0;
  213. while (__a != __b && __c != __d)
  214. {
  215. if (_M_comp(*__a, *__c))
  216. { ++__a; }
  217. else if (_M_comp(*__c, *__a))
  218. { ++__c; }
  219. else
  220. {
  221. ++__a;
  222. ++__c;
  223. ++__counter;
  224. }
  225. }
  226. return __counter;
  227. }
  228. _OutputIterator
  229. __first_empty(_IIter, _IIter, _OutputIterator __out) const
  230. { return __out; }
  231. _OutputIterator
  232. __second_empty(_IIter, _IIter, _OutputIterator __out) const
  233. { return __out; }
  234. };
  235. template<class _IIter, class _OutputIterator, class _Compare>
  236. struct __union_func
  237. {
  238. typedef typename std::iterator_traits<_IIter>::difference_type
  239. _DifferenceType;
  240. __union_func(_Compare __comp) : _M_comp(__comp) {}
  241. _Compare _M_comp;
  242. _OutputIterator
  243. _M_invoke(_IIter __a, const _IIter __b, _IIter __c,
  244. const _IIter __d, _OutputIterator __r) const
  245. {
  246. while (__a != __b && __c != __d)
  247. {
  248. if (_M_comp(*__a, *__c))
  249. {
  250. *__r = *__a;
  251. ++__a;
  252. }
  253. else if (_M_comp(*__c, *__a))
  254. {
  255. *__r = *__c;
  256. ++__c;
  257. }
  258. else
  259. {
  260. *__r = *__a;
  261. ++__a;
  262. ++__c;
  263. }
  264. ++__r;
  265. }
  266. return std::copy(__c, __d, std::copy(__a, __b, __r));
  267. }
  268. _DifferenceType
  269. __count(_IIter __a, _IIter __b, _IIter __c, _IIter __d) const
  270. {
  271. _DifferenceType __counter = 0;
  272. while (__a != __b && __c != __d)
  273. {
  274. if (_M_comp(*__a, *__c))
  275. { ++__a; }
  276. else if (_M_comp(*__c, *__a))
  277. { ++__c; }
  278. else
  279. {
  280. ++__a;
  281. ++__c;
  282. }
  283. ++__counter;
  284. }
  285. __counter += (__b - __a);
  286. __counter += (__d - __c);
  287. return __counter;
  288. }
  289. _OutputIterator
  290. __first_empty(_IIter __c, _IIter __d, _OutputIterator __out) const
  291. { return std::copy(__c, __d, __out); }
  292. _OutputIterator
  293. __second_empty(_IIter __a, _IIter __b, _OutputIterator __out) const
  294. { return std::copy(__a, __b, __out); }
  295. };
  296. template<typename _IIter,
  297. typename _OutputIterator,
  298. typename _Operation>
  299. _OutputIterator
  300. __parallel_set_operation(_IIter __begin1, _IIter __end1,
  301. _IIter __begin2, _IIter __end2,
  302. _OutputIterator __result, _Operation __op)
  303. {
  304. _GLIBCXX_CALL((__end1 - __begin1) + (__end2 - __begin2))
  305. typedef std::iterator_traits<_IIter> _TraitsType;
  306. typedef typename _TraitsType::difference_type _DifferenceType;
  307. typedef typename std::pair<_IIter, _IIter> _IteratorPair;
  308. if (__begin1 == __end1)
  309. return __op.__first_empty(__begin2, __end2, __result);
  310. if (__begin2 == __end2)
  311. return __op.__second_empty(__begin1, __end1, __result);
  312. const _DifferenceType __size = (__end1 - __begin1) + (__end2 - __begin2);
  313. const _IteratorPair __sequence[2] = { std::make_pair(__begin1, __end1),
  314. std::make_pair(__begin2, __end2) };
  315. _OutputIterator __return_value = __result;
  316. _DifferenceType *__borders;
  317. _IteratorPair *__block_begins;
  318. _DifferenceType* __lengths;
  319. _ThreadIndex __num_threads =
  320. std::min<_DifferenceType>(__get_max_threads(),
  321. std::min(__end1 - __begin1, __end2 - __begin2));
  322. # pragma omp parallel num_threads(__num_threads)
  323. {
  324. # pragma omp single
  325. {
  326. __num_threads = omp_get_num_threads();
  327. __borders = new _DifferenceType[__num_threads + 2];
  328. __equally_split(__size, __num_threads + 1, __borders);
  329. __block_begins = new _IteratorPair[__num_threads + 1];
  330. // Very __start.
  331. __block_begins[0] = std::make_pair(__begin1, __begin2);
  332. __lengths = new _DifferenceType[__num_threads];
  333. } //single
  334. _ThreadIndex __iam = omp_get_thread_num();
  335. // _Result from multiseq_partition.
  336. _IIter __offset[2];
  337. const _DifferenceType __rank = __borders[__iam + 1];
  338. multiseq_partition(__sequence, __sequence + 2,
  339. __rank, __offset, __op._M_comp);
  340. // allowed to read?
  341. // together
  342. // *(__offset[ 0 ] - 1) == *__offset[ 1 ]
  343. if (__offset[ 0 ] != __begin1 && __offset[1] != __end2
  344. && !__op._M_comp(*(__offset[0] - 1), *__offset[1])
  345. && !__op._M_comp(*__offset[1], *(__offset[0] - 1)))
  346. {
  347. // Avoid split between globally equal elements: move one to
  348. // front in first sequence.
  349. --__offset[0];
  350. }
  351. _IteratorPair __block_end = __block_begins[__iam + 1] =
  352. _IteratorPair(__offset[0], __offset[1]);
  353. // Make sure all threads have their block_begin result written out.
  354. # pragma omp barrier
  355. _IteratorPair __block_begin = __block_begins[__iam];
  356. // Begin working for the first block, while the others except
  357. // the last start to count.
  358. if (__iam == 0)
  359. {
  360. // The first thread can copy already.
  361. __lengths[ __iam ] =
  362. __op._M_invoke(__block_begin.first, __block_end.first,
  363. __block_begin.second, __block_end.second,
  364. __result) - __result;
  365. }
  366. else
  367. {
  368. __lengths[ __iam ] =
  369. __op.__count(__block_begin.first, __block_end.first,
  370. __block_begin.second, __block_end.second);
  371. }
  372. // Make sure everyone wrote their lengths.
  373. # pragma omp barrier
  374. _OutputIterator __r = __result;
  375. if (__iam == 0)
  376. {
  377. // Do the last block.
  378. for (_ThreadIndex __i = 0; __i < __num_threads; ++__i)
  379. __r += __lengths[__i];
  380. __block_begin = __block_begins[__num_threads];
  381. // Return the result iterator of the last block.
  382. __return_value =
  383. __op._M_invoke(__block_begin.first, __end1,
  384. __block_begin.second, __end2, __r);
  385. }
  386. else
  387. {
  388. for (_ThreadIndex __i = 0; __i < __iam; ++__i)
  389. __r += __lengths[ __i ];
  390. // Reset begins for copy pass.
  391. __op._M_invoke(__block_begin.first, __block_end.first,
  392. __block_begin.second, __block_end.second, __r);
  393. }
  394. }
  395. return __return_value;
  396. }
  397. template<typename _IIter,
  398. typename _OutputIterator,
  399. typename _Compare>
  400. inline _OutputIterator
  401. __parallel_set_union(_IIter __begin1, _IIter __end1,
  402. _IIter __begin2, _IIter __end2,
  403. _OutputIterator __result, _Compare __comp)
  404. {
  405. return __parallel_set_operation(__begin1, __end1, __begin2, __end2,
  406. __result,
  407. __union_func< _IIter, _OutputIterator,
  408. _Compare>(__comp));
  409. }
  410. template<typename _IIter,
  411. typename _OutputIterator,
  412. typename _Compare>
  413. inline _OutputIterator
  414. __parallel_set_intersection(_IIter __begin1, _IIter __end1,
  415. _IIter __begin2, _IIter __end2,
  416. _OutputIterator __result, _Compare __comp)
  417. {
  418. return __parallel_set_operation(__begin1, __end1, __begin2, __end2,
  419. __result,
  420. __intersection_func<_IIter,
  421. _OutputIterator, _Compare>(__comp));
  422. }
  423. template<typename _IIter,
  424. typename _OutputIterator,
  425. typename _Compare>
  426. inline _OutputIterator
  427. __parallel_set_difference(_IIter __begin1, _IIter __end1,
  428. _IIter __begin2, _IIter __end2,
  429. _OutputIterator __result, _Compare __comp)
  430. {
  431. return __parallel_set_operation(__begin1, __end1, __begin2, __end2,
  432. __result,
  433. __difference_func<_IIter,
  434. _OutputIterator, _Compare>(__comp));
  435. }
  436. template<typename _IIter,
  437. typename _OutputIterator,
  438. typename _Compare>
  439. inline _OutputIterator
  440. __parallel_set_symmetric_difference(_IIter __begin1, _IIter __end1,
  441. _IIter __begin2, _IIter __end2,
  442. _OutputIterator __result,
  443. _Compare __comp)
  444. {
  445. return __parallel_set_operation(__begin1, __end1, __begin2, __end2,
  446. __result,
  447. __symmetric_difference_func<_IIter,
  448. _OutputIterator, _Compare>(__comp));
  449. }
  450. }
  451. #endif /* _GLIBCXX_PARALLEL_SET_OPERATIONS_H */