/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once #include "cmConfigure.h" // IWYU pragma: keep #include #include #include namespace RangeIterators { template class FilterIterator { public: using iterator_category = std::bidirectional_iterator_tag; using value_type = typename std::iterator_traits::value_type; using difference_type = typename std::iterator_traits::difference_type; using pointer = typename std::iterator_traits::pointer; using reference = typename std::iterator_traits::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()) { return *this->Cur; } private: void SatisfyPredicate() { while (this->Cur != this->End && !this->Pred(*this->Cur)) { ++this->Cur; } } Iter Cur; Iter End; UnaryPredicate Pred; }; template class TransformIterator { public: using iterator_category = std::bidirectional_iterator_tag; using value_type = typename std::remove_cv< typename std::remove_reference()( *std::declval()))>::type>::type; using difference_type = typename std::iterator_traits::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()(*std::declval())) { return this->Func(*this->Base); } private: Iter Base; UnaryFunction Func; }; } // namespace RangeIterators template class cmRange { public: using const_iterator = Iter; using value_type = typename std::iterator_traits::value_type; using difference_type = typename std::iterator_traits::difference_type; cmRange(Iter b, Iter e) : Begin(std::move(b)) , End(std::move(e)) { } Iter begin() const { return this->Begin; } Iter end() const { return this->End; } bool empty() const { return this->Begin == this->End; } difference_type size() const { return std::distance(this->Begin, this->End); } cmRange& advance(difference_type amount) & { std::advance(this->Begin, amount); return *this; } cmRange advance(difference_type amount) && { std::advance(this->Begin, amount); return std::move(*this); } cmRange& retreat(difference_type amount) & { std::advance(this->End, -amount); return *this; } cmRange retreat(difference_type amount) && { std::advance(this->End, -amount); return std::move(*this); } template bool all_of(UnaryPredicate p) const { return std::all_of(this->Begin, this->End, std::ref(p)); } template bool any_of(UnaryPredicate p) const { return std::any_of(this->Begin, this->End, std::ref(p)); } template bool none_of(UnaryPredicate p) const { return std::none_of(this->Begin, this->End, std::ref(p)); } template auto filter(UnaryPredicate p) const -> cmRange> { using It = RangeIterators::FilterIterator; return { It(this->Begin, this->End, p), It(this->End, this->End, p) }; } template auto transform(UnaryFunction f) const -> cmRange> { using It = RangeIterators::TransformIterator; return { It(this->Begin, f), It(this->End, f) }; } private: Iter Begin; Iter End; }; template bool operator==(cmRange const& left, cmRange const& right) { return left.size() == right.size() && std::equal(left.begin(), left.end(), right.begin()); } template auto cmMakeRange(Iter1 begin, Iter2 end) -> cmRange { return { begin, end }; } template auto cmMakeRange(Range const& range) -> cmRange { return { range.begin(), range.end() }; } template auto cmReverseRange(Range const& range) -> cmRange { return { range.rbegin(), range.rend() }; }