algorithm 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // -*-c++-*-
  2. // vim: set ft=cpp:
  3. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  4. file Copyright.txt or https://cmake.org/licensing for details. */
  5. #ifndef cmext_algorithm
  6. #define cmext_algorithm
  7. #include <algorithm>
  8. #include <iterator>
  9. #include <memory>
  10. #include <utility>
  11. #include <cm/type_traits>
  12. #include <cmext/iterator>
  13. #include <cmext/type_traits>
  14. #if defined(__SUNPRO_CC) && defined(__sparc)
  15. # include <list>
  16. # include <vector>
  17. #endif
  18. namespace cm {
  19. #if defined(__SUNPRO_CC) && defined(__sparc)
  20. // Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
  21. // templates with constraints.
  22. // So, on this platform, use only simple templates.
  23. # define APPEND_TWO(C1, C2) \
  24. template <typename T, typename U> \
  25. void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r) \
  26. { \
  27. std::transform( \
  28. r.begin(), r.end(), std::back_inserter(v), \
  29. [](std::unique_ptr<U>& item) { return std::move(item); }); \
  30. r.clear(); \
  31. } \
  32. \
  33. template <typename T, typename U> \
  34. void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r) \
  35. { \
  36. std::transform( \
  37. r.begin(), r.end(), std::back_inserter(v), \
  38. [](const std::unique_ptr<U>& item) { return item.get(); }); \
  39. }
  40. # define APPEND_ONE(C) \
  41. template <typename T, typename InputIt, \
  42. cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = \
  43. 0> \
  44. void append(C<T>& v, InputIt first, InputIt last) \
  45. { \
  46. v.insert(v.end(), first, last); \
  47. } \
  48. \
  49. template <typename T, typename Range, \
  50. cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0> \
  51. void append(C<T>& v, Range const& r) \
  52. { \
  53. v.insert(v.end(), r.begin(), r.end()); \
  54. }
  55. # define APPEND(C) \
  56. APPEND_TWO(C, C) \
  57. APPEND_ONE(C)
  58. # define APPEND_MIX(C1, C2) \
  59. APPEND_TWO(C1, C2) \
  60. APPEND_TWO(C2, C1)
  61. // For now, manage only support for std::vector and std::list.
  62. // Other sequential container support can be added if needed.
  63. APPEND(std::vector)
  64. APPEND(std::list)
  65. APPEND_MIX(std::vector, std::list)
  66. # undef APPEND
  67. # undef APPEND_MIX
  68. # undef APPEND_TWO
  69. # undef APPEND_ONE
  70. #else
  71. template <
  72. typename Container1, typename Container2,
  73. cm::enable_if_t<
  74. cm::is_sequence_container<Container1>::value &&
  75. cm::is_unique_ptr<typename Container1::value_type>::value &&
  76. cm::is_unique_ptr<typename Container2::value_type>::value &&
  77. std::is_convertible<typename Container2::value_type::pointer,
  78. typename Container1::value_type::pointer>::value,
  79. int> = 0>
  80. void append(Container1& v, Container2&& r)
  81. {
  82. std::transform(
  83. r.begin(), r.end(), std::back_inserter(v),
  84. [](typename Container2::value_type& item) { return std::move(item); });
  85. r.clear();
  86. }
  87. template <typename Container1, typename Container2,
  88. cm::enable_if_t<
  89. cm::is_sequence_container<Container1>::value &&
  90. std::is_pointer<typename Container1::value_type>::value &&
  91. cm::is_unique_ptr<typename Container2::value_type>::value &&
  92. std::is_convertible<typename Container2::value_type::pointer,
  93. typename Container1::value_type>::value,
  94. int> = 0>
  95. # if defined(__SUNPRO_CC)
  96. void append(Container1& v, Container2 const& r, detail::overload_selector<0>)
  97. # else
  98. void append(Container1& v, Container2 const& r)
  99. # endif
  100. {
  101. std::transform(
  102. r.begin(), r.end(), std::back_inserter(v),
  103. [](const typename Container2::value_type& item) { return item.get(); });
  104. }
  105. template <
  106. typename Container, typename InputIt,
  107. cm::enable_if_t<
  108. cm::is_sequence_container<Container>::value &&
  109. cm::is_input_iterator<InputIt>::value &&
  110. std::is_convertible<typename std::iterator_traits<InputIt>::value_type,
  111. typename Container::value_type>::value,
  112. int> = 0>
  113. void append(Container& v, InputIt first, InputIt last)
  114. {
  115. v.insert(v.end(), first, last);
  116. }
  117. template <typename Container, typename Range,
  118. cm::enable_if_t<
  119. cm::is_sequence_container<Container>::value &&
  120. cm::is_input_range<Range>::value &&
  121. !cm::is_unique_ptr<typename Container::value_type>::value &&
  122. !cm::is_unique_ptr<typename Range::value_type>::value &&
  123. std::is_convertible<typename Range::value_type,
  124. typename Container::value_type>::value,
  125. int> = 0>
  126. # if defined(__SUNPRO_CC)
  127. void append(Container& v, Range const& r, detail::overload_selector<1>)
  128. # else
  129. void append(Container& v, Range const& r)
  130. # endif
  131. {
  132. v.insert(v.end(), r.begin(), r.end());
  133. }
  134. # if defined(__SUNPRO_CC)
  135. template <typename T, typename U>
  136. void append(T& v, U const& r)
  137. {
  138. cm::append(v, r, detail::overload_selector<1>{});
  139. }
  140. # endif
  141. #endif
  142. #if defined(__SUNPRO_CC)
  143. template <typename Iterator, typename Key>
  144. auto contains(Iterator first, Iterator last, Key const& key,
  145. detail::overload_selector<1>) -> decltype(first->first == key)
  146. #else
  147. template <typename Iterator, typename Key,
  148. cm::enable_if_t<
  149. cm::is_input_iterator<Iterator>::value &&
  150. std::is_convertible<Key,
  151. typename std::iterator_traits<
  152. Iterator>::value_type::first_type>::value,
  153. int> = 0>
  154. bool contains(Iterator first, Iterator last, Key const& key)
  155. #endif
  156. {
  157. return std::find_if(
  158. first, last,
  159. [&key](
  160. typename std::iterator_traits<Iterator>::value_type const& item) {
  161. return item.first == key;
  162. }) != last;
  163. }
  164. #if defined(__SUNPRO_CC)
  165. template <typename Iterator, typename Key>
  166. bool contains(Iterator first, Iterator last, Key const& key,
  167. detail::overload_selector<0>)
  168. #else
  169. template <
  170. typename Iterator, typename Key,
  171. cm::enable_if_t<
  172. cm::is_input_iterator<Iterator>::value &&
  173. std::is_convertible<
  174. Key, typename std::iterator_traits<Iterator>::value_type>::value,
  175. int> = 0>
  176. bool contains(Iterator first, Iterator last, Key const& key)
  177. #endif
  178. {
  179. return std::find(first, last, key) != last;
  180. }
  181. #if defined(__SUNPRO_CC)
  182. template <typename Iterator, typename Key>
  183. bool contains(Iterator first, Iterator last, Key const& key)
  184. {
  185. return contains(first, last, key, detail::overload_selector<1>{});
  186. }
  187. #endif
  188. #if defined(__SUNPRO_CC)
  189. template <typename Range, typename Key>
  190. auto contains(Range const& range, Key const& key, detail::overload_selector<1>)
  191. -> decltype(range.find(key) != range.end())
  192. #else
  193. template <
  194. typename Range, typename Key,
  195. cm::enable_if_t<cm::is_associative_container<Range>::value ||
  196. cm::is_unordered_associative_container<Range>::value,
  197. int> = 0>
  198. bool contains(Range const& range, Key const& key)
  199. #endif
  200. {
  201. return range.find(key) != range.end();
  202. }
  203. #if defined(__SUNPRO_CC)
  204. template <typename Range, typename Key>
  205. bool contains(Range const& range, Key const& key, detail::overload_selector<0>)
  206. #else
  207. template <
  208. typename Range, typename Key,
  209. cm::enable_if_t<cm::is_input_range<Range>::value &&
  210. !(cm::is_associative_container<Range>::value ||
  211. cm::is_unordered_associative_container<Range>::value),
  212. int> = 0>
  213. bool contains(Range const& range, Key const& key)
  214. #endif
  215. {
  216. return std::find(std::begin(range), std::end(range), key) != std::end(range);
  217. }
  218. #if defined(__SUNPRO_CC)
  219. template <typename Range, typename Key>
  220. bool contains(Range const& range, Key const& key)
  221. {
  222. return contains(range, key, detail::overload_selector<1>{});
  223. }
  224. #endif
  225. } // namespace cm
  226. #endif