Skip to content

Commit

Permalink
[libc++] Robust against C++20-hostile iterators
Browse files Browse the repository at this point in the history
Reviewed By: ldionne, #libc, EricWF

Spies: EricWF, libcxx-commits, mgrang

Differential Revision: https://reviews.llvm.org/D127669
  • Loading branch information
philnik777 committed Jun 16, 2022
1 parent e35096a commit a4c8056
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// Check that all STL classic algorithms can be instantiated with a C++20-hostile iterator

// ADDITIONAL_COMPILE_FLAGS: -Wno-ambiguous-reversed-operator

#include <algorithm>
#include <functional>
#include <random>

#include "test_macros.h"

template <class Sub, class Iterator>
struct IteratorAdaptorBase {
using OutTraits = std::iterator_traits<Iterator>;
using iterator_category = typename OutTraits::iterator_category;
using value_type = typename OutTraits::value_type;
using pointer = typename OutTraits::pointer;
using reference = typename OutTraits::reference;
using difference_type = typename OutTraits::difference_type;

IteratorAdaptorBase() {}
IteratorAdaptorBase(Iterator) {}

Sub& sub() { return static_cast<Sub&>(*this); }
const Sub& sub() const { return static_cast<Sub&>(*this); }

const Iterator& base() const { return it_; }

reference get() const { return *it_; }
reference operator*() const { return *it_; }
pointer operator->() const { return it_; }
reference operator[](difference_type) const { return *it_; }

Sub& operator++() { return static_cast<Sub&>(*this); }
Sub& operator--() { return static_cast<Sub&>(*this); }
Sub operator++(int) { return static_cast<Sub&>(*this); }
Sub operator--(int) { return static_cast<Sub&>(*this); }

Sub& operator+=(difference_type) { return static_cast<Sub&>(*this); }
Sub& operator-=(difference_type) { return static_cast<Sub&>(*this); }
bool operator==(Sub) const { return false; }
bool operator!=(Sub) const { return false; }
bool operator==(Iterator b) const { return *this == Sub(b); }
bool operator!=(Iterator b) const { return *this != Sub(b); }

friend Sub operator+(Sub, difference_type) { return Sub(); }
friend Sub operator+(difference_type, Sub) { return Sub(); }
friend Sub operator-(Sub, difference_type) { return Sub(); }
friend difference_type operator-(Sub, Sub) { return 0; }

friend bool operator<(Sub, Sub) { return false; }
friend bool operator>(Sub, Sub) { return false; }
friend bool operator<=(Sub, Sub) { return false; }
friend bool operator>=(Sub, Sub) { return false; }

private:
Iterator it_;
};

template <typename It>
struct Cpp20HostileIterator
: IteratorAdaptorBase<Cpp20HostileIterator<It>, It> {
Cpp20HostileIterator() {}
Cpp20HostileIterator(It) {}
};

struct Pred {
bool operator()(int, int) { return false; }
bool operator()(int) { return false; }
int operator()() { return 0; }
};

