Start by creating a vector to hold a unique values of the input range. We
expect that in most cases, there will be relatively few duplicates, so
reserving enough memory for a complete copy is worthwhile. Unlike a solution
involving a std::set, this algorithm allocates all the memory it needs
in one go and in one place, so it is more cache friendly.
Populate the unique copy with a lower_bound insert algorithm and record the
indices of duplicates. This is the same complexity as the std::set insert
algorithm, but without the need to allocate memory on the heap and other
disadvantages of std::set.
Remove the duplicates with the cmRemoveIndices algorithm.
Implement ContainerAlgorithms::RemoveN to remove N elements to the
end of a container by rotating. The rotate is implemented in terms
of the efficient swap algorithm, optimized even more in the standard
library implementation when the compiler supports the rvalue-references
feature to move elements. Implement cmRemoveN with a Range API
for completeness.
std::rotate in C++11 is specified to return an iterator, but
c++98 specifies it to return void. libstdc++ 5.0 will be the first
version to have the correct return type. Implement
ContainerAlgorithms::Rotate in terms of std::rotate and return the
correct iterator from it. While std::rotate requires forward iterators,
this workaround means cmRotate requires bidirectional iterators. As
most of CMake uses random access iterators anyway, this should not
be a problem.
Implement cmRemoveIndices in terms of the RemoveN algorithm, such
that each element which is not removed is rotated only once. This
can not use the cmRemoveN range-API algorithm because that would
require creating a new range, but the range must be taken by reference
and so it can't be a temporary.
These remove algorithms are not part of the STL and I couldn't find them
anywhere else either.
This can make a pair of iterators API compatible with the
cmJoin algorithm and other range-based algorithms.
Accept different iterator types in the cmRange adaptor so that
a const and non-const iterator are accepted.