CMake/Source/cmRange.h
2019-02-21 08:24:26 -05:00

240 lines
5.4 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmRange_h
#define cmRange_h
#include "cmConfigure.h" // IWYU pragma: keep
#include <algorithm>
#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
{
public:
using const_iterator = Iter;
using value_type = typename std::iterator_traits<Iter>::value_type;
using difference_type = typename std::iterator_traits<Iter>::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 <typename UnaryPredicate>
bool all_of(UnaryPredicate p) const
{
return std::all_of(this->Begin, this->End, std::ref(p));
}
template <typename UnaryPredicate>
bool any_of(UnaryPredicate p) const
{
return std::any_of(this->Begin, this->End, std::ref(p));
}
template <typename UnaryPredicate>
bool none_of(UnaryPredicate p) const
{
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;
};
template <typename Iter1, typename Iter2>
bool operator==(cmRange<Iter1> const& left, cmRange<Iter2> const& right)
{
return left.size() == right.size() &&
std::equal(left.begin(), left.end(), right.begin());
}
template <typename Iter1, typename Iter2>
auto cmMakeRange(Iter1 begin, Iter2 end) -> cmRange<Iter1>
{
return { begin, end };
}
template <typename Range>
auto cmMakeRange(Range const& range) -> cmRange<decltype(range.begin())>
{
return { range.begin(), range.end() };
}
template <typename Range>
auto cmReverseRange(Range const& range) -> cmRange<decltype(range.rbegin())>
{
return { range.rbegin(), range.rend() };
}
#endif