Skip to content

Commit

Permalink
Fix basic_iterator for output cursors that don't provide post_increme…
Browse files Browse the repository at this point in the history
…nt().

* Added a post-increment operator overload to basic_iterator that returns a
  self reference for non-input cursors that don't provide post_increment().

* Added a test to validate that output iterators that hold state are correctly
  updated for post-increment dereference assignment.

* Updated a static_assert for ostream_iterator to reflect that post-increment
  now returns a self reference.  This is consistent with the implementation of
  ostream_iterator in libstdc++.
  • Loading branch information
tahonermann committed Dec 7, 2016
1 parent b704dad commit 862126a
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
9 changes: 9 additions & 0 deletions include/stl2/detail/iterator/basic_iterator.hpp
Expand Up @@ -726,6 +726,15 @@ STL2_OPEN_NAMESPACE {
++*this;
}

constexpr basic_iterator& operator++(int) &
noexcept(noexcept(++declval<basic_iterator&>()))
requires !cursor::Input<C>() &&
!cursor::PostIncrement<C>()
{
++*this;
return *this;
}

constexpr decltype(auto) operator++(int) &
noexcept(noexcept(declval<C&>().post_increment()))
requires cursor::PostIncrement<C>()
Expand Down
55 changes: 54 additions & 1 deletion test/iterator/basic_iterator.cpp
Expand Up @@ -310,6 +310,30 @@ std::ostream& operator<<(std::ostream& os, R&& rng) {
return os;
}

template <stl2::Iterator I>
class output_cursor {
public:
struct mixin : protected stl2::detail::ebo_box<output_cursor> {
mixin() = default;
using mixin::ebo_box::ebo_box;
};

output_cursor() = default;
constexpr output_cursor(I i) noexcept
: i_{i} {}

template <class T>
requires stl2::OutputIterator<I, const T&>()
constexpr void write(const T& t) noexcept {
*i_++ = t;
}

private:
I i_;
};
template <stl2::Iterator I>
using output_iterator = stl2::basic_iterator<output_cursor<I>>;

void test_fl() {
std::cout << "test_fl:\n";
::forward_list<int> list = {0, 1, 2, 3};
Expand Down Expand Up @@ -484,7 +508,7 @@ void test_counted() {
CHECK((one <= three));
CHECK(!(one >= three));
}
}
}

void test_always() {
std::cout << "test_always:\n";
Expand Down Expand Up @@ -598,6 +622,34 @@ void test_proxy_array() {
CHECK(a[3] == 1);
}

void test_output() {
std::cout << "test_output:\n";

auto vec = std::vector<int>{0,0,0};
auto wi = vec.begin();

using I = ::output_iterator<decltype(wi)>;
static_assert(stl2::models::WeaklyIncrementable<I>);
static_assert(!stl2::models::Incrementable<I>);
static_assert(!stl2::models::Decrementable<I>);
static_assert(!stl2::models::Readable<I>);
static_assert(stl2::models::Writable<I, int>);
static_assert(stl2::models::DefaultConstructible<I>);
static_assert(stl2::models::Copyable<I>);
static_assert(stl2::models::Semiregular<I>);
static_assert(stl2::models::Iterator<I>);
static_assert(!stl2::models::InputIterator<I>);
static_assert(stl2::models::OutputIterator<I, int>);

I i{wi};
*i++ = 1;
*i++ = 2;
*i++ = 3;
CHECK(vec[0] == 1);
CHECK(vec[1] == 2);
CHECK(vec[2] == 3);
}

int main() {
test_rv();
test_fl();
Expand All @@ -606,5 +658,6 @@ int main() {
test_always();
test_back_inserter();
test_proxy_array();
test_output();
return ::test_result();
}
2 changes: 1 addition & 1 deletion test/iterator/ostream_iterator.cpp
Expand Up @@ -49,7 +49,7 @@ int main() {
static_assert(models::Same<I&, decltype(*i)>);
static_assert(models::Same<I&, decltype(*i = 42)>);
static_assert(models::Same<I&, decltype(++i)>);
static_assert(models::Same<I, decltype(i++)>);
static_assert(models::Same<I&, decltype(i++)>);

static_assert(noexcept(I{}));
static_assert(noexcept(I{ss}));
Expand Down

0 comments on commit 862126a

Please sign in to comment.