1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10// UNSUPPORTED: no-exceptions
11
12// If the invocation of any non-const member function of `iterator` exits via an
13// exception, the iterator acquires a singular value.
14
15#include <ranges>
16
17#include <tuple>
18
19#include "../types.h"
20
21struct ThrowOnIncrementIterator {
22 int* it_;
23
24 using value_type = int;
25 using difference_type = std::intptr_t;
26 using iterator_concept = std::input_iterator_tag;
27
28 ThrowOnIncrementIterator() = default;
29 explicit ThrowOnIncrementIterator(int* it) : it_(it) {}
30
31 ThrowOnIncrementIterator& operator++() {
32 ++it_;
33 throw 5;
34 return *this;
35 }
36 void operator++(int) { ++it_; }
37
38 int& operator*() const { return *it_; }
39
40 friend bool operator==(ThrowOnIncrementIterator const&, ThrowOnIncrementIterator const&) = default;
41};
42
43struct ThrowOnIncrementView : IntBufferView {
44 ThrowOnIncrementIterator begin() const { return ThrowOnIncrementIterator{buffer_}; }
45 ThrowOnIncrementIterator end() const { return ThrowOnIncrementIterator{buffer_ + size_}; }
46};
47
48// Cannot run the test at compile time because it is not allowed to throw exceptions
49void test() {
50 int buffer[] = {1, 2, 3};
51 {
52 // zip iterator should be able to be destroyed after member function throws
53 std::ranges::zip_view v{ThrowOnIncrementView{buffer}};
54 auto it = v.begin();
55 try {
56 ++it;
57 assert(false); // should not be reached as the above expression should throw.
58 } catch (int e) {
59 assert(e == 5);
60 }
61 }
62
63 {
64 // zip iterator should be able to be assigned after member function throws
65 std::ranges::zip_view v{ThrowOnIncrementView{buffer}};
66 auto it = v.begin();
67 try {
68 ++it;
69 assert(false); // should not be reached as the above expression should throw.
70 } catch (int e) {
71 assert(e == 5);
72 }
73 it = v.begin();
74 auto [x] = *it;
75 assert(x == 1);
76 }
77}
78
79int main(int, char**) {
80 test();
81
82 return 0;
83}
84

source code of libcxx/test/std/ranges/range.adaptors/range.zip/iterator/singular.pass.cpp