blob: 7eb385b00e328ce0c706fac4c901b4ebc5815ef7 [file] [log] [blame]
Ian Hodson2ee91b42012-05-14 12:29:36 +01001// Copyright 2000 The RE2 Authors. All Rights Reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Sometimes it is necessary to allocate a large number of small
6// objects. Doing this the usual way (malloc, new) is slow,
7// especially for multithreaded programs. An UnsafeArena provides a
8// mark/release method of memory management: it asks for a large chunk
9// from the operating system and doles it out bit by bit as required.
10// Then you free all the memory at once by calling UnsafeArena::Reset().
11// The "Unsafe" refers to the fact that UnsafeArena is not safe to
12// call from multiple threads.
13//
14// The global operator new that can be used as follows:
15//
16// #include "lib/arena-inl.h"
17//
18// UnsafeArena arena(1000);
19// Foo* foo = new (AllocateInArena, &arena) Foo;
20//
21
22#ifndef RE2_UTIL_ARENA_H_
23#define RE2_UTIL_ARENA_H_
24
25namespace re2 {
26
27// This class is thread-compatible.
28class UnsafeArena {
29 public:
30 UnsafeArena(const size_t block_size);
31 virtual ~UnsafeArena();
32
33 void Reset();
34
35 // This should be the worst-case alignment for any type. This is
36 // good for IA-32, SPARC version 7 (the last one I know), and
37 // supposedly Alpha. i386 would be more time-efficient with a
38 // default alignment of 8, but ::operator new() uses alignment of 4,
39 // and an assertion will fail below after the call to MakeNewBlock()
40 // if you try to use a larger alignment.
41#ifdef __i386__
42 static const int kDefaultAlignment = 4;
43#else
44 static const int kDefaultAlignment = 8;
45#endif
46
47 private:
48 void* GetMemoryFallback(const size_t size, const int align);
49
50 public:
51 void* GetMemory(const size_t size, const int align) {
52 if ( size > 0 && size < remaining_ && align == 1 ) { // common case
53 last_alloc_ = freestart_;
54 freestart_ += size;
55 remaining_ -= size;
56 return reinterpret_cast<void*>(last_alloc_);
57 }
58 return GetMemoryFallback(size, align);
59 }
60
61 private:
62 struct AllocatedBlock {
63 char *mem;
64 size_t size;
65 };
66
67 // The returned AllocatedBlock* is valid until the next call to AllocNewBlock
68 // or Reset (i.e. anything that might affect overflow_blocks_).
69 AllocatedBlock *AllocNewBlock(const size_t block_size);
70
71 const AllocatedBlock *IndexToBlock(int index) const;
72
73 const size_t block_size_;
74 char* freestart_; // beginning of the free space in most recent block
75 char* freestart_when_empty_; // beginning of the free space when we're empty
76 char* last_alloc_; // used to make sure ReturnBytes() is safe
77 size_t remaining_;
78 // STL vector isn't as efficient as it could be, so we use an array at first
79 int blocks_alloced_; // how many of the first_blocks_ have been alloced
80 AllocatedBlock first_blocks_[16]; // the length of this array is arbitrary
81 // if the first_blocks_ aren't enough, expand into overflow_blocks_.
82 vector<AllocatedBlock>* overflow_blocks_;
83
84 void FreeBlocks(); // Frees all except first block
85
86 DISALLOW_EVIL_CONSTRUCTORS(UnsafeArena);
87};
88
89// Operators for allocation on the arena
90// Syntax: new (AllocateInArena, arena) MyClass;
91// STL containers, etc.
92enum AllocateInArenaType { AllocateInArena };
93
94} // namespace re2
95
96inline void* operator new(size_t size,
97 re2::AllocateInArenaType /* unused */,
98 re2::UnsafeArena *arena) {
99 return reinterpret_cast<char*>(arena->GetMemory(size, 1));
100}
101
102#endif // RE2_UTIL_ARENA_H_
103