191 lines
5.2 KiB
C++
191 lines
5.2 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; }
|
|
};
|
|
|
|
namespace detail {
|
|
|
|
template <class C>
|
|
requires requires(const C &c) { c.read(); }
|
|
using reference_t = decltype(std::declval<const C &>().read());
|
|
|
|
namespace detail {
|
|
template <class C> struct deduced_value_t {
|
|
template <class T> static auto deduce(int) -> typename T::value_type;
|
|
template <class T> static auto deduce(...) -> std::decay_t<reference_t<T>>;
|
|
|
|
using type = decltype(deduce<C>(0));
|
|
};
|
|
} // namespace detail
|
|
|
|
template <class C>
|
|
requires std::same_as<typename detail::deduced_value_t<C>::type,
|
|
std::decay_t<typename detail::deduced_value_t<C>::type>>
|
|
using value_type_t = typename detail::deduced_value_t<C>::type;
|
|
|
|
namespace detail {
|
|
template <class C> struct deduced_difference_t {
|
|
template <class T> static auto deduce(int) -> typename T::difference_type;
|
|
template <class T>
|
|
static auto deduce(long) -> decltype(std::declval<const T &>().distance_to(
|
|
std::declval<const T &>()));
|
|
template <class T> static auto deduce(...) -> std::ptrdiff_t;
|
|
|
|
using type = decltype(deduce<C>(0));
|
|
};
|
|
} // namespace detail
|
|
|
|
template <class C>
|
|
using difference_type_t = typename detail::deduced_difference_t<C>::type;
|
|
|
|
template <typename I> struct iterator_traits {
|
|
using difference_type = difference_type_t<I>;
|
|
using value_type = value_type_t<I>;
|
|
using reference = reference_t<I>;
|
|
};
|
|
} // namespace detail
|
|
|
|
template <typename I> struct iterator_t {
|
|
private:
|
|
I base_;
|
|
|
|
public:
|
|
iterator_t() requires(std::is_default_constructible_v<I>) : base_({}) {}
|
|
iterator_t(const I &base) : base_(base) {}
|
|
iterator_t(I &&base) : base_(std::move(base)) {}
|
|
|
|
auto constexpr base() const -> const I & { return base_; }
|
|
auto constexpr base() -> I & { return base_; }
|
|
|
|
// input_or_output_iterator
|
|
auto constexpr operator++(int) -> iterator_t
|
|
requires(std::input_or_output_iterator<I>) {
|
|
const auto ret = *this;
|
|
base()++;
|
|
return ret;
|
|
}
|
|
auto constexpr operator++()
|
|
-> iterator_t &requires(std::input_or_output_iterator<I>) {
|
|
this ++;
|
|
return *this;
|
|
}
|
|
|
|
// input_iterator
|
|
auto constexpr operator*() const -> const std::iter_reference_t<I>
|
|
requires(std::input_iterator<I>) { return *base(); }
|
|
|
|
// output_iterator
|
|
template <typename T = decltype(*base_)>
|
|
auto constexpr operator*() -> std::iter_reference_t<I>
|
|
requires(std::output_iterator<I, T>) { return *base(); }
|
|
|
|
// forward_iterator
|
|
auto constexpr operator==(const iterator_t &rhs) const
|
|
-> bool requires(std::forward_iterator<I>) {
|
|
return base() == rhs.base();
|
|
}
|
|
|
|
template <std::sentinel_for<I> S>
|
|
auto constexpr operator==(const S &rhs) const
|
|
-> bool requires(std::forward_iterator<I>) {
|
|
return base() == rhs;
|
|
}
|
|
|
|
// bidirectional_iterator
|
|
auto constexpr operator--(int) -> iterator_t
|
|
requires(std::bidirectional_iterator<I>) {
|
|
const auto ret = *this;
|
|
base()--;
|
|
return ret;
|
|
}
|
|
auto constexpr operator--()
|
|
-> iterator_t &requires(std::bidirectional_iterator<I>) {
|
|
base()--;
|
|
return *this;
|
|
}
|
|
|
|
// random_access_iterator
|
|
auto constexpr operator<=>(const iterator_t &rhs) const
|
|
-> std::strong_ordering {
|
|
return base() <=> rhs.base();
|
|
}
|
|
|
|
auto constexpr operator-(const iterator_t &rhs) const
|
|
-> std::iter_difference_t<I> {
|
|
return base() - rhs.base();
|
|
}
|
|
auto constexpr operator+(const std::iter_difference_t<I> &n) const
|
|
-> iterator_t {
|
|
return iterator_t(base() + n);
|
|
}
|
|
friend auto constexpr operator+(const std::iter_difference_t<I> &n,
|
|
const iterator_t &rhs) -> iterator_t {
|
|
return rhs + n;
|
|
}
|
|
auto constexpr operator-(const std::iter_difference_t<I> &n) const
|
|
-> iterator_t {
|
|
return iterator_t(base() - n);
|
|
}
|
|
|
|
auto operator+=(const std::iter_difference_t<I> &n) -> iterator_t & {
|
|
*this = iterator_t(base() + n);
|
|
return *this;
|
|
}
|
|
auto operator-=(const std::iter_difference_t<I> &n) -> iterator_t & {
|
|
*this = iterator_t(base() - n);
|
|
return *this;
|
|
}
|
|
|
|
auto constexpr operator[](const std::iter_difference_t<I> &n) const
|
|
-> const std::iter_reference_t<I> {
|
|
return base()[n];
|
|
}
|
|
auto operator[](const std::iter_difference_t<I> &n)
|
|
-> std::iter_reference_t<I> {
|
|
return base()[n];
|
|
}
|
|
};
|
|
|
|
template <typename T, typename I>
|
|
concept iterator = std::same_as<typename iterator_t<I>::value_type, T>;
|
|
|
|
} // namespace util
|
|
|
|
namespace std {
|
|
template <typename I>
|
|
struct iterator_traits<util::iterator_t<I>> : public iterator_traits<I> {};
|
|
} // namespace std
|