Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 94 additions & 6 deletions include/beman/utf_view/to_utf_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,18 @@ namespace detail {
return 0xDC00 <= c && c <= 0xDFFF;
}

template<typename T>
template<typename T, exposition_only_code_unit ToType>
struct iter_category_impl {};

template<std::ranges::forward_range R>
struct iter_category_impl<R> {
template<std::ranges::forward_range R, exposition_only_code_unit ToType>
struct iter_category_impl<R, ToType> {
static consteval auto impl() {
using category = typename std::iterator_traits<std::ranges::iterator_t<R>>::iterator_category;
if constexpr (std::derived_from<category, std::bidirectional_iterator_tag>) {
if constexpr (std::derived_from<category, std::random_access_iterator_tag>
&& std::same_as<char32_t, std::ranges::range_value_t<R>>
&& std::same_as<char32_t, ToType>) {
return std::random_access_iterator_tag{};
} else if constexpr (std::derived_from<category, std::bidirectional_iterator_tag>) {
return std::bidirectional_iterator_tag{};
} else if constexpr (std::derived_from<category, std::forward_iterator_tag>) {
return std::forward_iterator_tag{};
Expand Down Expand Up @@ -265,7 +269,8 @@ template <std::ranges::input_range V, to_utf_view_kind E, exposition_only_code_u
template <bool Const>
/* PAPER: class to_utf_view<V, E, ToType>::@*iterator*@ { */
/* !PAPER */
struct to_utf_view<V, E, ToType>::exposition_only_iterator : detail::iter_category_impl<V> {
struct to_utf_view<V, E, ToType>::exposition_only_iterator
: detail::iter_category_impl<V, ToType> {
/* PAPER */
private:
using exposition_only_Base = exposition_only_maybe_const<Const, V>; // @*exposition only*@
Expand All @@ -274,7 +279,11 @@ struct to_utf_view<V, E, ToType>::exposition_only_iterator : detail::iter_catego
using from_type = std::ranges::range_value_t<V>; // @*exposition only*@

static consteval auto iter_concept_impl() {
if constexpr (std::ranges::bidirectional_range<exposition_only_Base>) {
if constexpr (std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, from_type>
&& std::same_as<char32_t, ToType>) {
return std::random_access_iterator_tag{};
} else if constexpr (std::ranges::bidirectional_range<exposition_only_Base>) {
return std::bidirectional_iterator_tag{};
} else if constexpr (std::ranges::forward_range<exposition_only_Base>) {
return std::forward_iterator_tag{};
Expand Down Expand Up @@ -454,6 +463,85 @@ struct to_utf_view<V, E, ToType>::exposition_only_iterator : detail::iter_catego
return lhs.exposition_only_current_ == rhs.exposition_only_current_ && lhs.exposition_only_buf_index_ == rhs.exposition_only_buf_index_;
}

friend constexpr auto operator<=>(
exposition_only_iterator const& lhs, exposition_only_iterator const& rhs)
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
return lhs.exposition_only_current_ <=> rhs.exposition_only_current_;
}

friend constexpr exposition_only_iterator& operator+=(
exposition_only_iterator& it, difference_type const n)
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
it.exposition_only_current_ += n;
it.exposition_only_reseat();
return it;
}

friend constexpr exposition_only_iterator operator+(
exposition_only_iterator it, difference_type const n)
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
it += n;
return it;
}

friend constexpr exposition_only_iterator operator+(
difference_type const n, exposition_only_iterator it)
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
it += n;
return it;
}

friend constexpr exposition_only_iterator& operator-=(
exposition_only_iterator& it, difference_type const n)
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
it.exposition_only_current_ -= n;
it.exposition_only_reseat();
return it;
}

friend constexpr exposition_only_iterator operator-(
exposition_only_iterator it, difference_type const n)
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
it -= n;
return it;
}

friend constexpr difference_type operator-(
exposition_only_iterator const& lhs,
exposition_only_iterator const& rhs)
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
return lhs.exposition_only_current_ - rhs.exposition_only_current_;
}

constexpr value_type operator[](difference_type const n) const
requires std::ranges::random_access_range<exposition_only_Base>
&& std::same_as<char32_t, std::ranges::range_value_t<exposition_only_Base>>
&& std::same_as<char32_t, ToType>
{
return *(*this + n);
}

private:
/* !PAPER */

Expand Down
67 changes: 65 additions & 2 deletions papers/P2728.md
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,61 @@ public:
return lhs.@*current_*@ == rhs.@*current_*@ && lhs.@*buf_index_*@ == rhs.@*buf_index_*@;
}

friend constexpr auto operator<=>(@*iterator*@ const& lhs, @*iterator*@ const& rhs)
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
return lhs.@*current_*@ <=> rhs.@*current_*@;
}

