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.

252 lines
9.4KB

  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. /** @file parallel/merge.h
  21. * @brief Parallel implementation of std::merge().
  22. * This file is a GNU parallel extension to the Standard C++ Library.
  23. */
  24. // Written by Johannes Singler.
  25. #ifndef _GLIBCXX_PARALLEL_MERGE_H
  26. #define _GLIBCXX_PARALLEL_MERGE_H 1
  27. #include <parallel/basic_iterator.h>
  28. #include <bits/stl_algo.h>
  29. namespace __gnu_parallel
  30. {
  31. /** @brief Merge routine being able to merge only the @c __max_length
  32. * smallest elements.
  33. *
  34. * The @c __begin iterators are advanced accordingly, they might not
  35. * reach @c __end, in contrast to the usual variant.
  36. * @param __begin1 Begin iterator of first sequence.
  37. * @param __end1 End iterator of first sequence.
  38. * @param __begin2 Begin iterator of second sequence.
  39. * @param __end2 End iterator of second sequence.
  40. * @param __target Target begin iterator.
  41. * @param __max_length Maximum number of elements to merge.
  42. * @param __comp Comparator.
  43. * @return Output end iterator. */
  44. template<typename _RAIter1, typename _RAIter2,
  45. typename _OutputIterator, typename _DifferenceTp,
  46. typename _Compare>
  47. _OutputIterator
  48. __merge_advance_usual(_RAIter1& __begin1, _RAIter1 __end1,
  49. _RAIter2& __begin2, _RAIter2 __end2,
  50. _OutputIterator __target,
  51. _DifferenceTp __max_length, _Compare __comp)
  52. {
  53. typedef _DifferenceTp _DifferenceType;
  54. while (__begin1 != __end1 && __begin2 != __end2 && __max_length > 0)
  55. {
  56. // array1[__i1] < array0[i0]
  57. if (__comp(*__begin2, *__begin1))
  58. *__target++ = *__begin2++;
  59. else
  60. *__target++ = *__begin1++;
  61. --__max_length;
  62. }
  63. if (__begin1 != __end1)
  64. {
  65. __target = std::copy(__begin1, __begin1 + __max_length, __target);
  66. __begin1 += __max_length;
  67. }
  68. else
  69. {
  70. __target = std::copy(__begin2, __begin2 + __max_length, __target);
  71. __begin2 += __max_length;
  72. }
  73. return __target;
  74. }
  75. /** @brief Merge routine being able to merge only the @c __max_length
  76. * smallest elements.
  77. *
  78. * The @c __begin iterators are advanced accordingly, they might not
  79. * reach @c __end, in contrast to the usual variant.
  80. * Specially designed code should allow the compiler to generate
  81. * conditional moves instead of branches.
  82. * @param __begin1 Begin iterator of first sequence.
  83. * @param __end1 End iterator of first sequence.
  84. * @param __begin2 Begin iterator of second sequence.
  85. * @param __end2 End iterator of second sequence.
  86. * @param __target Target begin iterator.
  87. * @param __max_length Maximum number of elements to merge.
  88. * @param __comp Comparator.
  89. * @return Output end iterator. */
  90. template<typename _RAIter1, typename _RAIter2,
  91. typename _OutputIterator, typename _DifferenceTp,
  92. typename _Compare>
  93. _OutputIterator
  94. __merge_advance_movc(_RAIter1& __begin1, _RAIter1 __end1,
  95. _RAIter2& __begin2, _RAIter2 __end2,
  96. _OutputIterator __target,
  97. _DifferenceTp __max_length, _Compare __comp)
  98. {
  99. typedef _DifferenceTp _DifferenceType;
  100. typedef typename std::iterator_traits<_RAIter1>::value_type
  101. _ValueType1;
  102. typedef typename std::iterator_traits<_RAIter2>::value_type
  103. _ValueType2;
  104. #if _GLIBCXX_PARALLEL_ASSERTIONS
  105. _GLIBCXX_PARALLEL_ASSERT(__max_length >= 0);
  106. #endif
  107. while (__begin1 != __end1 && __begin2 != __end2 && __max_length > 0)
  108. {
  109. _RAIter1 __next1 = __begin1 + 1;
  110. _RAIter2 __next2 = __begin2 + 1;
  111. _ValueType1 __element1 = *__begin1;
  112. _ValueType2 __element2 = *__begin2;
  113. if (__comp(__element2, __element1))
  114. {
  115. __element1 = __element2;
  116. __begin2 = __next2;
  117. }
  118. else
  119. __begin1 = __next1;
  120. *__target = __element1;
  121. ++__target;
  122. --__max_length;
  123. }
  124. if (__begin1 != __end1)
  125. {
  126. __target = std::copy(__begin1, __begin1 + __max_length, __target);
  127. __begin1 += __max_length;
  128. }
  129. else
  130. {
  131. __target = std::copy(__begin2, __begin2 + __max_length, __target);
  132. __begin2 += __max_length;
  133. }
  134. return __target;
  135. }
  136. /** @brief Merge routine being able to merge only the @c __max_length
  137. * smallest elements.
  138. *
  139. * The @c __begin iterators are advanced accordingly, they might not
  140. * reach @c __end, in contrast to the usual variant.
  141. * Static switch on whether to use the conditional-move variant.
  142. * @param __begin1 Begin iterator of first sequence.
  143. * @param __end1 End iterator of first sequence.
  144. * @param __begin2 Begin iterator of second sequence.
  145. * @param __end2 End iterator of second sequence.
  146. * @param __target Target begin iterator.
  147. * @param __max_length Maximum number of elements to merge.
  148. * @param __comp Comparator.
  149. * @return Output end iterator. */
  150. template<typename _RAIter1, typename _RAIter2,
  151. typename _OutputIterator, typename _DifferenceTp,
  152. typename _Compare>
  153. inline _OutputIterator
  154. __merge_advance(_RAIter1& __begin1, _RAIter1 __end1,
  155. _RAIter2& __begin2, _RAIter2 __end2,
  156. _OutputIterator __target, _DifferenceTp __max_length,
  157. _Compare __comp)
  158. {
  159. _GLIBCXX_CALL(__max_length)
  160. return __merge_advance_movc(__begin1, __end1, __begin2, __end2,
  161. __target, __max_length, __comp);
  162. }
  163. /** @brief Merge routine fallback to sequential in case the
  164. iterators of the two input sequences are of different type.
  165. * @param __begin1 Begin iterator of first sequence.
  166. * @param __end1 End iterator of first sequence.
  167. * @param __begin2 Begin iterator of second sequence.
  168. * @param __end2 End iterator of second sequence.
  169. * @param __target Target begin iterator.
  170. * @param __max_length Maximum number of elements to merge.
  171. * @param __comp Comparator.
  172. * @return Output end iterator. */
  173. template<typename _RAIter1, typename _RAIter2,
  174. typename _RAIter3, typename _Compare>
  175. inline _RAIter3
  176. __parallel_merge_advance(_RAIter1& __begin1, _RAIter1 __end1,
  177. _RAIter2& __begin2,
  178. // different iterators, parallel implementation
  179. // not available
  180. _RAIter2 __end2, _RAIter3 __target, typename
  181. std::iterator_traits<_RAIter1>::
  182. difference_type __max_length, _Compare __comp)
  183. { return __merge_advance(__begin1, __end1, __begin2, __end2, __target,
  184. __max_length, __comp); }
  185. /** @brief Parallel merge routine being able to merge only the @c
  186. * __max_length smallest elements.
  187. *
  188. * The @c __begin iterators are advanced accordingly, they might not
  189. * reach @c __end, in contrast to the usual variant.
  190. * The functionality is projected onto parallel_multiway_merge.
  191. * @param __begin1 Begin iterator of first sequence.
  192. * @param __end1 End iterator of first sequence.
  193. * @param __begin2 Begin iterator of second sequence.
  194. * @param __end2 End iterator of second sequence.
  195. * @param __target Target begin iterator.
  196. * @param __max_length Maximum number of elements to merge.
  197. * @param __comp Comparator.
  198. * @return Output end iterator.
  199. */
  200. template<typename _RAIter1, typename _RAIter3,
  201. typename _Compare>
  202. inline _RAIter3
  203. __parallel_merge_advance(_RAIter1& __begin1, _RAIter1 __end1,
  204. _RAIter1& __begin2, _RAIter1 __end2,
  205. _RAIter3 __target, typename
  206. std::iterator_traits<_RAIter1>::
  207. difference_type __max_length, _Compare __comp)
  208. {
  209. typedef typename
  210. std::iterator_traits<_RAIter1>::value_type _ValueType;
  211. typedef typename std::iterator_traits<_RAIter1>::
  212. difference_type _DifferenceType1 /* == difference_type2 */;
  213. typedef typename std::iterator_traits<_RAIter3>::
  214. difference_type _DifferenceType3;
  215. typedef typename std::pair<_RAIter1, _RAIter1>
  216. _IteratorPair;
  217. _IteratorPair __seqs[2] = { std::make_pair(__begin1, __end1),
  218. std::make_pair(__begin2, __end2) };
  219. _RAIter3 __target_end = parallel_multiway_merge
  220. < /* __stable = */ true, /* __sentinels = */ false>
  221. (__seqs, __seqs + 2, __target, multiway_merge_exact_splitting
  222. < /* __stable = */ true, _IteratorPair*,
  223. _Compare, _DifferenceType1>, __max_length, __comp,
  224. omp_get_max_threads());
  225. return __target_end;
  226. }
  227. } //namespace __gnu_parallel
  228. #endif /* _GLIBCXX_PARALLEL_MERGE_H */