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 // <memory>
10 
11 // unique_ptr
12 
13 // T& unique_ptr::operator[](size_t) const
14 
15 #include <memory>
16 #include <cassert>
17 #include <type_traits>
18 #include <array>
19 
20 #include "test_macros.h"
21 #include "type_algorithms.h"
22 
23 static int next = 0;
24 struct EnumeratedDefaultCtor {
25   EnumeratedDefaultCtor() : value(0) { value = ++next; }
26   int value;
27 };
28 
29 template <std::size_t Size>
30 struct WithTrivialDtor {
31   std::array<char, Size> padding = {'x'};
32   TEST_CONSTEXPR_CXX23 friend bool operator==(WithTrivialDtor const& x, WithTrivialDtor const& y) {
33     return x.padding == y.padding;
34   }
35 };
36 
37 template <std::size_t Size>
38 struct WithNonTrivialDtor {
39   std::array<char, Size> padding = {'x'};
40   TEST_CONSTEXPR_CXX23 friend bool operator==(WithNonTrivialDtor const& x, WithNonTrivialDtor const& y) {
41     return x.padding == y.padding;
42   }
43   TEST_CONSTEXPR_CXX23 ~WithNonTrivialDtor() {}
44 };
45 
46 template <class T>
47 struct CustomDeleter : std::default_delete<T> {};
48 
49 struct NoopDeleter {
50   template <class T>
51   TEST_CONSTEXPR_CXX23 void operator()(T*) const {}
52 };
53 
54 TEST_CONSTEXPR_CXX23 bool test() {
55   // Basic test
56   {
57     std::unique_ptr<int[]> p(new int[3]);
58     {
59       int& result = p[0];
60       result      = 0;
61     }
62     {
63       int& result = p[1];
64       result      = 1;
65     }
66     {
67       int& result = p[2];
68       result      = 2;
69     }
70 
71     assert(p[0] == 0);
72     assert(p[1] == 1);
73     assert(p[2] == 2);
74   }
75 
76   // Ensure that the order of access is correct after initializing a unique_ptr but
77   // before actually modifying any of its elements. The implementation would have to
78   // really try for this not to be the case, but we still check it.
79   //
80   // This requires assigning known values to the elements when they are first constructed,
81   // which requires global state.
82   {
83     if (!TEST_IS_CONSTANT_EVALUATED) {
84       std::unique_ptr<EnumeratedDefaultCtor[]> p(new EnumeratedDefaultCtor[3]);
85       assert(p[0].value == 1);
86       assert(p[1].value == 2);
87       assert(p[2].value == 3);
88     }
89   }
90 
91   // Make sure operator[] is const-qualified
92   {
93     std::unique_ptr<int[]> const p(new int[3]);
94     p[0] = 42;
95     assert(p[0] == 42);
96   }
97 
98   // Make sure we properly handle types with trivial and non-trivial destructors of different
99   // sizes. This is relevant because some implementations may want to use properties of the
100   // ABI like array cookies and these properties often depend on e.g. the triviality of T's
101   // destructor, T's size and so on.
102 #if TEST_STD_VER >= 20 // this test is too painful to write before C++20
103   {
104     using TrickyCookieTypes = types::type_list<
105         WithTrivialDtor<1>,
106         WithTrivialDtor<2>,
107         WithTrivialDtor<3>,
108         WithTrivialDtor<4>,
109         WithTrivialDtor<8>,
110         WithTrivialDtor<16>,
111         WithTrivialDtor<256>,
112         WithNonTrivialDtor<1>,
113         WithNonTrivialDtor<2>,
114         WithNonTrivialDtor<3>,
115         WithNonTrivialDtor<4>,
116         WithNonTrivialDtor<8>,
117         WithNonTrivialDtor<16>,
118         WithNonTrivialDtor<256>>;
119     types::for_each(TrickyCookieTypes(), []<class T> {
120       // Array allocated with `new T[n]`, default deleter
121       {
122         std::unique_ptr<T[], std::default_delete<T[]>> p(new T[3]);
123         assert(p[0] == T());
124         assert(p[1] == T());
125         assert(p[2] == T());
126       }
127 
128       // Array allocated with `new T[n]`, custom deleter
129       {
130         std::unique_ptr<T[], CustomDeleter<T[]>> p(new T[3]);
131         assert(p[0] == T());
132         assert(p[1] == T());
133         assert(p[2] == T());
134       }
135 
136       // Array not allocated with `new T[n]`, custom deleter
137       //
138       // This test aims to ensure that the implementation doesn't try to use an array cookie
139       // when there is none.
140       {
141         T array[50] = {};
142         std::unique_ptr<T[], NoopDeleter> p(&array[0]);
143         assert(p[0] == T());
144         assert(p[1] == T());
145         assert(p[2] == T());
146       }
147     });
148   }
149 #endif // C++20
150 
151   return true;
152 }
153 
154 int main(int, char**) {
155   test();
156 #if TEST_STD_VER >= 23
157   static_assert(test());
158 #endif
159 
160   return 0;
161 }
162