cpp_iterators

#include <compare>
#include <concepts>
#include <cstddef>
#include <iterator>
#include <type_traits>

template <typename TYPE>
struct Container {

    template <typename T>
    struct Iterator {
        static_assert(std::is_same_v<std::remove_const_t<T>, TYPE>);

        using iterator_concept = std::contiguous_iterator_tag; // TODO
        using iterator_category = std::random_access_iterator_tag; // TODO

        // cast non-const to const
        template <typename U>
            requires (std::is_const_v<T> &&
                      std::same_as<std::remove_const_t<T>, U>)
        constexpr Iterator(Iterator<U> const& other) noexcept : ptr_(other.ptr_) {} // TODO

        // INPUT-OR-OUTPUT: dereference, increment, signed difference type.
        using difference_type = std::ptrdiff_t;

        constexpr T& operator*() const noexcept {
            // TODO
        }

        constexpr Iterator& operator++() noexcept {
            ++ptr_; // TODO
            return *this;
        }

        constexpr Iterator operator++(int) noexcept {
            auto previous = *this;
            ++*this;
            return previous;
        }

        // INPUT: adds readable dereference and an associated value type.
        using value_type = std::remove_cv_t<T>;
        // operator* above already supports reading through a const iterator object.
        // For T = int,       its return type is int&.
        // For T = const int, its return type is const int&.
        // No new function is needed here: T& and value_type satisfy indirectly_readable.
        // Input alone does not require copying, default construction, or equality.

        // OUTPUT: adds writable dereference; independent of the input hierarchy.
        // No extra iterator member is needed: assignment acts on the returned T&.
        // Required expressions for an appropriate value:
        //     *it = value;
        //     *it++ = value;
        // These work for Iterator<int>, but not Iterator<const int>.
        // Our reference return also satisfies indirectly_writable's other forms.

        // FORWARD //
        constexpr Iterator() noexcept = default;
        // Copy/move construction and copy/move assignment are implicit.
        // Postfix ++ above must return Iterator, representing the old position.
        constexpr bool operator==(const Iterator&) const noexcept = default;

        // BIDIRECTIONAL //
        constexpr Iterator& operator--() noexcept {
            --ptr_; // TODO
            return *this;
        }

        constexpr Iterator operator--(int) noexcept {
            auto previous = *this;
            --*this;
            return previous;
        }

        // RANDOM ACCESS //
        constexpr Iterator& operator+=(difference_type n) noexcept {
            ptr_ += n; // TODO
            return *this;
        }

        constexpr Iterator& operator-=(difference_type n) noexcept {
            ptr_ -= n; // TODO
            return *this;
        }

        constexpr Iterator operator+(difference_type n) const noexcept {
            auto result = *this;
            return result += n;
        }

        friend constexpr Iterator operator+(difference_type n, Iterator it) noexcept {
            return it += n;
        }

        constexpr Iterator operator-(difference_type n) const noexcept {
            auto result = *this;
            return result -= n;
        }

        constexpr difference_type operator-(const Iterator& other) const noexcept {
            // TODO
            if (ptr_ == other.ptr_) return 0; // Includes two default iterators.
            return ptr_ - other.ptr_;
        }

        constexpr T& operator[](difference_type n) const noexcept {
            return ptr_[n]; // Same return type as operator*.
        }

        constexpr auto operator<=>(const Iterator&) const noexcept = default;

        // CONTIGUOUS: adds address extraction and contiguous storage guarantees.
        constexpr T* operator->() const noexcept {
            return ptr_; // Makes std::to_address(it) work, including at end.
        }

        // Conventional aliases for iterator_traits / legacy interoperability.
        using reference = T&;
        using pointer = T*;

    private:
        T* ptr_ = nullptr; // TODO

        template <typename> friend struct Iterator; // Allow mutable -> const access.
    };
};