algorithm 9.0 KB

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