cpp-utils/include/iterator.hpp
2022-06-30 17:06:17 +01:00

187 lines
5.9 KiB
C++

#pragma once
#include <compare>
#include <cstddef>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <xutility>
namespace util {
template <int I, class... Ts>
decltype(auto) get(Ts&&... ts) {
return std::get<I>(std::forward_as_tuple(ts...));
}
template <class Iterator>
class Range {
Iterator m_begin, m_end;
public:
Range(const Iterator _begin, const Iterator _end)
: m_begin(_begin), m_end(_end) {}
Range(const std::pair<const Iterator, const Iterator>& t) {
m_begin = t.first;
m_end = t.second;
}
template <typename... Args>
Range(Args&&... args) : m_begin(get<0>(args...)), m_end(get<1>(args...)) {}
auto begin() -> Iterator { return m_begin; }
auto begin() const -> const Iterator { return m_begin; }
auto end() -> Iterator { return m_end; }
auto end() const -> const Iterator { return m_end; }
};
template <typename V, typename I = V *> struct BaseIterator {
using value_type = V;
using reference = V &;
using difference_type = std::ptrdiff_t;
I base_iter;
BaseIterator(const I &iter) : base_iter(iter) {}
BaseIterator(I &&iter) : base_iter(std::move(iter)) {}
};
template <typename V, typename I = V *>
struct InputOrOutputIterator : public BaseIterator<V, I> {
InputOrOutputIterator(const I &iter) : BaseIterator<V, I>(iter) {}
InputOrOutputIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
auto constexpr operator*() const -> void {}
auto constexpr operator++(int) -> InputOrOutputIterator {
const auto ret = *this;
this->base_iter++;
return ret;
}
auto constexpr operator++() -> InputOrOutputIterator & {
this ++;
return *this;
}
};
template <typename V, typename I = V *>
struct InputIterator : public InputOrOutputIterator<V, I>,
public std::input_iterator_tag {
InputIterator(const I &iter) : BaseIterator<V, I>(iter) {}
InputIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
auto constexpr operator*() const -> const V & { return *this->base_iter; }
};
template <typename V, typename I = V *>
struct OutputIterator : public InputOrOutputIterator<V, I>,
public std::output_iterator_tag {
OutputIterator(const I &iter) : BaseIterator<V, I>(iter) {}
OutputIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
auto constexpr operator*() -> V & { return *this->base_iter; }
};
template <typename V, typename I = V *>
struct ForwardIterator : public InputIterator<V, I>,
public std::forward_iterator_tag {
ForwardIterator(const I &iter) : BaseIterator<V, I>(iter) {}
ForwardIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
auto constexpr operator==(const ForwardIterator &rhs) const -> bool {
return this->base_iter == rhs.base_iter;
}
};
template <typename V, typename I = V *>
struct BidirectionalIterator : public ForwardIterator<V, I>,
public std::bidirectional_iterator_tag {
BidirectionalIterator(const I &iter) : BaseIterator<V, I>(iter) {}
BidirectionalIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
auto constexpr operator--(int) -> BidirectionalIterator {
const auto ret = *this;
this->base_iter--;
return ret;
}
auto constexpr operator--() -> BidirectionalIterator & {
this --;
return *this;
}
};
template <typename V, typename I = V *>
struct RandomAccessIterator : public BidirectionalIterator<V, I>,
public std::random_access_iterator_tag {
using difference_type = typename BaseIterator<V, I>::difference_type;
RandomAccessIterator(const I &iter) : BaseIterator<V, I>(iter) {}
RandomAccessIterator(I &&iter) : BaseIterator<V, I>(std::move(iter)) {}
auto constexpr operator<=>(const RandomAccessIterator &rhs) const
-> std::strong_ordering {
return this->base_iter <=> rhs.base_iter;
}
auto constexpr operator-(const RandomAccessIterator &rhs) const
-> difference_type {
return this->base_iter - rhs.base_iter;
}
auto constexpr operator+(const difference_type &n) const
-> RandomAccessIterator {
return RandomAccessIterator(this->base_iter + n);
}
friend auto constexpr operator+(const difference_type &n,
const RandomAccessIterator &rhs)
-> RandomAccessIterator {
return rhs + n;
}
auto constexpr operator-(const difference_type &n) const
-> RandomAccessIterator {
return RandomAccessIterator(this->base_iter - n);
}
auto operator+=(const difference_type &n) -> RandomAccessIterator & {
*this = RandomAccessIterator(this->base_iter + n);
return *this;
}
auto operator-=(const difference_type &n) -> RandomAccessIterator & {
*this = RandomAccessIterator(this->base_iter - n);
return *this;
}
auto constexpr operator[](const difference_type &n) const -> const V & {
return this->base_iter[n];
}
auto operator[](const difference_type &n) -> V & {
return this->base_iter[n];
}
};
template <typename I>
using Iterator = std::conditional_t<
std::random_access_iterator<I>,
RandomAccessIterator<std::iter_value_t<I>, I>,
std::conditional_t<
std::bidirectional_iterator<I>,
BidirectionalIterator<std::iter_value_t<I>, I>,
std::conditional_t<
std::forward_iterator<I>, ForwardIterator<std::iter_value_t<I>, I>,
std::conditional_t<
std::output_iterator<I, decltype(*std::declval<I>())>,
OutputIterator<std::iter_value_t<I>, I>,
std::conditional_t<
std::input_iterator<I>,
InputIterator<std::iter_value_t<I>, I>,
std::conditional_t<
std::input_or_output_iterator<I>,
InputOrOutputIterator<std::iter_value_t<I>, I>,
RandomAccessIterator<I, I *>>>>>>>;
template <std::ranges::range R>
using RangeIterator = Iterator<std::ranges::iterator_t<R>>;
} // namespace util