void test() {
Cpp20HostileIterator<int*> it;
Pred pred;
std::mt19937_64 rng;

(void) std::adjacent_find(it, it);
(void) std::adjacent_find(it, it, pred);
(void) std::all_of(it, it, pred);
(void) std::any_of(it, it, pred);
(void) std::binary_search(it, it, 0);
(void) std::binary_search(it, it, 0, pred);
(void) std::copy_if(it, it, it, pred);
(void) std::copy_n(it, 0, it);
(void) std::copy(it, it, it);
(void) std::count_if(it, it, pred);
(void) std::count(it, it, 0);
(void) std::equal_range(it, it, 0);
(void) std::equal_range(it, it, 0, pred);
(void) std::equal(it, it, it);
(void) std::equal(it, it, it, pred);
#if TEST_STD_VER > 11
(void) std::equal(it, it, it, it);
(void) std::equal(it, it, it, it, pred);
#endif
(void) std::fill_n(it, 0, 0);
(void) std::fill(it, it, 0);
(void) std::find_end(it, it, it, it);
(void) std::find_end(it, it, it, it, pred);
(void) std::find_first_of(it, it, it, it);
(void) std::find_first_of(it, it, it, it, pred);
(void) std::find_if_not(it, it, pred);
(void) std::find_if(it, it, pred);
(void) std::find(it, it, 0);
#if TEST_STD_VER > 14
(void) std::for_each_n(it, 0, pred);
#endif
(void) std::for_each(it, it, pred);
(void) std::generate_n(it, 0, pred);
(void) std::generate(it, it, pred);
(void) std::includes(it, it, it, it);
(void) std::includes(it, it, it, it, pred);
// (void) std::inplace_merge(it, it, it);
// (void) std::inplace_merge(it, it, it, pred);
(void) std::is_heap_until(it, it);
(void) std::is_heap_until(it, it, pred);
(void) std::is_heap(it, it);
(void) std::is_heap(it, it, pred);
(void) std::is_partitioned(it, it, pred);
(void) std::is_permutation(it, it, it);
(void) std::is_permutation(it, it, it, pred);
#if TEST_STD_VER > 11
(void) std::is_permutation(it, it, it, it);
(void) std::is_permutation(it, it, it, it, pred);
#endif
(void) std::is_sorted_until(it, it);
(void) std::is_sorted_until(it, it, pred);
(void) std::is_sorted(it, it);
(void) std::is_sorted(it, it, pred);
(void) std::lexicographical_compare(it, it, it, it);
(void) std::lexicographical_compare(it, it, it, it, pred);
(void) std::lower_bound(it, it, 0);
(void) std::lower_bound(it, it, 0, pred);
(void) std::make_heap(it, it);
(void) std::make_heap(it, it, pred);
(void) std::max_element(it, it);
(void) std::max_element(it, it, pred);
(void) std::merge(it, it, it, it, it);
(void) std::merge(it, it, it, it, it, pred);
(void) std::min_element(it, it);
(void) std::min_element(it, it, pred);
(void) std::minmax_element(it, it);
(void) std::minmax_element(it, it, pred);
(void) std::mismatch(it, it, it);
(void) std::mismatch(it, it, it, pred);
(void) std::move_backward(it, it, it);
(void) std::move(it, it, it);
(void) std::next_permutation(it, it);
(void) std::next_permutation(it, it, pred);
(void) std::none_of(it, it, pred);
(void) std::nth_element(it, it, it);
(void) std::nth_element(it, it, it, pred);
(void) std::partial_sort_copy(it, it, it, it);
(void) std::partial_sort_copy(it, it, it, it, pred);
(void) std::partial_sort(it, it, it);
(void) std::partial_sort(it, it, it, pred);
(void) std::partition_copy(it, it, it, it, pred);
(void) std::partition_point(it, it, pred);
(void) std::partition(it, it, pred);
(void) std::pop_heap(it, it);
(void) std::pop_heap(it, it, pred);
(void) std::prev_permutation(it, it);
(void) std::prev_permutation(it, it, pred);
(void) std::push_heap(it, it);
(void) std::push_heap(it, it, pred);
(void) std::remove_copy_if(it, it, it, pred);
(void) std::remove_copy(it, it, it, 0);
(void) std::remove_if(it, it, pred);
(void) std::remove(it, it, 0);
(void) std::replace_copy_if(it, it, it, pred, 0);
(void) std::replace_copy(it, it, it, 0, 0);
(void) std::replace_if(it, it, pred, 0);
(void) std::replace(it, it, 0, 0);
(void) std::reverse_copy(it, it, it);
(void) std::reverse(it, it);
(void) std::rotate_copy(it, it, it, it);
(void) std::rotate(it, it, it);
#if TEST_STD_VER > 14
(void) std::sample(it, it, it, 0, rng);
#endif
(void) std::search(it, it, it, it);
(void) std::search(it, it, it, it, pred);
#if TEST_STD_VER > 14
(void) std::search(it, it, std::default_searcher<Cpp20HostileIterator<int*>>(it, it));
#endif
(void) std::set_difference(it, it, it, it, it);
(void) std::set_difference(it, it, it, it, it, pred);
(void) std::set_intersection(it, it, it, it, it);
(void) std::set_intersection(it, it, it, it, it, pred);
(void) std::set_symmetric_difference(it, it, it, it, it);
(void) std::set_symmetric_difference(it, it, it, it, it, pred);
(void) std::set_union(it, it, it, it, it);
(void) std::set_union(it, it, it, it, it, pred);
#if TEST_STD_VER > 17
(void) std::shift_left(it, it, 0);
(void) std::shift_right(it, it, 0);
#endif
(void) std::shuffle(it, it, rng);
(void) std::sort_heap(it, it);
(void) std::sort_heap(it, it, pred);
(void) std::sort(it, it);
(void) std::sort(it, it, pred);
(void) std::stable_partition(it, it, pred);
// (void) std::stable_sort(it, it);
(void) std::swap_ranges(it, it, it);
(void) std::transform(it, it, it, pred);
(void) std::transform(it, it, it, it, pred);
(void) std::unique_copy(it, it, it);
(void) std::unique(it, it);
(void) std::upper_bound(it, it, 0);
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,6 @@ test()
test(Iter(v.data()), Iter(v.data()+v.size()), x);
}

