//===----------------------------------------------------------------------===// // // 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 // // template // requires invocable && indirectly_writable> // constexpr O generate_n(O first, iter_difference_t n, F gen); // Since C++20 #include #include #include #include #include #include "almost_satisfies_types.h" #include "test_iterators.h" struct IntGen { int operator()() const; }; struct UncopyableGen { UncopyableGen(const UncopyableGen&) = delete; int operator()() const; }; static_assert(!std::copy_constructible); static_assert(std::invocable); struct UninvocableGen { }; static_assert(std::copy_constructible); static_assert(!std::invocable); struct IntPtrGen { int* operator()() const; }; // Test type constraints. // ====================================================== template concept HasGenerateNIter = requires(Iter&& iter, Gen&& gen) { std::ranges::generate_n(std::forward(iter), 0, std::forward(gen)); }; static_assert(HasGenerateNIter); // !input_or_output_iterator static_assert(!HasGenerateNIter); // !copy_constructible static_assert(!HasGenerateNIter); // !invocable static_assert(!HasGenerateNIter); // !indirectly_writable> static_assert(!HasGenerateNIter); template constexpr void test_one(std::array in, std::size_t n, Gen gen, std::array expected) { assert(n <= N); auto begin = Iter(in.data()); std::same_as decltype(auto) result = std::ranges::generate_n(std::move(begin), n, gen); assert(base(result) == in.data() + n); assert(in == expected); } template constexpr void test_iter() { auto gen = [ctr = 1] () mutable { return ctr++; }; // Empty sequence. test_one({}, 0, gen, {}); // 1-element sequence, n = 0. test_one(std::array{-10}, 0, gen, {-10}); // 1-element sequence, n = 1. test_one(std::array{-10}, 1, gen, {1}); // Longer sequence, n = 3. test_one(std::array{-10, -20, -30, -40, -50}, 3, gen, {1, 2, 3, -40, -50}); // Longer sequence, n = 5. test_one(std::array{}, 5, gen, {1, 2, 3, 4, 5}); } constexpr void test_iterators() { test_iter>(); test_iter>(); test_iter>(); test_iter>(); test_iter>(); test_iter>(); test_iter>(); test_iter>(); test_iter(); } constexpr bool test() { test_iterators(); { // Complexity: exactly N evaluations of `gen()` and assignments. struct AssignedOnce { bool assigned = false; constexpr AssignedOnce& operator=(const AssignedOnce&) { assert(!assigned); assigned = true; return *this; } }; int gen_invocations = 0; auto gen = [&gen_invocations] { ++gen_invocations; return AssignedOnce(); }; constexpr std::size_t N1 = 10; constexpr std::size_t N2 = N1 / 2; std::array in; auto result = std::ranges::generate_n(in.begin(), N2, gen); assert(std::ranges::all_of(std::ranges::subrange(in.begin(), result), &AssignedOnce::assigned)); assert(std::ranges::none_of(std::ranges::subrange(result, in.end()), &AssignedOnce::assigned)); assert(gen_invocations == N2); } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }