Skip to content

Commit

Permalink
[libc++] Fix LWG3533 "Make base() const& consistent..."
Browse files Browse the repository at this point in the history
Fixed in counted_iterator and transform_view::iterator.
The LWG issue also affected elements_view::iterator, but we haven't
implemented that one yet, and whoever does implement it will get
the fix for free if they just follow the working draft's wording.

Drive-by stop calling `.base()` on test iterators in the test,
and improve the transform_view::iterator/sentinel tests.

Differential Revision: https://reviews.llvm.org/D117329
  • Loading branch information
Arthur O'Dwyer committed Jan 27, 2022
1 parent c99a585 commit 4b3e0d2
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 57 deletions.
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2bIssues.csv
Expand Up @@ -81,7 +81,7 @@
`3529 <https://wg21.link/LWG3529>`__,"``priority_queue(first, last)`` should construct ``c`` with ``(first, last)``","June 2021","",""
`3530 <https://wg21.link/LWG3530>`__,"``BUILTIN-PTR-MEOW`` should not opt the type out of syntactic checks","June 2021","",""
`3532 <https://wg21.link/LWG3532>`__,"``split_view<V, P>::inner-iterator<true>::operator++(int)`` should depend on ``Base``","June 2021","","","|ranges|"
`3533 <https://wg21.link/LWG3533>`__,"Make ``base() const &`` consistent across iterator wrappers that supports ``input_iterators``","June 2021","","","|ranges|"
`3533 <https://wg21.link/LWG3533>`__,"Make ``base() const &`` consistent across iterator wrappers that supports ``input_iterators``","June 2021","|Complete|","14.0","|ranges|"
`3536 <https://wg21.link/LWG3536>`__,"Should ``chrono::from_stream()`` assign zero to duration for failure?","June 2021","","","|chrono|"
`3539 <https://wg21.link/LWG3539>`__,"``format_to`` must not copy models of ``output_iterator<const charT&>``","June 2021","","","|format|"
`3540 <https://wg21.link/LWG3540>`__,"§[format.arg] There should be no const in ``basic_format_arg(const T* p)``","June 2021","|Complete|","14.0","|format|"
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__iterator/counted_iterator.h
Expand Up @@ -96,7 +96,7 @@ class counted_iterator
}

_LIBCPP_HIDE_FROM_ABI
constexpr const _Iter& base() const& { return __current_; }
constexpr const _Iter& base() const& noexcept { return __current_; }

_LIBCPP_HIDE_FROM_ABI
constexpr _Iter base() && { return _VSTD::move(__current_); }
Expand Down
4 changes: 1 addition & 3 deletions libcxx/include/__ranges/transform_view.h
Expand Up @@ -195,9 +195,7 @@ class transform_view<_View, _Fn>::__iterator
: __parent_(__i.__parent_), __current_(_VSTD::move(__i.__current_)) {}

