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