allocators.h
Engine/source/persistence/rapidjson/allocators.h
Classes:
class
C-runtime library allocator.
class
Default memory allocator used by the parser and DOM.
class
Chunk header for perpending to each chunk.
Public Defines
define
RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY() (64 * 1024)
User-defined kDefaultChunkCapacity definition.
Detailed Description
Public Defines
RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY() (64 * 1024)
User-defined kDefaultChunkCapacity definition.
User can define this as any
sizethat is a power of 2.
1 2// Tencent is pleased to support the open source community by making RapidJSON available. 3// 4// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 5// 6// Licensed under the MIT License (the "License"); you may not use this file except 7// in compliance with the License. You may obtain a copy of the License at 8// 9// http://opensource.org/licenses/MIT 10// 11// Unless required by applicable law or agreed to in writing, software distributed 12// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 13// CONDITIONS OF ANY KIND, either express or implied. See the License for the 14// specific language governing permissions and limitations under the License. 15 16#ifndef RAPIDJSON_ALLOCATORS_H_ 17#define RAPIDJSON_ALLOCATORS_H_ 18 19#include "rapidjson.h" 20 21RAPIDJSON_NAMESPACE_BEGIN 22 23/////////////////////////////////////////////////////////////////////////////// 24// Allocator 25 26/*! \class rapidjson::Allocator 27 \brief Concept for allocating, resizing and freeing memory block. 28 29 Note that Malloc() and Realloc() are non-static but Free() is static. 30 31 So if an allocator need to support Free(), it needs to put its pointer in 32 the header of memory block. 33 34\code 35concept Allocator { 36 static const bool kNeedFree; //!< Whether this allocator needs to call Free(). 37 38 // Allocate a memory block. 39 // \param size of the memory block in bytes. 40 // \returns pointer to the memory block. 41 void* Malloc(size_t size); 42 43 // Resize a memory block. 44 // \param originalPtr The pointer to current memory block. Null pointer is permitted. 45 // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) 46 // \param newSize the new size in bytes. 47 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); 48 49 // Free a memory block. 50 // \param pointer to the memory block. Null pointer is permitted. 51 static void Free(void *ptr); 52}; 53\endcode 54*/ 55 56 57/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY 58 \ingroup RAPIDJSON_CONFIG 59 \brief User-defined kDefaultChunkCapacity definition. 60 61 User can define this as any \c size that is a power of 2. 62*/ 63 64#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY 65#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) 66#endif 67 68 69/////////////////////////////////////////////////////////////////////////////// 70// CrtAllocator 71 72//! C-runtime library allocator. 73/*! This class is just wrapper for standard C library memory routines. 74 \note implements Allocator concept 75*/ 76class CrtAllocator { 77public: 78 static const bool kNeedFree = true; 79 void* Malloc(size_t size) { 80 if (size) // behavior of malloc(0) is implementation defined. 81 return std::malloc(size); 82 else 83 return NULL; // standardize to returning NULL. 84 } 85 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { 86 (void)originalSize; 87 if (newSize == 0) { 88 std::free(originalPtr); 89 return NULL; 90 } 91 return std::realloc(originalPtr, newSize); 92 } 93 static void Free(void *ptr) { std::free(ptr); } 94}; 95 96/////////////////////////////////////////////////////////////////////////////// 97// MemoryPoolAllocator 98 99//! Default memory allocator used by the parser and DOM. 100/*! This allocator allocate memory blocks from pre-allocated memory chunks. 101 102 It does not free memory blocks. And Realloc() only allocate new memory. 103 104 The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. 105 106 User may also supply a buffer as the first chunk. 107 108 If the user-buffer is full then additional chunks are allocated by BaseAllocator. 109 110 The user-buffer is not deallocated by this allocator. 111 112 \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. 113 \note implements Allocator concept 114*/ 115template <typename BaseAllocator = CrtAllocator> 116class MemoryPoolAllocator { 117public: 118 static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) 119 120 //! Constructor with chunkSize. 121 /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. 122 \param baseAllocator The allocator for allocating memory chunks. 123 */ 124 MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 125 chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) 126 { 127 } 128 129 //! Constructor with user-supplied buffer. 130 /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. 131 132 The user buffer will not be deallocated when this allocator is destructed. 133 134 \param buffer User supplied buffer. 135 \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). 136 \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. 137 \param baseAllocator The allocator for allocating memory chunks. 138 */ 139 MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 140 chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) 141 { 142 RAPIDJSON_ASSERT(buffer != 0); 143 RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); 144 chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer); 145 chunkHead_->capacity = size - sizeof(ChunkHeader); 146 chunkHead_->size = 0; 147 chunkHead_->next = 0; 148 } 149 150 //! Destructor. 151 /*! This deallocates all memory chunks, excluding the user-supplied buffer. 152 */ 153 ~MemoryPoolAllocator() { 154 Clear(); 155 RAPIDJSON_DELETE(ownBaseAllocator_); 156 } 157 158 //! Deallocates all memory chunks, excluding the user-supplied buffer. 159 void Clear() { 160 while (chunkHead_ && chunkHead_ != userBuffer_) { 161 ChunkHeader* next = chunkHead_->next; 162 baseAllocator_->Free(chunkHead_); 163 chunkHead_ = next; 164 } 165 if (chunkHead_ && chunkHead_ == userBuffer_) 166 chunkHead_->size = 0; // Clear user buffer 167 } 168 169 //! Computes the total capacity of allocated memory chunks. 170 /*! \return total capacity in bytes. 171 */ 172 size_t Capacity() const { 173 size_t capacity = 0; 174 for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) 175 capacity += c->capacity; 176 return capacity; 177 } 178 179 //! Computes the memory blocks allocated. 180 /*! \return total used bytes. 181 */ 182 size_t Size() const { 183 size_t size = 0; 184 for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) 185 size += c->size; 186 return size; 187 } 188 189 //! Allocates a memory block. (concept Allocator) 190 void* Malloc(size_t size) { 191 if (!size) 192 return NULL; 193 194 size = RAPIDJSON_ALIGN(size); 195 if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) 196 if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) 197 return NULL; 198 199 void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; 200 chunkHead_->size += size; 201 return buffer; 202 } 203 204 //! Resizes a memory block (concept Allocator) 205 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { 206 if (originalPtr == 0) 207 return Malloc(newSize); 208 209 if (newSize == 0) 210 return NULL; 211 212 originalSize = RAPIDJSON_ALIGN(originalSize); 213 newSize = RAPIDJSON_ALIGN(newSize); 214 215 // Do not shrink if new size is smaller than original 216 if (originalSize >= newSize) 217 return originalPtr; 218 219 // Simply expand it if it is the last allocation and there is sufficient space 220 if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { 221 size_t increment = static_cast<size_t>(newSize - originalSize); 222 if (chunkHead_->size + increment <= chunkHead_->capacity) { 223 chunkHead_->size += increment; 224 return originalPtr; 225 } 226 } 227 228 // Realloc process: allocate and copy memory, do not free original buffer. 229 if (void* newBuffer = Malloc(newSize)) { 230 if (originalSize) 231 std::memcpy(newBuffer, originalPtr, originalSize); 232 return newBuffer; 233 } 234 else 235 return NULL; 236 } 237 238 //! Frees a memory block (concept Allocator) 239 static void Free(void *ptr) { (void)ptr; } // Do nothing 240 241private: 242 //! Copy constructor is not permitted. 243 MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; 244 //! Copy assignment operator is not permitted. 245 MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; 246 247 //! Creates a new chunk. 248 /*! \param capacity Capacity of the chunk in bytes. 249 \return true if success. 250 */ 251 bool AddChunk(size_t capacity) { 252 if (!baseAllocator_) 253 ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); 254 if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { 255 chunk->capacity = capacity; 256 chunk->size = 0; 257 chunk->next = chunkHead_; 258 chunkHead_ = chunk; 259 return true; 260 } 261 else 262 return false; 263 } 264 265 static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. 266 267 //! Chunk header for perpending to each chunk. 268 /*! Chunks are stored as a singly linked list. 269 */ 270 struct ChunkHeader { 271 size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). 272 size_t size; //!< Current size of allocated memory in bytes. 273 ChunkHeader *next; //!< Next chunk in the linked list. 274 }; 275 276 ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. 277 size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. 278 void *userBuffer_; //!< User supplied buffer. 279 BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. 280 BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. 281}; 282 283RAPIDJSON_NAMESPACE_END 284 285#endif // RAPIDJSON_ENCODINGS_H_ 286