_LIBCPP_HIDE_FROM_ABI
constexpr iterator_t<_Base> base() const&
requires copyable<iterator_t<_Base>>
{
constexpr const iterator_t<_Base>& base() const& noexcept {
return __current_;
}

Expand Down
Expand Up @@ -32,26 +32,27 @@ constexpr bool test() {

{
std::counted_iterator iter(cpp20_input_iterator<int*>{buffer}, 8);
assert(iter.base().base() == buffer);
assert(std::move(iter).base().base() == buffer);
assert(base(iter.base()) == buffer);
assert(base(std::move(iter).base()) == buffer);

ASSERT_NOEXCEPT(iter.base());
ASSERT_SAME_TYPE(decltype(iter.base()), const cpp20_input_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(std::move(iter).base()), cpp20_input_iterator<int*>);
}

{
std::counted_iterator iter(forward_iterator<int*>{buffer}, 8);
assert(iter.base() == forward_iterator<int*>{buffer});
assert(std::move(iter).base() == forward_iterator<int*>{buffer});
assert(base(iter.base()) == buffer);
assert(base(std::move(iter).base()) == buffer);

ASSERT_SAME_TYPE(decltype(iter.base()), const forward_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(std::move(iter).base()), forward_iterator<int*>);
}

{
std::counted_iterator iter(contiguous_iterator<int*>{buffer}, 8);
assert(iter.base() == contiguous_iterator<int*>{buffer});
assert(std::move(iter).base() == contiguous_iterator<int*>{buffer});
assert(base(iter.base()) == buffer);
assert(base(std::move(iter).base()) == buffer);

ASSERT_SAME_TYPE(decltype(iter.base()), const contiguous_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(std::move(iter).base()), contiguous_iterator<int*>);
Expand All @@ -68,26 +69,26 @@ constexpr bool test() {

{
const std::counted_iterator iter(cpp20_input_iterator<int*>{buffer}, 8);
assert(iter.base().base() == buffer);
assert(std::move(iter).base().base() == buffer);
assert(base(iter.base()) == buffer);
assert(base(std::move(iter).base()) == buffer);

ASSERT_SAME_TYPE(decltype(iter.base()), const cpp20_input_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(std::move(iter).base()), const cpp20_input_iterator<int*>&);
}

{
const std::counted_iterator iter(forward_iterator<int*>{buffer}, 7);
assert(iter.base() == forward_iterator<int*>{buffer});
assert(std::move(iter).base() == forward_iterator<int*>{buffer});
assert(base(iter.base()) == buffer);
assert(base(std::move(iter).base()) == buffer);

ASSERT_SAME_TYPE(decltype(iter.base()), const forward_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(std::move(iter).base()), const forward_iterator<int*>&);
}

{
const std::counted_iterator iter(contiguous_iterator<int*>{buffer}, 6);
assert(iter.base() == contiguous_iterator<int*>{buffer});
assert(std::move(iter).base() == contiguous_iterator<int*>{buffer});
assert(base(iter.base()) == buffer);
assert(base(std::move(iter).base()) == buffer);

ASSERT_SAME_TYPE(decltype(iter.base()), const contiguous_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(std::move(iter).base()), const contiguous_iterator<int*>&);
Expand Down
79 changes: 58 additions & 21 deletions libcxx/test/std/ranges/range.adaptors/range.transform/end.pass.cpp
Expand Up @@ -32,50 +32,87 @@ constexpr bool test() {
using TransformView = std::ranges::transform_view<ForwardView, PlusOneMutable>;
static_assert(std::ranges::common_range<TransformView>);
TransformView tv;
auto end = tv.end();
ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t<ForwardView>);
assert(base(end.base()) == globalBuff + 8);
auto it = tv.end();
using It = decltype(it);
ASSERT_SAME_TYPE(decltype(static_cast<It&>(it).base()), const forward_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(static_cast<It&&>(it).base()), forward_iterator<int*>);
ASSERT_SAME_TYPE(decltype(static_cast<const It&>(it).base()), const forward_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(static_cast<const It&&>(it).base()), const forward_iterator<int*>&);
assert(base(it.base()) == globalBuff + 8);
assert(base(std::move(it).base()) == globalBuff + 8);
static_assert(!HasConstQualifiedEnd<TransformView>);
}
{
using TransformView = std::ranges::transform_view<InputView, PlusOneMutable>;
static_assert(!std::ranges::common_range<TransformView>);
TransformView tv;
auto end = tv.end();
ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t<InputView>);
assert(base(base(end.base())) == globalBuff + 8);
auto sent = tv.end();
using Sent = decltype(sent);
ASSERT_SAME_TYPE(decltype(static_cast<Sent&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<Sent&&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<const Sent&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<const Sent&&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
assert(base(base(sent.base())) == globalBuff + 8);
assert(base(base(std::move(sent).base())) == globalBuff + 8);
static_assert(!HasConstQualifiedEnd<TransformView>);
}
{
using TransformView = std::ranges::transform_view<InputView, PlusOne>;
static_assert(!std::ranges::common_range<TransformView>);
TransformView tv;
auto end = tv.end();
ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t<InputView>);
assert(base(base(end.base())) == globalBuff + 8);
auto cend = std::as_const(tv).end();
ASSERT_SAME_TYPE(decltype(cend.base()), std::ranges::sentinel_t<const InputView>);
assert(base(base(cend.base())) == globalBuff + 8);
auto sent = tv.end();
using Sent = decltype(sent);
ASSERT_SAME_TYPE(decltype(static_cast<Sent&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<Sent&&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<const Sent&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<const Sent&&>(sent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
assert(base(base(sent.base())) == globalBuff + 8);
assert(base(base(std::move(sent).base())) == globalBuff + 8);

auto csent = std::as_const(tv).end();
using CSent = decltype(csent);
ASSERT_SAME_TYPE(decltype(static_cast<CSent&>(csent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<CSent&&>(csent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<const CSent&>(csent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
ASSERT_SAME_TYPE(decltype(static_cast<const CSent&&>(csent).base()), sentinel_wrapper<cpp20_input_iterator<int*>>);
assert(base(base(csent.base())) == globalBuff + 8);
assert(base(base(std::move(csent).base())) == globalBuff + 8);
}
{
using TransformView = std::ranges::transform_view<MoveOnlyView, PlusOneMutable>;
static_assert(std::ranges::common_range<TransformView>);
TransformView tv;
auto end = tv.end();
ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t<MoveOnlyView>);
assert(end.base() == globalBuff + 8);
auto it = tv.end();
using It = decltype(it);
ASSERT_SAME_TYPE(decltype(static_cast<It&>(it).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<It&&>(it).base()), int*);
ASSERT_SAME_TYPE(decltype(static_cast<const It&>(it).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<const It&&>(it).base()), int* const&);
assert(base(it.base()) == globalBuff + 8);
assert(base(std::move(it).base()) == globalBuff + 8);
static_assert(!HasConstQualifiedEnd<TransformView>);
}
{
using TransformView = std::ranges::transform_view<MoveOnlyView, PlusOne>;
static_assert(std::ranges::common_range<TransformView>);
TransformView tv;
auto end = tv.end();
ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t<MoveOnlyView>);
assert(end.base() == globalBuff + 8);
auto cend = std::as_const(tv).end();
ASSERT_SAME_TYPE(decltype(cend.base()), std::ranges::sentinel_t<const MoveOnlyView>);
assert(cend.base() == globalBuff + 8);
auto it = tv.end();
using It = decltype(it);
ASSERT_SAME_TYPE(decltype(static_cast<It&>(it).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<It&&>(it).base()), int*);
ASSERT_SAME_TYPE(decltype(static_cast<const It&>(it).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<const It&&>(it).base()), int* const&);
assert(base(it.base()) == globalBuff + 8);
assert(base(std::move(it).base()) == globalBuff + 8);

auto csent = std::as_const(tv).end();
using CSent = decltype(csent);
ASSERT_SAME_TYPE(decltype(static_cast<CSent&>(csent).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<CSent&&>(csent).base()), int*);
ASSERT_SAME_TYPE(decltype(static_cast<const CSent&>(csent).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<const CSent&&>(csent).base()), int* const&);
assert(base(base(csent.base())) == globalBuff + 8);
assert(base(base(std::move(csent).base())) == globalBuff + 8);
}
return true;
}
Expand Down
Expand Up @@ -17,31 +17,32 @@
#include "test_macros.h"
#include "../types.h"

template<class It>
concept HasBase = requires(It it) {
static_cast<It>(it).base();
};

constexpr bool test() {
{
using TransformView = std::ranges::transform_view<MoveOnlyView, PlusOneMutable>;
TransformView tv;
auto begin = tv.begin();
ASSERT_SAME_TYPE(decltype(begin.base()), int*);
assert(begin.base() == globalBuff);
ASSERT_SAME_TYPE(decltype(std::move(begin).base()), int*);
assert(std::move(begin).base() == globalBuff);
auto it = tv.begin();
using It = decltype(it);
ASSERT_SAME_TYPE(decltype(static_cast<It&>(it).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<It&&>(it).base()), int*);
ASSERT_SAME_TYPE(decltype(static_cast<const It&>(it).base()), int* const&);
ASSERT_SAME_TYPE(decltype(static_cast<const It&&>(it).base()), int* const&);
ASSERT_NOEXCEPT(it.base());
assert(base(it.base()) == globalBuff);
assert(base(std::move(it).base()) == globalBuff);
}
{
using TransformView = std::ranges::transform_view<InputView, PlusOneMutable>;
TransformView tv;
auto begin = tv.begin();
static_assert(!HasBase<decltype(begin)&>);
static_assert(HasBase<decltype(begin)&&>);
static_assert(!HasBase<const decltype(begin)&>);
static_assert(!HasBase<const decltype(begin)&&>);
std::same_as<cpp20_input_iterator<int *>> auto it = std::move(begin).base();
assert(base(it) == globalBuff);
auto it = tv.begin();
using It = decltype(it);
ASSERT_SAME_TYPE(decltype(static_cast<It&>(it).base()), const cpp20_input_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(static_cast<It&&>(it).base()), cpp20_input_iterator<int*>);
ASSERT_SAME_TYPE(decltype(static_cast<const It&>(it).base()), const cpp20_input_iterator<int*>&);
ASSERT_SAME_TYPE(decltype(static_cast<const It&&>(it).base()), const cpp20_input_iterator<int*>&);
ASSERT_NOEXCEPT(it.base());
assert(base(it.base()) == globalBuff);
assert(base(std::move(it).base()) == globalBuff);
}
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions libcxx/test/std/ranges/range.adaptors/range.transform/types.h
Expand Up @@ -46,8 +46,8 @@ struct ForwardView : std::ranges::view_base {
constexpr explicit ForwardView(int* ptr = globalBuff) : ptr_(ptr) {}
constexpr ForwardView(ForwardView&&) = default;
constexpr ForwardView& operator=(ForwardView&&) = default;
constexpr auto begin() const { return ForwardIter(ptr_); }
constexpr auto end() const { return ForwardIter(ptr_ + 8); }
constexpr auto begin() const { return forward_iterator<int*>(ptr_); }
constexpr auto end() const { return forward_iterator<int*>(ptr_ + 8); }
};
static_assert(std::ranges::view<ForwardView>);
static_assert(std::ranges::forward_range<ForwardView>);
Expand Down

0 comments on commit 4b3e0d2

Please sign in to comment.