Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(36)

Side by Side Diff: base/stack_container.h

Issue 11360174: Move stack_container and linked_list to the new containers subdirectory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/linked_list_unittest.cc ('k') | base/stack_container_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 #ifndef BASE_STACK_CONTAINER_H_
6 #define BASE_STACK_CONTAINER_H_
7
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "build/build_config.h"
13 #include "base/memory/aligned_memory.h"
14
15 // This allocator can be used with STL containers to provide a stack buffer
16 // from which to allocate memory and overflows onto the heap. This stack buffer
17 // would be allocated on the stack and allows us to avoid heap operations in
18 // some situations.
19 //
20 // STL likes to make copies of allocators, so the allocator itself can't hold
21 // the data. Instead, we make the creator responsible for creating a
22 // StackAllocator::Source which contains the data. Copying the allocator
23 // merely copies the pointer to this shared source, so all allocators created
24 // based on our allocator will share the same stack buffer.
25 //
26 // This stack buffer implementation is very simple. The first allocation that
27 // fits in the stack buffer will use the stack buffer. Any subsequent
28 // allocations will not use the stack buffer, even if there is unused room.
29 // This makes it appropriate for array-like containers, but the caller should
30 // be sure to reserve() in the container up to the stack buffer size. Otherwise
31 // the container will allocate a small array which will "use up" the stack
32 // buffer.
33 template<typename T, size_t stack_capacity>
34 class StackAllocator : public std::allocator<T> {
35 public:
36 typedef typename std::allocator<T>::pointer pointer;
37 typedef typename std::allocator<T>::size_type size_type;
38
39 // Backing store for the allocator. The container owner is responsible for
40 // maintaining this for as long as any containers using this allocator are
41 // live.
42 struct Source {
43 Source() : used_stack_buffer_(false) {
44 }
45
46 // Casts the buffer in its right type.
47 T* stack_buffer() { return stack_buffer_.template data_as<T>(); }
48 const T* stack_buffer() const {
49 return stack_buffer_.template data_as<T>();
50 }
51
52 // The buffer itself. It is not of type T because we don't want the
53 // constructors and destructors to be automatically called. Define a POD
54 // buffer of the right size instead.
55 base::AlignedMemory<sizeof(T[stack_capacity]), ALIGNOF(T)> stack_buffer_;
56 #if defined(OS_ANDROID)
57 COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612);
58 #endif
59
60 // Set when the stack buffer is used for an allocation. We do not track
61 // how much of the buffer is used, only that somebody is using it.
62 bool used_stack_buffer_;
63 };
64
65 // Used by containers when they want to refer to an allocator of type U.
66 template<typename U>
67 struct rebind {
68 typedef StackAllocator<U, stack_capacity> other;
69 };
70
71 // For the straight up copy c-tor, we can share storage.
72 StackAllocator(const StackAllocator<T, stack_capacity>& rhs)
73 : std::allocator<T>(), source_(rhs.source_) {
74 }
75
76 // ISO C++ requires the following constructor to be defined,
77 // and std::vector in VC++2008SP1 Release fails with an error
78 // in the class _Container_base_aux_alloc_real (from <xutility>)
79 // if the constructor does not exist.
80 // For this constructor, we cannot share storage; there's
81 // no guarantee that the Source buffer of Ts is large enough
82 // for Us.
83 // TODO: If we were fancy pants, perhaps we could share storage
84 // iff sizeof(T) == sizeof(U).
85 template<typename U, size_t other_capacity>
86 StackAllocator(const StackAllocator<U, other_capacity>& other)
87 : source_(NULL) {
88 }
89
90 explicit StackAllocator(Source* source) : source_(source) {
91 }
92
93 // Actually do the allocation. Use the stack buffer if nobody has used it yet
94 // and the size requested fits. Otherwise, fall through to the standard
95 // allocator.
96 pointer allocate(size_type n, void* hint = 0) {
97 if (source_ != NULL && !source_->used_stack_buffer_
98 && n <= stack_capacity) {
99 source_->used_stack_buffer_ = true;
100 return source_->stack_buffer();
101 } else {
102 return std::allocator<T>::allocate(n, hint);
103 }
104 }
105
106 // Free: when trying to free the stack buffer, just mark it as free. For
107 // non-stack-buffer pointers, just fall though to the standard allocator.
108 void deallocate(pointer p, size_type n) {
109 if (source_ != NULL && p == source_->stack_buffer())
110 source_->used_stack_buffer_ = false;
111 else
112 std::allocator<T>::deallocate(p, n);
113 }
114
115 private:
116 Source* source_;
117 };
118
119 // A wrapper around STL containers that maintains a stack-sized buffer that the
120 // initial capacity of the vector is based on. Growing the container beyond the
121 // stack capacity will transparently overflow onto the heap. The container must
122 // support reserve().
123 //
124 // WATCH OUT: the ContainerType MUST use the proper StackAllocator for this
125 // type. This object is really intended to be used only internally. You'll want
126 // to use the wrappers below for different types.
127 template<typename TContainerType, int stack_capacity>
128 class StackContainer {
129 public:
130 typedef TContainerType ContainerType;
131 typedef typename ContainerType::value_type ContainedType;
132 typedef StackAllocator<ContainedType, stack_capacity> Allocator;
133
134 // Allocator must be constructed before the container!
135 StackContainer() : allocator_(&stack_data_), container_(allocator_) {
136 // Make the container use the stack allocation by reserving our buffer size
137 // before doing anything else.
138 container_.reserve(stack_capacity);
139 }
140
141 // Getters for the actual container.
142 //
143 // Danger: any copies of this made using the copy constructor must have
144 // shorter lifetimes than the source. The copy will share the same allocator
145 // and therefore the same stack buffer as the original. Use std::copy to
146 // copy into a "real" container for longer-lived objects.
147 ContainerType& container() { return container_; }
148 const ContainerType& container() const { return container_; }
149
150 // Support operator-> to get to the container. This allows nicer syntax like:
151 // StackContainer<...> foo;
152 // std::sort(foo->begin(), foo->end());
153 ContainerType* operator->() { return &container_; }
154 const ContainerType* operator->() const { return &container_; }
155
156 #ifdef UNIT_TEST
157 // Retrieves the stack source so that that unit tests can verify that the
158 // buffer is being used properly.
159 const typename Allocator::Source& stack_data() const {
160 return stack_data_;
161 }
162 #endif
163
164 protected:
165 typename Allocator::Source stack_data_;
166 Allocator allocator_;
167 ContainerType container_;
168
169 DISALLOW_COPY_AND_ASSIGN(StackContainer);
170 };
171
172 // StackString
173 template<size_t stack_capacity>
174 class StackString : public StackContainer<
175 std::basic_string<char,
176 std::char_traits<char>,
177 StackAllocator<char, stack_capacity> >,
178 stack_capacity> {
179 public:
180 StackString() : StackContainer<
181 std::basic_string<char,
182 std::char_traits<char>,
183 StackAllocator<char, stack_capacity> >,
184 stack_capacity>() {
185 }
186
187 private:
188 DISALLOW_COPY_AND_ASSIGN(StackString);
189 };
190
191 // StackWString
192 template<size_t stack_capacity>
193 class StackWString : public StackContainer<
194 std::basic_string<wchar_t,
195 std::char_traits<wchar_t>,
196 StackAllocator<wchar_t, stack_capacity> >,
197 stack_capacity> {
198 public:
199 StackWString() : StackContainer<
200 std::basic_string<wchar_t,
201 std::char_traits<wchar_t>,
202 StackAllocator<wchar_t, stack_capacity> >,
203 stack_capacity>() {
204 }
205
206 private:
207 DISALLOW_COPY_AND_ASSIGN(StackWString);
208 };
209
210 // StackVector
211 //
212 // Example:
213 // StackVector<int, 16> foo;
214 // foo->push_back(22); // we have overloaded operator->
215 // foo[0] = 10; // as well as operator[]
216 template<typename T, size_t stack_capacity>
217 class StackVector : public StackContainer<
218 std::vector<T, StackAllocator<T, stack_capacity> >,
219 stack_capacity> {
220 public:
221 StackVector() : StackContainer<
222 std::vector<T, StackAllocator<T, stack_capacity> >,
223 stack_capacity>() {
224 }
225
226 // We need to put this in STL containers sometimes, which requires a copy
227 // constructor. We can't call the regular copy constructor because that will
228 // take the stack buffer from the original. Here, we create an empty object
229 // and make a stack buffer of its own.
230 StackVector(const StackVector<T, stack_capacity>& other)
231 : StackContainer<
232 std::vector<T, StackAllocator<T, stack_capacity> >,
233 stack_capacity>() {
234 this->container().assign(other->begin(), other->end());
235 }
236
237 StackVector<T, stack_capacity>& operator=(
238 const StackVector<T, stack_capacity>& other) {
239 this->container().assign(other->begin(), other->end());
240 return *this;
241 }
242
243 // Vectors are commonly indexed, which isn't very convenient even with
244 // operator-> (using "->at()" does exception stuff we don't want).
245 T& operator[](size_t i) { return this->container().operator[](i); }
246 const T& operator[](size_t i) const {
247 return this->container().operator[](i);
248 }
249 };
250
251 #endif // BASE_STACK_CONTAINER_H_
OLDNEW
« no previous file with comments | « base/linked_list_unittest.cc ('k') | base/stack_container_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698