cmAlgorithms.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #ifndef cmAlgorithms_h
  4. #define cmAlgorithms_h
  5. #include "cmConfigure.h" // IWYU pragma: keep
  6. #include "cmRange.h"
  7. #include "cm_kwiml.h"
  8. #include <algorithm>
  9. #include <functional>
  10. #include <iterator>
  11. #include <unordered_set>
  12. #include <utility>
  13. #include <vector>
  14. template <std::size_t N>
  15. struct cmOverloadPriority : cmOverloadPriority<N - 1>
  16. {
  17. };
  18. template <>
  19. struct cmOverloadPriority<0>
  20. {
  21. };
  22. template <typename FwdIt>
  23. FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last)
  24. {
  25. const typename std::iterator_traits<FwdIt>::difference_type dist =
  26. std::distance(middle, last);
  27. std::rotate(first, middle, last);
  28. std::advance(first, dist);
  29. return first;
  30. }
  31. template <typename Container, typename Predicate>
  32. void cmEraseIf(Container& cont, Predicate pred)
  33. {
  34. cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
  35. }
  36. template <typename Range, typename Key>
  37. auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<2>)
  38. -> decltype(range.exists(key))
  39. {
  40. return range.exists(key);
  41. }
  42. template <typename Range, typename Key>
  43. auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<1>)
  44. -> decltype(range.find(key) != range.end())
  45. {
  46. return range.find(key) != range.end();
  47. }
  48. template <typename Range, typename Key>
  49. bool cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<0>)
  50. {
  51. using std::begin;
  52. using std::end;
  53. return std::find(begin(range), end(range), key) != end(range);
  54. }
  55. template <typename Range, typename Key>
  56. bool cmContains(Range const& range, Key const& key)
  57. {
  58. return cmContainsImpl(range, key, cmOverloadPriority<2>{});
  59. }
  60. namespace ContainerAlgorithms {
  61. template <typename T>
  62. struct cmIsPair
  63. {
  64. enum
  65. {
  66. value = false
  67. };
  68. };
  69. template <typename K, typename V>
  70. struct cmIsPair<std::pair<K, V>>
  71. {
  72. enum
  73. {
  74. value = true
  75. };
  76. };
  77. template <typename Range,
  78. bool valueTypeIsPair = cmIsPair<typename Range::value_type>::value>
  79. struct DefaultDeleter
  80. {
  81. void operator()(typename Range::value_type value) const { delete value; }
  82. };
  83. template <typename Range>
  84. struct DefaultDeleter<Range, /* valueTypeIsPair = */ true>
  85. {
  86. void operator()(typename Range::value_type value) const
  87. {
  88. delete value.second;
  89. }
  90. };
  91. template <typename FwdIt>
  92. FwdIt RemoveN(FwdIt i1, FwdIt i2, size_t n)
  93. {
  94. FwdIt m = i1;
  95. std::advance(m, n);
  96. return cmRotate(i1, m, i2);
  97. }
  98. template <typename Range>
  99. struct BinarySearcher
  100. {
  101. using argument_type = typename Range::value_type;
  102. BinarySearcher(Range const& r)
  103. : m_range(r)
  104. {
  105. }
  106. bool operator()(argument_type const& item) const
  107. {
  108. return std::binary_search(m_range.begin(), m_range.end(), item);
  109. }
  110. private:
  111. Range const& m_range;
  112. };
  113. }
  114. class cmListFileBacktrace;
  115. using cmBacktraceRange =
  116. cmRange<std::vector<cmListFileBacktrace>::const_iterator>;
  117. template <typename Range>
  118. void cmDeleteAll(Range const& r)
  119. {
  120. std::for_each(r.begin(), r.end(),
  121. ContainerAlgorithms::DefaultDeleter<Range>());
  122. }
  123. template <typename T, typename Range>
  124. void cmAppend(std::vector<T>& v, Range const& r)
  125. {
  126. v.insert(v.end(), r.begin(), r.end());
  127. }
  128. template <typename T, typename InputIt>
  129. void cmAppend(std::vector<T>& v, InputIt first, InputIt last)
  130. {
  131. v.insert(v.end(), first, last);
  132. }
  133. template <typename Range>
  134. typename Range::const_iterator cmRemoveN(Range& r, size_t n)
  135. {
  136. return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n);
  137. }
  138. template <typename Range, typename InputRange>
  139. typename Range::const_iterator cmRemoveIndices(Range& r, InputRange const& rem)
  140. {
  141. typename InputRange::const_iterator remIt = rem.begin();
  142. typename InputRange::const_iterator remEnd = rem.end();
  143. const auto rangeEnd = r.end();
  144. if (remIt == remEnd) {
  145. return rangeEnd;
  146. }
  147. auto writer = r.begin();
  148. std::advance(writer, *remIt);
  149. auto pivot = writer;
  150. typename InputRange::value_type prevRem = *remIt;
  151. ++remIt;
  152. size_t count = 1;
  153. for (; writer != rangeEnd && remIt != remEnd; ++count, ++remIt) {
  154. std::advance(pivot, *remIt - prevRem);
  155. prevRem = *remIt;
  156. writer = ContainerAlgorithms::RemoveN(writer, pivot, count);
  157. }
  158. return ContainerAlgorithms::RemoveN(writer, rangeEnd, count);
  159. }
  160. template <typename Range, typename MatchRange>
  161. typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
  162. {
  163. return std::remove_if(r.begin(), r.end(),
  164. ContainerAlgorithms::BinarySearcher<MatchRange>(m));
  165. }
  166. template <typename ForwardIterator>
  167. ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
  168. {
  169. using Value = typename std::iterator_traits<ForwardIterator>::value_type;
  170. using Hash = struct
  171. {
  172. std::size_t operator()(ForwardIterator it) const
  173. {
  174. return std::hash<Value>{}(*it);
  175. }
  176. };
  177. using Equal = struct
  178. {
  179. bool operator()(ForwardIterator it1, ForwardIterator it2) const
  180. {
  181. return *it1 == *it2;
  182. }
  183. };
  184. std::unordered_set<ForwardIterator, Hash, Equal> uniq;
  185. ForwardIterator result = first;
  186. while (first != last) {
  187. if (!cmContains(uniq, first)) {
  188. if (result != first) {
  189. *result = std::move(*first);
  190. }
  191. uniq.insert(result);
  192. ++result;
  193. }
  194. ++first;
  195. }
  196. return result;
  197. }
  198. template <typename Range>
  199. typename Range::const_iterator cmRemoveDuplicates(Range& r)
  200. {
  201. return cmRemoveDuplicates(r.begin(), r.end());
  202. }
  203. template <typename Range, typename T>
  204. typename Range::const_iterator cmFindNot(Range const& r, T const& t)
  205. {
  206. return std::find_if(r.begin(), r.end(), [&t](T const& i) { return i != t; });
  207. }
  208. template <class Iter>
  209. std::reverse_iterator<Iter> cmMakeReverseIterator(Iter it)
  210. {
  211. return std::reverse_iterator<Iter>(it);
  212. }
  213. namespace cm {
  214. #if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
  215. using std::size;
  216. #else
  217. // std::size backport from C++17.
  218. template <class C>
  219. # if !defined(_MSC_VER) || _MSC_VER >= 1900
  220. constexpr
  221. # endif
  222. auto
  223. size(C const& c) -> decltype(c.size())
  224. {
  225. return c.size();
  226. }
  227. template <typename T, size_t N>
  228. # if !defined(_MSC_VER) || _MSC_VER >= 1900
  229. constexpr
  230. # endif
  231. std::size_t
  232. size(const T (&)[N]) throw()
  233. {
  234. return N;
  235. }
  236. #endif
  237. template <typename T>
  238. int isize(const T& t)
  239. {
  240. return static_cast<int>(cm::size(t));
  241. }
  242. #if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
  243. using std::cbegin;
  244. using std::cend;
  245. #else
  246. // std::c{begin,end} backport from C++14
  247. template <class C>
  248. # if defined(_MSC_VER) && _MSC_VER < 1900
  249. auto cbegin(C const& c)
  250. # else
  251. constexpr auto cbegin(C const& c) noexcept(noexcept(std::begin(c)))
  252. # endif
  253. -> decltype(std::begin(c))
  254. {
  255. return std::begin(c);
  256. }
  257. template <class C>
  258. # if defined(_MSC_VER) && _MSC_VER < 1900
  259. auto cend(C const& c)
  260. # else
  261. constexpr auto cend(C const& c) noexcept(noexcept(std::end(c)))
  262. # endif
  263. -> decltype(std::end(c))
  264. {
  265. return std::end(c);
  266. }
  267. #endif
  268. } // namespace cm
  269. #endif