diff --git a/tests/std/include/test_generator_support.hpp b/tests/std/include/test_generator_support.hpp new file mode 100644 index 0000000000..3fa0b5dfa8 --- /dev/null +++ b/tests/std/include/test_generator_support.hpp @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include +#include +#include +#include +#include + +template +class TestAllocator : public std::allocator { +public: + using value_type = T; + using is_always_equal = AlwaysEqual; + using difference_type = DifferenceType; + using size_type = std::make_unsigned_t; + + TestAllocator() = default; + + template + TestAllocator(const TestAllocator&) {} + + T* allocate(const size_type s) { + return static_cast(::operator new(static_cast(s * sizeof(T)), std::align_val_t{alignof(T)})); + } + + void deallocate(T* const p, size_type s) { + ::operator delete(p, s * sizeof(T), std::align_val_t{alignof(T)}); + } + + operator std::pmr::polymorphic_allocator() const { + return {}; + } + + bool operator==(const TestAllocator&) const = default; +}; + +struct MoveOnly { + MoveOnly() = default; + MoveOnly(const MoveOnly&) = delete; + MoveOnly& operator=(const MoveOnly&) = delete; + MoveOnly(MoveOnly&&) = default; + MoveOnly& operator=(MoveOnly&&) = default; +}; + +static_assert(std::movable); +static_assert(!std::copyable); + +struct Immovable { + Immovable() = default; + Immovable(Immovable&&) = delete; + Immovable& operator=(Immovable&&) = delete; +}; + +static_assert(!std::movable); + +template +class Proxy { +public: + Proxy(const T&) {} +}; + +template +class Proxy { +public: + Proxy(const T& _value_) : value(_value_) {} + + bool operator==(const Proxy& other) const { + return value == other.value; + } + + bool operator==(const T& x) const { + return value == x; + } + +private: + const T& value; +}; diff --git a/tests/std/test.lst b/tests/std/test.lst index 2d7e7cee3a..b368ae753c 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -650,6 +650,7 @@ tests\P2474R2_views_repeat_death tests\P2494R2_move_only_range_adaptors tests\P2502R2_generator tests\P2502R2_generator_death +tests\P2502R2_generator_iterator tests\P2502R2_generator_promise tests\P2505R5_monadic_functions_for_std_expected tests\P2510R3_text_formatting_pointers diff --git a/tests/std/tests/P2502R2_generator/test.cpp b/tests/std/tests/P2502R2_generator/test.cpp index ddc3af912e..2232e29981 100644 --- a/tests/std/tests/P2502R2_generator/test.cpp +++ b/tests/std/tests/P2502R2_generator/test.cpp @@ -33,7 +33,6 @@ constexpr bool static_checks() { // Non-portable size checks static_assert(sizeof(G) == sizeof(void*)); static_assert(sizeof(typename G::promise_type) == 3 * sizeof(void*)); - static_assert(sizeof(ranges::iterator_t) == sizeof(void*)); return true; } diff --git a/tests/std/tests/P2502R2_generator_iterator/env.lst b/tests/std/tests/P2502R2_generator_iterator/env.lst new file mode 100644 index 0000000000..642f530ffa --- /dev/null +++ b/tests/std/tests/P2502R2_generator_iterator/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_latest_matrix.lst diff --git a/tests/std/tests/P2502R2_generator_iterator/test.cpp b/tests/std/tests/P2502R2_generator_iterator/test.cpp new file mode 100644 index 0000000000..6e9954ab45 --- /dev/null +++ b/tests/std/tests/P2502R2_generator_iterator/test.cpp @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include "test_generator_support.hpp" + +using namespace std; + +template +generator generate_zero() { + co_return; +} + +template +using gen_value_t = conditional_t, remove_cvref_t, V>; + +template +using gen_reference_t = conditional_t, Ref&&, Ref>; + +template > + requires default_initializable + && (same_as, ValueType> || constructible_from, ValueType&>) +generator generate_one() { + if constexpr (same_as, ValueType>) { + // non-proxy reference case + if constexpr (is_reference_v) { + remove_reference_t val{}; + co_yield static_cast(val); + } else { + co_yield ValueType{}; + } + } else { + ValueType val{}; + // proxy reference case + if constexpr (is_reference_v) { + // yielding a non-prvalue proxy reference is super weird, but not forbidden + remove_reference_t ref{val}; + co_yield static_cast(ref); + } else { + co_yield Ref{val}; + } + } +} + +#if !(defined(__clang__) && defined(_M_IX86)) // TRANSITION, LLVM-56507 +template +generator generate_one_recursively() { + co_yield ranges::elements_of{generate_zero()}; + co_yield ranges::elements_of{generate_one()}; + co_yield ranges::elements_of{generate_zero()}; +} +#endif // ^^^ no workaround ^^^ + +template +void test_one() { + using Gen = generator; + using Iter = ranges::iterator_t; + static_assert(input_iterator); + static_assert(sizeof(Iter) == sizeof(void*)); // NB: implementation defined + + // Test member types + static_assert(same_as>); + static_assert(same_as); + + // Test copying functions + static_assert(!is_copy_constructible_v); + static_assert(!is_copy_assignable_v); + + { // Test move constructor + Gen g = generate_zero(); + Iter i = g.begin(); + Iter j = move(i); + assert(j == default_sentinel); + + static_assert(is_nothrow_move_constructible_v); + } + + { // Test move assignment operator + Gen g1 = generate_one(); + Iter i = g1.begin(); + Gen g2 = generate_zero(); + Iter j = g2.begin(); + + same_as decltype(auto) k = (i = move(j)); + assert(&k == &i); + assert(k == default_sentinel); + static_assert(is_nothrow_move_assignable_v); + } + + { // Test indirection + auto g = generate_one(); + auto i = g.begin(); + + same_as> decltype(auto) r = *i; + + using ValueType = gen_value_t; + if constexpr (default_initializable && equality_comparable) { + assert(r == ValueType{}); + } + } + +#if !(defined(__clang__) && defined(_M_IX86)) // TRANSITION, LLVM-56507 + { // Test pre-incrementation + auto g = generate_one_recursively(); + auto i = g.begin(); + + same_as decltype(auto) i_ref = ++i; + assert(&i_ref == &i); + assert(i_ref == default_sentinel); + } + + { // Test post-incrementation + auto g = generate_one_recursively(); + auto i = g.begin(); + i++; + assert(i == default_sentinel); + + static_assert(is_void_v); + } +#endif // ^^^ no workaround ^^^ + + { // Test equal operator + auto g1 = generate_one(); + auto i = g1.begin(); + auto g2 = generate_zero(); + auto j = g2.begin(); + + same_as decltype(auto) b1 = i == default_sentinel; + assert(!b1); + + same_as decltype(auto) b2 = default_sentinel == j; + assert(b2); + + same_as decltype(auto) b3 = i != default_sentinel; + assert(b3); + + same_as decltype(auto) b4 = default_sentinel != j; + assert(!b4); + } +} + +template +void test_with_allocator() { + test_one(); + test_one>(); + test_one>(); + test_one>(); +} + +template +void test_with_type() { + test_with_allocator(); + test_with_allocator(); + test_with_allocator(); + test_with_allocator(); + test_with_allocator(); + + test_with_allocator, T>(); + test_with_allocator&, T>(); + test_with_allocator&, T>(); + test_with_allocator&&, T>(); + test_with_allocator&&, T>(); +} + +int main() { + test_with_type(); + test_with_type(); + test_with_type(); + test_with_type(); +} diff --git a/tests/std/tests/P2502R2_generator_promise/test.cpp b/tests/std/tests/P2502R2_generator_promise/test.cpp index 38cccc9ca4..43958421fd 100644 --- a/tests/std/tests/P2502R2_generator_promise/test.cpp +++ b/tests/std/tests/P2502R2_generator_promise/test.cpp @@ -18,37 +18,10 @@ #include #include "range_algorithm_support.hpp" +#include "test_generator_support.hpp" using namespace std; -template -class TestAllocator : public allocator { -public: - using value_type = T; - using is_always_equal = AlwaysEqual; - using difference_type = DifferenceType; - using size_type = make_unsigned_t; - - TestAllocator() = default; - - template - TestAllocator(const TestAllocator&) {} - - T* allocate(const size_type s) { - return static_cast(::operator new(static_cast(s * sizeof(T)), align_val_t{alignof(T)})); - } - - void deallocate(T* const p, size_type s) { - ::operator delete(p, s * sizeof(T), align_val_t{alignof(T)}); - } - - operator pmr::polymorphic_allocator() const { - return {}; - } - - bool operator==(const TestAllocator&) const = default; -}; - template concept HasOperatorNew = requires(Args&&... args) { { Promise::operator new(forward(args)...) } -> same_as; @@ -62,28 +35,6 @@ struct generator_allocator> { using type = Alloc; }; -struct MoveOnly { - MoveOnly(const MoveOnly&) = delete; - MoveOnly& operator=(const MoveOnly&) = delete; - MoveOnly(MoveOnly&&) = default; - MoveOnly& operator=(MoveOnly&&) = default; -}; - -static_assert(movable); -static_assert(!copyable); - -struct Immovable { - Immovable(Immovable&&) = delete; - Immovable& operator=(Immovable&&) = delete; -}; - -static_assert(!movable); - -template -struct Proxy { - Proxy(const T&); // not defined -}; - template requires convertible_to, typename Gen::yielded> void test_yield_elements_of_range(typename Gen::promise_type& p) {