friend constexpr @*iterator*@& operator+=(@*iterator*@& it, difference_type const n)
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
it.@*current_*@ += n;
it.@*reseat*@();
return it;
}

friend constexpr @*iterator*@ operator+(@*iterator*@ it, difference_type const n)
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
it += n;
return it;
}

friend constexpr @*iterator*@ operator+(difference_type const n, @*iterator*@ it)
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
it += n;
return it;
}

friend constexpr @*iterator*@& operator-=(@*iterator*@& it, difference_type const n)
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
it.@*current_*@ -= n;
it.@*reseat*@();
return it;
}

friend constexpr @*iterator*@ operator-(@*iterator*@ it, difference_type const n)
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
it -= n;
return it;
}

friend constexpr difference_type operator-(@*iterator*@ const& lhs, @*iterator*@ const& rhs)
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
return lhs.@*current_*@ - rhs.@*current_*@;
}

constexpr value_type operator[](difference_type const n) const
requires random_access_range<@*Base*@> && same_as<char32_t, range_value_t<@*Base*@>> && same_as<char32_t, ToType>
{
return *(*this + n);
}

private:
constexpr sentinel_t<@*Base*@> @*end*@() const { // @*exposition only*@
return @*end_*@;
Expand Down Expand Up @@ -950,7 +1005,10 @@ point.

`to_utf_view::@*iterator*@::iterator_concept` is defined as follows:

- If `V` models `bidirectional_range`, then `iterator_concept` is `bidirectional_iterator_tag`.
- If `V` models `random_access_range`, and `range_value_t<V>` is `char32_t`,
and `ToType` is `char32_t`, then `iterator_concept` is
`random_access_iterator_tag`.
- Otherwise, if `V` models `bidirectional_range`, then `iterator_concept` is `bidirectional_iterator_tag`.
- Otherwise, if `V` models `forward_range`, then `iterator_concept` is `forward_iterator_tag`.
- Otherwise, `iterator_concept` is `input_iterator_tag`.

Expand All @@ -959,7 +1017,10 @@ The member *typedef-name* `iterator_category` is defined if and only if `V` mode
In that case, `to_utf_view::@*iterator*@::iterator_category` is defined as follows:

- Let `C` denote the type `iterator_traits<iterator_t<V>>::iterator_category`.
- If `C` models `derived_from<bidirectional_iterator_tag>`, then `iterator_category` denotes `bidirectional_iterator_tag`.
- If `C` models `derived_from<random_access_iterator_tag>`, and
`range_value_t<V>` is `char32_t`, and `ToType` is `char32_t`, then
`iterator_category` denotes `random_access_iterator_tag`.
- Otherwise, if `C` models `derived_from<bidirectional_iterator_tag>`, then `iterator_category` denotes `bidirectional_iterator_tag`.
- Otherwise, if `C` models `derived_from<forward_iterator_tag>`, then `iterator_category` denotes `forward_iterator_tag`.
- Otherwise, `iterator_category` denotes `C`.

Expand Down Expand Up @@ -1311,6 +1372,8 @@ But we voted in favor of providing it for forward ranges:
- Revert SIMD support and add design discussion of why it was rejected
- Rename `to_utf_view_error_kind` to `to_utf_view_kind` per SG9 discussion
- Implement `it.base_code_units()` for forward ranges per SG9 feedback
- Add random access support for UTF-32-to-UTF-32 self-transcode per SG9
feedback

## Changes since R13

Expand Down
109 changes: 109 additions & 0 deletions tests/beman/utf_view/std_archetypes/iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,115 @@ struct basic_bidirectional_iterator_archetype {
using bidirectional_iterator_archetype =
basic_bidirectional_iterator_archetype<std::uint8_t>;

template <std::copyable State, typename ValueType = detail::value_type_archetype<State>,
typename ReferenceType = detail::reference_type_archetype<State>>
struct basic_random_access_iterator_archetype {
using value_type = ValueType;
using reference_type = ReferenceType;
using difference_type = std::ptrdiff_t;
using iterator_concept = std::random_access_iterator_tag;
constexpr basic_random_access_iterator_archetype()
: x{} { }
constexpr explicit basic_random_access_iterator_archetype(State x_in)
: x{std::move(x_in)} { }
basic_random_access_iterator_archetype(basic_random_access_iterator_archetype const&) =
default;
basic_random_access_iterator_archetype& operator=(
basic_random_access_iterator_archetype const&) = default;
basic_random_access_iterator_archetype(basic_random_access_iterator_archetype&&) =
default;
basic_random_access_iterator_archetype& operator=(
basic_random_access_iterator_archetype&&) = default;

constexpr reference_type operator*() const {
return reference_type{x};
}
constexpr basic_random_access_iterator_archetype& operator++() {
++x;
return *this;
}
constexpr basic_random_access_iterator_archetype operator++(int) {
basic_random_access_iterator_archetype result{*this};
++x;
return result;
}
constexpr basic_random_access_iterator_archetype& operator--() {
--x;
return *this;
}
constexpr basic_random_access_iterator_archetype operator--(int) {
basic_random_access_iterator_archetype result{*this};
--x;
return result;
}

friend constexpr boolean_testable_archetype operator==(
basic_random_access_iterator_archetype const& lhs,
basic_random_access_iterator_archetype const& rhs) {
return boolean_testable_archetype{lhs.x == rhs.x};
}
friend constexpr boolean_testable_archetype operator!=(
basic_random_access_iterator_archetype const& lhs,
basic_random_access_iterator_archetype const& rhs) {
return boolean_testable_archetype{lhs.x != rhs.x};
}
friend constexpr auto operator<=>(
basic_random_access_iterator_archetype const& lhs,
basic_random_access_iterator_archetype const& rhs) {
return lhs.x <=> rhs.x;
}

friend constexpr basic_random_access_iterator_archetype& operator+=(
basic_random_access_iterator_archetype& it,
std::ptrdiff_t const n) {
it.x += n;
return it;
}

friend constexpr basic_random_access_iterator_archetype operator+(
basic_random_access_iterator_archetype it,
std::ptrdiff_t const n) {
it += n;
return it;
}

friend constexpr basic_random_access_iterator_archetype operator+(
std::ptrdiff_t const n,
basic_random_access_iterator_archetype it) {
it += n;
return it;
}

friend constexpr basic_random_access_iterator_archetype& operator-=(
basic_random_access_iterator_archetype& it,
std::ptrdiff_t const n) {
it.x -= n;
return it;
}

friend constexpr basic_random_access_iterator_archetype operator-(
basic_random_access_iterator_archetype it,
std::ptrdiff_t const n) {
it -= n;
return it;
}

friend constexpr std::ptrdiff_t operator-(
basic_random_access_iterator_archetype const& lhs,
basic_random_access_iterator_archetype const& rhs) {
return lhs.x - rhs.x;
}

constexpr reference_type operator[](std::ptrdiff_t const n) const {
return *(*this + n);
}

State x;
};

using random_access_iterator_archetype =
basic_random_access_iterator_archetype<std::uint8_t>;

} // namespace beman::utf_view::tests::std_archetypes

#endif // BEMAN_UTF_VIEW_TESTS_STD_ARCHETYPES_ITERATOR_HPP
2 changes: 2 additions & 0 deletions tests/beman/utf_view/std_archetypes/iterator.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ static_assert(std::forward_iterator<forward_iterator_archetype>);
static_assert(std::forward_iterator<basic_forward_iterator_archetype<int>>);
static_assert(std::bidirectional_iterator<bidirectional_iterator_archetype>);
static_assert(std::bidirectional_iterator<basic_bidirectional_iterator_archetype<int>>);
static_assert(std::random_access_iterator<random_access_iterator_archetype>);
static_assert(std::random_access_iterator<basic_random_access_iterator_archetype<int>>);

} // namespace beman::utf_view::tests::std_archetypes
Loading
Loading