1 // Tencent is pleased to support the open source community by making RapidJSON available.
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
8 // http://opensource.org/licenses/MIT
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
15 #ifndef RAPIDJSON_ALLOCATORS_H_
16 #define RAPIDJSON_ALLOCATORS_H_
18 #include "rapidjson.h"
20 RAPIDJSON_NAMESPACE_BEGIN
22 ///////////////////////////////////////////////////////////////////////////////
25 /*! \class rapidjson::Allocator
26 \brief Concept for allocating, resizing and freeing memory block.
28 Note that Malloc() and Realloc() are non-static but Free() is static.
30 So if an allocator need to support Free(), it needs to put its pointer in
31 the header of memory block.
35 static const bool kNeedFree; //!< Whether this allocator needs to call Free().
37 // Allocate a memory block.
38 // \param size of the memory block in bytes.
39 // \returns pointer to the memory block.
40 void* Malloc(size_t size);
42 // Resize a memory block.
43 // \param originalPtr The pointer to current memory block. Null pointer is permitted.
44 // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
45 // \param newSize the new size in bytes.
46 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
48 // Free a memory block.
49 // \param pointer to the memory block. Null pointer is permitted.
50 static void Free(void *ptr);
56 /*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
57 \ingroup RAPIDJSON_CONFIG
58 \brief User-defined kDefaultChunkCapacity definition.
60 User can define this as any \c size that is a power of 2.
63 #ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
64 #define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
68 ///////////////////////////////////////////////////////////////////////////////
71 //! C-runtime library allocator.
72 /*! This class is just wrapper for standard C library memory routines.
73 \note implements Allocator concept
77 static const bool kNeedFree = true;
78 void* Malloc(size_t size) {
79 if (size) // behavior of malloc(0) is implementation defined.
80 return RAPIDJSON_MALLOC(size);
82 return NULL; // standardize to returning NULL.
84 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
87 RAPIDJSON_FREE(originalPtr);
90 return RAPIDJSON_REALLOC(originalPtr, newSize);
92 static void Free(void *ptr) { RAPIDJSON_FREE(ptr); }
95 ///////////////////////////////////////////////////////////////////////////////
96 // MemoryPoolAllocator
98 //! Default memory allocator used by the parser and DOM.
99 /*! This allocator allocate memory blocks from pre-allocated memory chunks.
101 It does not free memory blocks. And Realloc() only allocate new memory.
103 The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
105 User may also supply a buffer as the first chunk.
107 If the user-buffer is full then additional chunks are allocated by BaseAllocator.
109 The user-buffer is not deallocated by this allocator.
111 \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
112 \note implements Allocator concept
114 template <typename BaseAllocator = CrtAllocator>
115 class MemoryPoolAllocator {
117 static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
119 //! Constructor with chunkSize.
120 /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
121 \param baseAllocator The allocator for allocating memory chunks.
123 MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
124 chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
128 //! Constructor with user-supplied buffer.
129 /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
131 The user buffer will not be deallocated when this allocator is destructed.
133 \param buffer User supplied buffer.
134 \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
135 \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
136 \param baseAllocator The allocator for allocating memory chunks.
138 MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
139 chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
141 RAPIDJSON_ASSERT(buffer != 0);
142 RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
143 chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
144 chunkHead_->capacity = size - sizeof(ChunkHeader);
145 chunkHead_->size = 0;
146 chunkHead_->next = 0;
150 /*! This deallocates all memory chunks, excluding the user-supplied buffer.
152 ~MemoryPoolAllocator() {
154 RAPIDJSON_DELETE(ownBaseAllocator_);
157 //! Deallocates all memory chunks, excluding the user-supplied buffer.
159 while (chunkHead_ && chunkHead_ != userBuffer_) {
160 ChunkHeader* next = chunkHead_->next;
161 baseAllocator_->Free(chunkHead_);
164 if (chunkHead_ && chunkHead_ == userBuffer_)
165 chunkHead_->size = 0; // Clear user buffer
168 //! Computes the total capacity of allocated memory chunks.
169 /*! \return total capacity in bytes.
171 size_t Capacity() const {
173 for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
174 capacity += c->capacity;
178 //! Computes the memory blocks allocated.
179 /*! \return total used bytes.
181 size_t Size() const {
183 for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
188 //! Allocates a memory block. (concept Allocator)
189 void* Malloc(size_t size) {
193 size = RAPIDJSON_ALIGN(size);
194 if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
195 if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
198 void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
199 chunkHead_->size += size;
203 //! Resizes a memory block (concept Allocator)
204 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
205 if (originalPtr == 0)
206 return Malloc(newSize);
211 originalSize = RAPIDJSON_ALIGN(originalSize);
212 newSize = RAPIDJSON_ALIGN(newSize);
214 // Do not shrink if new size is smaller than original
215 if (originalSize >= newSize)
218 // Simply expand it if it is the last allocation and there is sufficient space
219 if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
220 size_t increment = static_cast<size_t>(newSize - originalSize);
221 if (chunkHead_->size + increment <= chunkHead_->capacity) {
222 chunkHead_->size += increment;
227 // Realloc process: allocate and copy memory, do not free original buffer.
228 if (void* newBuffer = Malloc(newSize)) {
230 std::memcpy(newBuffer, originalPtr, originalSize);
237 //! Frees a memory block (concept Allocator)
238 static void Free(void *ptr) { (void)ptr; } // Do nothing
241 //! Copy constructor is not permitted.
242 MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
243 //! Copy assignment operator is not permitted.
244 MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
246 //! Creates a new chunk.
247 /*! \param capacity Capacity of the chunk in bytes.
248 \return true if success.
250 bool AddChunk(size_t capacity) {
252 ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
253 if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
254 chunk->capacity = capacity;
256 chunk->next = chunkHead_;
264 static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
266 //! Chunk header for perpending to each chunk.
267 /*! Chunks are stored as a singly linked list.
270 size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
271 size_t size; //!< Current size of allocated memory in bytes.
272 ChunkHeader *next; //!< Next chunk in the linked list.
275 ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
276 size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
277 void *userBuffer_; //!< User supplied buffer.
278 BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
279 BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
282 RAPIDJSON_NAMESPACE_END
284 #endif // RAPIDJSON_ENCODINGS_H_