1// 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
104