void test_instantiation() {
auto iter = Cpp20HostileIterator<int*>();
std::lower_bound(iter, iter, 0);
}

int main(int, char**)
{
int d[] = {0, 1, 2, 3};
Expand Down
55 changes: 0 additions & 55 deletions libcxx/test/support/test_iterators.h
Original file line number Diff line number Diff line change
Expand Up @@ -794,59 +794,4 @@ class Iterator {

#endif // TEST_STD_VER > 17

template <class Sub, class Iterator>
struct IteratorAdaptorBase {
using OutTraits = std::iterator_traits<Iterator>;
using iterator_category = typename OutTraits::iterator_category;
using value_type = typename OutTraits::value_type;
using pointer = typename OutTraits::pointer;
using reference = typename OutTraits::reference;
using difference_type = typename OutTraits::difference_type;

IteratorAdaptorBase() {}
IteratorAdaptorBase(Iterator) {}

Sub& sub() { return static_cast<Sub&>(*this); }
const Sub& sub() const { return static_cast<Sub&>(*this); }

const Iterator& base() const { return it_; }

reference get() const { return *it_; }
reference operator*() const { return *it_; }
pointer operator->() const { return it_; }
reference operator[](difference_type) const { return *it_; }

Sub& operator++() { return static_cast<Sub&>(*this); }
Sub& operator--() { return static_cast<Sub&>(*this); }
Sub operator++(int) { return static_cast<Sub&>(*this); }
Sub operator--(int) { return static_cast<Sub&>(*this); }

Sub& operator+=(difference_type) { return static_cast<Sub&>(*this); }
Sub& operator-=(difference_type) { return static_cast<Sub&>(*this); }
bool operator==(Sub) const { return false; }
bool operator!=(Sub) const { return false; }
bool operator==(Iterator b) const { return *this == Sub(b); }
bool operator!=(Iterator b) const { return *this != Sub(b); }

friend Sub operator+(Sub, difference_type) { Sub(); }
friend Sub operator+(difference_type, Sub) { Sub(); }
friend Sub operator-(Sub, difference_type) { Sub(); }
friend difference_type operator-(Sub, Sub) { return 0; }

friend bool operator<(Sub, Sub) { return false; }
friend bool operator>(Sub, Sub) { return false; }
friend bool operator<=(Sub, Sub) { return false; }
friend bool operator>=(Sub, Sub) { return false; }

private:
Iterator it_;
};

template <typename It>
struct Cpp20HostileIterator
: IteratorAdaptorBase<Cpp20HostileIterator<It>, It> {
Cpp20HostileIterator() {}
Cpp20HostileIterator(It it);
};

#endif // SUPPORT_TEST_ITERATORS_H

0 comments on commit a4c8056

Please sign in to comment.