/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #ifndef cmAlgorithms_h #define cmAlgorithms_h #include "cmConfigure.h" // IWYU pragma: keep #include "cm_kwiml.h" #include #include #include #include #include #include #include #include #include inline bool cmHasLiteralPrefixImpl(const std::string& str1, const char* str2, size_t N) { return strncmp(str1.c_str(), str2, N) == 0; } inline bool cmHasLiteralPrefixImpl(const char* str1, const char* str2, size_t N) { return strncmp(str1, str2, N) == 0; } inline bool cmHasLiteralSuffixImpl(const std::string& str1, const char* str2, size_t N) { size_t len = str1.size(); return len >= N && strcmp(str1.c_str() + len - N, str2) == 0; } inline bool cmHasLiteralSuffixImpl(const char* str1, const char* str2, size_t N) { size_t len = strlen(str1); return len >= N && strcmp(str1 + len - N, str2) == 0; } template bool cmHasLiteralPrefix(const T& str1, const char (&str2)[N]) { return cmHasLiteralPrefixImpl(str1, str2, N - 1); } template bool cmHasLiteralSuffix(const T& str1, const char (&str2)[N]) { return cmHasLiteralSuffixImpl(str1, str2, N - 1); } struct cmStrCmp { cmStrCmp(const char* test) : m_test(test) { } cmStrCmp(const std::string& test) : m_test(test) { } bool operator()(const std::string& input) const { return m_test == input; } bool operator()(const char* input) const { return strcmp(input, m_test.c_str()) == 0; } private: const std::string m_test; }; template FwdIt cmRotate(FwdIt first, FwdIt middle, FwdIt last) { const typename std::iterator_traits::difference_type dist = std::distance(middle, last); std::rotate(first, middle, last); std::advance(first, dist); return first; } template void cmEraseIf(Container& cont, Predicate pred) { cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end()); } namespace ContainerAlgorithms { template struct cmIsPair { enum { value = false }; }; template struct cmIsPair> { enum { value = true }; }; template ::value> struct DefaultDeleter { void operator()(typename Range::value_type value) const { delete value; } }; template struct DefaultDeleter { void operator()(typename Range::value_type value) const { delete value.second; } }; template FwdIt RemoveN(FwdIt i1, FwdIt i2, size_t n) { FwdIt m = i1; std::advance(m, n); return cmRotate(i1, m, i2); } template struct BinarySearcher { typedef typename Range::value_type argument_type; BinarySearcher(Range const& r) : m_range(r) { } bool operator()(argument_type const& item) const { return std::binary_search(m_range.begin(), m_range.end(), item); } private: Range const& m_range; }; } template struct cmRange { typedef const_iterator_ const_iterator; typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::difference_type difference_type; cmRange(const_iterator begin_, const_iterator end_) : Begin(begin_) , End(end_) { } const_iterator begin() const { return Begin; } const_iterator end() const { return End; } bool empty() const { return std::distance(Begin, End) == 0; } difference_type size() const { return std::distance(Begin, End); } cmRange& advance(KWIML_INT_intptr_t amount) { std::advance(Begin, amount); return *this; } cmRange& retreat(KWIML_INT_intptr_t amount) { std::advance(End, -amount); return *this; } private: const_iterator Begin; const_iterator End; }; typedef cmRange::const_iterator> cmStringRange; class cmListFileBacktrace; typedef cmRange::const_iterator> cmBacktraceRange; template cmRange cmMakeRange(Iter1 begin, Iter2 end) { return cmRange(begin, end); } template cmRange cmMakeRange(Range const& range) { return cmRange(range.begin(), range.end()); } template void cmDeleteAll(Range const& r) { std::for_each(r.begin(), r.end(), ContainerAlgorithms::DefaultDeleter()); } template std::string cmJoin(Range const& r, const char* delimiter) { if (r.empty()) { return std::string(); } std::ostringstream os; typedef typename Range::value_type ValueType; typedef typename Range::const_iterator InputIt; const InputIt first = r.begin(); InputIt last = r.end(); --last; std::copy(first, last, std::ostream_iterator(os, delimiter)); os << *last; return os.str(); } template std::string cmJoin(Range const& r, std::string const& delimiter) { return cmJoin(r, delimiter.c_str()); } template typename Range::const_iterator cmRemoveN(Range& r, size_t n) { return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n); } template typename Range::const_iterator cmRemoveIndices(Range& r, InputRange const& rem) { typename InputRange::const_iterator remIt = rem.begin(); typename InputRange::const_iterator remEnd = rem.end(); const typename Range::iterator rangeEnd = r.end(); if (remIt == remEnd) { return rangeEnd; } typename Range::iterator writer = r.begin(); std::advance(writer, *remIt); typename Range::iterator pivot = writer; typename InputRange::value_type prevRem = *remIt; ++remIt; size_t count = 1; for (; writer != rangeEnd && remIt != remEnd; ++count, ++remIt) { std::advance(pivot, *remIt - prevRem); prevRem = *remIt; writer = ContainerAlgorithms::RemoveN(writer, pivot, count); } return ContainerAlgorithms::RemoveN(writer, rangeEnd, count); } template typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m) { return std::remove_if(r.begin(), r.end(), ContainerAlgorithms::BinarySearcher(m)); } namespace ContainerAlgorithms { template struct RemoveDuplicatesAPI { typedef typename Range::const_iterator const_iterator; typedef typename Range::const_iterator value_type; static bool lessThan(value_type a, value_type b) { return *a < *b; } static value_type uniqueValue(const_iterator a) { return a; } template static bool valueCompare(It it, const_iterator it2) { return **it != *it2; } }; template struct RemoveDuplicatesAPI { typedef typename Range::const_iterator const_iterator; typedef T* value_type; static bool lessThan(value_type a, value_type b) { return a < b; } static value_type uniqueValue(const_iterator a) { return *a; } template static bool valueCompare(It it, const_iterator it2) { return *it != *it2; } }; } template typename Range::const_iterator cmRemoveDuplicates(Range& r) { typedef ContainerAlgorithms::RemoveDuplicatesAPI API; typedef typename API::value_type T; std::vector unique; unique.reserve(r.size()); std::vector indices; size_t count = 0; const typename Range::const_iterator end = r.end(); for (typename Range::const_iterator it = r.begin(); it != end; ++it, ++count) { const typename std::vector::iterator low = std::lower_bound( unique.begin(), unique.end(), API::uniqueValue(it), API::lessThan); if (low == unique.end() || API::valueCompare(low, it)) { unique.insert(low, API::uniqueValue(it)); } else { indices.push_back(count); } } if (indices.empty()) { return end; } return cmRemoveIndices(r, indices); } template std::string cmWrap(std::string const& prefix, Range const& r, std::string const& suffix, std::string const& sep) { if (r.empty()) { return std::string(); } return prefix + cmJoin(r, suffix + sep + prefix) + suffix; } template std::string cmWrap(char prefix, Range const& r, char suffix, std::string const& sep) { return cmWrap(std::string(1, prefix), r, std::string(1, suffix), sep); } template typename Range::const_iterator cmFindNot(Range const& r, T const& t) { return std::find_if(r.begin(), r.end(), [&t](T const& i) { return i != t; }); } template cmRange cmReverseRange( Range const& range) { return cmRange(range.rbegin(), range.rend()); } template std::reverse_iterator cmMakeReverseIterator(Iter it) { return std::reverse_iterator(it); } inline bool cmHasSuffix(const std::string& str, const std::string& suffix) { if (str.size() < suffix.size()) { return false; } return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } inline void cmStripSuffixIfExists(std::string& str, const std::string& suffix) { if (cmHasSuffix(str, suffix)) { str.resize(str.size() - suffix.size()); } } namespace cm { #if defined(CMake_HAVE_CXX_MAKE_UNIQUE) using std::make_unique; #else template std::unique_ptr make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } #endif #if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L using std::size; #else // std::size backport from C++17. template #if !defined(_MSC_VER) || _MSC_VER >= 1900 constexpr #endif auto size(C const& c) -> decltype(c.size()) { return c.size(); } template #if !defined(_MSC_VER) || _MSC_VER >= 1900 constexpr #endif std::size_t size(const T (&)[N]) throw() { return N; } #endif #if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L using std::cbegin; using std::cend; #else // std::c{begin,end} backport from C++14 template #if defined(_MSC_VER) && _MSC_VER < 1900 auto cbegin(C const& c) #else constexpr auto cbegin(C const& c) noexcept(noexcept(std::begin(c))) #endif -> decltype(std::begin(c)) { return std::begin(c); } template #if defined(_MSC_VER) && _MSC_VER < 1900 auto cend(C const& c) #else constexpr auto cend(C const& c) noexcept(noexcept(std::end(c))) #endif -> decltype(std::end(c)) { return std::end(c); } #endif } // namespace cm #endif