0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / NCollection / NCollection_IncAllocator.cxx
CommitLineData
1103eb60 1// Copyright (c) 2002-2023 OPEN CASCADE SAS
b311480e 2//
973c2be1 3// This file is part of Open CASCADE Technology software library.
b311480e 4//
d5f74e42 5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
b311480e 10//
973c2be1 11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
b311480e 13
7fd59977 14#include <NCollection_IncAllocator.hxx>
1103eb60 15
23be7421 16#include <Standard_Mutex.hxx>
7fd59977 17#include <Standard_OutOfMemory.hxx>
7fd59977 18
1103eb60 19#include <cmath>
7fd59977 20
1103eb60 21IMPLEMENT_STANDARD_RTTIEXT(NCollection_IncAllocator, NCollection_BaseAllocator)
92efcf78 22
c99551fa
K
23namespace
24{
1103eb60 25 // Bounds for checking block size level
26 static constexpr unsigned THE_SMALL_BOUND_BLOCK_SIZE = NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE * 16; // 196 KB
27 static constexpr unsigned THE_MEDIUM_BOUND_BLOCK_SIZE = NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE * 64; // 786 KB
28 static constexpr unsigned THE_LARGE_BOUND_BLOCK_SIZE = NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE * 1024; // 12 MB
29
30 //=======================================================================
31 //function : computeLevel
32 //purpose :
33 //=======================================================================
34 NCollection_IncAllocator::IBlockSizeLevel computeLevel(const unsigned int theSize)
c99551fa 35 {
1103eb60 36 if (theSize < NCollection_IncAllocator::THE_DEFAULT_BLOCK_SIZE)
37 {
38 return NCollection_IncAllocator::IBlockSizeLevel::Min;
39 }
40 else if (theSize < THE_SMALL_BOUND_BLOCK_SIZE)
41 {
42 return NCollection_IncAllocator::IBlockSizeLevel::Small;
43 }
44 else if (theSize < THE_MEDIUM_BOUND_BLOCK_SIZE)
45 {
46 return NCollection_IncAllocator::IBlockSizeLevel::Medium;
47 }
48 else if (theSize < THE_LARGE_BOUND_BLOCK_SIZE)
49 {
50 return NCollection_IncAllocator::IBlockSizeLevel::Large;
51 }
52 else
53 {
54 return NCollection_IncAllocator::IBlockSizeLevel::Max;
55 }
c99551fa 56 }
23be7421
M
57}
58
59//=======================================================================
1103eb60 60//function : NCollection_IncAllocator
61//purpose : Constructor
23be7421 62//=======================================================================
1103eb60 63NCollection_IncAllocator::NCollection_IncAllocator(const size_t theDefaultSize) :
64 myBlockSize(static_cast<unsigned>(theDefaultSize < THE_MINIMUM_BLOCK_SIZE ? THE_DEFAULT_BLOCK_SIZE : theDefaultSize))
65{}
302f96fb 66
23be7421 67//=======================================================================
1103eb60 68//function : SetThreadSafe
69//purpose : Constructor
23be7421 70//=======================================================================
1103eb60 71void NCollection_IncAllocator::SetThreadSafe (const bool theIsThreadSafe)
23be7421 72{
1103eb60 73 if(theIsThreadSafe)
64531d9c 74 {
1103eb60 75 if (!myMutex)
76 {
77 myMutex = new Standard_Mutex;
78 }
64531d9c 79 }
1103eb60 80 else
23be7421 81 {
1103eb60 82 delete myMutex;
83 myMutex = nullptr;
23be7421 84 }
7fd59977 85}
86
87//=======================================================================
88//function : ~NCollection_IncAllocator
89//purpose : Destructor
90//=======================================================================
1103eb60 91NCollection_IncAllocator::~NCollection_IncAllocator()
7fd59977 92{
1103eb60 93 clean();
95c882e9 94 delete myMutex;
7fd59977 95}
96
95c882e9 97//=======================================================================
1103eb60 98//function : AllocateOptimal
99//purpose : allocate a memory
95c882e9 100//=======================================================================
1103eb60 101void* NCollection_IncAllocator::AllocateOptimal(const size_t theSize)
95c882e9 102{
1103eb60 103 Standard_Mutex::Sentry aLock(myMutex);
104 // Allocating using general block
105 IBlock* aBlock = nullptr;
106 // Use allocated blocks
107 if (myAllocationHeap && myAllocationHeap->AvailableSize >= theSize)
95c882e9 108 {
1103eb60 109 aBlock = myAllocationHeap;
95c882e9 110 }
1103eb60 111 else // Allocate new general block
95c882e9 112 {
1103eb60 113 if (++myBlockCount % 5 == 0) // increase count before checking
114 {
115 increaseBlockSize();
116 }
117 if (myBlockSize < theSize)
118 {
119 myBlockSize = static_cast<unsigned>(theSize);
120 }
121 void* aBufferBlock = Standard::AllocateOptimal(myBlockSize + sizeof(IBlock));
122 aBlock = new (aBufferBlock) IBlock(aBufferBlock, myBlockSize);
123 aBlock->NextBlock = myAllocationHeap;
124 aBlock->NextOrderedBlock = myOrderedBlocks;
125 myOrderedBlocks = aBlock;
126 myAllocationHeap = aBlock;
95c882e9 127 }
1103eb60 128 void* aRes = aBlock->CurPointer;
129 aBlock->CurPointer += theSize;
130 aBlock->AvailableSize -= theSize;
131 if (aBlock->AvailableSize < 16)
132 {
133 myAllocationHeap = aBlock->NextBlock;
134 aBlock->NextBlock = myUsedHeap;
135 myUsedHeap = aBlock;
136 }
137 else
138 {
139 IBlock* aBlockIter = aBlock->NextBlock;
140 IBlock* aBlockToReplaceAfter = nullptr;
141 while (aBlockIter) // Search new sorted position
142 {
143 if (aBlockIter->AvailableSize > aBlock->AvailableSize)
144 {
145 aBlockToReplaceAfter = aBlockIter;
146 aBlockIter = aBlockIter->NextBlock;
147 continue;
148 }
149 break;
150 }
151 if (aBlockToReplaceAfter) // Update list order
152 {
153 IBlock* aNext = aBlockToReplaceAfter->NextBlock;
154 aBlockToReplaceAfter->NextBlock = aBlock;
155 myAllocationHeap = aBlock->NextBlock;
156 aBlock->NextBlock = aNext;
157 }
158 }
159 return aRes;
95c882e9 160}
161
7fd59977 162//=======================================================================
163//function : Allocate
1103eb60 164//purpose : Allocate a memory
7fd59977 165//=======================================================================
1103eb60 166void* NCollection_IncAllocator::Allocate(const size_t theSize)
7fd59977 167{
1103eb60 168 return AllocateOptimal(theSize);
7fd59977 169}
170
171//=======================================================================
1103eb60 172//function : clean
7fd59977 173//purpose :
174//=======================================================================
1103eb60 175void NCollection_IncAllocator::clean()
7fd59977 176{
1103eb60 177 Standard_Mutex::Sentry aLock(myMutex);
178 IBlock* aHeapIter = myOrderedBlocks;
179 while (aHeapIter)
db56cc2d 180 {
1103eb60 181 IBlock* aCur = aHeapIter;
182 aHeapIter = aHeapIter->NextOrderedBlock;
183 Standard::Free(aCur);
db56cc2d 184 }
1103eb60 185 myOrderedBlocks = nullptr;
186 myAllocationHeap = nullptr;
187 myUsedHeap = nullptr;
188 myBlockCount = 0;
189 myBlockSize = THE_DEFAULT_BLOCK_SIZE;
7fd59977 190}
191
192//=======================================================================
1103eb60 193//function : increaseBlockSize
7fd59977 194//purpose :
195//=======================================================================
1103eb60 196void NCollection_IncAllocator::increaseBlockSize()
7fd59977 197{
1103eb60 198 switch (computeLevel(myBlockSize))
199 {
200 case NCollection_IncAllocator::IBlockSizeLevel::Min:
201 myBlockSize *= 8;
202 break;
203 case NCollection_IncAllocator::IBlockSizeLevel::Small:
204 myBlockSize *= 4;
205 break;
206 case NCollection_IncAllocator::IBlockSizeLevel::Medium:
207 myBlockSize *= 2;
208 break;
209 case NCollection_IncAllocator::IBlockSizeLevel::Large:
210 myBlockSize = static_cast<unsigned>(std::lround(myBlockSize * 1.5));
211 break;
212 case NCollection_IncAllocator::IBlockSizeLevel::Max:
213 break;
7fd59977 214 }
215}
216
217//=======================================================================
1103eb60 218//function : resetBlock
7fd59977 219//purpose :
220//=======================================================================
1103eb60 221void NCollection_IncAllocator::resetBlock(IBlock* theBlock) const
7fd59977 222{
1103eb60 223 theBlock->AvailableSize = theBlock->AvailableSize + (theBlock->CurPointer - (reinterpret_cast<char*>(theBlock) + sizeof(IBlock)));
224 theBlock->CurPointer = reinterpret_cast<char*>(theBlock) + sizeof(IBlock);
7fd59977 225}
226
227//=======================================================================
1103eb60 228//function : Reset
229//purpose :
7fd59977 230//=======================================================================
1103eb60 231void NCollection_IncAllocator::Reset(const Standard_Boolean theReleaseMemory)
7fd59977 232{
1103eb60 233 if (theReleaseMemory)
234 {
235 clean();
236 return;
237 }
238 Standard_Mutex::Sentry aLock(myMutex);
239 IBlock* aHeapIter = myOrderedBlocks;
240 while (aHeapIter)
241 {
242 IBlock* aCur = aHeapIter;
243 aHeapIter = aHeapIter->NextOrderedBlock;
244 aCur->NextBlock = aHeapIter;
245 resetBlock(aCur); // reset size and pointer
246 }
247 myAllocationHeap = myOrderedBlocks;
248 myUsedHeap = nullptr;
7fd59977 249}
250
251//=======================================================================
1103eb60 252//function : IBlockSmall::IBlockSmall
7fd59977 253//purpose :
254//=======================================================================
1103eb60 255NCollection_IncAllocator::IBlock::IBlock(void* thePointer,
256 const size_t theSize) :
257 CurPointer(static_cast<char*>(thePointer) + sizeof(IBlock)),
258 AvailableSize(theSize)
259{}