1 /* Copyright (c) 2015 Gerald Knizia
2 *
3 * This file is part of the IboView program (see: http://www.iboview.org)
4 *
5 * IboView is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * IboView is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
16 *
17 * Please see IboView documentation in README.txt for:
18 * -- A list of included external software and their licenses. The included
19 * external software's copyright is not touched by this agreement.
20 * -- Notes on re-distribution and contributions to/further development of
21 * the IboView software
22 */
23
24 #ifndef _CX_MEMORYSTACK_H
25 #define _CX_MEMORYSTACK_H
26
27 #include <stddef.h> // for size_t
28 #include <string.h> // for memset
29
30 typedef unsigned int
31 uint;
32
33 namespace ct {
34
35 /// An object managing a continuous block of memory. Used for allocation-free
36 /// temporary work space storage.
37 /// Notes:
38 /// - Deallocations must occur in reverse allocation order. A deallocation
39 /// FREES ALL MEMORY ALLOCATED AFTER THE ALLOCATION POINT.
40 /// - Both alloc and free are effectively non-ops in terms of computational
41 /// cost. Any work space, no matter how large or small, can be allocated
42 /// at will.
43 /// - There is no memory fragmentation.
44 struct FMemoryStack
45 {
46 /// allocate nSizeInBytes bytes off the stack. Return pointer to start.
47 virtual void* Alloc(size_t nSizeInBytes) = 0;
48 /// Free pointer p on stack. Should be an address returned by Alloc.
49 virtual void Free(void *p) = 0;
50 /// return amount of memory left (in bytes).
51 virtual size_t MemoryLeft() = 0;
52
53 /// allocate nObjects objects of size sizeof(T). Store pointer in p.
54 /// Usage:
55 /// MyType *p;
56 /// Mem.Alloc(p, 10); // allocate array of 10 objects of type MyType.
57 template<class T>
58 inline void Alloc(T *&p, size_t nObjects = 1){
59 p = reinterpret_cast<T*>( this->Alloc(sizeof(T) * nObjects) );
60 // note: objects are not constructed. Use only for PODs!
61 }
62
63 /// as Alloc(), but set allocated memory to zero.
64 template<class T>
65 inline void ClearAlloc(T *&p, size_t nObjects = 1){
66 Alloc(p, nObjects);
67 ::memset(p, 0, sizeof(T) * nObjects);
68 }
69
70 template<class T>
AllocNFMemoryStack71 inline T* AllocN(size_t nObjects, T const &){
72 return reinterpret_cast<T*>( this->Alloc(sizeof(T) * nObjects) );
73 }
74
75 template<class T>
ClearAllocNFMemoryStack76 inline T* ClearAllocN(size_t nObjects, T const &){
77 T *p;
78 this->Alloc(p, nObjects);
79 ::memset(p, 0, sizeof(T) * nObjects);
80 return p;
81 }
82
83 /// align stack to next 'Boundary' (must be power of two)-boundary .
84 virtual void Align(uint Boundary);
85
86 virtual ~FMemoryStack();
87 };
88
89 /// A memory stack defined by a base pointer and a size. Can own
90 /// the memory managed, but can also be put on memory allocated from
91 /// elsewhere.
92 struct FMemoryStack2 : public FMemoryStack {
93 /// creates a stack of 'nInitialSize' bytes on the global heap.
94 /// If nInitialSize is 0, the stack is created empty and a storage
95 /// area can be later assigned by AssignMemory() or Create().
96 explicit FMemoryStack2(size_t nInitialSize = 0) : m_pDataStart(0), m_pDataAligned(0) { Create(nInitialSize); }
97 /// if pBase != 0 && nActualSize >= nNeededSize:
98 /// creates a stack of 'nActualSize' bytes at memory pBase (i.e., at a memory location given from the outside)
99 /// otherwise
100 /// construction equivalent to FMemoryStack2((nNeededSize != 0)? nNeededSize : nActualSize).
101 FMemoryStack2(char *pBase, size_t nActualSize, size_t nNeededSize = 0);
102 inline void PushTopMark();
103 inline void PopTopMark();
104
105 void* Alloc(size_t nSizeInBytes); // override
106 using FMemoryStack::Alloc;
107 void Free(void *p); // override
108 size_t MemoryLeft(); // override
109 ~FMemoryStack2(); // override
110
111 /// create a new stack of size 'nSize' bytes on the global heap.
112 void Create( size_t nSize );
113 /// create a new stack in the storage area marked by 'pBase',
114 /// of 'nSize' bytes. This assumes that pBase is already allocated
115 /// from elsewhere.
116 void AssignMemory(char *pBase_, size_t nSize);
117 void Destroy();
118 void Align(uint Boundary); // override
119
120 private:
121 size_t
122 m_Pos, m_Size;
123 char
124 *m_pDataStart,
125 *m_pDataAligned; // next default-aligned address beyond m_pDataStart.
126 void DefaultAlign();
127 bool m_bOwnMemory; // if true, we allocated m_pData and need to free it on Destroy().
128
129 private:
130 FMemoryStack2(FMemoryStack2 const &); // not implemented
131 void operator = (FMemoryStack2 const &); // not implemented
132 };
133
134 // allocate a block of memory from pMem, and free it when the object goes out of scope.
135 template<class FType>
136 struct TMemoryLock
137 {
138 FType
139 *p; // pointer to allocated data
140
141 // allocate nCount objects from pMem, and store the pointer in this->p
142 inline TMemoryLock(size_t nCount, FMemoryStack *pMem);
143 // allocate nCount objects from pMem, and store the pointer in this->p and pOutsidePtr.
144 inline TMemoryLock(FType *&pOutsidePtr, size_t nCount, FMemoryStack *pMem);
145 inline ~TMemoryLock();
146
147 operator FType* () { return p; }
148 operator FType const* () const { return p; }
149
150 FMemoryStack
151 *m_pMemoryStack;
152 };
153
154 template<class FType>
TMemoryLock(size_t nCount,FMemoryStack * pMem)155 TMemoryLock<FType>::TMemoryLock(size_t nCount, FMemoryStack *pMem)
156 {
157 m_pMemoryStack = pMem;
158 m_pMemoryStack->Alloc(p, nCount);
159 }
160
161 template<class FType>
TMemoryLock(FType * & pOutsidePtr,size_t nCount,FMemoryStack * pMem)162 TMemoryLock<FType>::TMemoryLock(FType *&pOutsidePtr, size_t nCount, FMemoryStack *pMem)
163 {
164 m_pMemoryStack = pMem;
165 m_pMemoryStack->Alloc(p, nCount);
166 pOutsidePtr = p;
167 }
168
169 template<class FType>
~TMemoryLock()170 TMemoryLock<FType>::~TMemoryLock()
171 {
172 m_pMemoryStack->Free(p);
173 p = 0;
174 }
175
176
177 /// split a base memory stack into sub-stacks, one for each openmp thread.
178 struct FMemoryStackArray
179 {
180 explicit FMemoryStackArray(FMemoryStack &BaseStack);
181 ~FMemoryStackArray();
182
183 FMemoryStack2
184 *pSubStacks;
185 FMemoryStack
186 *pBaseStack;
187 uint
188 nThreads;
189
190 // return substack for the calling openmp thread.
191 FMemoryStack2 &GetStackOfThread();
192
193 // destroy this object (explicitly) already now
194 void Release();
195
196 char
197 *pStackBase;
198 private:
199 FMemoryStackArray(FMemoryStackArray const &); // not implemented
200 void operator = (FMemoryStackArray const &); // not implemented
201 };
202
203
204
205 } // namespace ct
206
207
208 #endif // _CX_MEMORYSTACK_H
209