algorithm 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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 <string>
  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, std::list, and
  62. // std::basic_string. Other sequential container support can be added if
  63. // needed.
  64. APPEND(std::vector)
  65. APPEND(std::list)
  66. APPEND(std::basic_string)
  67. APPEND_MIX(std::vector, std::list)
  68. APPEND_MIX(std::vector, std::basic_string)
  69. APPEND_MIX(std::list, std::basic_string)
  70. # undef APPEND
  71. # undef APPEND_MIX
  72. # undef APPEND_TWO
  73. # undef APPEND_ONE
  74. #else
  75. template <
  76. typename Container1, typename Container2,
  77. cm::enable_if_t<
  78. cm::is_sequence_container<Container1>::value &&
  79. cm::is_unique_ptr<typename Container1::value_type>::value &&
  80. cm::is_unique_ptr<typename Container2::value_type>::value &&
  81. std::is_convertible<typename Container2::value_type::pointer,
  82. typename Container1::value_type::pointer>::value,
  83. int> = 0>
  84. void append(Container1& v, Container2&& r)
  85. {
  86. std::transform(
  87. r.begin(), r.end(), std::back_inserter(v),
  88. [](typename Container2::value_type& item) { return std::move(item); });
  89. r.clear();
  90. }
  91. template <typename Container1, typename Container2,
  92. cm::enable_if_t<
  93. cm::is_sequence_container<Container1>::value &&
  94. std::is_pointer<typename Container1::value_type>::value &&
  95. cm::is_unique_ptr<typename Container2::value_type>::value &&
  96. std::is_convertible<typename Container2::value_type::pointer,
  97. typename Container1::value_type>::value,
  98. int> = 0>
  99. # if defined(__SUNPRO_CC)
  100. void append(Container1& v, Container2 const& r, detail::overload_selector<0>)
  101. # else
  102. void append(Container1& v, Container2 const& r)
  103. # endif
  104. {
  105. std::transform(
  106. r.begin(), r.end(), std::back_inserter(v),
  107. [](const typename Container2::value_type& item) { return item.get(); });
  108. }
  109. template <
  110. typename Container, typename InputIt,
  111. cm::enable_if_t<
  112. cm::is_sequence_container<Container>::value &&
  113. cm::is_input_iterator<InputIt>::value &&
  114. std::is_convertible<typename std::iterator_traits<InputIt>::value_type,
  115. typename Container::value_type>::value,
  116. int> = 0>
  117. void append(Container& v, InputIt first, InputIt last)
  118. {
  119. v.insert(v.end(), first, last);
  120. }
  121. template <typename Container, typename Range,
  122. cm::enable_if_t<
  123. cm::is_sequence_container<Container>::value &&
  124. cm::is_input_range<Range>::value &&
  125. !cm::is_unique_ptr<typename Container::value_type>::value &&
  126. !cm::is_unique_ptr<typename Range::value_type>::value &&
  127. std::is_convertible<typename Range::value_type,
  128. typename Container::value_type>::value,
  129. int> = 0>
  130. # if defined(__SUNPRO_CC)
  131. void append(Container& v, Range const& r, detail::overload_selector<1>)
  132. # else
  133. void append(Container& v, Range const& r)
  134. # endif
  135. {
  136. v.insert(v.end(), r.begin(), r.end());
  137. }
  138. # if defined(__SUNPRO_CC)
  139. template <typename T, typename U>
  140. void append(T& v, U const& r)
  141. {
  142. cm::append(v, r, detail::overload_selector<1>{});
  143. }
  144. # endif
  145. #endif
  146. #if defined(__SUNPRO_CC)
  147. template <typename Iterator, typename Key>
  148. auto contains(Iterator first, Iterator last, Key const& key,
  149. detail::overload_selector<1>) -> decltype(first->first == key)
  150. #else
  151. template <typename Iterator, typename Key,
  152. cm::enable_if_t<
  153. cm::is_input_iterator<Iterator>::value &&
  154. std::is_convertible<Key,
  155. typename std::iterator_traits<
  156. Iterator>::value_type::first_type>::value,
  157. int> = 0>
  158. bool contains(Iterator first, Iterator last, Key const& key)
  159. #endif
  160. {
  161. return std::find_if(
  162. first, last,
  163. [&key](
  164. typename std::iterator_traits<Iterator>::value_type const& item) {
  165. return item.first == key;
  166. }) != last;
  167. }
  168. #if defined(__SUNPRO_CC)
  169. template <typename Iterator, typename Key>
  170. bool contains(Iterator first, Iterator last, Key const& key,
  171. detail::overload_selector<0>)
  172. #else
  173. template <
  174. typename Iterator, typename Key,
  175. cm::enable_if_t<
  176. cm::is_input_iterator<Iterator>::value &&
  177. std::is_convertible<
  178. Key, typename std::iterator_traits<Iterator>::value_type>::value,
  179. int> = 0>
  180. bool contains(Iterator first, Iterator last, Key const& key)
  181. #endif
  182. {
  183. return std::find(first, last, key) != last;
  184. }
  185. #if defined(__SUNPRO_CC)
  186. template <typename Iterator, typename Key>
  187. bool contains(Iterator first, Iterator last, Key const& key)
  188. {
  189. return contains(first, last, key, detail::overload_selector<1>{});
  190. }
  191. #endif
  192. #if defined(__SUNPRO_CC)
  193. template <typename Range, typename Key>
  194. auto contains(Range const& range, Key const& key,
  195. detail::overload_selector<1>) -> decltype(range.find(key) !=
  196. range.end())
  197. #else
  198. template <
  199. typename Range, typename Key,
  200. cm::enable_if_t<cm::is_associative_container<Range>::value ||
  201. cm::is_unordered_associative_container<Range>::value,
  202. int> = 0>
  203. bool contains(Range const& range, Key const& key)
  204. #endif
  205. {
  206. return range.find(key) != range.end();
  207. }
  208. #if defined(__SUNPRO_CC)
  209. template <typename Range, typename Key>
  210. bool contains(Range const& range, Key const& key, detail::overload_selector<0>)
  211. #else
  212. template <
  213. typename Range, typename Key,
  214. cm::enable_if_t<cm::is_input_range<Range>::value &&
  215. !(cm::is_associative_container<Range>::value ||
  216. cm::is_unordered_associative_container<Range>::value),
  217. int> = 0>
  218. bool contains(Range const& range, Key const& key)
  219. #endif
  220. {
  221. return std::find(std::begin(range), std::end(range), key) != std::end(range);
  222. }
  223. #if defined(__SUNPRO_CC)
  224. template <typename Range, typename Key>
  225. bool contains(Range const& range, Key const& key)
  226. {
  227. return contains(range, key, detail::overload_selector<1>{});
  228. }
  229. #endif
  230. } // namespace cm