0024166: Unable to create file with "Save" menu of voxeldemo Qt sample
[occt.git] / src / NCollection / NCollection_IncAllocator.cxx
CommitLineData
b311480e 1// Created on: 2002-04-12
2// Created by: Alexander GRIGORIEV
3// Copyright (c) 2002-2012 OPEN CASCADE SAS
4//
5// The content of this file is subject to the Open CASCADE Technology Public
6// License Version 6.5 (the "License"). You may not use the content of this file
7// except in compliance with the License. Please obtain a copy of the License
8// at http://www.opencascade.org and read it completely before using this file.
9//
10// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12//
13// The Original Code and all software distributed under the License is
14// distributed on an "AS IS" basis, without warranty of any kind, and the
15// Initial Developer hereby disclaims all such warranties, including without
16// limitation, any warranties of merchantability, fitness for a particular
17// purpose or non-infringement. Please see the License for the specific terms
18// and conditions governing the rights and limitations under the License.
19
7fd59977 20#include <NCollection_IncAllocator.hxx>
23be7421
M
21#include <NCollection_DataMap.hxx>
22#include <NCollection_Map.hxx>
23#include <Standard_Mutex.hxx>
7fd59977 24#include <Standard_OutOfMemory.hxx>
25#include <stdio.h>
64531d9c 26#include <fstream>
27#include <iomanip>
7fd59977 28
29IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator)
30IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator)
31
c99551fa
K
32namespace
33{
34
35 inline size_t IMEM_SIZE (const size_t theSize)
36 {
37 return (theSize - 1) / sizeof(NCollection_IncAllocator::aligned_t) + 1;
38 }
39
40 inline size_t IMEM_ALIGN (const void* theAddress)
41 {
42 return sizeof(NCollection_IncAllocator::aligned_t) * IMEM_SIZE (size_t(theAddress));
43 }
44
45 #define IMEM_FREE(p_bl) (size_t(p_bl->p_end_block - p_bl->p_free_space))
46
74d80fb9 47#ifdef DEB
302f96fb 48 // auxiliary dummy function used to get a place where break point can be set
49 inline void place_for_breakpoint() {}
74d80fb9 50#endif
c99551fa 51};
7fd59977 52
53#define MaxLookup 16
54
23be7421
M
55static Standard_Boolean IS_DEBUG = Standard_False;
56
57//=======================================================================
58/**
59 * Static data map (address -> AllocatorID)
60 */
61//=======================================================================
62static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
63{
64 static NCollection_DataMap<Standard_Address, Standard_Size> TheMap;
65 return TheMap;
66}
67
68//=======================================================================
69/**
70 * Static map (AllocatorID)
71 */
72//=======================================================================
73static NCollection_Map<Standard_Size>& StorageIDSet()
74{
75 static NCollection_Map<Standard_Size> TheMap;
76 return TheMap;
77}
78
79//=======================================================================
80//function : IncAllocator_SetDebugFlag
81//purpose : Turn on/off debugging of memory allocation
82//=======================================================================
83
84Standard_EXPORT void IncAllocator_SetDebugFlag(const Standard_Boolean theDebug)
85{
86 IS_DEBUG = theDebug;
87}
88
302f96fb 89#ifdef DEB
90
23be7421
M
91//=======================================================================
92/**
93 * Static value of the current allocation ID. It provides unique
94 * numbering of allocators.
95 */
96//=======================================================================
97static Standard_Size CurrentID = 0;
98static Standard_Size CATCH_ID = 0;
99
100//=======================================================================
101//function : Debug_Create
102//purpose : Store the allocator address in the internal maps
103//=======================================================================
104
105static void Debug_Create(Standard_Address theAlloc)
106{
107 static Standard_Mutex aMutex;
bd0c22ce 108 aMutex.Lock();
23be7421
M
109 StorageIDMap().Bind(theAlloc, ++CurrentID);
110 StorageIDSet().Add(CurrentID);
23be7421 111 if (CurrentID == CATCH_ID)
302f96fb 112 place_for_breakpoint();
113 aMutex.Unlock();
23be7421
M
114}
115
116//=======================================================================
117//function : Debug_Destroy
118//purpose : Forget the allocator address from the internal maps
119//=======================================================================
120
121static void Debug_Destroy(Standard_Address theAlloc)
122{
123 static Standard_Mutex aMutex;
bd0c22ce 124 aMutex.Lock();
23be7421
M
125 if (StorageIDMap().IsBound(theAlloc))
126 {
127 Standard_Size anID = StorageIDMap()(theAlloc);
128 StorageIDSet().Remove(anID);
129 StorageIDMap().UnBind(theAlloc);
130 }
bd0c22ce 131 aMutex.Unlock();
23be7421
M
132}
133
302f96fb 134#endif /* DEB */
135
23be7421
M
136//=======================================================================
137//function : IncAllocator_PrintAlive
138//purpose : Outputs the alive numbers to the file inc_alive.d
139//=======================================================================
140
141Standard_EXPORT void IncAllocator_PrintAlive()
142{
64531d9c 143 if (StorageIDSet().IsEmpty())
144 {
145 return;
146 }
147
148 std::ofstream aFileOut ("inc_alive.d", std::ios_base::trunc | std::ios_base::out);
149 if (!aFileOut.is_open())
150 {
151 std::cout << "failure writing file inc_alive.d" << std::endl;
152 return;
153 }
154 aFileOut.imbue (std::locale ("C"));
155 aFileOut << std::fixed << std::setprecision(1);
156
157 aFileOut << "Alive IncAllocators (number, size in Kb)\n";
158 Standard_Size aTotSize = 0;
159 Standard_Integer nbAlloc = 0;
160 for (NCollection_DataMap<Standard_Address, Standard_Size>::Iterator itMap (StorageIDMap());
161 itMap.More(); itMap.Next())
23be7421 162 {
64531d9c 163 const NCollection_IncAllocator* anAlloc = static_cast<NCollection_IncAllocator*>(itMap.Key());
164 Standard_Size anID = itMap.Value();
165 Standard_Size aSize = anAlloc->GetMemSize();
166 aTotSize += aSize;
167 nbAlloc++;
168 aFileOut << std::setw(20) << anID << ' '
169 << std::setw(20) << (double(aSize) / 1024.0)
170 << '\n';
23be7421 171 }
64531d9c 172 aFileOut << "Total:\n"
173 << std::setw(20) << nbAlloc << ' '
174 << std::setw(20) << (double(aTotSize) / 1024.0)
175 << '\n';
176 aFileOut.close();
23be7421
M
177}
178
7fd59977 179//=======================================================================
180//function : NCollection_IncAllocator()
181//purpose : Constructor
182//=======================================================================
183
184NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
185{
186#ifdef ALLOC_TRACK_USAGE
187 printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
188#endif
23be7421
M
189#ifdef DEB
190 if (IS_DEBUG)
191 Debug_Create(this);
192#endif
8ba3c5e0 193 const size_t aDefault = DefaultBlockSize;
7fd59977 194 const size_t aSize = IMEM_SIZE(sizeof(IBlock)) +
8ba3c5e0 195 IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : aDefault);
7fd59977 196 IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t));
197 myFirstBlock = aBlock;
db56cc2d 198 mySize = aSize - IMEM_SIZE(sizeof(IBlock));
23be7421 199 myMemSize = aSize * sizeof(aligned_t);
7fd59977 200 if (aBlock == NULL)
201 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
202 aBlock -> p_free_space = (aligned_t *) IMEM_ALIGN (&aBlock[1]);
203 aBlock -> p_end_block = ((aligned_t *) aBlock) + aSize;
204 aBlock -> p_next = NULL;
205}
206
207//=======================================================================
208//function : ~NCollection_IncAllocator
209//purpose : Destructor
210//=======================================================================
211
212NCollection_IncAllocator::~NCollection_IncAllocator ()
213{
23be7421
M
214#ifdef DEB
215 if (IS_DEBUG)
216 Debug_Destroy(this);
217#endif
7fd59977 218 Clean();
219 free (myFirstBlock);
220}
221
222//=======================================================================
223//function : Allocate
224//purpose : allocate a memory
225//remark : returns NULL if allocation fails
226//=======================================================================
227
228void * NCollection_IncAllocator::Allocate (const size_t aSize)
229{
230 aligned_t * aResult = NULL;
231 const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
232
233 if (cSize > mySize) {
234 /* If the requested size exceeds normal allocation size, allocate
235 a separate block and place it as the head of the list */
236 aResult = (aligned_t *) allocateNewBlock (cSize+1);
237 if (aResult)
238 myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
db56cc2d 239 else
240 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
7fd59977 241 } else
242 if (cSize <= IMEM_FREE(myFirstBlock)) {
243 /* If the requested size fits into the free space in the 1st block */
244 aResult = myFirstBlock -> allocateInBlock (cSize);
245 } else {
246 /* Search for a block in the list with enough free space */
247 int aMaxLookup = MaxLookup; /* limit the number of blocks to query */
248 IBlock * aCurrentBlock = myFirstBlock -> p_next;
249 while (aCurrentBlock && aMaxLookup--) {
250 if (cSize <= IMEM_FREE(aCurrentBlock)) {
251 aResult = aCurrentBlock -> allocateInBlock (cSize);
252 break;
253 }
254 aCurrentBlock = aCurrentBlock -> p_next;
255 }
256 if (aResult == NULL) {
257 /* There is no available block with enough free space. Create a new
258 one and place it in the head of the list */
259 aResult = (aligned_t *) allocateNewBlock (mySize);
260 if (aResult)
261 myFirstBlock -> p_free_space = aResult + cSize;
db56cc2d 262 else
263 {
264 const size_t aDefault = IMEM_SIZE(DefaultBlockSize);
265 if (cSize > aDefault)
266 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
267 else
268 {
269 aResult = (aligned_t *) allocateNewBlock (aDefault);
270 if (aResult)
271 myFirstBlock -> p_free_space = aResult + cSize;
272 else
273 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
274 }
275 }
7fd59977 276 }
277 }
278 return aResult;
279}
280
281//=======================================================================
282//function : Reallocate
283//purpose :
284//=======================================================================
285
286void * NCollection_IncAllocator::Reallocate (void * theAddress,
287 const size_t oldSize,
288 const size_t newSize)
289{
290// Check that the dummy parameters are OK
291 if (theAddress == NULL || oldSize == 0)
292 return Allocate (newSize);
293 const size_t cOldSize = IMEM_SIZE(oldSize);
294 const size_t cNewSize = newSize ? IMEM_SIZE(newSize) : 0;
295 aligned_t * anAddress = (aligned_t *) theAddress;
296
297// We check only the LAST allocation to do the real extension/contraction
298 if (anAddress + cOldSize == myFirstBlock -> p_free_space) {
299 myFirstBlock -> p_free_space = anAddress;
300// If the new size fits into the memory block => OK
301// This also includes any case of contraction
302 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
303 myFirstBlock -> p_free_space += cNewSize;
304 return anAddress;
305 }
306 }
307// In case of contraction of non-terminating allocation, do nothing
308 else if (cOldSize >= cNewSize)
309 return anAddress;
310// Extension of non-terminated allocation if there is enough room in the
311// current memory block
312 if (cNewSize <= IMEM_FREE(myFirstBlock)) {
313 aligned_t * aResult = myFirstBlock -> allocateInBlock (cNewSize);
314 if (aResult)
315 for (unsigned i = 0; i < cOldSize; i++)
316 aResult[i] = anAddress[i];
317 return aResult;
318 }
319
320// This is either of the cases:
321// - extension of non-terminating allocation, or
322// - extension of terminating allocation when the new size is too big
323// In both cases create a new memory block, allocate memory and copy there
324// the reallocated memory.
db56cc2d 325 size_t cMaxSize = mySize > cNewSize ? mySize : cNewSize;
326 aligned_t * aResult = (aligned_t *) allocateNewBlock (cMaxSize);
7fd59977 327 if (aResult) {
328 myFirstBlock -> p_free_space = aResult + cNewSize;
329 for (unsigned i = 0; i < cOldSize; i++)
330 aResult[i] = anAddress[i];
331 }
db56cc2d 332 else
333 {
334 Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
335 }
7fd59977 336 return aResult;
337}
338
339//=======================================================================
340//function : Free
341//purpose :
342//=======================================================================
343
344void NCollection_IncAllocator::Free (void *)
345{}
346
347//=======================================================================
348//function : Clean
349//purpose :
350//=======================================================================
351
352void NCollection_IncAllocator::Clean ()
353{
354#ifdef ALLOC_TRACK_USAGE
355 printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
356 double(GetMemSize())/1024, this);
357#endif
358 IBlock * aBlock = myFirstBlock;
359 if (aBlock) {
360 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
361 aBlock = aBlock -> p_next;
362 while (aBlock) {
363 IBlock * aNext = aBlock -> p_next;
364 free (aBlock);
365 aBlock = aNext;
366 }
367 myFirstBlock -> p_next = NULL;
368 }
23be7421 369 myMemSize = 0;
7fd59977 370}
371
372//=======================================================================
373//function : Reset
374//purpose :
375//=======================================================================
376
377void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
378{
379 if (doReleaseMem)
380 Clean();
381 else {
382 Standard_Integer aBlockCount(0);
383 IBlock * aBlock = myFirstBlock;
384 while (aBlock)
385 if (aBlockCount++ < MaxLookup) {
386 aBlock -> p_free_space = (aligned_t *) &aBlock[1];
387 if (aBlockCount < MaxLookup)
388 aBlock = aBlock -> p_next;
389 else {
390 IBlock * aNext = aBlock -> p_next;
391 aBlock -> p_next = NULL;
392 aBlock = aNext;
393 }
394 } else {
395 IBlock * aNext = aBlock -> p_next;
23be7421 396 myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
7fd59977 397 free (aBlock);
398 aBlock = aNext;
399 }
400 }
401}
402
403//=======================================================================
404//function : GetMemSize
405//purpose : diagnostic utility
406//=======================================================================
407
408size_t NCollection_IncAllocator::GetMemSize () const
409{
23be7421
M
410// size_t aResult = 0;
411// IBlock * aBlock = myFirstBlock;
412// while (aBlock) {
413// aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
414// aBlock = aBlock -> p_next;
415// }
416// return aResult * sizeof (aligned_t);
417 return myMemSize;
7fd59977 418}
419
420//=======================================================================
421//function : allocateNewBlock
422//purpose :
423//=======================================================================
424
425void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
426{
427 aligned_t * aResult = 0L;
428 const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
429 IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
430 if (aBlock) {
431 aBlock -> p_end_block = ((aligned_t *)aBlock) + aSz;
432 aBlock -> p_next = myFirstBlock;
433 myFirstBlock = aBlock;
434 aResult = (aligned_t *) IMEM_ALIGN(&aBlock[1]);
23be7421 435 myMemSize += aSz * sizeof(aligned_t);
7fd59977 436 }
7fd59977 437 return aResult;
438}