lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
|
00001 /*****************************************************/ 00002 /* lean Memory (c) Tobias Zirr 2011 */ 00003 /*****************************************************/ 00004 00005 #ifndef LEAN_MEMORY_CHUNK_HEAP 00006 #define LEAN_MEMORY_CHUNK_HEAP 00007 00008 #include "../lean.h" 00009 #include "../tags/noncopyable.h" 00010 #include "alignment.h" 00011 #include "default_heap.h" 00012 00013 namespace lean 00014 { 00015 namespace memory 00016 { 00017 00019 template <size_t Size> 00020 struct optional_mem_block 00021 { 00022 char memory[Size]; 00023 00024 LEAN_INLINE char* get() { return memory; } 00025 LEAN_INLINE const char* get() const { return memory; } 00026 00027 LEAN_INLINE operator char*() { return memory; } 00028 LEAN_INLINE operator const char*() const { return memory; } 00029 }; 00030 template <> 00031 struct optional_mem_block<0> 00032 { 00033 LEAN_INLINE char* get() { return nullptr; } 00034 LEAN_INLINE const char* get() const { return nullptr; } 00035 00036 LEAN_INLINE operator char*() { return nullptr; } 00037 LEAN_INLINE operator const char*() const { return nullptr; } 00038 }; 00039 00041 template <size_t ChunkSize, class Heap = default_heap, size_t StaticChunkSize = ChunkSize, size_t DefaultAlignment = sizeof(void*)> 00042 class chunk_heap : public lean::noncopyable 00043 { 00044 public: 00046 typedef Heap heap_type; 00048 typedef typename heap_type::size_type size_type; 00050 static const size_type chunk_size = ChunkSize; 00052 static const size_type default_alignment = DefaultAlignment; 00053 00054 private: 00055 // Optional first static chunk 00056 optional_mem_block<StaticChunkSize> m_firstChunk; 00057 00058 // Current chunk 00059 char *m_chunk; 00060 char *m_chunkOffset; 00061 char *m_chunkEnd; 00062 00063 // Next chunk size 00064 size_type m_nextChunkSize; 00065 00067 struct chunk_header 00068 { 00069 char *prev_chunk; 00070 00072 chunk_header(char *prev_chunk) 00073 : prev_chunk(prev_chunk) { } 00074 }; 00075 // Chunk alignment 00076 static const size_t chunk_alignment = alignof(chunk_header); 00077 00079 LEAN_INLINE static chunk_header* to_chunk_header(char *chunk) 00080 { 00081 return reinterpret_cast<chunk_header*>(chunk) - 1; 00082 } 00083 00085 template <size_t Alignment> 00086 char* allocate_aligned(size_type size) 00087 { 00088 // Get next free memory location 00089 char *aligned = align<Alignment>(m_chunkOffset); 00090 00091 // Allocate new chunk, if old chunk too small 00092 if (size + static_cast<size_type>(aligned - m_chunkOffset) > static_cast<size_type>(m_chunkEnd - m_chunkOffset)) 00093 { 00094 // Make sure new chunk is large enough for requested amount of memory + alignment 00095 size_type alignedSize = size + (Alignment - 1); 00096 00097 size_type nextChunkSize = m_nextChunkSize; 00098 if (nextChunkSize < alignedSize) 00099 nextChunkSize = alignedSize; 00100 00101 nextChunkSize += sizeof(chunk_header); 00102 00103 char *nextChunkBase = static_cast<char*>( Heap::allocate<chunk_alignment>(nextChunkSize) ); 00104 new( static_cast<void*>(nextChunkBase) ) chunk_header(m_chunk); 00105 00106 m_chunk = nextChunkBase + sizeof(chunk_header); 00107 m_chunkOffset = m_chunk; 00108 m_chunkEnd = nextChunkBase + nextChunkSize; 00109 00110 // Reset chunk size 00111 if (chunk_size != 0) 00112 m_nextChunkSize = chunk_size; 00113 00114 // Get next free memory location 00115 aligned = align<Alignment>(m_chunkOffset); 00116 } 00117 00118 // Memory now occupied 00119 m_chunkOffset = aligned + size; 00120 00121 return aligned; 00122 } 00123 00124 public: 00126 LEAN_INLINE chunk_heap(size_type chunkSize = ChunkSize) 00127 : m_chunk(m_firstChunk), 00128 m_chunkOffset(m_firstChunk), 00129 m_chunkEnd(m_firstChunk.get() + StaticChunkSize), 00130 m_nextChunkSize(chunkSize) { } 00132 LEAN_INLINE ~chunk_heap() 00133 { 00134 clear(); 00135 } 00136 00138 LEAN_INLINE void nextChunkSize(size_type nextSize) { m_nextChunkSize = nextSize; } 00140 LEAN_INLINE size_type nextChunkSize() const { return m_nextChunkSize; } 00141 00143 LEAN_INLINE size_type capacity() const { return m_chunkEnd - m_chunkOffset; } 00144 00150 LEAN_INLINE void reserve(size_type newCapacity, size_type minChunkSize = chunk_size) 00151 { 00152 size_type currentCapacity = capacity(); 00153 00154 if (newCapacity > currentCapacity) 00155 nextChunkSize( max(newCapacity - currentCapacity, minChunkSize) ); 00156 } 00157 00159 void clear() 00160 { 00161 // Free as many chunks as possible 00162 while (m_chunk != m_firstChunk) 00163 { 00164 chunk_header *freeChunkBase = to_chunk_header(m_chunk); 00165 00166 // Immediately store previous chunk in case clear is re-called after exception 00167 m_chunk = freeChunkBase->prev_chunk; 00168 m_chunkOffset = m_chunk; 00169 m_chunkEnd = m_chunk; 00170 00171 Heap::free<chunk_alignment>(freeChunkBase); 00172 } 00173 00174 // Re-initialize with first chunk 00175 m_chunkEnd = m_chunk + StaticChunkSize; 00176 } 00177 00179 void clearButFirst() 00180 { 00181 if (m_chunk != m_firstChunk && to_chunk_header(m_chunk)->prev_chunk == m_firstChunk) 00182 // Re-initialize first dynamic chunk 00183 m_chunkOffset = m_chunk; 00184 else 00185 clear(); 00186 } 00187 00189 bool currentStatic() 00190 { 00191 return (m_chunk == m_firstChunk); 00192 } 00194 char* currentOffset() 00195 { 00196 return m_chunkOffset; 00197 } 00199 char* clearCurrent() 00200 { 00201 // Re-initialize with current chunk 00202 m_chunkOffset = m_chunk; 00203 return m_chunk; 00204 } 00206 char* clearFreeNext() 00207 { 00208 if (m_chunk != m_firstChunk) 00209 { 00210 chunk_header *freeChunkBase = to_chunk_header(m_chunk); 00211 00212 // Immediately store previous chunk (exception-safe) 00213 m_chunk = freeChunkBase->prev_chunk; 00214 m_chunkOffset = m_chunk; 00215 m_chunkEnd = (m_chunk == m_firstChunk) ? m_chunk + StaticChunkSize : m_chunk; 00216 00217 Heap::free<chunk_alignment>(freeChunkBase); 00218 } 00219 00220 return m_chunk; 00221 } 00222 00224 LEAN_INLINE void* allocate(size_type size) { return allocate<default_alignment>(size); } 00226 LEAN_INLINE void free(void *memory) { free<default_alignment>(memory); } 00227 00229 template <size_t Alignment> 00230 LEAN_INLINE void* allocate(size_type size) 00231 { 00232 return allocate_aligned<Alignment>(size); 00233 } 00235 template <size_t Alignment> 00236 LEAN_INLINE void free(void *memory) 00237 { 00238 // Freeing of individual memory blocks unsupported 00239 } 00240 }; 00241 00242 } // namespace 00243 00244 using memory::chunk_heap; 00245 00246 } // namespace 00247 00248 #endif