1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/containers/stack_container.h"
9 #include "base/memory/aligned_memory.h"
10 #include "base/memory/ref_counted.h"
11 #include "testing/gtest/include/gtest/gtest.h"
17 class Dummy
: public base::RefCounted
<Dummy
> {
19 explicit Dummy(int* alive
) : alive_(alive
) {
24 friend class base::RefCounted
<Dummy
>;
35 TEST(StackContainer
, Vector
) {
36 const int stack_size
= 3;
37 StackVector
<int, stack_size
> vect
;
38 const int* stack_buffer
= &vect
.stack_data().stack_buffer()[0];
40 // The initial |stack_size| elements should appear in the stack buffer.
41 EXPECT_EQ(static_cast<size_t>(stack_size
), vect
.container().capacity());
42 for (int i
= 0; i
< stack_size
; i
++) {
43 vect
.container().push_back(i
);
44 EXPECT_EQ(stack_buffer
, &vect
.container()[0]);
45 EXPECT_TRUE(vect
.stack_data().used_stack_buffer_
);
48 // Adding more elements should push the array onto the heap.
49 for (int i
= 0; i
< stack_size
; i
++) {
50 vect
.container().push_back(i
+ stack_size
);
51 EXPECT_NE(stack_buffer
, &vect
.container()[0]);
52 EXPECT_FALSE(vect
.stack_data().used_stack_buffer_
);
55 // The array should still be in order.
56 for (int i
= 0; i
< stack_size
* 2; i
++)
57 EXPECT_EQ(i
, vect
.container()[i
]);
59 // Resize to smaller. Our STL implementation won't reallocate in this case,
60 // otherwise it might use our stack buffer. We reserve right after the resize
61 // to guarantee it isn't using the stack buffer, even though it doesn't have
63 vect
.container().resize(stack_size
);
64 vect
.container().reserve(stack_size
* 2);
65 EXPECT_FALSE(vect
.stack_data().used_stack_buffer_
);
67 // Copying the small vector to another should use the same allocator and use
68 // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since
69 // they have to get the template types just right and it can cause errors.
70 std::vector
<int, StackAllocator
<int, stack_size
> > other(vect
.container());
71 EXPECT_EQ(stack_buffer
, &other
.front());
72 EXPECT_TRUE(vect
.stack_data().used_stack_buffer_
);
73 for (int i
= 0; i
< stack_size
; i
++)
74 EXPECT_EQ(i
, other
[i
]);
77 TEST(StackContainer
, VectorDoubleDelete
) {
78 // Regression testing for double-delete.
79 typedef StackVector
<scoped_refptr
<Dummy
>, 2> Vector
;
80 typedef Vector::ContainerType Container
;
84 scoped_refptr
<Dummy
> dummy(new Dummy(&alive
));
87 vect
->push_back(dummy
);
90 Dummy
* dummy_unref
= dummy
.get();
94 Container::iterator itr
= std::find(vect
->begin(), vect
->end(), dummy_unref
);
95 EXPECT_EQ(itr
->get(), dummy_unref
);
99 // Shouldn't crash at exit.
104 template <size_t alignment
>
107 AlignedData() { memset(data_
.void_data(), 0, alignment
); }
109 base::AlignedMemory
<alignment
, alignment
> data_
;
112 } // anonymous namespace
114 #define EXPECT_ALIGNED(ptr, align) \
115 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
117 TEST(StackContainer
, BufferAlignment
) {
118 StackVector
<wchar_t, 16> text
;
119 text
->push_back(L
'A');
120 EXPECT_ALIGNED(&text
[0], ALIGNOF(wchar_t));
122 StackVector
<double, 1> doubles
;
123 doubles
->push_back(0.0);
124 EXPECT_ALIGNED(&doubles
[0], ALIGNOF(double));
126 StackVector
<AlignedData
<16>, 1> aligned16
;
127 aligned16
->push_back(AlignedData
<16>());
128 EXPECT_ALIGNED(&aligned16
[0], 16);
130 #if !defined(__GNUC__) || defined(ARCH_CPU_X86_FAMILY)
131 // It seems that non-X86 gcc doesn't respect greater than 16 byte alignment.
132 // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33721 for details.
133 // TODO(sbc):re-enable this if GCC starts respecting higher alignments.
134 StackVector
<AlignedData
<256>, 1> aligned256
;
135 aligned256
->push_back(AlignedData
<256>());
136 EXPECT_ALIGNED(&aligned256
[0], 256);
140 template class StackVector
<int, 2>;
141 template class StackVector
<scoped_refptr
<Dummy
>, 2>;