0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / NCollection / NCollection_AccAllocator.cxx
CommitLineData
9df7f429 1// Created on: 2013-11-12
2// Created by: Maxim YAKUNIN (myn)
3// Copyright (c) 2002-2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16#include <NCollection_AccAllocator.hxx>
17#include <Standard_OutOfMemory.hxx>
18#include <Standard_Assert.hxx>
19
20
92efcf78 21IMPLEMENT_STANDARD_RTTIEXT(NCollection_AccAllocator,NCollection_BaseAllocator)
22
9df7f429 23//=======================================================================
24//function : NCollection_AccAllocator
25//purpose : Constructor
26//=======================================================================
27NCollection_AccAllocator::NCollection_AccAllocator(const size_t theBlockSize)
28: myBlockSize(theBlockSize), mypLastBlock(0L)
29{
30 allocateNewBlock(myBlockSize);
31}
32
33//=======================================================================
34//function : ~NCollection_AccAllocator
35//purpose : Destructor
36//=======================================================================
37NCollection_AccAllocator::~NCollection_AccAllocator()
38{
39 for (Block* aBlock = mypLastBlock; aBlock; aBlock = aBlock->prevBlock)
40 {
41 Standard::Free(aBlock->address);
42 }
43}
44
45//=======================================================================
46//function : Allocate
47//purpose : Allocate a memory
48//=======================================================================
49void* NCollection_AccAllocator::Allocate(const size_t theSize)
50{
51 const AlignedSize aSize(theSize);
52 Block* aBlock;
53
54 if (aSize <= mypLastBlock->FreeSize())
55 {
56 aBlock = mypLastBlock;
57 }
58 else if (aSize > myBlockSize)
59 {
60 // If the requested size exceeds normal allocation size,
61 // allocate a separate block
62 aBlock = allocateNewBlock(aSize);
63 }
64 else
65 {
66 // Search for a block in the list with enough free space
67 Standard_Integer aBlocksRest = MaxLookupBlocks;
68 for (aBlock = mypLastBlock->prevBlock;
69 aBlock != 0L && --aBlocksRest;
70 aBlock = aBlock->prevBlock)
71 {
72 if (aSize <= aBlock->FreeSize())
73 break;
74 }
75 if (aBlock == 0L || !aBlocksRest)
76 // There is no available block with enough free space, create a new one
77 aBlock = allocateNewBlock(myBlockSize);
78 }
79
80 void* anAddress = aBlock->Allocate(aSize);
0797d9d3 81#ifdef OCCT_DEBUG_FINDBLOCK
9df7f429 82 Key aKey;
83 Standard_ASSERT_VOID(aBlock == findBlock(anAddress, aKey),
84 "improper work of NCollection_AccAllocator::findBlock");
85#endif
86 return anAddress;
87}
88
89//=======================================================================
90//function : Free
91//purpose : Free a previously allocated memory
92//=======================================================================
93void NCollection_AccAllocator::Free(void* theAddress)
94{
95 Key aKey;
96 Block* aBlock = findBlock(theAddress, aKey);
97
98#if !defined No_Exception && !defined No_Standard_ProgramError
7c47a3d6 99 if (aBlock == 0L || aBlock->IsEmpty())
9df7f429 100 {
9775fa61 101 throw Standard_ProgramError("NCollection_AccAllocator::Free: \
102 Trying to free an invalid address");
9df7f429 103 }
104#endif
105
106 aBlock->Free();
7c47a3d6 107 if (aBlock->IsEmpty())
9df7f429 108 {
109 Standard_Address anAddress = aBlock->address;
110
111 // Deallocate and remove the free block if there are more blocks
112 if (myBlocks.Size() > 1)
113 {
114 Standard::Free(anAddress);
115 Block** appBlock;
116 for (appBlock = &mypLastBlock;
117 *appBlock != 0L;
118 appBlock = &(*appBlock)->prevBlock)
119 {
120 if (*appBlock == aBlock)
121 {
122 *appBlock = aBlock->prevBlock;
123 break;
124 }
125 }
126 myBlocks.UnBind(aKey);
127 }
128 // If there are no more blocks, reallocate the block to the default size
129 else
130 {
7c47a3d6 131 Standard_Address aNewAddress = Standard::Reallocate(anAddress,
132 myBlockSize);
133 if (aNewAddress == anAddress)
9df7f429 134 {
7c47a3d6 135 // Normally, the reallocation keeps the block at the same address
136 // (since no block can be smaller than the default size, and thus
137 // the allocated memory is just shrunk or untouched).
138 // In this case, just update the block's free size.
139 aBlock->SetFreeSize(myBlockSize);
140 }
141 else
142 {
143 // Reallocation still may return a different address even if the new
144 // size is equal to or smaller than the old one (this can happen in
145 // debug mode).
146 Key aNewKey = getKey(aNewAddress);
147 if (aNewKey.Value == aKey.Value)
148 {
149 // If the new address have the same key,
150 // just update the block's address and free size
151 aBlock->address = aNewAddress;
152 aBlock->SetFreeSize(myBlockSize);
153 }
154 else
155 {
156 // If the new address have different key,
157 // rebind the block to the map of blocks with the new key.
158 myBlocks.Clear(Standard_False);
159 mypLastBlock = myBlocks.Bound(aNewKey,
160 Block(aNewAddress, myBlockSize));
161 }
9df7f429 162 }
9df7f429 163 }
164 }
165}
166
167//=======================================================================
168//function : findBlock
169//purpose : Find a block that the given allocation unit belongs to
170//=======================================================================
171NCollection_AccAllocator::Block*
172NCollection_AccAllocator::findBlock(const Standard_Address theAddress, Key& theKey)
173{
174 theKey = getKey(theAddress);
175
176 Block* aBlock = myBlocks.ChangeSeek(theKey);
177 if (aBlock && aBlock->address <= theAddress)
178 {
179 return aBlock;
180 }
181
182 theKey.Value--;
183 aBlock = myBlocks.ChangeSeek(theKey);
184 if (aBlock &&
185 (Standard_Byte*)aBlock->address + (Standard_Size)myBlockSize > theAddress)
186 {
187 return aBlock;
188 }
189
190 return 0L;
191}
192
193//=======================================================================
194//function : allocateNewBlock
195//purpose : Allocate a new block and return a pointer to it
196//=======================================================================
197NCollection_AccAllocator::Block*
198NCollection_AccAllocator::allocateNewBlock(const Standard_Size theSize)
199{
200 Standard_Address anAddress = Standard::Allocate(theSize);
201 // we depend on the fact that Standard::Allocate always returns
202 // a pointer aligned to a 4 byte boundary
7c47a3d6 203 mypLastBlock = myBlocks.Bound(getKey(anAddress),
204 Block(anAddress, theSize, mypLastBlock));
0797d9d3 205#ifdef OCCT_DEBUG_FINDBLOCK
9df7f429 206 Key aKey;
7c47a3d6 207 Standard_ASSERT_VOID(
208 mypLastBlock == findBlock((Standard_Byte*)mypLastBlock->allocStart-1, aKey),
209 "improper work of NCollection_AccAllocator::findBlock");
9df7f429 210#endif
211 return mypLastBlock;
212}