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>
14 // constexpr void destroy(ForwardIt, ForwardIt);
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         std::destroy(pool, pool + 5);
49         ASSERT_SAME_TYPE(decltype(std::destroy(pool, pool + 5)), void);
50         assert(counter == 0);
51 
52         std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
53     }
54     {
55         using Array = Counted[3][2];
56         using Alloc = std::allocator<Array>;
57         int counter = 0;
58         Alloc alloc;
59         Array* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
60 
61         for (Array* p = pool; p != pool + 5; ++p) {
62             Array& arr = *p;
63             for (int i = 0; i != 3; ++i) {
64                 for (int j = 0; j != 2; ++j) {
65                     std::allocator_traits<Alloc>::construct(alloc, std::addressof(arr[i][j]), &counter);
66                 }
67             }
68         }
69         assert(counter == 5 * 3 * 2);
70 
71         std::destroy(pool, pool + 5);
72         ASSERT_SAME_TYPE(decltype(std::destroy(pool, pool + 5)), void);
73         assert(counter == 0);
74 
75         std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
76     }
77 
78     return true;
79 }
80 #endif
81 
82 template <class It>
test()83 TEST_CONSTEXPR_CXX20 void test() {
84     using Alloc = std::allocator<Counted>;
85     int counter = 0;
86     Alloc alloc;
87     Counted* pool = std::allocator_traits<Alloc>::allocate(alloc, 5);
88 
89     for (Counted* p = pool; p != pool + 5; ++p)
90         std::allocator_traits<Alloc>::construct(alloc, p, &counter);
91     assert(counter == 5);
92 
93     std::destroy(It(pool), It(pool + 5));
94     ASSERT_SAME_TYPE(decltype(std::destroy(It(pool), It(pool + 5))), void);
95     assert(counter == 0);
96 
97     std::allocator_traits<Alloc>::deallocate(alloc, pool, 5);
98 }
99 
tests()100 TEST_CONSTEXPR_CXX20 bool tests() {
101     test<Counted*>();
102     test<forward_iterator<Counted*>>();
103     return true;
104 }
105 
main(int,char **)106 int main(int, char**) {
107     tests();
108 #if TEST_STD_VER > 17
109     test_arrays();
110     static_assert(tests());
111     // TODO: Until std::construct_at has support for arrays, it's impossible to test this
112     //       in a constexpr context (see https://reviews.llvm.org/D114903).
113     // static_assert(test_arrays());
114 #endif
115     return 0;
116 }
117