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
10
11// <memory>
12//
13// namespace ranges {
14// template<nothrow-input-iterator InputIterator>
15// requires destructible<iter_value_t<InputIterator>>
16// constexpr InputIterator destroy_n(InputIterator first, iter_difference_t<InputIterator> n) noexcept; // since C++20
17// }
18
19#include <cassert>
20#include <memory>
21#include <ranges>
22#include <type_traits>
23
24#include "test_iterators.h"
25#include "test_macros.h"
26
27// TODO(varconst): consolidate the ADL checks into a single file.
28// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
29// implementations are allowed to use a different mechanism to achieve this effect, so this check is
30// libc++-specific.
31LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::destroy_n)>);
32
33struct NotNothrowDtrable {
34 ~NotNothrowDtrable() noexcept(false) {}
35};
36static_assert(!std::is_invocable_v<decltype(std::ranges::destroy_n), NotNothrowDtrable*, int>);
37
38struct Counted {
39 int& count;
40
41 constexpr Counted(int& count_ref) : count(count_ref) { ++count; }
42 constexpr Counted(const Counted& rhs) : count(rhs.count) { ++count; }
43 constexpr ~Counted() { --count; }
44
45 friend void operator&(Counted) = delete;
46};
47
48template <class Iterator>
49constexpr void test() {
50 {
51 constexpr int N = 5;
52 std::allocator<Counted> alloc;
53 using Traits = std::allocator_traits<decltype(alloc)>;
54 int counter = 0;
55
56 Counted* out = Traits::allocate(a&: alloc, n: N);
57 for (int i = 0; i != N; ++i) {
58 Traits::construct(a&: alloc, p: out + i, args&: counter);
59 }
60 assert(counter == N);
61
62 std::ranges::destroy_n(Iterator(out), N);
63 assert(counter == 0);
64
65 Traits::deallocate(a&: alloc, p: out, n: N);
66 }
67}
68
69constexpr bool tests() {
70 test<Counted*>();
71 test<forward_iterator<Counted*>>();
72
73 return true;
74}
75
76constexpr bool test_arrays() {
77 // One-dimensional array.
78 {
79 constexpr int N = 5;
80 constexpr int M = 3;
81
82 using Array = Counted[M];
83 std::allocator<Array> alloc;
84 using Traits = std::allocator_traits<decltype(alloc)>;
85 int counter = 0;
86
87 Array* buffer = Traits::allocate(a&: alloc, n: N);
88 for (int i = 0; i != N; ++i) {
89 Array& array_ref = *(buffer + i);
90 for (int j = 0; j != M; ++j) {
91 Traits::construct(a&: alloc, p: std::addressof(r&: array_ref[j]), args&: counter);
92 }
93 }
94 assert(counter == N * M);
95
96 std::ranges::destroy_n(buffer, N);
97 assert(counter == 0);
98
99 Traits::deallocate(a&: alloc, p: buffer, n: N);
100 }
101
102 // Multidimensional array.
103 {
104 constexpr int N = 5;
105 constexpr int A = 3;
106 constexpr int B = 3;
107
108 using Array = Counted[A][B];
109 std::allocator<Array> alloc;
110 using Traits = std::allocator_traits<decltype(alloc)>;
111 int counter = 0;
112
113 Array* buffer = Traits::allocate(a&: alloc, n: N);
114 for (int i = 0; i != N; ++i) {
115 Array& array_ref = *(buffer + i);
116 for (int j = 0; j != A; ++j) {
117 for (int k = 0; k != B; ++k) {
118 Traits::construct(a&: alloc, p: std::addressof(r&: array_ref[j][k]), args&: counter);
119 }
120 }
121 }
122 assert(counter == N * A * B);
123
124 std::ranges::destroy_n(buffer, N);
125 assert(counter == 0);
126
127 Traits::deallocate(a&: alloc, p: buffer, n: N);
128 }
129
130 return true;
131}
132
133int main(int, char**) {
134 tests();
135 test_arrays();
136
137 static_assert(tests());
138 // TODO: Until std::construct_at has support for arrays, it's impossible to test this
139 // in a constexpr context (see https://reviews.llvm.org/D114903).
140 // static_assert(test_arrays());
141
142 return 0;
143}
144

source code of libcxx/test/std/utilities/memory/specialized.algorithms/specialized.destroy/ranges_destroy_n.pass.cpp