Parcourir la source

cmRange: Add functions filter and transform

Regina Pfeifer il y a 6 ans
Parent
commit
a8d51ef8b7
1 fichiers modifiés avec 132 ajouts et 0 suppressions
  1. 132 0
      Source/cmRange.h

+ 132 - 0
Source/cmRange.h

@@ -9,6 +9,122 @@
 #include <functional>
 #include <iterator>
 
+namespace RangeIterators {
+
+template <typename Iter, typename UnaryPredicate>
+class FilterIterator
+{
+public:
+  using iterator_category = std::bidirectional_iterator_tag;
+  using value_type = typename std::iterator_traits<Iter>::value_type;
+  using difference_type = typename std::iterator_traits<Iter>::difference_type;
+  using pointer = typename std::iterator_traits<Iter>::pointer;
+  using reference = typename std::iterator_traits<Iter>::reference;
+
+  FilterIterator(Iter b, Iter e, UnaryPredicate p)
+    : Cur(std::move(b))
+    , End(std::move(e))
+    , Pred(std::move(p))
+  {
+    this->SatisfyPredicate();
+  }
+
+  FilterIterator& operator++()
+  {
+    ++this->Cur;
+    this->SatisfyPredicate();
+    return *this;
+  }
+
+  FilterIterator& operator--()
+  {
+    do {
+      --this->Cur;
+    } while (!this->Pred(*this->Cur));
+    return *this;
+  }
+
+  bool operator==(FilterIterator const& other) const
+  {
+    return this->Cur == other.Cur;
+  }
+
+  bool operator!=(FilterIterator const& other) const
+  {
+    return !this->operator==(other);
+  }
+
+  auto operator*() const -> decltype(*std::declval<Iter>())
+  {
+    return *this->Cur;
+  }
+
+private:
+  void SatisfyPredicate()
+  {
+    while (this->Cur != this->End && !this->Pred(*this->Cur)) {
+      ++this->Cur;
+    }
+  }
+
+  Iter Cur;
+  Iter End;
+  UnaryPredicate Pred;
+};
+
+template <typename Iter, typename UnaryFunction>
+class TransformIterator
+{
+public:
+  using iterator_category = std::bidirectional_iterator_tag;
+  using value_type =
+    typename std::remove_cv<typename std::remove_reference<decltype(
+      std::declval<UnaryFunction>()(*std::declval<Iter>()))>::type>::type;
+  using difference_type = typename std::iterator_traits<Iter>::difference_type;
+  using pointer = value_type const*;
+  using reference = value_type const&;
+
+  TransformIterator(Iter i, UnaryFunction f)
+    : Base(std::move(i))
+    , Func(std::move(f))
+  {
+  }
+
+  TransformIterator& operator++()
+  {
+    ++this->Base;
+    return *this;
+  }
+
+  TransformIterator& operator--()
+  {
+    --this->Base;
+    return *this;
+  }
+
+  bool operator==(TransformIterator const& other) const
+  {
+    return this->Base == other.Base;
+  }
+
+  bool operator!=(TransformIterator const& other) const
+  {
+    return !this->operator==(other);
+  }
+
+  auto operator*() const
+    -> decltype(std::declval<UnaryFunction>()(*std::declval<Iter>()))
+  {
+    return this->Func(*this->Base);
+  }
+
+private:
+  Iter Base;
+  UnaryFunction Func;
+};
+
+} // namespace RangeIterators
+
 template <typename Iter>
 class cmRange
 {
@@ -74,6 +190,22 @@ public:
     return std::none_of(this->Begin, this->End, std::ref(p));
   }
 
+  template <typename UnaryPredicate>
+  auto filter(UnaryPredicate p) const
+    -> cmRange<RangeIterators::FilterIterator<Iter, UnaryPredicate>>
+  {
+    using It = RangeIterators::FilterIterator<Iter, UnaryPredicate>;
+    return { It(this->Begin, this->End, p), It(this->End, this->End, p) };
+  }
+
+  template <typename UnaryFunction>
+  auto transform(UnaryFunction f) const
+    -> cmRange<RangeIterators::TransformIterator<Iter, UnaryFunction>>
+  {
+    using It = RangeIterators::TransformIterator<Iter, UnaryFunction>;
+    return { It(this->Begin, f), It(this->End, f) };
+  }
+
 private:
   Iter Begin;
   Iter End;