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.
Namespaces:
namespace
Detailed Description
1 2#ifndef RAPIDJSON_ALLOCATORS_H_ 3#define RAPIDJSON_ALLOCATORS_H_ 4 5#include "rapidjson.h" 6 7namespace rapidjson { 8 9/////////////////////////////////////////////////////////////////////////////// 10// Allocator 11 12/*! \class rapidjson::Allocator 13 \brief Concept for allocating, resizing and freeing memory block. 14 15 Note that Malloc() and Realloc() are non-static but Free() is static. 16 17 So if an allocator need to support Free(), it needs to put its pointer in 18 the header of memory block. 19 20\code 21concept Allocator { 22 static const bool kNeedFree; //!< Whether this allocator needs to call Free(). 23 24 // Allocate a memory block. 25 // \param size of the memory block in bytes. 26 // \returns pointer to the memory block. 27 void* Malloc(size_t size); 28 29 // Resize a memory block. 30 // \param originalPtr The pointer to current memory block. Null pointer is permitted. 31 // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) 32 // \param newSize the new size in bytes. 33 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); 34 35 // Free a memory block. 36 // \param pointer to the memory block. Null pointer is permitted. 37 static void Free(void *ptr); 38}; 39\endcode 40*/ 41 42/////////////////////////////////////////////////////////////////////////////// 43// CrtAllocator 44 45//! C-runtime library allocator. 46/*! This class is just wrapper for standard C library memory routines. 47 \implements Allocator 48*/ 49class CrtAllocator { 50public: 51 static const bool kNeedFree = true; 52 void* Malloc(size_t size) { return malloc(size); } 53 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); } 54 static void Free(void *ptr) { free(ptr); } 55}; 56 57/////////////////////////////////////////////////////////////////////////////// 58// MemoryPoolAllocator 59 60//! Default memory allocator used by the parser and DOM. 61/*! This allocator allocate memory blocks from pre-allocated memory chunks. 62 63 It does not free memory blocks. And Realloc() only allocate new memory. 64 65 The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. 66 67 User may also supply a buffer as the first chunk. 68 69 If the user-buffer is full then additional chunks are allocated by BaseAllocator. 70 71 The user-buffer is not deallocated by this allocator. 72 73 \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. 74 \implements Allocator 75*/ 76template <typename BaseAllocator = CrtAllocator> 77class MemoryPoolAllocator { 78public: 79 static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) 80 81 //! Constructor with chunkSize. 82 /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. 83 \param baseAllocator The allocator for allocating memory chunks. 84 */ 85 MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 86 chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) 87 { 88 if (!baseAllocator_) 89 ownBaseAllocator_ = baseAllocator_ = new BaseAllocator(); 90 AddChunk(chunk_capacity_); 91 } 92 93 //! Constructor with user-supplied buffer. 94 /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. 95 96 The user buffer will not be deallocated when this allocator is destructed. 97 98 \param buffer User supplied buffer. 99 \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). 100 \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. 101 \param baseAllocator The allocator for allocating memory chunks. 102 */ 103 MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 104 chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) 105 { 106 RAPIDJSON_ASSERT(buffer != 0); 107 RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); 108 chunkHead_ = (ChunkHeader*)buffer; 109 chunkHead_->capacity = size - sizeof(ChunkHeader); 110 chunkHead_->size = 0; 111 chunkHead_->next = 0; 112 } 113 114 //! Destructor. 115 /*! This deallocates all memory chunks, excluding the user-supplied buffer. 116 */ 117 ~MemoryPoolAllocator() { 118 Clear(); 119 delete ownBaseAllocator_; 120 } 121 122 //! Deallocates all memory chunks, excluding the user-supplied buffer. 123 void Clear() { 124 while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) { 125 ChunkHeader* next = chunkHead_->next; 126 baseAllocator_->Free(chunkHead_); 127 chunkHead_ = next; 128 } 129 } 130 131 //! Computes the total capacity of allocated memory chunks. 132 /*! \return total capacity in bytes. 133 */ 134 size_t Capacity() { 135 size_t capacity = 0; 136 for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) 137 capacity += c->capacity; 138 return capacity; 139 } 140 141 //! Computes the memory blocks allocated. 142 /*! \return total used bytes. 143 */ 144 size_t Size() { 145 size_t size = 0; 146 for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) 147 size += c->size; 148 return size; 149 } 150 151 //! Allocates a memory block. (concept Allocator) 152 void* Malloc(size_t size) { 153 size = RAPIDJSON_ALIGN(size); 154 if (chunkHead_->size + size > chunkHead_->capacity) 155 AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); 156 157 char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size; 158 chunkHead_->size += size; 159 return buffer; 160 } 161 162 //! Resizes a memory block (concept Allocator) 163 void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { 164 if (originalPtr == 0) 165 return Malloc(newSize); 166 167 // Do not shrink if new size is smaller than original 168 if (originalSize >= newSize) 169 return originalPtr; 170 171 // Simply expand it if it is the last allocation and there is sufficient space 172 if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { 173 size_t increment = newSize - originalSize; 174 increment = RAPIDJSON_ALIGN(increment); 175 if (chunkHead_->size + increment <= chunkHead_->capacity) { 176 chunkHead_->size += increment; 177 return originalPtr; 178 } 179 } 180 181 // Realloc process: allocate and copy memory, do not free original buffer. 182 void* newBuffer = Malloc(newSize); 183 RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. 184 return memcpy(newBuffer, originalPtr, originalSize); 185 } 186 187 //! Frees a memory block (concept Allocator) 188 static void Free(void *ptr) { (void)ptr; } // Do nothing 189 190private: 191 //! Creates a new chunk. 192 /*! \param capacity Capacity of the chunk in bytes. 193 */ 194 void AddChunk(size_t capacity) { 195 ChunkHeader* chunk = (ChunkHeader*)baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity); 196 chunk->capacity = capacity; 197 chunk->size = 0; 198 chunk->next = chunkHead_; 199 chunkHead_ = chunk; 200 } 201 202 static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. 203 204 //! Chunk header for perpending to each chunk. 205 /*! Chunks are stored as a singly linked list. 206 */ 207 struct ChunkHeader { 208 size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). 209 size_t size; //!< Current size of allocated memory in bytes. 210 ChunkHeader *next; //!< Next chunk in the linked list. 211 }; 212 213 ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. 214 size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. 215 char *userBuffer_; //!< User supplied buffer. 216 BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. 217 BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. 218}; 219 220} // namespace rapidjson 221 222#endif // RAPIDJSON_ENCODINGS_H_ 223
