cmAlgorithms.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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 <algorithm>
  7. #include <functional>
  8. #include <iterator>
  9. #include <memory>
  10. #include <unordered_set>
  11. #include <utility>
  12. #include <vector>
  13. #include "cm_kwiml.h"
  14. #include "cmRange.h"
  15. template <std::size_t N>
  16. struct cmOverloadPriority : cmOverloadPriority<N - 1>
  17. {
  18. };
  19. template <>
  20. struct cmOverloadPriority<0>
  21. {
  22. };
  23. template <typename FwdIt>
  24. FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last)
  25. {
  26. const typename std::iterator_traits<FwdIt>::difference_type dist =
  27. std::distance(middle, last);
  28. std::rotate(first, middle, last);
  29. std::advance(first, dist);
  30. return first;
  31. }
  32. template <typename Range, typename Key>
  33. auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<2>)
  34. -> decltype(range.exists(key))
  35. {
  36. return range.exists(key);
  37. }
  38. template <typename Range, typename Key>
  39. auto cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<1>)
  40. -> decltype(range.find(key) != range.end())
  41. {
  42. return range.find(key) != range.end();
  43. }
  44. template <typename Range, typename Key>
  45. bool cmContainsImpl(Range const& range, Key const& key, cmOverloadPriority<0>)
  46. {
  47. using std::begin;
  48. using std::end;
  49. return std::find(begin(range), end(range), key) != end(range);
  50. }
  51. template <typename Range, typename Key>
  52. bool cmContains(Range const& range, Key const& key)
  53. {
  54. return cmContainsImpl(range, key, cmOverloadPriority<2>{});
  55. }
  56. namespace ContainerAlgorithms {
  57. template <typename FwdIt>
  58. FwdIt RemoveN(FwdIt i1, FwdIt i2, size_t n)
  59. {
  60. FwdIt m = i1;
  61. std::advance(m, n);
  62. return cmRotate(i1, m, i2);
  63. }
  64. template <typename Range>
  65. struct BinarySearcher
  66. {
  67. using argument_type = typename Range::value_type;
  68. BinarySearcher(Range const& r)
  69. : m_range(r)
  70. {
  71. }
  72. bool operator()(argument_type const& item) const
  73. {
  74. return std::binary_search(m_range.begin(), m_range.end(), item);
  75. }
  76. private:
  77. Range const& m_range;
  78. };
  79. }
  80. class cmListFileBacktrace;
  81. using cmBacktraceRange =
  82. cmRange<std::vector<cmListFileBacktrace>::const_iterator>;
  83. template <typename Range>
  84. typename Range::const_iterator cmRemoveN(Range& r, size_t n)
  85. {
  86. return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n);
  87. }
  88. template <typename Range, typename InputRange>
  89. typename Range::const_iterator cmRemoveIndices(Range& r, InputRange const& rem)
  90. {
  91. typename InputRange::const_iterator remIt = rem.begin();
  92. typename InputRange::const_iterator remEnd = rem.end();
  93. const auto rangeEnd = r.end();
  94. if (remIt == remEnd) {
  95. return rangeEnd;
  96. }
  97. auto writer = r.begin();
  98. std::advance(writer, *remIt);
  99. auto pivot = writer;
  100. typename InputRange::value_type prevRem = *remIt;
  101. ++remIt;
  102. size_t count = 1;
  103. for (; writer != rangeEnd && remIt != remEnd; ++count, ++remIt) {
  104. std::advance(pivot, *remIt - prevRem);
  105. prevRem = *remIt;
  106. writer = ContainerAlgorithms::RemoveN(writer, pivot, count);
  107. }
  108. return ContainerAlgorithms::RemoveN(writer, rangeEnd, count);
  109. }
  110. template <typename Range, typename MatchRange>
  111. typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
  112. {
  113. return std::remove_if(r.begin(), r.end(),
  114. ContainerAlgorithms::BinarySearcher<MatchRange>(m));
  115. }
  116. template <typename ForwardIterator>
  117. ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
  118. {
  119. using Value = typename std::iterator_traits<ForwardIterator>::value_type;
  120. using Hash = struct
  121. {
  122. std::size_t operator()(ForwardIterator it) const
  123. {
  124. return std::hash<Value>{}(*it);
  125. }
  126. };
  127. using Equal = struct
  128. {
  129. bool operator()(ForwardIterator it1, ForwardIterator it2) const
  130. {
  131. return *it1 == *it2;
  132. }
  133. };
  134. std::unordered_set<ForwardIterator, Hash, Equal> uniq;
  135. ForwardIterator result = first;
  136. while (first != last) {
  137. if (!cmContains(uniq, first)) {
  138. if (result != first) {
  139. *result = std::move(*first);
  140. }
  141. uniq.insert(result);
  142. ++result;
  143. }
  144. ++first;
  145. }
  146. return result;
  147. }
  148. template <typename Range>
  149. typename Range::const_iterator cmRemoveDuplicates(Range& r)
  150. {
  151. return cmRemoveDuplicates(r.begin(), r.end());
  152. }
  153. template <typename Range, typename T>
  154. typename Range::const_iterator cmFindNot(Range const& r, T const& t)
  155. {
  156. return std::find_if(r.begin(), r.end(), [&t](T const& i) { return i != t; });
  157. }
  158. #endif