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