Skip to content

Commit

Permalink
Implement LWG-3717 common_view::end should improve `random_access_r…
Browse files Browse the repository at this point in the history
…ange` case (#3266)
  • Loading branch information
frederick-vs-ja authored Dec 6, 2022
1 parent 7164d1c commit 4483e87
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 2 deletions.
4 changes: 2 additions & 2 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -4824,7 +4824,7 @@ namespace ranges {

_NODISCARD constexpr auto end() {
if constexpr (random_access_range<_Vw> && sized_range<_Vw>) {
return _RANGES begin(_Base) + _RANGES size(_Base);
return _RANGES begin(_Base) + _RANGES distance(_Base);
} else {
return common_iterator<iterator_t<_Vw>, sentinel_t<_Vw>>{_RANGES end(_Base)};
}
Expand All @@ -4834,7 +4834,7 @@ namespace ranges {
requires range<const _Vw>
{
if constexpr (random_access_range<const _Vw> && sized_range<const _Vw>) {
return _RANGES begin(_Base) + _RANGES size(_Base);
return _RANGES begin(_Base) + _RANGES distance(_Base);
} else {
return common_iterator<iterator_t<const _Vw>, sentinel_t<const _Vw>>{_RANGES end(_Base)};
}
Expand Down
120 changes: 120 additions & 0 deletions tests/std/tests/P0896R4_views_common/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,128 @@ struct instantiator {
}
};

template <class T>
struct difference_type_only_iterator {
static_assert(is_object_v<T>);

friend constexpr bool operator==(difference_type_only_iterator, difference_type_only_iterator) = default;
friend constexpr auto operator<=>(difference_type_only_iterator, difference_type_only_iterator) = default;

using iterator_concept = contiguous_iterator_tag;
using value_type = remove_cvref_t<T>;

constexpr T& operator*() const noexcept {
return *ptr_;
}

constexpr T* operator->() const noexcept {
return ptr_;
}

constexpr difference_type_only_iterator& operator++() noexcept {
++ptr_;
return *this;
}

constexpr difference_type_only_iterator operator++(int) noexcept {
auto result = *this;
++*this;
return result;
}

constexpr difference_type_only_iterator& operator--() noexcept {
--ptr_;
return *this;
}

constexpr difference_type_only_iterator operator--(int) noexcept {
auto result = *this;
--*this;
return result;
}

constexpr difference_type_only_iterator& operator+=(same_as<ptrdiff_t> auto n) noexcept {
ptr_ += n;
return *this;
}

constexpr difference_type_only_iterator& operator-=(same_as<ptrdiff_t> auto n) noexcept {
ptr_ -= n;
return *this;
}

friend constexpr difference_type_only_iterator operator+(
difference_type_only_iterator i, same_as<ptrdiff_t> auto n) noexcept {
i += n;
return i;
}

friend constexpr difference_type_only_iterator operator+(
same_as<ptrdiff_t> auto n, difference_type_only_iterator i) noexcept {
i += n;
return i;
}

friend constexpr difference_type_only_iterator operator-(
difference_type_only_iterator i, same_as<ptrdiff_t> auto n) noexcept {
i -= n;
return i;
}

friend constexpr ptrdiff_t operator-(difference_type_only_iterator i, difference_type_only_iterator j) noexcept {
return i.ptr_ - j.ptr_;
}

constexpr T& operator[](same_as<ptrdiff_t> auto n) const noexcept {
return ptr_[n];
}

T* ptr_;
};

template <class T>
struct difference_type_only_sentinel {
static_assert(is_object_v<T>);

friend constexpr bool operator==(difference_type_only_iterator<T> i, difference_type_only_sentinel s) noexcept {
return i.ptr_ == s.ptr_end_;
}

friend constexpr ptrdiff_t operator-(difference_type_only_iterator<T> i, difference_type_only_sentinel s) noexcept {
return i.ptr_ - s.ptr_end_;
}

friend constexpr ptrdiff_t operator-(difference_type_only_sentinel s, difference_type_only_iterator<T> i) noexcept {
return s.ptr_end_ - i.ptr_;
}

T* ptr_end_;
};

template <class T>
constexpr bool test_lwg3717() {
remove_cv_t<T> x{};

auto cmv_sr = ranges::subrange(difference_type_only_iterator<T>{&x}, difference_type_only_sentinel<T>{&x + 1})
| views::common;

static_assert(ranges::contiguous_range<decltype(cmv_sr)>);
static_assert(ranges::contiguous_range<const decltype(cmv_sr)>);

assert(ranges::end(cmv_sr) == ranges::begin(cmv_sr) + ptrdiff_t{1});
assert(ranges::end(as_const(cmv_sr)) == ranges::begin(as_const(cmv_sr)) + ptrdiff_t{1});

return true;
}

int main() {
// Get full instantiation coverage
static_assert((test_in<instantiator, const int>(), true));
test_in<instantiator, const int>();

static_assert(test_lwg3717<int>());
static_assert(test_lwg3717<const int>());

assert(test_lwg3717<int>());
assert(test_lwg3717<const int>());
}

0 comments on commit 4483e87

Please sign in to comment.