1 /* Apache License, Version 2.0 */
2 
3 #include "BLI_array.hh"
4 #include "BLI_exception_safety_test_utils.hh"
5 #include "BLI_strict_flags.h"
6 #include "BLI_vector.hh"
7 #include "testing/testing.h"
8 
9 namespace blender::tests {
10 
TEST(array,DefaultConstructor)11 TEST(array, DefaultConstructor)
12 {
13   Array<int> array;
14   EXPECT_EQ(array.size(), 0);
15   EXPECT_TRUE(array.is_empty());
16 }
17 
TEST(array,SizeConstructor)18 TEST(array, SizeConstructor)
19 {
20   Array<int> array(5);
21   EXPECT_EQ(array.size(), 5);
22   EXPECT_FALSE(array.is_empty());
23 }
24 
TEST(array,FillConstructor)25 TEST(array, FillConstructor)
26 {
27   Array<int> array(5, 8);
28   EXPECT_EQ(array.size(), 5);
29   EXPECT_EQ(array[0], 8);
30   EXPECT_EQ(array[1], 8);
31   EXPECT_EQ(array[2], 8);
32   EXPECT_EQ(array[3], 8);
33   EXPECT_EQ(array[4], 8);
34 }
35 
TEST(array,InitializerListConstructor)36 TEST(array, InitializerListConstructor)
37 {
38   Array<int> array = {4, 5, 6, 7};
39   EXPECT_EQ(array.size(), 4);
40   EXPECT_EQ(array[0], 4);
41   EXPECT_EQ(array[1], 5);
42   EXPECT_EQ(array[2], 6);
43   EXPECT_EQ(array[3], 7);
44 }
45 
TEST(array,SpanConstructor)46 TEST(array, SpanConstructor)
47 {
48   int stackarray[4] = {6, 7, 8, 9};
49   Span<int> span(stackarray, ARRAY_SIZE(stackarray));
50   Array<int> array(span);
51   EXPECT_EQ(array.size(), 4);
52   EXPECT_EQ(array[0], 6);
53   EXPECT_EQ(array[1], 7);
54   EXPECT_EQ(array[2], 8);
55   EXPECT_EQ(array[3], 9);
56 }
57 
TEST(array,CopyConstructor)58 TEST(array, CopyConstructor)
59 {
60   Array<int> array = {5, 6, 7, 8};
61   Array<int> new_array(array);
62 
63   EXPECT_EQ(array.size(), 4);
64   EXPECT_EQ(new_array.size(), 4);
65   EXPECT_NE(array.data(), new_array.data());
66   EXPECT_EQ(new_array[0], 5);
67   EXPECT_EQ(new_array[1], 6);
68   EXPECT_EQ(new_array[2], 7);
69   EXPECT_EQ(new_array[3], 8);
70 }
71 
TEST(array,MoveConstructor)72 TEST(array, MoveConstructor)
73 {
74   Array<int> array = {5, 6, 7, 8};
75   Array<int> new_array(std::move(array));
76 
77   EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */
78   EXPECT_EQ(new_array.size(), 4);
79   EXPECT_EQ(new_array[0], 5);
80   EXPECT_EQ(new_array[1], 6);
81   EXPECT_EQ(new_array[2], 7);
82   EXPECT_EQ(new_array[3], 8);
83 }
84 
TEST(array,CopyAssignment)85 TEST(array, CopyAssignment)
86 {
87   Array<int> array = {1, 2, 3};
88   Array<int> new_array = {4};
89   EXPECT_EQ(new_array.size(), 1);
90   new_array = array;
91   EXPECT_EQ(new_array.size(), 3);
92   EXPECT_EQ(array.size(), 3);
93   EXPECT_NE(array.data(), new_array.data());
94   EXPECT_EQ(new_array[0], 1);
95   EXPECT_EQ(new_array[1], 2);
96   EXPECT_EQ(new_array[2], 3);
97 }
98 
TEST(array,MoveAssignment)99 TEST(array, MoveAssignment)
100 {
101   Array<int> array = {1, 2, 3};
102   Array<int> new_array = {4};
103   EXPECT_EQ(new_array.size(), 1);
104   new_array = std::move(array);
105   EXPECT_EQ(new_array.size(), 3);
106   EXPECT_EQ(array.size(), 0); /* NOLINT: bugprone-use-after-move */
107   EXPECT_EQ(new_array[0], 1);
108   EXPECT_EQ(new_array[1], 2);
109   EXPECT_EQ(new_array[2], 3);
110 }
111 
112 /**
113  * Tests that the trivially constructible types are not zero-initialized. We do not want that for
114  * performance reasons.
115  */
TEST(array,TrivialTypeSizeConstructor)116 TEST(array, TrivialTypeSizeConstructor)
117 {
118   Array<char, 1> *array = new Array<char, 1>(1);
119   char *ptr = &(*array)[0];
120   array->~Array();
121 
122   const char magic = 42;
123   *ptr = magic;
124   EXPECT_EQ(*ptr, magic);
125 
126   new (array) Array<char, 1>(1);
127   EXPECT_EQ((*array)[0], magic);
128   EXPECT_EQ(*ptr, magic);
129   delete array;
130 }
131 
132 struct ConstructibleType {
133   char value;
134 
ConstructibleTypeblender::tests::ConstructibleType135   ConstructibleType()
136   {
137     value = 42;
138   }
139 };
140 
TEST(array,NoInitializationSizeConstructor)141 TEST(array, NoInitializationSizeConstructor)
142 {
143   using MyArray = Array<ConstructibleType>;
144 
145   TypedBuffer<MyArray> buffer;
146   memset((void *)&buffer, 100, sizeof(MyArray));
147 
148   /* Doing this to avoid some compiler optimization. */
149   for (int64_t i : IndexRange(sizeof(MyArray))) {
150     EXPECT_EQ(((char *)buffer.ptr())[i], 100);
151   }
152 
153   {
154     MyArray &array = *new (buffer) MyArray(1, NoInitialization());
155     EXPECT_EQ(array[0].value, 100);
156     array.clear_without_destruct();
157     array.~Array();
158   }
159   {
160     MyArray &array = *new (buffer) MyArray(1);
161     EXPECT_EQ(array[0].value, 42);
162     array.~Array();
163   }
164 }
165 
TEST(array,Fill)166 TEST(array, Fill)
167 {
168   Array<int> array(5);
169   array.fill(3);
170   EXPECT_EQ(array.size(), 5u);
171   EXPECT_EQ(array[0], 3);
172   EXPECT_EQ(array[1], 3);
173   EXPECT_EQ(array[2], 3);
174   EXPECT_EQ(array[3], 3);
175   EXPECT_EQ(array[4], 3);
176 }
177 
TEST(array,ReverseIterator)178 TEST(array, ReverseIterator)
179 {
180   Array<int> array = {3, 4, 5, 6};
181   Vector<int> reversed_vec;
182 
183   for (auto it = array.rbegin(); it != array.rend(); ++it) {
184     reversed_vec.append(*it);
185     *it += 10;
186   }
187 
188   EXPECT_EQ_ARRAY(reversed_vec.data(), Span({6, 5, 4, 3}).data(), 4);
189   EXPECT_EQ_ARRAY(array.data(), Span({13, 14, 15, 16}).data(), 4);
190 }
191 
TEST(array,SpanConstructorExceptions)192 TEST(array, SpanConstructorExceptions)
193 {
194   std::array<ExceptionThrower, 4> values;
195   values[2].throw_during_copy = true;
196   Span<ExceptionThrower> span{values};
197   EXPECT_ANY_THROW({ Array<ExceptionThrower> array(span); });
198 }
199 
TEST(array,SizeValueConstructorExceptions)200 TEST(array, SizeValueConstructorExceptions)
201 {
202   ExceptionThrower value;
203   value.throw_during_copy = true;
204   EXPECT_ANY_THROW({ Array<ExceptionThrower> array(5, value); });
205 }
206 
TEST(array,MoveConstructorExceptions)207 TEST(array, MoveConstructorExceptions)
208 {
209   Array<ExceptionThrower, 4> array(3);
210   array[1].throw_during_move = true;
211   EXPECT_ANY_THROW({ Array<ExceptionThrower> array_copy(std::move(array)); });
212 }
213 
TEST(array,CopyAssignmentExceptions)214 TEST(array, CopyAssignmentExceptions)
215 {
216   Array<ExceptionThrower> array(5);
217   array[3].throw_during_copy = true;
218   Array<ExceptionThrower> array_copy(10);
219   EXPECT_ANY_THROW({ array_copy = array; });
220 }
221 
TEST(array,MoveAssignmentExceptions)222 TEST(array, MoveAssignmentExceptions)
223 {
224   Array<ExceptionThrower, 4> array(4);
225   array[2].throw_during_move = true;
226   Array<ExceptionThrower> array_moved(10);
227   EXPECT_ANY_THROW({ array_moved = std::move(array); });
228 }
229 
TEST(array,Last)230 TEST(array, Last)
231 {
232   Array<int> array = {5, 7, 8, 9};
233   EXPECT_EQ(array.last(), 9);
234   array.last() = 1;
235   EXPECT_EQ(array[3], 1);
236   EXPECT_EQ(const_cast<const Array<int> &>(array).last(), 1);
237 }
238 
TEST(array,Reinitialize)239 TEST(array, Reinitialize)
240 {
241   Array<std::string> array = {"hello", "world"};
242   EXPECT_EQ(array.size(), 2);
243   EXPECT_EQ(array[1], "world");
244   array.reinitialize(3);
245   EXPECT_EQ(array.size(), 3);
246   EXPECT_EQ(array[0], "");
247   EXPECT_EQ(array[1], "");
248   EXPECT_EQ(array[2], "");
249   array.reinitialize(0);
250   EXPECT_EQ(array.size(), 0);
251 }
252 
253 }  // namespace blender::tests
254