#pragma once #include #include #include #include #include #include namespace util { template decltype(auto) get(Ts&&... ts) { return std::get(std::forward_as_tuple(ts...)); } template 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& t) { m_begin = t.first; m_end = t.second; } template 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 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 struct InputOrOutputIterator : public BaseIterator { InputOrOutputIterator(const I &iter) : BaseIterator(iter) {} InputOrOutputIterator(I &&iter) : BaseIterator(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 struct InputIterator : public InputOrOutputIterator, public std::input_iterator_tag { InputIterator(const I &iter) : BaseIterator(iter) {} InputIterator(I &&iter) : BaseIterator(std::move(iter)) {} auto constexpr operator*() const -> const V & { return *this->base_iter; } }; template struct OutputIterator : public InputOrOutputIterator, public std::output_iterator_tag { OutputIterator(const I &iter) : BaseIterator(iter) {} OutputIterator(I &&iter) : BaseIterator(std::move(iter)) {} auto constexpr operator*() -> V & { return *this->base_iter; } }; template struct ForwardIterator : public InputIterator, public std::forward_iterator_tag { ForwardIterator(const I &iter) : BaseIterator(iter) {} ForwardIterator(I &&iter) : BaseIterator(std::move(iter)) {} auto constexpr operator==(const ForwardIterator &rhs) const -> bool { return this->base_iter == rhs.base_iter; } }; template struct BidirectionalIterator : public ForwardIterator, public std::bidirectional_iterator_tag { BidirectionalIterator(const I &iter) : BaseIterator(iter) {} BidirectionalIterator(I &&iter) : BaseIterator(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 struct RandomAccessIterator : public BidirectionalIterator, public std::random_access_iterator_tag { using difference_type = typename BaseIterator::difference_type; RandomAccessIterator(const I &iter) : BaseIterator(iter) {} RandomAccessIterator(I &&iter) : BaseIterator(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 using Iterator = std::conditional_t< std::random_access_iterator, RandomAccessIterator, I>, std::conditional_t< std::bidirectional_iterator, BidirectionalIterator, I>, std::conditional_t< std::forward_iterator, ForwardIterator, I>, std::conditional_t< std::output_iterator())>, OutputIterator, I>, std::conditional_t< std::input_iterator, InputIterator, I>, std::conditional_t< std::input_or_output_iterator, InputOrOutputIterator, I>, RandomAccessIterator>>>>>>; template using RangeIterator = Iterator>; } // namespace util