1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/container/fixed_array.h"
16
17 #include <stdio.h>
18
19 #include <cstring>
20 #include <list>
21 #include <memory>
22 #include <numeric>
23 #include <scoped_allocator>
24 #include <stdexcept>
25 #include <string>
26 #include <vector>
27
28 #include "gmock/gmock.h"
29 #include "gtest/gtest.h"
30 #include "absl/base/config.h"
31 #include "absl/base/internal/exception_testing.h"
32 #include "absl/base/options.h"
33 #include "absl/container/internal/counting_allocator.h"
34 #include "absl/hash/hash_testing.h"
35 #include "absl/memory/memory.h"
36
37 using ::testing::ElementsAreArray;
38
39 namespace {
40
41 // Helper routine to determine if a absl::FixedArray used stack allocation.
42 template <typename ArrayType>
IsOnStack(const ArrayType & a)43 static bool IsOnStack(const ArrayType& a) {
44 return a.size() <= ArrayType::inline_elements;
45 }
46
47 class ConstructionTester {
48 public:
ConstructionTester()49 ConstructionTester() : self_ptr_(this), value_(0) { constructions++; }
~ConstructionTester()50 ~ConstructionTester() {
51 assert(self_ptr_ == this);
52 self_ptr_ = nullptr;
53 destructions++;
54 }
55
56 // These are incremented as elements are constructed and destructed so we can
57 // be sure all elements are properly cleaned up.
58 static int constructions;
59 static int destructions;
60
CheckConstructed()61 void CheckConstructed() { assert(self_ptr_ == this); }
62
set(int value)63 void set(int value) { value_ = value; }
get()64 int get() { return value_; }
65
66 private:
67 // self_ptr_ should always point to 'this' -- that's how we can be sure the
68 // constructor has been called.
69 ConstructionTester* self_ptr_;
70 int value_;
71 };
72
73 int ConstructionTester::constructions = 0;
74 int ConstructionTester::destructions = 0;
75
76 // ThreeInts will initialize its three ints to the value stored in
77 // ThreeInts::counter. The constructor increments counter so that each object
78 // in an array of ThreeInts will have different values.
79 class ThreeInts {
80 public:
ThreeInts()81 ThreeInts() {
82 x_ = counter;
83 y_ = counter;
84 z_ = counter;
85 ++counter;
86 }
87
88 static int counter;
89
90 int x_, y_, z_;
91 };
92
93 int ThreeInts::counter = 0;
94
TEST(FixedArrayTest,CopyCtor)95 TEST(FixedArrayTest, CopyCtor) {
96 absl::FixedArray<int, 10> on_stack(5);
97 std::iota(on_stack.begin(), on_stack.end(), 0);
98 absl::FixedArray<int, 10> stack_copy = on_stack;
99 EXPECT_THAT(stack_copy, ElementsAreArray(on_stack));
100 EXPECT_TRUE(IsOnStack(stack_copy));
101
102 absl::FixedArray<int, 10> allocated(15);
103 std::iota(allocated.begin(), allocated.end(), 0);
104 absl::FixedArray<int, 10> alloced_copy = allocated;
105 EXPECT_THAT(alloced_copy, ElementsAreArray(allocated));
106 EXPECT_FALSE(IsOnStack(alloced_copy));
107 }
108
TEST(FixedArrayTest,MoveCtor)109 TEST(FixedArrayTest, MoveCtor) {
110 absl::FixedArray<std::unique_ptr<int>, 10> on_stack(5);
111 for (int i = 0; i < 5; ++i) {
112 on_stack[i] = absl::make_unique<int>(i);
113 }
114
115 absl::FixedArray<std::unique_ptr<int>, 10> stack_copy = std::move(on_stack);
116 for (int i = 0; i < 5; ++i) EXPECT_EQ(*(stack_copy[i]), i);
117 EXPECT_EQ(stack_copy.size(), on_stack.size());
118
119 absl::FixedArray<std::unique_ptr<int>, 10> allocated(15);
120 for (int i = 0; i < 15; ++i) {
121 allocated[i] = absl::make_unique<int>(i);
122 }
123
124 absl::FixedArray<std::unique_ptr<int>, 10> alloced_copy =
125 std::move(allocated);
126 for (int i = 0; i < 15; ++i) EXPECT_EQ(*(alloced_copy[i]), i);
127 EXPECT_EQ(allocated.size(), alloced_copy.size());
128 }
129
TEST(FixedArrayTest,SmallObjects)130 TEST(FixedArrayTest, SmallObjects) {
131 // Small object arrays
132 {
133 // Short arrays should be on the stack
134 absl::FixedArray<int> array(4);
135 EXPECT_TRUE(IsOnStack(array));
136 }
137
138 {
139 // Large arrays should be on the heap
140 absl::FixedArray<int> array(1048576);
141 EXPECT_FALSE(IsOnStack(array));
142 }
143
144 {
145 // Arrays of <= default size should be on the stack
146 absl::FixedArray<int, 100> array(100);
147 EXPECT_TRUE(IsOnStack(array));
148 }
149
150 {
151 // Arrays of > default size should be on the heap
152 absl::FixedArray<int, 100> array(101);
153 EXPECT_FALSE(IsOnStack(array));
154 }
155
156 {
157 // Arrays with different size elements should use approximately
158 // same amount of stack space
159 absl::FixedArray<int> array1(0);
160 absl::FixedArray<char> array2(0);
161 EXPECT_LE(sizeof(array1), sizeof(array2) + 100);
162 EXPECT_LE(sizeof(array2), sizeof(array1) + 100);
163 }
164
165 {
166 // Ensure that vectors are properly constructed inside a fixed array.
167 absl::FixedArray<std::vector<int>> array(2);
168 EXPECT_EQ(0, array[0].size());
169 EXPECT_EQ(0, array[1].size());
170 }
171
172 {
173 // Regardless of absl::FixedArray implementation, check that a type with a
174 // low alignment requirement and a non power-of-two size is initialized
175 // correctly.
176 ThreeInts::counter = 1;
177 absl::FixedArray<ThreeInts> array(2);
178 EXPECT_EQ(1, array[0].x_);
179 EXPECT_EQ(1, array[0].y_);
180 EXPECT_EQ(1, array[0].z_);
181 EXPECT_EQ(2, array[1].x_);
182 EXPECT_EQ(2, array[1].y_);
183 EXPECT_EQ(2, array[1].z_);
184 }
185 }
186
TEST(FixedArrayTest,AtThrows)187 TEST(FixedArrayTest, AtThrows) {
188 absl::FixedArray<int> a = {1, 2, 3};
189 EXPECT_EQ(a.at(2), 3);
190 ABSL_BASE_INTERNAL_EXPECT_FAIL(a.at(3), std::out_of_range,
191 "failed bounds check");
192 }
193
TEST(FixedArrayTest,Hardened)194 TEST(FixedArrayTest, Hardened) {
195 #if !defined(NDEBUG) || ABSL_OPTION_HARDENED
196 absl::FixedArray<int> a = {1, 2, 3};
197 EXPECT_EQ(a[2], 3);
198 EXPECT_DEATH_IF_SUPPORTED(a[3], "");
199 EXPECT_DEATH_IF_SUPPORTED(a[-1], "");
200
201 absl::FixedArray<int> empty(0);
202 EXPECT_DEATH_IF_SUPPORTED(empty[0], "");
203 EXPECT_DEATH_IF_SUPPORTED(empty[-1], "");
204 EXPECT_DEATH_IF_SUPPORTED(empty.front(), "");
205 EXPECT_DEATH_IF_SUPPORTED(empty.back(), "");
206 #endif
207 }
208
TEST(FixedArrayRelationalsTest,EqualArrays)209 TEST(FixedArrayRelationalsTest, EqualArrays) {
210 for (int i = 0; i < 10; ++i) {
211 absl::FixedArray<int, 5> a1(i);
212 std::iota(a1.begin(), a1.end(), 0);
213 absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
214
215 EXPECT_TRUE(a1 == a2);
216 EXPECT_FALSE(a1 != a2);
217 EXPECT_TRUE(a2 == a1);
218 EXPECT_FALSE(a2 != a1);
219 EXPECT_FALSE(a1 < a2);
220 EXPECT_FALSE(a1 > a2);
221 EXPECT_FALSE(a2 < a1);
222 EXPECT_FALSE(a2 > a1);
223 EXPECT_TRUE(a1 <= a2);
224 EXPECT_TRUE(a1 >= a2);
225 EXPECT_TRUE(a2 <= a1);
226 EXPECT_TRUE(a2 >= a1);
227 }
228 }
229
TEST(FixedArrayRelationalsTest,UnequalArrays)230 TEST(FixedArrayRelationalsTest, UnequalArrays) {
231 for (int i = 1; i < 10; ++i) {
232 absl::FixedArray<int, 5> a1(i);
233 std::iota(a1.begin(), a1.end(), 0);
234 absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
235 --a2[i / 2];
236
237 EXPECT_FALSE(a1 == a2);
238 EXPECT_TRUE(a1 != a2);
239 EXPECT_FALSE(a2 == a1);
240 EXPECT_TRUE(a2 != a1);
241 EXPECT_FALSE(a1 < a2);
242 EXPECT_TRUE(a1 > a2);
243 EXPECT_TRUE(a2 < a1);
244 EXPECT_FALSE(a2 > a1);
245 EXPECT_FALSE(a1 <= a2);
246 EXPECT_TRUE(a1 >= a2);
247 EXPECT_TRUE(a2 <= a1);
248 EXPECT_FALSE(a2 >= a1);
249 }
250 }
251
252 template <int stack_elements>
TestArray(int n)253 static void TestArray(int n) {
254 SCOPED_TRACE(n);
255 SCOPED_TRACE(stack_elements);
256 ConstructionTester::constructions = 0;
257 ConstructionTester::destructions = 0;
258 {
259 absl::FixedArray<ConstructionTester, stack_elements> array(n);
260
261 EXPECT_THAT(array.size(), n);
262 EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n);
263 EXPECT_THAT(array.begin() + n, array.end());
264
265 // Check that all elements were constructed
266 for (int i = 0; i < n; i++) {
267 array[i].CheckConstructed();
268 }
269 // Check that no other elements were constructed
270 EXPECT_THAT(ConstructionTester::constructions, n);
271
272 // Test operator[]
273 for (int i = 0; i < n; i++) {
274 array[i].set(i);
275 }
276 for (int i = 0; i < n; i++) {
277 EXPECT_THAT(array[i].get(), i);
278 EXPECT_THAT(array.data()[i].get(), i);
279 }
280
281 // Test data()
282 for (int i = 0; i < n; i++) {
283 array.data()[i].set(i + 1);
284 }
285 for (int i = 0; i < n; i++) {
286 EXPECT_THAT(array[i].get(), i + 1);
287 EXPECT_THAT(array.data()[i].get(), i + 1);
288 }
289 } // Close scope containing 'array'.
290
291 // Check that all constructed elements were destructed.
292 EXPECT_EQ(ConstructionTester::constructions,
293 ConstructionTester::destructions);
294 }
295
296 template <int elements_per_inner_array, int inline_elements>
TestArrayOfArrays(int n)297 static void TestArrayOfArrays(int n) {
298 SCOPED_TRACE(n);
299 SCOPED_TRACE(inline_elements);
300 SCOPED_TRACE(elements_per_inner_array);
301 ConstructionTester::constructions = 0;
302 ConstructionTester::destructions = 0;
303 {
304 using InnerArray = ConstructionTester[elements_per_inner_array];
305 // Heap-allocate the FixedArray to avoid blowing the stack frame.
306 auto array_ptr =
307 absl::make_unique<absl::FixedArray<InnerArray, inline_elements>>(n);
308 auto& array = *array_ptr;
309
310 ASSERT_EQ(array.size(), n);
311 ASSERT_EQ(array.memsize(),
312 sizeof(ConstructionTester) * elements_per_inner_array * n);
313 ASSERT_EQ(array.begin() + n, array.end());
314
315 // Check that all elements were constructed
316 for (int i = 0; i < n; i++) {
317 for (int j = 0; j < elements_per_inner_array; j++) {
318 (array[i])[j].CheckConstructed();
319 }
320 }
321 // Check that no other elements were constructed
322 ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array);
323
324 // Test operator[]
325 for (int i = 0; i < n; i++) {
326 for (int j = 0; j < elements_per_inner_array; j++) {
327 (array[i])[j].set(i * elements_per_inner_array + j);
328 }
329 }
330 for (int i = 0; i < n; i++) {
331 for (int j = 0; j < elements_per_inner_array; j++) {
332 ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j);
333 ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j);
334 }
335 }
336
337 // Test data()
338 for (int i = 0; i < n; i++) {
339 for (int j = 0; j < elements_per_inner_array; j++) {
340 (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j);
341 }
342 }
343 for (int i = 0; i < n; i++) {
344 for (int j = 0; j < elements_per_inner_array; j++) {
345 ASSERT_EQ((array[i])[j].get(), (i + 1) * elements_per_inner_array + j);
346 ASSERT_EQ((array.data()[i])[j].get(),
347 (i + 1) * elements_per_inner_array + j);
348 }
349 }
350 } // Close scope containing 'array'.
351
352 // Check that all constructed elements were destructed.
353 EXPECT_EQ(ConstructionTester::constructions,
354 ConstructionTester::destructions);
355 }
356
TEST(IteratorConstructorTest,NonInline)357 TEST(IteratorConstructorTest, NonInline) {
358 int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
359 absl::FixedArray<int, ABSL_ARRAYSIZE(kInput) - 1> const fixed(
360 kInput, kInput + ABSL_ARRAYSIZE(kInput));
361 ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
362 for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
363 ASSERT_EQ(kInput[i], fixed[i]);
364 }
365 }
366
TEST(IteratorConstructorTest,Inline)367 TEST(IteratorConstructorTest, Inline) {
368 int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
369 absl::FixedArray<int, ABSL_ARRAYSIZE(kInput)> const fixed(
370 kInput, kInput + ABSL_ARRAYSIZE(kInput));
371 ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
372 for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
373 ASSERT_EQ(kInput[i], fixed[i]);
374 }
375 }
376
TEST(IteratorConstructorTest,NonPod)377 TEST(IteratorConstructorTest, NonPod) {
378 char const* kInput[] = {"red", "orange", "yellow", "green",
379 "blue", "indigo", "violet"};
380 absl::FixedArray<std::string> const fixed(kInput,
381 kInput + ABSL_ARRAYSIZE(kInput));
382 ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
383 for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
384 ASSERT_EQ(kInput[i], fixed[i]);
385 }
386 }
387
TEST(IteratorConstructorTest,FromEmptyVector)388 TEST(IteratorConstructorTest, FromEmptyVector) {
389 std::vector<int> const empty;
390 absl::FixedArray<int> const fixed(empty.begin(), empty.end());
391 EXPECT_EQ(0, fixed.size());
392 EXPECT_EQ(empty.size(), fixed.size());
393 }
394
TEST(IteratorConstructorTest,FromNonEmptyVector)395 TEST(IteratorConstructorTest, FromNonEmptyVector) {
396 int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
397 std::vector<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
398 absl::FixedArray<int> const fixed(items.begin(), items.end());
399 ASSERT_EQ(items.size(), fixed.size());
400 for (size_t i = 0; i < items.size(); ++i) {
401 ASSERT_EQ(items[i], fixed[i]);
402 }
403 }
404
TEST(IteratorConstructorTest,FromBidirectionalIteratorRange)405 TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) {
406 int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
407 std::list<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
408 absl::FixedArray<int> const fixed(items.begin(), items.end());
409 EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
410 }
411
TEST(InitListConstructorTest,InitListConstruction)412 TEST(InitListConstructorTest, InitListConstruction) {
413 absl::FixedArray<int> fixed = {1, 2, 3};
414 EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3}));
415 }
416
TEST(FillConstructorTest,NonEmptyArrays)417 TEST(FillConstructorTest, NonEmptyArrays) {
418 absl::FixedArray<int> stack_array(4, 1);
419 EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
420
421 absl::FixedArray<int, 0> heap_array(4, 1);
422 EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
423 }
424
TEST(FillConstructorTest,EmptyArray)425 TEST(FillConstructorTest, EmptyArray) {
426 absl::FixedArray<int> empty_fill(0, 1);
427 absl::FixedArray<int> empty_size(0);
428 EXPECT_EQ(empty_fill, empty_size);
429 }
430
TEST(FillConstructorTest,NotTriviallyCopyable)431 TEST(FillConstructorTest, NotTriviallyCopyable) {
432 std::string str = "abcd";
433 absl::FixedArray<std::string> strings = {str, str, str, str};
434
435 absl::FixedArray<std::string> array(4, str);
436 EXPECT_EQ(array, strings);
437 }
438
TEST(FillConstructorTest,Disambiguation)439 TEST(FillConstructorTest, Disambiguation) {
440 absl::FixedArray<size_t> a(1, 2);
441 EXPECT_THAT(a, testing::ElementsAre(2));
442 }
443
TEST(FixedArrayTest,ManySizedArrays)444 TEST(FixedArrayTest, ManySizedArrays) {
445 std::vector<int> sizes;
446 for (int i = 1; i < 100; i++) sizes.push_back(i);
447 for (int i = 100; i <= 1000; i += 100) sizes.push_back(i);
448 for (int n : sizes) {
449 TestArray<0>(n);
450 TestArray<1>(n);
451 TestArray<64>(n);
452 TestArray<1000>(n);
453 }
454 }
455
TEST(FixedArrayTest,ManySizedArraysOfArraysOf1)456 TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) {
457 for (int n = 1; n < 1000; n++) {
458 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n)));
459 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n)));
460 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n)));
461 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n)));
462 }
463 }
464
TEST(FixedArrayTest,ManySizedArraysOfArraysOf2)465 TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) {
466 for (int n = 1; n < 1000; n++) {
467 TestArrayOfArrays<2, 0>(n);
468 TestArrayOfArrays<2, 1>(n);
469 TestArrayOfArrays<2, 64>(n);
470 TestArrayOfArrays<2, 1000>(n);
471 }
472 }
473
474 // If value_type is put inside of a struct container,
475 // we might evoke this error in a hardened build unless data() is carefully
476 // written, so check on that.
477 // error: call to int __builtin___sprintf_chk(etc...)
478 // will always overflow destination buffer [-Werror]
TEST(FixedArrayTest,AvoidParanoidDiagnostics)479 TEST(FixedArrayTest, AvoidParanoidDiagnostics) {
480 absl::FixedArray<char, 32> buf(32);
481 sprintf(buf.data(), "foo"); // NOLINT(runtime/printf)
482 }
483
TEST(FixedArrayTest,TooBigInlinedSpace)484 TEST(FixedArrayTest, TooBigInlinedSpace) {
485 struct TooBig {
486 char c[1 << 20];
487 }; // too big for even one on the stack
488
489 // Simulate the data members of absl::FixedArray, a pointer and a size_t.
490 struct Data {
491 TooBig* p;
492 size_t size;
493 };
494
495 // Make sure TooBig objects are not inlined for 0 or default size.
496 static_assert(sizeof(absl::FixedArray<TooBig, 0>) == sizeof(Data),
497 "0-sized absl::FixedArray should have same size as Data.");
498 static_assert(alignof(absl::FixedArray<TooBig, 0>) == alignof(Data),
499 "0-sized absl::FixedArray should have same alignment as Data.");
500 static_assert(sizeof(absl::FixedArray<TooBig>) == sizeof(Data),
501 "default-sized absl::FixedArray should have same size as Data");
502 static_assert(
503 alignof(absl::FixedArray<TooBig>) == alignof(Data),
504 "default-sized absl::FixedArray should have same alignment as Data.");
505 }
506
507 // PickyDelete EXPECTs its class-scope deallocation funcs are unused.
508 struct PickyDelete {
PickyDelete__anon100667ba0111::PickyDelete509 PickyDelete() {}
~PickyDelete__anon100667ba0111::PickyDelete510 ~PickyDelete() {}
operator delete__anon100667ba0111::PickyDelete511 void operator delete(void* p) {
512 EXPECT_TRUE(false) << __FUNCTION__;
513 ::operator delete(p);
514 }
operator delete[]__anon100667ba0111::PickyDelete515 void operator delete[](void* p) {
516 EXPECT_TRUE(false) << __FUNCTION__;
517 ::operator delete[](p);
518 }
519 };
520
TEST(FixedArrayTest,UsesGlobalAlloc)521 TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray<PickyDelete, 0> a(5); }
522
TEST(FixedArrayTest,Data)523 TEST(FixedArrayTest, Data) {
524 static const int kInput[] = {2, 3, 5, 7, 11, 13, 17};
525 absl::FixedArray<int> fa(std::begin(kInput), std::end(kInput));
526 EXPECT_EQ(fa.data(), &*fa.begin());
527 EXPECT_EQ(fa.data(), &fa[0]);
528
529 const absl::FixedArray<int>& cfa = fa;
530 EXPECT_EQ(cfa.data(), &*cfa.begin());
531 EXPECT_EQ(cfa.data(), &cfa[0]);
532 }
533
TEST(FixedArrayTest,Empty)534 TEST(FixedArrayTest, Empty) {
535 absl::FixedArray<int> empty(0);
536 absl::FixedArray<int> inline_filled(1);
537 absl::FixedArray<int, 0> heap_filled(1);
538 EXPECT_TRUE(empty.empty());
539 EXPECT_FALSE(inline_filled.empty());
540 EXPECT_FALSE(heap_filled.empty());
541 }
542
TEST(FixedArrayTest,FrontAndBack)543 TEST(FixedArrayTest, FrontAndBack) {
544 absl::FixedArray<int, 3 * sizeof(int)> inlined = {1, 2, 3};
545 EXPECT_EQ(inlined.front(), 1);
546 EXPECT_EQ(inlined.back(), 3);
547
548 absl::FixedArray<int, 0> allocated = {1, 2, 3};
549 EXPECT_EQ(allocated.front(), 1);
550 EXPECT_EQ(allocated.back(), 3);
551
552 absl::FixedArray<int> one_element = {1};
553 EXPECT_EQ(one_element.front(), one_element.back());
554 }
555
TEST(FixedArrayTest,ReverseIteratorInlined)556 TEST(FixedArrayTest, ReverseIteratorInlined) {
557 absl::FixedArray<int, 5 * sizeof(int)> a = {0, 1, 2, 3, 4};
558
559 int counter = 5;
560 for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
561 iter != a.rend(); ++iter) {
562 counter--;
563 EXPECT_EQ(counter, *iter);
564 }
565 EXPECT_EQ(counter, 0);
566
567 counter = 5;
568 for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
569 iter != a.rend(); ++iter) {
570 counter--;
571 EXPECT_EQ(counter, *iter);
572 }
573 EXPECT_EQ(counter, 0);
574
575 counter = 5;
576 for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
577 counter--;
578 EXPECT_EQ(counter, *iter);
579 }
580 EXPECT_EQ(counter, 0);
581 }
582
TEST(FixedArrayTest,ReverseIteratorAllocated)583 TEST(FixedArrayTest, ReverseIteratorAllocated) {
584 absl::FixedArray<int, 0> a = {0, 1, 2, 3, 4};
585
586 int counter = 5;
587 for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
588 iter != a.rend(); ++iter) {
589 counter--;
590 EXPECT_EQ(counter, *iter);
591 }
592 EXPECT_EQ(counter, 0);
593
594 counter = 5;
595 for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
596 iter != a.rend(); ++iter) {
597 counter--;
598 EXPECT_EQ(counter, *iter);
599 }
600 EXPECT_EQ(counter, 0);
601
602 counter = 5;
603 for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
604 counter--;
605 EXPECT_EQ(counter, *iter);
606 }
607 EXPECT_EQ(counter, 0);
608 }
609
TEST(FixedArrayTest,Fill)610 TEST(FixedArrayTest, Fill) {
611 absl::FixedArray<int, 5 * sizeof(int)> inlined(5);
612 int fill_val = 42;
613 inlined.fill(fill_val);
614 for (int i : inlined) EXPECT_EQ(i, fill_val);
615
616 absl::FixedArray<int, 0> allocated(5);
617 allocated.fill(fill_val);
618 for (int i : allocated) EXPECT_EQ(i, fill_val);
619
620 // It doesn't do anything, just make sure this compiles.
621 absl::FixedArray<int> empty(0);
622 empty.fill(fill_val);
623 }
624
625 #ifndef __GNUC__
TEST(FixedArrayTest,DefaultCtorDoesNotValueInit)626 TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
627 using T = char;
628 constexpr auto capacity = 10;
629 using FixedArrType = absl::FixedArray<T, capacity>;
630 constexpr auto scrubbed_bits = 0x95;
631 constexpr auto length = capacity / 2;
632
633 alignas(FixedArrType) unsigned char buff[sizeof(FixedArrType)];
634 std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrType));
635
636 FixedArrType* arr =
637 ::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length);
638 EXPECT_THAT(*arr, testing::Each(scrubbed_bits));
639 arr->~FixedArrType();
640 }
641 #endif // __GNUC__
642
TEST(AllocatorSupportTest,CountInlineAllocations)643 TEST(AllocatorSupportTest, CountInlineAllocations) {
644 constexpr size_t inlined_size = 4;
645 using Alloc = absl::container_internal::CountingAllocator<int>;
646 using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
647
648 int64_t allocated = 0;
649 int64_t active_instances = 0;
650
651 {
652 const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
653
654 Alloc alloc(&allocated, &active_instances);
655
656 AllocFxdArr arr(ia, ia + inlined_size, alloc);
657 static_cast<void>(arr);
658 }
659
660 EXPECT_EQ(allocated, 0);
661 EXPECT_EQ(active_instances, 0);
662 }
663
TEST(AllocatorSupportTest,CountOutoflineAllocations)664 TEST(AllocatorSupportTest, CountOutoflineAllocations) {
665 constexpr size_t inlined_size = 4;
666 using Alloc = absl::container_internal::CountingAllocator<int>;
667 using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
668
669 int64_t allocated = 0;
670 int64_t active_instances = 0;
671
672 {
673 const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
674 Alloc alloc(&allocated, &active_instances);
675
676 AllocFxdArr arr(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
677
678 EXPECT_EQ(allocated, arr.size() * sizeof(int));
679 static_cast<void>(arr);
680 }
681
682 EXPECT_EQ(active_instances, 0);
683 }
684
TEST(AllocatorSupportTest,CountCopyInlineAllocations)685 TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
686 constexpr size_t inlined_size = 4;
687 using Alloc = absl::container_internal::CountingAllocator<int>;
688 using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
689
690 int64_t allocated1 = 0;
691 int64_t allocated2 = 0;
692 int64_t active_instances = 0;
693 Alloc alloc(&allocated1, &active_instances);
694 Alloc alloc2(&allocated2, &active_instances);
695
696 {
697 int initial_value = 1;
698
699 AllocFxdArr arr1(inlined_size / 2, initial_value, alloc);
700
701 EXPECT_EQ(allocated1, 0);
702
703 AllocFxdArr arr2(arr1, alloc2);
704
705 EXPECT_EQ(allocated2, 0);
706 static_cast<void>(arr1);
707 static_cast<void>(arr2);
708 }
709
710 EXPECT_EQ(active_instances, 0);
711 }
712
TEST(AllocatorSupportTest,CountCopyOutoflineAllocations)713 TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
714 constexpr size_t inlined_size = 4;
715 using Alloc = absl::container_internal::CountingAllocator<int>;
716 using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
717
718 int64_t allocated1 = 0;
719 int64_t allocated2 = 0;
720 int64_t active_instances = 0;
721 Alloc alloc(&allocated1, &active_instances);
722 Alloc alloc2(&allocated2, &active_instances);
723
724 {
725 int initial_value = 1;
726
727 AllocFxdArr arr1(inlined_size * 2, initial_value, alloc);
728
729 EXPECT_EQ(allocated1, arr1.size() * sizeof(int));
730
731 AllocFxdArr arr2(arr1, alloc2);
732
733 EXPECT_EQ(allocated2, inlined_size * 2 * sizeof(int));
734 static_cast<void>(arr1);
735 static_cast<void>(arr2);
736 }
737
738 EXPECT_EQ(active_instances, 0);
739 }
740
TEST(AllocatorSupportTest,SizeValAllocConstructor)741 TEST(AllocatorSupportTest, SizeValAllocConstructor) {
742 using testing::AllOf;
743 using testing::Each;
744 using testing::SizeIs;
745
746 constexpr size_t inlined_size = 4;
747 using Alloc = absl::container_internal::CountingAllocator<int>;
748 using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
749
750 {
751 auto len = inlined_size / 2;
752 auto val = 0;
753 int64_t allocated = 0;
754 AllocFxdArr arr(len, val, Alloc(&allocated));
755
756 EXPECT_EQ(allocated, 0);
757 EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
758 }
759
760 {
761 auto len = inlined_size * 2;
762 auto val = 0;
763 int64_t allocated = 0;
764 AllocFxdArr arr(len, val, Alloc(&allocated));
765
766 EXPECT_EQ(allocated, len * sizeof(int));
767 EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0)));
768 }
769 }
770
771 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
TEST(FixedArrayTest,AddressSanitizerAnnotations1)772 TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
773 absl::FixedArray<int, 32> a(10);
774 int* raw = a.data();
775 raw[0] = 0;
776 raw[9] = 0;
777 EXPECT_DEATH_IF_SUPPORTED(raw[-2] = 0, "container-overflow");
778 EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
779 EXPECT_DEATH_IF_SUPPORTED(raw[10] = 0, "container-overflow");
780 EXPECT_DEATH_IF_SUPPORTED(raw[31] = 0, "container-overflow");
781 }
782
TEST(FixedArrayTest,AddressSanitizerAnnotations2)783 TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
784 absl::FixedArray<char, 17> a(12);
785 char* raw = a.data();
786 raw[0] = 0;
787 raw[11] = 0;
788 EXPECT_DEATH_IF_SUPPORTED(raw[-7] = 0, "container-overflow");
789 EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
790 EXPECT_DEATH_IF_SUPPORTED(raw[12] = 0, "container-overflow");
791 EXPECT_DEATH_IF_SUPPORTED(raw[17] = 0, "container-overflow");
792 }
793
TEST(FixedArrayTest,AddressSanitizerAnnotations3)794 TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
795 absl::FixedArray<uint64_t, 20> a(20);
796 uint64_t* raw = a.data();
797 raw[0] = 0;
798 raw[19] = 0;
799 EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
800 EXPECT_DEATH_IF_SUPPORTED(raw[20] = 0, "container-overflow");
801 }
802
TEST(FixedArrayTest,AddressSanitizerAnnotations4)803 TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
804 absl::FixedArray<ThreeInts> a(10);
805 ThreeInts* raw = a.data();
806 raw[0] = ThreeInts();
807 raw[9] = ThreeInts();
808 // Note: raw[-1] is pointing to 12 bytes before the container range. However,
809 // there is only a 8-byte red zone before the container range, so we only
810 // access the last 4 bytes of the struct to make sure it stays within the red
811 // zone.
812 EXPECT_DEATH_IF_SUPPORTED(raw[-1].z_ = 0, "container-overflow");
813 EXPECT_DEATH_IF_SUPPORTED(raw[10] = ThreeInts(), "container-overflow");
814 // The actual size of storage is kDefaultBytes=256, 21*12 = 252,
815 // so reading raw[21] should still trigger the correct warning.
816 EXPECT_DEATH_IF_SUPPORTED(raw[21] = ThreeInts(), "container-overflow");
817 }
818 #endif // ABSL_HAVE_ADDRESS_SANITIZER
819
TEST(FixedArrayTest,AbslHashValueWorks)820 TEST(FixedArrayTest, AbslHashValueWorks) {
821 using V = absl::FixedArray<int>;
822 std::vector<V> cases;
823
824 // Generate a variety of vectors some of these are small enough for the inline
825 // space but are stored out of line.
826 for (int i = 0; i < 10; ++i) {
827 V v(i);
828 for (int j = 0; j < i; ++j) {
829 v[j] = j;
830 }
831 cases.push_back(v);
832 }
833
834 EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
835 }
836
837 } // namespace
838