move getMapIdByValue to FieldMask.h
[hiphop-php.git] / hphp / util / arena.h
blob116c25f01e7042768fc64f48ab0f63422787541c
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #pragma once
18 #include <vector>
19 #include <cstdlib>
20 #include <cstring>
22 #include "hphp/util/pointer-list.h"
24 namespace HPHP {
26 //////////////////////////////////////////////////////////////////////
28 /**
29 * Arena/ArenaImpl is an allocator that frees all its memory when the arena
30 * instance is destroyed. It is a bump-pointer allocator.
32 * There are two main methods to allocate memory from the arena:
33 * 1) alloc() allocates raw memory for which no destructor is invoked when the
34 * arena is destroyed.
35 * 2) allocD<C>() allocates memory for an object of class C, whose destructor
36 * (or a custom callback) is invoked when the arena is destroyed.
38 * Allocations smaller than kMinBytes bytes are rounded up to kMinBytes, and
39 * all allocations are kMinBytes-aligned.
41 * Allocations larger than kChunkBytes are acquired directly from
42 * malloc.
44 * The Arena typedef is for convenience when you want a default
45 * configuration. Use ArenaImpl if you want something specific.
47 template<size_t kChunkBytes> struct ArenaImpl;
48 typedef ArenaImpl<4096> Arena;
50 //////////////////////////////////////////////////////////////////////
52 template<size_t kChunkBytes>
53 struct ArenaImpl {
54 public:
55 ArenaImpl();
56 ~ArenaImpl();
59 * Allocate a raw chunk of memory with `nbytes' bytes. No destructors will be
60 * called when the arena is destroyed.
62 void* alloc(size_t nbytes);
65 * Allocate a chunk of memory large enough to hold an object of class C, and
66 * register a destructor to be invoked when the arena is destroyed. A custom
67 * `dtor' to be invoked can be provided, otherwise C's destructor is invoked.
69 template<class C>
70 C* allocD();
72 template<class C, class D>
73 C* allocD(D dtor);
76 * Return the amount of memory this arena has handed out via alloc().
78 size_t size() const;
81 * Return the amount of memory the arena has allocated, but not yet
82 * handed out via alloc(). This can be used to estimate memory
83 * usage ignoring arena overhead.
85 * Note that this is only an estimate, because we will include
86 * fragmentation on the ends of slabs or due to alignment.
88 size_t slackEstimate() const { return kChunkBytes - m_offset; }
90 private:
91 struct Destroyer {
92 void* obj;
93 void (*dtor)(void*);
94 Destroyer* next;
97 // copying Arenas will end badly.
98 ArenaImpl(const ArenaImpl&);
99 ArenaImpl& operator=(const ArenaImpl&);
101 static const size_t kMinBytes = 8;
103 void* allocSlow(size_t nbytes);
104 void createSlab();
106 char* m_current;
107 uint32_t m_offset;
108 std::vector<char*> m_ptrs;
109 PointerList<char> m_externalPtrs;
110 Destroyer* m_dtors;
111 bool m_bypassSlabAlloc;
112 #ifndef NDEBUG
113 size_t m_externalAllocSize;
114 #endif
117 //////////////////////////////////////////////////////////////////////
119 template<size_t kChunkBytes>
120 inline void* ArenaImpl<kChunkBytes>::alloc(size_t nbytes) {
121 nbytes = (nbytes + (kMinBytes - 1)) & ~(kMinBytes - 1); // round up
122 size_t newOff = m_offset + nbytes;
123 if (newOff <= kChunkBytes) {
124 char* ptr = m_current + m_offset;
125 m_offset = newOff;
126 return ptr;
128 return allocSlow(nbytes);
131 template<size_t kChunkBytes>
132 template<class C, class D>
133 inline C* ArenaImpl<kChunkBytes>::allocD(D dtor) {
134 auto ptr = (C*)alloc(sizeof(C));
135 auto dtorPtr = (Destroyer*)alloc(sizeof(Destroyer));
136 dtorPtr->obj = ptr;
137 dtorPtr->dtor = dtor;
138 dtorPtr->next = m_dtors;
139 m_dtors = dtorPtr;
140 return ptr;
143 template<size_t kChunkBytes>
144 template<class C>
145 inline C* ArenaImpl<kChunkBytes>::allocD() {
146 return allocD([](void* p) { static_cast<C*>(p)->~C(); });
149 void SetArenaSlabAllocBypass(bool f);
151 //////////////////////////////////////////////////////////////////////
153 } // HPHP
155 // These global-operator-new declarations cannot be in a namespace,
156 // but since they take Arena arguments we won't overload anything else.
158 template<size_t kChunkBytes>
159 inline void* operator new(size_t nbytes,
160 HPHP::ArenaImpl<kChunkBytes>& a) {
161 return a.alloc(nbytes);
164 template<size_t kChunkBytes>
165 inline void* operator new[](size_t nbytes,
166 HPHP::ArenaImpl<kChunkBytes>& a) {
167 return a.alloc(nbytes);
170 //////////////////////////////////////////////////////////////////////