| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "base/stack_container.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/memory/aligned_memory.h" | |
| 10 #include "base/memory/ref_counted.h" | |
| 11 #include "testing/gtest/include/gtest/gtest.h" | |
| 12 | |
| 13 namespace { | |
| 14 | |
| 15 class Dummy : public base::RefCounted<Dummy> { | |
| 16 public: | |
| 17 explicit Dummy(int* alive) : alive_(alive) { | |
| 18 ++*alive_; | |
| 19 } | |
| 20 | |
| 21 private: | |
| 22 friend class base::RefCounted<Dummy>; | |
| 23 | |
| 24 ~Dummy() { | |
| 25 --*alive_; | |
| 26 } | |
| 27 | |
| 28 int* const alive_; | |
| 29 }; | |
| 30 | |
| 31 } // namespace | |
| 32 | |
| 33 TEST(StackContainer, Vector) { | |
| 34 const int stack_size = 3; | |
| 35 StackVector<int, stack_size> vect; | |
| 36 const int* stack_buffer = &vect.stack_data().stack_buffer()[0]; | |
| 37 | |
| 38 // The initial |stack_size| elements should appear in the stack buffer. | |
| 39 EXPECT_EQ(static_cast<size_t>(stack_size), vect.container().capacity()); | |
| 40 for (int i = 0; i < stack_size; i++) { | |
| 41 vect.container().push_back(i); | |
| 42 EXPECT_EQ(stack_buffer, &vect.container()[0]); | |
| 43 EXPECT_TRUE(vect.stack_data().used_stack_buffer_); | |
| 44 } | |
| 45 | |
| 46 // Adding more elements should push the array onto the heap. | |
| 47 for (int i = 0; i < stack_size; i++) { | |
| 48 vect.container().push_back(i + stack_size); | |
| 49 EXPECT_NE(stack_buffer, &vect.container()[0]); | |
| 50 EXPECT_FALSE(vect.stack_data().used_stack_buffer_); | |
| 51 } | |
| 52 | |
| 53 // The array should still be in order. | |
| 54 for (int i = 0; i < stack_size * 2; i++) | |
| 55 EXPECT_EQ(i, vect.container()[i]); | |
| 56 | |
| 57 // Resize to smaller. Our STL implementation won't reallocate in this case, | |
| 58 // otherwise it might use our stack buffer. We reserve right after the resize | |
| 59 // to guarantee it isn't using the stack buffer, even though it doesn't have | |
| 60 // much data. | |
| 61 vect.container().resize(stack_size); | |
| 62 vect.container().reserve(stack_size * 2); | |
| 63 EXPECT_FALSE(vect.stack_data().used_stack_buffer_); | |
| 64 | |
| 65 // Copying the small vector to another should use the same allocator and use | |
| 66 // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since | |
| 67 // they have to get the template types just right and it can cause errors. | |
| 68 std::vector<int, StackAllocator<int, stack_size> > other(vect.container()); | |
| 69 EXPECT_EQ(stack_buffer, &other.front()); | |
| 70 EXPECT_TRUE(vect.stack_data().used_stack_buffer_); | |
| 71 for (int i = 0; i < stack_size; i++) | |
| 72 EXPECT_EQ(i, other[i]); | |
| 73 } | |
| 74 | |
| 75 TEST(StackContainer, VectorDoubleDelete) { | |
| 76 // Regression testing for double-delete. | |
| 77 typedef StackVector<scoped_refptr<Dummy>, 2> Vector; | |
| 78 typedef Vector::ContainerType Container; | |
| 79 Vector vect; | |
| 80 | |
| 81 int alive = 0; | |
| 82 scoped_refptr<Dummy> dummy(new Dummy(&alive)); | |
| 83 EXPECT_EQ(alive, 1); | |
| 84 | |
| 85 vect->push_back(dummy); | |
| 86 EXPECT_EQ(alive, 1); | |
| 87 | |
| 88 Dummy* dummy_unref = dummy.get(); | |
| 89 dummy = NULL; | |
| 90 EXPECT_EQ(alive, 1); | |
| 91 | |
| 92 Container::iterator itr = std::find(vect->begin(), vect->end(), dummy_unref); | |
| 93 EXPECT_EQ(itr->get(), dummy_unref); | |
| 94 vect->erase(itr); | |
| 95 EXPECT_EQ(alive, 0); | |
| 96 | |
| 97 // Shouldn't crash at exit. | |
| 98 } | |
| 99 | |
| 100 namespace { | |
| 101 | |
| 102 template <size_t alignment> | |
| 103 class AlignedData { | |
| 104 public: | |
| 105 AlignedData() { memset(data_.void_data(), 0, alignment); } | |
| 106 ~AlignedData() {} | |
| 107 base::AlignedMemory<alignment, alignment> data_; | |
| 108 }; | |
| 109 | |
| 110 } // anonymous namespace | |
| 111 | |
| 112 #define EXPECT_ALIGNED(ptr, align) \ | |
| 113 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) | |
| 114 | |
| 115 TEST(StackContainer, BufferAlignment) { | |
| 116 StackVector<wchar_t, 16> text; | |
| 117 text->push_back(L'A'); | |
| 118 EXPECT_ALIGNED(&text[0], ALIGNOF(wchar_t)); | |
| 119 | |
| 120 StackVector<double, 1> doubles; | |
| 121 doubles->push_back(0.0); | |
| 122 EXPECT_ALIGNED(&doubles[0], ALIGNOF(double)); | |
| 123 | |
| 124 StackVector<AlignedData<16>, 1> aligned16; | |
| 125 aligned16->push_back(AlignedData<16>()); | |
| 126 EXPECT_ALIGNED(&aligned16[0], 16); | |
| 127 | |
| 128 #if !defined(OS_ANDROID) | |
| 129 // It seems that android doesn't respect greater than 16 byte alignment for | |
| 130 // non-POD data on the stack, even though ALIGNOF(aligned256) == 256. | |
| 131 StackVector<AlignedData<256>, 1> aligned256; | |
| 132 aligned256->push_back(AlignedData<256>()); | |
| 133 EXPECT_ALIGNED(&aligned256[0], 256); | |
| 134 #endif | |
| 135 } | |
| 136 | |
| 137 template class StackVector<int, 2>; | |
| 138 template class StackVector<scoped_refptr<Dummy>, 2>; | |
| OLD | NEW |