mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-16 22:37:30 +08:00
cmAlgorithms: Refactor cmRemoveDuplicates
Use an iterator-based implementation with range-based one simply deferring to it. Also optimize a little by storing iterators to unique values to prevent creating value copies.
This commit is contained in:
@@ -233,27 +233,45 @@ typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& m)
|
|||||||
ContainerAlgorithms::BinarySearcher<MatchRange>(m));
|
ContainerAlgorithms::BinarySearcher<MatchRange>(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ForwardIterator>
|
||||||
|
ForwardIterator cmRemoveDuplicates(ForwardIterator first, ForwardIterator last)
|
||||||
|
{
|
||||||
|
using Value = typename std::iterator_traits<ForwardIterator>::value_type;
|
||||||
|
using Hash = struct
|
||||||
|
{
|
||||||
|
std::size_t operator()(ForwardIterator it) const
|
||||||
|
{
|
||||||
|
return std::hash<Value>{}(*it);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Equal = struct
|
||||||
|
{
|
||||||
|
bool operator()(ForwardIterator it1, ForwardIterator it2) const
|
||||||
|
{
|
||||||
|
return *it1 == *it2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::unordered_set<ForwardIterator, Hash, Equal> uniq;
|
||||||
|
|
||||||
|
ForwardIterator result = first;
|
||||||
|
while (first != last) {
|
||||||
|
if (uniq.find(first) == uniq.end()) {
|
||||||
|
if (result != first) {
|
||||||
|
*result = std::move(*first);
|
||||||
|
}
|
||||||
|
uniq.insert(result);
|
||||||
|
++result;
|
||||||
|
}
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
typename Range::const_iterator cmRemoveDuplicates(Range& r)
|
typename Range::const_iterator cmRemoveDuplicates(Range& r)
|
||||||
{
|
{
|
||||||
typedef typename Range::value_type T;
|
return cmRemoveDuplicates(r.begin(), r.end());
|
||||||
std::unordered_set<T> unique;
|
|
||||||
std::vector<size_t> 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::unordered_set<T>::iterator occur = unique.find(*it);
|
|
||||||
if (occur == unique.end()) {
|
|
||||||
unique.insert(*it);
|
|
||||||
} else {
|
|
||||||
indices.push_back(count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (indices.empty()) {
|
|
||||||
return end;
|
|
||||||
}
|
|
||||||
return cmRemoveIndices(r, indices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
|
Reference in New Issue
Block a user