187 lines
5.9 KiB
C++
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
|