#pragma once #include #include #include #include #include #include #include #include // NOLINTBEGIN(modernize-use-constraints) namespace stdx { inline namespace v1 { namespace detail { template constexpr auto is_byteratorish_v = std::is_base_of_v::iterator_category> and std::is_trivially_copyable_v::value_type>; template constexpr auto iterator_value_type() -> decltype(*std::declval::pointer>()); template using iterator_value_t = decltype(iterator_value_type()); } // namespace detail template class byterator { using byte_t = std::remove_reference_t>; byte_t *ptr; [[nodiscard]] constexpr friend auto operator==(byterator const &x, byterator const &y) -> bool { return x.ptr == y.ptr; } template , T>, int> = 0> [[nodiscard]] constexpr friend auto operator==(byterator const &x, It y) -> bool { return static_cast(x.ptr) == static_cast(stdx::to_address(y)); } #if __cpp_impl_three_way_comparison >= 201907L [[nodiscard]] constexpr friend auto operator<=>(byterator const &x, byterator const &y) { return x.ptr <=> y.ptr; } #else [[nodiscard]] constexpr friend auto operator!=(byterator const &x, byterator const &y) -> bool { return not(x == y); } template [[nodiscard]] constexpr friend auto operator==(It y, byterator const &x) -> bool { return x == y; } template [[nodiscard]] constexpr friend auto operator!=(byterator const &x, It y) -> bool { return not(x == y); } template [[nodiscard]] constexpr friend auto operator!=(It y, byterator const &x) -> bool { return not(x == y); } [[nodiscard]] constexpr friend auto operator<(byterator const &x, byterator const &y) -> bool { return std::less{}(x.ptr, y.ptr); } [[nodiscard]] constexpr friend auto operator<=(byterator const &x, byterator const &y) -> bool { return std::less_equal{}(x.ptr, y.ptr); } [[nodiscard]] constexpr friend auto operator>(byterator const &x, byterator const &y) -> bool { return std::greater{}(x.ptr, y.ptr); } [[nodiscard]] constexpr friend auto operator>=(byterator const &x, byterator const &y) -> bool { return std::greater_equal{}(x.ptr, y.ptr); } #endif public: using difference_type = std::ptrdiff_t; using value_type = std::byte; using pointer = value_type *; using reference = value_type &; using iterator_category = std::random_access_iterator_tag; template , int> = 0> explicit byterator(It it) : ptr(bit_cast(stdx::to_address(it))) {} [[nodiscard]] constexpr auto operator->() const -> byte_t * { return ptr; } [[nodiscard]] constexpr auto operator*() const -> byte_t & { return *ptr; } constexpr auto operator++() -> byterator & { ++ptr; return *this; } [[nodiscard]] constexpr auto operator++(int) -> byterator { auto tmp = *this; ++(*this); return tmp; } constexpr auto operator--() -> byterator & { --ptr; return *this; } [[nodiscard]] constexpr auto operator--(int) -> byterator { auto tmp = *this; --(*this); return tmp; } constexpr auto operator+=(difference_type d) -> byterator & { ptr += d; return *this; } constexpr auto operator-=(difference_type d) -> byterator & { ptr -= d; return *this; } [[nodiscard]] friend constexpr auto operator+(byterator i, difference_type d) -> byterator { i += d; return i; } [[nodiscard]] friend constexpr auto operator+(difference_type d, byterator i) -> byterator { i += d; return i; } [[nodiscard]] friend constexpr auto operator-(byterator i, difference_type d) -> byterator { i -= d; return i; } [[nodiscard]] friend constexpr auto operator-(byterator x, byterator y) -> difference_type { return x.ptr - y.ptr; } [[nodiscard]] constexpr auto operator[](difference_type n) -> byte_t & { return ptr[n]; } [[nodiscard]] constexpr auto operator[](difference_type n) const -> byte_t const & { return ptr[n]; } template , int> = 0> [[nodiscard]] auto peek() -> R { V v; std::memcpy(std::addressof(v), ptr, sizeof(V)); return static_cast(v); } template , int> = 0> [[nodiscard]] auto read() -> R { R ret = peek(); ptr += sizeof(V); return ret; } template >, int> = 0> auto write(V &&v) -> void { using R = remove_cvref_t; std::memcpy(ptr, std::addressof(v), sizeof(R)); ptr += sizeof(R); } template [[nodiscard]] auto peeku8() { return peek(); } template [[nodiscard]] auto readu8() { return read(); } template [[nodiscard]] auto writeu8(V &&v) { return write(static_cast(std::forward(v))); } template [[nodiscard]] auto peeku16() { return peek(); } template [[nodiscard]] auto readu16() { return read(); } template [[nodiscard]] auto writeu16(V &&v) { return write(static_cast(std::forward(v))); } template [[nodiscard]] auto peeku32() { return peek(); } template [[nodiscard]] auto readu32() { return read(); } template [[nodiscard]] auto writeu32(V &&v) { return write(static_cast(std::forward(v))); } }; template , int> = 0> byterator(It) -> byterator>; } // namespace v1 } // namespace stdx // NOLINTEND(modernize-use-constraints)