1 // Copyright (c) 2011 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. 4 5 #include "base/stack_container.h" 6 7 #include <algorithm> 8 9 #include "base/memory/ref_counted.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace { 13 14 class Dummy : public base::RefCounted<Dummy> { 15 public: 16 explicit Dummy(int* alive) : alive_(alive) { 17 ++*alive_; 18 } 19 20 private: 21 friend class base::RefCounted<Dummy>; 22 23 ~Dummy() { 24 --*alive_; 25 } 26 27 int* const alive_; 28 }; 29 30 } // namespace 31 32 TEST(StackContainer, Vector) { 33 const int stack_size = 3; 34 StackVector<int, stack_size> vect; 35 const int* stack_buffer = &vect.stack_data().stack_buffer()[0]; 36 37 // The initial |stack_size| elements should appear in the stack buffer. 38 EXPECT_EQ(static_cast<size_t>(stack_size), vect.container().capacity()); 39 for (int i = 0; i < stack_size; i++) { 40 vect.container().push_back(i); 41 EXPECT_EQ(stack_buffer, &vect.container()[0]); 42 EXPECT_TRUE(vect.stack_data().used_stack_buffer_); 43 } 44 45 // Adding more elements should push the array onto the heap. 46 for (int i = 0; i < stack_size; i++) { 47 vect.container().push_back(i + stack_size); 48 EXPECT_NE(stack_buffer, &vect.container()[0]); 49 EXPECT_FALSE(vect.stack_data().used_stack_buffer_); 50 } 51 52 // The array should still be in order. 53 for (int i = 0; i < stack_size * 2; i++) 54 EXPECT_EQ(i, vect.container()[i]); 55 56 // Resize to smaller. Our STL implementation won't reallocate in this case, 57 // otherwise it might use our stack buffer. We reserve right after the resize 58 // to guarantee it isn't using the stack buffer, even though it doesn't have 59 // much data. 60 vect.container().resize(stack_size); 61 vect.container().reserve(stack_size * 2); 62 EXPECT_FALSE(vect.stack_data().used_stack_buffer_); 63 64 // Copying the small vector to another should use the same allocator and use 65 // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since 66 // they have to get the template types just right and it can cause errors. 67 std::vector<int, StackAllocator<int, stack_size> > other(vect.container()); 68 EXPECT_EQ(stack_buffer, &other.front()); 69 EXPECT_TRUE(vect.stack_data().used_stack_buffer_); 70 for (int i = 0; i < stack_size; i++) 71 EXPECT_EQ(i, other[i]); 72 } 73 74 TEST(StackContainer, VectorDoubleDelete) { 75 // Regression testing for double-delete. 76 typedef StackVector<scoped_refptr<Dummy>, 2> Vector; 77 typedef Vector::ContainerType Container; 78 Vector vect; 79 80 int alive = 0; 81 scoped_refptr<Dummy> dummy(new Dummy(&alive)); 82 EXPECT_EQ(alive, 1); 83 84 vect->push_back(dummy); 85 EXPECT_EQ(alive, 1); 86 87 Dummy* dummy_unref = dummy.get(); 88 dummy = NULL; 89 EXPECT_EQ(alive, 1); 90 91 Container::iterator itr = std::find(vect->begin(), vect->end(), dummy_unref); 92 EXPECT_EQ(itr->get(), dummy_unref); 93 vect->erase(itr); 94 EXPECT_EQ(alive, 0); 95 96 // Shouldn't crash at exit. 97 } 98 99 TEST(StackContainer, BufferAlignment) { 100 StackVector<wchar_t, 16> text; 101 text->push_back(L'A'); 102 text->push_back(L'B'); 103 text->push_back(L'C'); 104 text->push_back(L'D'); 105 text->push_back(L'E'); 106 text->push_back(L'F'); 107 text->push_back(0); 108 109 const wchar_t* buffer = &text[1]; 110 bool even_aligned = (0 == (((size_t)buffer) & 0x1)); 111 EXPECT_EQ(even_aligned, true); 112 } 113 114 #ifdef COMPILER_MSVC 115 // Make sure all the class compiles correctly. 116 // TODO(pinkerton): i'm not sure why this doesn't compile on GCC, but 117 // it doesn't. 118 template StackVector<int, 2>; 119 template StackVector<scoped_refptr<Dummy>, 2>; 120 #endif 121