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:
Artur Ryt 2019-03-03 14:19:18 +01:00 committed by Brad King
parent 033728e867
commit bf1e73305a

View File

@ -233,27 +233,45 @@ typename Range::const_iterator cmRemoveMatching(Range& r, MatchRange const& 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>
typename Range::const_iterator cmRemoveDuplicates(Range& r)
{
typedef typename Range::value_type T;
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);
return cmRemoveDuplicates(r.begin(), r.end());
}
template <typename Range>