diff --git a/libcxx/test/std/ranges/range.adaptors/range.concat/ctor.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.concat/ctor.view.pass.cpp new file mode 100644 index 000000000000000..327165b5a1fae53 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.concat/ctor.view.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// constexpr filter_view(View, Pred); // explicit since C++23 + +#include +#include +#include + +#include "test_convertible.h" +#include "test_macros.h" +#include "types.h" + +struct Range : std::ranges::view_base { + constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) { } + constexpr int* begin() const { return begin_; } + constexpr int* end() const { return end_; } + +private: + int* begin_; + int* end_; +}; + +struct TrackingRange : TrackInitialization, std::ranges::view_base { + using TrackInitialization::TrackInitialization; + int* begin() const; + int* end() const; +}; + +constexpr bool test() { + int buff[] = {1, 2, 3, 4}; + + // Test explicit syntax + { + Range range(buff, buff + 4); + std::ranges::concat_view view(range); + auto it = view.begin(); + auto end = view.end(); + assert(*it++ == 1); + assert(*it++ == 2); + assert(*it++ == 3); + assert(*it++ == 4); + assert(it == end); + } + + // Make sure we move the view + { + bool moved = false, copied = false; + TrackingRange range(&moved, &copied); + [[maybe_unused]] std::ranges::concat_view view(std::move(range)); + assert(moved); + assert(!copied); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.concat/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.concat/end.pass.cpp new file mode 100644 index 000000000000000..e912c0af9efd2df --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.concat/end.pass.cpp @@ -0,0 +1,129 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// constexpr auto end(); + +#include + +#include +#include +#include +#include +#include "test_iterators.h" + +struct Range : std::ranges::view_base { + using Iterator = forward_iterator; + using Sentinel = sentinel_wrapper; + constexpr explicit Range(int* b, int* e) : begin_(b), end_(e) { } + constexpr Iterator begin() const { return Iterator(begin_); } + constexpr Sentinel end() const { return Sentinel(Iterator(end_)); } + +private: + int* begin_; + int* end_; +}; + +struct CommonRange : std::ranges::view_base { + using Iterator = forward_iterator; + constexpr explicit CommonRange(int* b, int* e) : begin_(b), end_(e) { } + constexpr Iterator begin() const { return Iterator(begin_); } + constexpr Iterator end() const { return Iterator(end_); } + +private: + int* begin_; + int* end_; +}; + +struct NotCommonRange : std::ranges::view_base +{ + constexpr explicit NotCommonRange(){} + char* begin(); + bool end(); +}; + +constexpr bool test() { + int buff[] = {1, 2, 3, 4, 5, 6, 7, 8}; + + // Check the return type of `.end()` + { + Range range(buff, buff + 1); + std::ranges::concat_view view(range); + using FilterSentinel = std::ranges::sentinel_t; + ASSERT_SAME_TYPE(FilterSentinel, decltype(view.end())); + } + + // Check a not a common range + { + Range range(buff, buff + 1); + std::ranges::concat_view view(range); + using FilterSentinel = std::default_sentinel_t; + ASSERT_SAME_TYPE(FilterSentinel, decltype(view.end())); + } + +// // end() on an empty range +// { +// Range range(buff, buff); +// auto pred = [](int) { return true; }; +// std::ranges::filter_view view(range, pred); +// auto end = view.end(); +// assert(base(base(end.base())) == buff); +// } + +// // end() on a 1-element range +// { +// Range range(buff, buff + 1); +// auto pred = [](int) { return true; }; +// std::ranges::filter_view view(range, pred); +// auto end = view.end(); +// assert(base(base(end.base())) == buff + 1); +// static_assert(!std::is_same_v); +// } + +// // end() on a 2-element range +// { +// Range range(buff, buff + 2); +// auto pred = [](int) { return true; }; +// std::ranges::filter_view view(range, pred); +// auto end = view.end(); +// assert(base(base(end.base())) == buff + 2); +// static_assert(!std::is_same_v); +// } + +// // end() on a N-element range +// { +// for (int k = 1; k != 8; ++k) { +// Range range(buff, buff + 8); +// auto pred = [=](int i) { return i == k; }; +// std::ranges::filter_view view(range, pred); +// auto end = view.end(); +// assert(base(base(end.base())) == buff + 8); +// static_assert(!std::is_same_v); +// } +// } + +// // end() on a common_range +// { +// CommonRange range(buff, buff + 8); +// auto pred = [](int i) { return i % 2 == 0; }; +// std::ranges::filter_view view(range, pred); +// auto end = view.end(); +// assert(base(end.base()) == buff + 8); +// static_assert(std::is_same_v); +// } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.concat/types.h b/libcxx/test/std/ranges/range.adaptors/range.concat/types.h new file mode 100644 index 000000000000000..43ee11042acb3d4 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.concat/types.h @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CONCAT_TYPES_H +#define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_CONCAT_TYPES_H + +#include +#include + +struct TrackInitialization { + constexpr explicit TrackInitialization(bool* moved, bool* copied) : moved_(moved), copied_(copied) { } + constexpr TrackInitialization(TrackInitialization const& other) : moved_(other.moved_), copied_(other.copied_) { + *copied_ = true; + } + constexpr TrackInitialization(TrackInitialization&& other) : moved_(other.moved_), copied_(other.copied_) { + *moved_ = true; + } + TrackInitialization& operator=(TrackInitialization const&) = default; + TrackInitialization& operator=(TrackInitialization&&) = default; + bool* moved_; + bool* copied_; +}; + +struct AlwaysTrue { + template + constexpr bool operator()(T const&) const { return true; } +}; + +template +struct minimal_view : std::ranges::view_base { + constexpr explicit minimal_view(Iter it, Sent sent) + : it_(base(std::move(it))) + , sent_(base(std::move(sent))) + { } + + minimal_view(minimal_view&&) = default; + minimal_view& operator=(minimal_view&&) = default; + + constexpr Iter begin() const { return Iter(it_); } + constexpr Sent end() const { return Sent(sent_); } + +private: + decltype(base(std::declval())) it_; + decltype(base(std::declval())) sent_; +}; + +template +class NoexceptIterMoveInputIterator { + int *it_; + +public: + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = int*; + using reference = int&; + + NoexceptIterMoveInputIterator() = default; + explicit constexpr NoexceptIterMoveInputIterator(int *it) : it_(it) {} + + friend constexpr decltype(auto) iter_move(const NoexceptIterMoveInputIterator& it) noexcept(IsNoexcept) { + return std::ranges::iter_move(it.it_); + } + + friend constexpr int* base(const NoexceptIterMoveInputIterator& i) { return i.it_; } + + constexpr reference operator*() const { return *it_; } + constexpr NoexceptIterMoveInputIterator& operator++() {++it_; return *this;} + constexpr NoexceptIterMoveInputIterator operator++(int) + { NoexceptIterMoveInputIterator tmp(*this); ++(*this); return tmp; } +}; + +template +class NoexceptIterSwapInputIterator { + int *it_; + +public: + using iterator_category = std::input_iterator_tag; + using value_type = int; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = int*; + using reference = int&; + + NoexceptIterSwapInputIterator() = default; + explicit constexpr NoexceptIterSwapInputIterator(int *it) : it_(it) {} + + friend constexpr void iter_swap(const NoexceptIterSwapInputIterator& a, const NoexceptIterSwapInputIterator& b) noexcept(IsNoexcept) { + return std::ranges::iter_swap(a.it_, b.it_); + } + + friend constexpr int* base(const NoexceptIterSwapInputIterator& i) { return i.it_; } + + constexpr reference operator*() const { return *it_; } + constexpr NoexceptIterSwapInputIterator& operator++() {++it_; return *this;} + constexpr NoexceptIterSwapInputIterator operator++(int) + { NoexceptIterSwapInputIterator tmp(*this); ++(*this); return tmp; } +}; + +#endif // TEST_STD_RANGES_RANGE_ADAPTORS_CONCAT_FILTER_TYPES_H