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