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