blob: d4aee747f3dfe31a06b1cefb83ed385e626c79c4 [file] [log] [blame]
Brian Silverman70325d62015-09-20 17:00:43 -04001// Copyright (c) 2000, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29// ---
30//
31// Reorganized by Craig Silverstein
32//
33// In this file we define the arena template code. This includes the
34// ArenaAllocator, which is meant only to be used with STL, and also
35// the Gladiator (which needs to know how to new and delete various
36// types of objects).
37//
38// If you're only using the MALLOC-LIKE functionality of the arena,
39// you don't need to include this file at all! You do need to include
40// it (in your own .cc file) if you want to use the STRING, STL, or
41// NEW aspects of the arena. See arena.h for details on these types.
42//
43// ArenaAllocator is an STL allocator, but because it relies on unequal
44// instances, it may not work with all standards-conforming STL
45// implementations. But it works with SGI STL so we're happy.
46//
47// Here's an example of how the ArenaAllocator would be used.
48// Say we have a vector of ints that we want to have use the arena
49// for memory allocation. Here's one way to do it:
50// UnsafeArena* arena = new UnsafeArena(1000); // or SafeArena(), or 10000
51// vector<int, ArenaAllocator<int, UnsafeArena> > v(arena);
52//
53// Note that every STL type always allows the allocator (in this case,
54// the arena, which is automatically promoted to an allocator) as the last
55// arg to the constructor. So if you would normally do
56// vector<...> v(foo, bar),
57// with the arena you can do
58// vector<...> v(foo, bar, arena);
59
60#ifndef BASE_ARENA_INL_H_
61#define BASE_ARENA_INL_H_
62
63#include <config.h>
64#include "base/arena.h"
65#include <assert.h>
66#include <stddef.h>
67#include <new>
68#include <memory>
69
70namespace ctemplate {
71
72// T is the type we want to allocate, and C is the type of the arena.
73// ArenaAllocator has the thread-safety characteristics of C.
74template <class T, class C> class ArenaAllocator {
75 public:
76 typedef T value_type;
77 typedef size_t size_type;
78 typedef ptrdiff_t difference_type;
79
80 typedef T* pointer;
81 typedef const T* const_pointer;
82 typedef T& reference;
83 typedef const T& const_reference;
84 pointer address(reference r) const { return &r; }
85 const_pointer address(const_reference r) const { return &r; }
86 size_type max_size() const { return size_t(-1) / sizeof(T); }
87
88 // DO NOT USE! The default constructor is for gcc3 compatibility only.
89 ArenaAllocator() : arena_(0) { }
90 // This is not an explicit constructor! So you can pass in an arena*
91 // to functions needing an ArenaAllocator (like the astring constructor)
92 // and everything will work ok.
93 ArenaAllocator(C* arena) : arena_(arena) { } // NOLINT
94 ~ArenaAllocator() { }
95
96 pointer allocate(size_type n,
97 std::allocator<void>::const_pointer /*hint*/ = 0) {
98 assert(arena_ && "No arena to allocate from!");
99 return reinterpret_cast<T*>(arena_->AllocAligned(n * sizeof(T),
100 kAlignment));
101 }
102 void deallocate(pointer p, size_type n) {
103 arena_->Free(p, n * sizeof(T));
104 }
105 void construct(pointer p, const T & val) {
106 new(reinterpret_cast<void*>(p)) T(val);
107 }
108 void construct(pointer p) {
109 new(reinterpret_cast<void*>(p)) T();
110 }
111 void destroy(pointer p) { p->~T(); }
112
113 C* arena(void) const { return arena_; }
114
115 template<class U> struct rebind {
116 typedef ArenaAllocator<U, C> other;
117 };
118
119 template<class U> ArenaAllocator(const ArenaAllocator<U, C>& other)
120 : arena_(other.arena()) { }
121
122 template<class U> bool operator==(const ArenaAllocator<U, C>& other) const {
123 return arena_ == other.arena();
124 }
125
126 template<class U> bool operator!=(const ArenaAllocator<U, C>& other) const {
127 return arena_ != other.arena();
128 }
129
130 protected:
131 static const int kAlignment;
132 C* arena_;
133};
134
135template<class T, class C> const int ArenaAllocator<T, C>::kAlignment =
136 (1 == sizeof(T) ? 1 : BaseArena::kDefaultAlignment);
137
138
139// 'new' must be in the global namespace.
140}
141using GOOGLE_NAMESPACE::UnsafeArena;
142
143
144// Operators for allocation on the arena
145// Syntax: new (AllocateInArena, arena) MyClass;
146// new (AllocateInArena, arena) MyClass[num];
147// Useful for classes you can't descend from Gladiator, such as POD,
148// STL containers, etc.
149enum AllocateInArenaType { AllocateInArena };
150
151inline void* operator new(size_t size,
152 AllocateInArenaType /* unused */,
153 UnsafeArena *arena) {
154 return arena->Alloc(size);
155}
156
157inline void* operator new[](size_t size,
158 AllocateInArenaType /* unused */,
159 UnsafeArena *arena) {
160 return arena->Alloc(size);
161}
162
163namespace ctemplate {
164
165// Ordinarily in C++, one allocates all instances of a class from an
166// arena. If that's what you want to do, you don't need Gladiator.
167// (However you may find ArenaOnlyGladiator useful.)
168//
169// However, for utility classes that are used by multiple clients, the
170// everything-in-one-arena model may not work. Some clients may wish
171// not to use an arena at all. Or perhaps a composite structure
172// (tree) will contain multiple objects (nodes) and some of those
173// objects will be created by a factory, using an arena, while other
174// objects will be created on-the-fly by an unsuspecting user who
175// doesn't know anything about the arena.
176//
177// To support that, have the arena-allocated class inherit from
178// Gladiator. The ordinary operator new will continue to allocate
179// from the heap. To allocate from an arena, do
180// Myclass * m = new (AllocateInArena, a) Myclass (args, to, constructor);
181// where a is either an arena or an allocator. Now you can call
182// delete on all the objects, whether they are allocated from an arena
183// or on the heap. Heap memory will be released, while arena memory will
184// not be.
185//
186// If a client knows that no objects were allocated on the heap, it
187// need not delete any objects (but it may if it wishes). The only
188// objects that must be deleted are those that were actually allocated
189// from the heap.
190//
191// NOTE: an exception to the google C++ style guide rule for "No multiple
192// implementation inheritance" is granted for this class: you can treat this
193// class as an "Interface" class, and use it in a multiple inheritence context,
194// even though it implements operator new/delete.
195
196class Gladiator {
197 public:
198 Gladiator() { }
199 virtual ~Gladiator() { }
200
201 // We do not override the array allocators, so array allocation and
202 // deallocation will always be from the heap. Typically, arrays are
203 // larger, and thus the costs of arena allocation are higher and the
204 // benefits smaller. Since arrays are typically allocated and deallocated
205 // very differently from scalars, this may not interfere too much with
206 // the arena concept. If it does pose a problem, flesh out the
207 // ArrayGladiator class below.
208
209 void* operator new(size_t size) {
210 void* ret = ::operator new(1 + size);
211 static_cast<char *>(ret)[size] = 1; // mark as heap-allocated
212 return ret;
213 }
214 // the ignored parameter keeps us from stepping on placement new
215 template<class T> void* operator new(size_t size, const int ignored,
216 T* allocator) {
217 if (allocator) {
218 void* ret = allocator->AllocAligned(1 + size,
219 BaseArena::kDefaultAlignment);
220 static_cast<char*>(ret)[size] = 0; // mark as arena-allocated
221 return ret;
222 } else {
223 return operator new(size); // this is the function above
224 }
225 }
226 void operator delete(void* memory, size_t size) {
227 if (static_cast<char*>(memory)[size]) {
228 assert (1 == static_cast<char *>(memory)[size]);
229 ::operator delete(memory);
230 } else {
231 // We never call the allocator's Free method. If we need to do
232 // that someday, we can store a pointer to the arena instead of
233 // the Boolean marker flag.
234 }
235 }
236 template<class T> void operator delete(void* memory, size_t size,
237 const int ign, T* allocator) {
238 // This "placement delete" can only be called if the constructor
239 // throws an exception.
240 if (allocator) {
241 allocator->Free(memory, 1 + size);
242 } else {
243 ::operator delete(memory);
244 }
245 }
246};
247
248// This avoids the space overhead of Gladiator if you just want to
249// override new and delete. It helps avoid some of the more common
250// problems that can occur when overriding new and delete.
251
252class ArenaOnlyGladiator {
253 public:
254 ArenaOnlyGladiator() { }
255 // No virtual destructor is needed because we ignore the size
256 // parameter in all the delete functions.
257 // virtual ~ArenaOnlyGladiator() { }
258
259 // can't just return NULL here -- compiler gives a warning. :-|
260 void* operator new(size_t /*size*/) {
261 assert(0);
262 return reinterpret_cast<void *>(1);
263 }
264 void* operator new[](size_t /*size*/) {
265 assert(0);
266 return reinterpret_cast<void *>(1);
267 }
268
269 // the ignored parameter keeps us from stepping on placement new
270 template<class T> void* operator new(size_t size, const int ignored,
271 T* allocator) {
272 assert(allocator);
273 return allocator->AllocAligned(size, BaseArena::kDefaultAlignment);
274 }
275 template<class T> void* operator new[](size_t size,
276 const int ignored, T* allocator) {
277 assert(allocator);
278 return allocator->AllocAligned (size, BaseArena::kDefaultAlignment);
279 }
280 void operator delete(void* /*memory*/, size_t /*size*/) { }
281 template<class T> void operator delete(void* memory, size_t size,
282 const int ign, T* allocator) { }
283 void operator delete [](void* /*memory*/) { }
284 template<class T> void operator delete(void* memory,
285 const int ign, T* allocator) { }
286};
287
288#if 0 // ********** for example purposes only; 100% untested.
289
290// Note that this implementation incurs an overhead of kHeaderSize for
291// every array that is allocated. *Before* the space is returned to the
292// user, we store the address of the Arena that owns the space, and
293// the length of th space itself.
294
295class ArrayGladiator : public Gladiator {
296 public:
297 void * operator new[] (size_t size) {
298 const int sizeplus = size + kHeaderSize;
299 void * const ret = ::operator new(sizeplus);
300 *static_cast<Arena **>(ret) = NULL; // mark as heap-allocated
301 *static_cast<size_t *>(ret + sizeof(Arena *)) = sizeplus;
302 return ret + kHeaderSize;
303 }
304 // the ignored parameter keeps us from stepping on placement new
305 template<class T> void * operator new[] (size_t size,
306 const int ignored, T * allocator) {
307 if (allocator) {
308 const int sizeplus = size + kHeaderSize;
309 void * const ret =
310 allocator->AllocAligned(sizeplus, BaseArena::kDefaultAlignment);
311 *static_cast<Arena **>(ret) = allocator->arena();
312 *static_cast<size_t *>(ret + sizeof(Arena *)) = sizeplus;
313 return ret + kHeaderSize;
314 } else {
315 return operator new[](size); // this is the function above
316 }
317 }
318 void operator delete [] (void * memory) {
319 memory -= kHeaderSize;
320 Arena * const arena = *static_cast<Arena **>(memory);
321 size_t sizeplus = *static_cast<size_t *>(memory + sizeof(arena));
322 if (arena) {
323 arena->SlowFree(memory, sizeplus);
324 } else {
325 ::operator delete (memory);
326 }
327 }
328 template<class T> void * operator delete (void * memory,
329 const int ign, T * allocator) {
330 // This "placement delete" can only be called if the constructor
331 // throws an exception.
332 memory -= kHeaderSize;
333 size_t sizeplus = *static_cast<size_t *>(memory + sizeof(Arena *));
334 if (allocator) {
335 allocator->Free(memory, 1 + size);
336 } else {
337 operator delete (memory);
338 }
339 }
340
341 protected:
342 static const int kMinSize = sizeof size_t + sizeof(Arena *);
343 static const int kHeaderSize = kMinSize > BaseArena::kDefaultAlignment ?
344 2 * BaseArena::kDefaultAlignment : BaseArena::kDefaultAlignment;
345};
346
347#endif // ********** example
348
349}
350
351#endif // BASE_ARENA_INL_H_