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
10 
11 // <memory>
12 
13 // template <class ForwardIt, class Size>
14 // constexpr ForwardIt destroy_n(ForwardIt, Size s);
15 
16 #include <memory>
17 #include <cassert>
18 #include <type_traits>
19 
20 #include "test_macros.h"
21 #include "test_iterators.h"
22 
23 struct Counted {
24     int* counter_;
CountedCounted25     TEST_CONSTEXPR Counted(int* counter) : counter_(counter) { ++*counter_; }
CountedCounted26     TEST_CONSTEXPR Counted(Counted const& other) : counter_(other.counter_) { ++*counter_; }
~CountedCounted27     TEST_CONSTEXPR_CXX20 ~Counted() { --*counter_; }
28     friend void operator&(Counted) = delete;
29 };
30 
31 #if TEST_STD_VER > 17
test_arrays()32 constexpr bool test_arrays()  {
33     {
34         using Array = Counted[3];
35         using Alloc = std::allocator<Array>;
36         int counter = 0;
37         Alloc alloc;
38         Array* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
39 
40         for (Array* p = pool; p != pool + 5; ++p) {
41             Array& arr = *p;
42             for (int i = 0; i != 3; ++i) {
43                 std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i]), &counter);
44             }
45         }
46         assert(counter == 5 * 3);
47 
48         Array* p = std::destroy_n(pool, 5);
49         ASSERT_SAME_TYPE(decltype(std::destroy_n(pool, 5)), Array*);
50         assert(p == pool + 5);
51         assert(counter == 0);
52 
53         std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
54     }
55     {
56         using Array = Counted[3][2];
57         using Alloc = std::allocator<Array>;
58         int counter = 0;
59         Alloc alloc;
60         Array* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
61 
62         for (Array* p = pool; p != pool + 5; ++p) {
63             Array& arr = *p;
64             for (int i = 0; i != 3; ++i) {
65                 for (int j = 0; j != 2; ++j) {
66                     std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i][j]), &counter);
67                 }
68             }
69         }
70         assert(counter == 5 * 3 * 2);
71 
72         Array* p = std::destroy_n(pool, 5);
73         ASSERT_SAME_TYPE(decltype(std::destroy_n(pool, 5)), Array*);
74         assert(p == pool + 5);
75         assert(counter == 0);
76 
77         std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
78     }
79 
80     return true;
81 }
82 #endif
83 
84 template <class It>
test()85 TEST_CONSTEXPR_CXX20 void test() {
86     using Alloc = std::allocator<Counted>;
87     int counter = 0;
88     Alloc alloc;
89     Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
90 
91     for (Counted* p = pool; p != pool + 5; ++p)
92         std::allocator_traits<Alloc>::construct(alloc, p, &counter);
93     assert(counter == 5);
94 
95     It it = std::destroy_n(It(pool), 5);
96     ASSERT_SAME_TYPE(decltype(std::destroy_n(It(pool), 5)), It);
97     assert(it == It(pool + 5));
98     assert(counter == 0);
99 
100     std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
101 }
102 
tests()103 TEST_CONSTEXPR_CXX20 bool tests() {
104     test<Counted*>();
105     test<forward_iterator<Counted*>>();
106     return true;
107 }
108 
main(int,char **)109 int main(int, char**) {
110     tests();
111 #if TEST_STD_VER > 17
112     test_arrays();
113     static_assert(tests());
114     // TODO: Until std::construct_at has support for arrays, it's impossible to test this
115     //       in a constexpr context (see https://reviews.llvm.org/D114903).
116     // static_assert(test_arrays());
117 #endif
118     return 0;
119 }
120