Browse Source

cmAlgorithms: Implement algorithm for removing indexes.

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.
Stephen Kelly 10 years ago
parent
commit
0b5cf0dabd
1 changed files with 38 additions and 0 deletions
  1. 38 0
      Source/cmAlgorithms.h

+ 38 - 0
Source/cmAlgorithms.h

@@ -138,6 +138,22 @@ private:
   const_iterator End;
 };
 
+template<typename BiDirIt>
+BiDirIt Rotate(BiDirIt first, BiDirIt middle, BiDirIt last)
+{
+  typename std::iterator_traits<BiDirIt>::difference_type dist =
+      std::distance(first, middle);
+  std::rotate(first, middle, last);
+  std::advance(last, -dist);
+  return last;
+}
+
+template<typename Iter>
+Iter RemoveN(Iter i1, Iter i2, size_t n)
+{
+  return ContainerAlgorithms::Rotate(i1, i1 + n, i2);
+}
+
 }
 
 template<typename Iter1, typename Iter2>
@@ -188,4 +204,26 @@ std::string cmJoin(Range const& r, std::string delimiter)
   return cmJoin(r, delimiter.c_str());
 };
 
+template<typename Range>
+typename Range::const_iterator cmRemoveN(Range& r, size_t n)
+{
+  return ContainerAlgorithms::RemoveN(r.begin(), r.end(), n);
+}
+
+template<typename Range, typename InputRange>
+typename Range::const_iterator cmRemoveIndices(Range& r, InputRange const& rem)
+{
+  typename InputRange::const_iterator remIt = rem.begin();
+
+  typename Range::iterator writer = r.begin() + *remIt;
+  ++remIt;
+  size_t count = 1;
+  for ( ; writer != r.end() && remIt != rem.end(); ++count, ++remIt)
+    {
+    writer = ContainerAlgorithms::RemoveN(writer, r.begin() + *remIt, count);
+    }
+  writer = ContainerAlgorithms::RemoveN(writer, r.end(), count);
+  return writer;
+}
+
 #endif