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 | |
21 | IMPLEMENT_STANDARD_HANDLE (NCollection_AccAllocator, NCollection_BaseAllocator) |
22 | IMPLEMENT_STANDARD_RTTIEXT (NCollection_AccAllocator, NCollection_BaseAllocator) |
23 | |
24 | //======================================================================= |
25 | //function : NCollection_AccAllocator |
26 | //purpose : Constructor |
27 | //======================================================================= |
28 | NCollection_AccAllocator::NCollection_AccAllocator(const size_t theBlockSize) |
29 | : myBlockSize(theBlockSize), mypLastBlock(0L) |
30 | { |
31 | allocateNewBlock(myBlockSize); |
32 | } |
33 | |
34 | //======================================================================= |
35 | //function : ~NCollection_AccAllocator |
36 | //purpose : Destructor |
37 | //======================================================================= |
38 | NCollection_AccAllocator::~NCollection_AccAllocator() |
39 | { |
40 | for (Block* aBlock = mypLastBlock; aBlock; aBlock = aBlock->prevBlock) |
41 | { |
42 | Standard::Free(aBlock->address); |
43 | } |
44 | } |
45 | |
46 | //======================================================================= |
47 | //function : Allocate |
48 | //purpose : Allocate a memory |
49 | //======================================================================= |
50 | void* NCollection_AccAllocator::Allocate(const size_t theSize) |
51 | { |
52 | const AlignedSize aSize(theSize); |
53 | Block* aBlock; |
54 | |
55 | if (aSize <= mypLastBlock->FreeSize()) |
56 | { |
57 | aBlock = mypLastBlock; |
58 | } |
59 | else if (aSize > myBlockSize) |
60 | { |
61 | // If the requested size exceeds normal allocation size, |
62 | // allocate a separate block |
63 | aBlock = allocateNewBlock(aSize); |
64 | } |
65 | else |
66 | { |
67 | // Search for a block in the list with enough free space |
68 | Standard_Integer aBlocksRest = MaxLookupBlocks; |
69 | for (aBlock = mypLastBlock->prevBlock; |
70 | aBlock != 0L && --aBlocksRest; |
71 | aBlock = aBlock->prevBlock) |
72 | { |
73 | if (aSize <= aBlock->FreeSize()) |
74 | break; |
75 | } |
76 | if (aBlock == 0L || !aBlocksRest) |
77 | // There is no available block with enough free space, create a new one |
78 | aBlock = allocateNewBlock(myBlockSize); |
79 | } |
80 | |
81 | void* anAddress = aBlock->Allocate(aSize); |
0797d9d3 |
82 | #ifdef OCCT_DEBUG_FINDBLOCK |
9df7f429 |
83 | Key aKey; |
84 | Standard_ASSERT_VOID(aBlock == findBlock(anAddress, aKey), |
85 | "improper work of NCollection_AccAllocator::findBlock"); |
86 | #endif |
87 | return anAddress; |
88 | } |
89 | |
90 | //======================================================================= |
91 | //function : Free |
92 | //purpose : Free a previously allocated memory |
93 | //======================================================================= |
94 | void NCollection_AccAllocator::Free(void* theAddress) |
95 | { |
96 | Key aKey; |
97 | Block* aBlock = findBlock(theAddress, aKey); |
98 | |
99 | #if !defined No_Exception && !defined No_Standard_ProgramError |
7c47a3d6 |
100 | if (aBlock == 0L || aBlock->IsEmpty()) |
9df7f429 |
101 | { |
102 | Standard_ProgramError::Raise("NCollection_AccAllocator::Free: \ |
103 | Trying to free an invalid address"); |
104 | } |
105 | #endif |
106 | |
107 | aBlock->Free(); |
7c47a3d6 |
108 | if (aBlock->IsEmpty()) |
9df7f429 |
109 | { |
110 | Standard_Address anAddress = aBlock->address; |
111 | |
112 | // Deallocate and remove the free block if there are more blocks |
113 | if (myBlocks.Size() > 1) |
114 | { |
115 | Standard::Free(anAddress); |
116 | Block** appBlock; |
117 | for (appBlock = &mypLastBlock; |
118 | *appBlock != 0L; |
119 | appBlock = &(*appBlock)->prevBlock) |
120 | { |
121 | if (*appBlock == aBlock) |
122 | { |
123 | *appBlock = aBlock->prevBlock; |
124 | break; |
125 | } |
126 | } |
127 | myBlocks.UnBind(aKey); |
128 | } |
129 | // If there are no more blocks, reallocate the block to the default size |
130 | else |
131 | { |
7c47a3d6 |
132 | Standard_Address aNewAddress = Standard::Reallocate(anAddress, |
133 | myBlockSize); |
134 | if (aNewAddress == anAddress) |
9df7f429 |
135 | { |
7c47a3d6 |
136 | // Normally, the reallocation keeps the block at the same address |
137 | // (since no block can be smaller than the default size, and thus |
138 | // the allocated memory is just shrunk or untouched). |
139 | // In this case, just update the block's free size. |
140 | aBlock->SetFreeSize(myBlockSize); |
141 | } |
142 | else |
143 | { |
144 | // Reallocation still may return a different address even if the new |
145 | // size is equal to or smaller than the old one (this can happen in |
146 | // debug mode). |
147 | Key aNewKey = getKey(aNewAddress); |
148 | if (aNewKey.Value == aKey.Value) |
149 | { |
150 | // If the new address have the same key, |
151 | // just update the block's address and free size |
152 | aBlock->address = aNewAddress; |
153 | aBlock->SetFreeSize(myBlockSize); |
154 | } |
155 | else |
156 | { |
157 | // If the new address have different key, |
158 | // rebind the block to the map of blocks with the new key. |
159 | myBlocks.Clear(Standard_False); |
160 | mypLastBlock = myBlocks.Bound(aNewKey, |
161 | Block(aNewAddress, myBlockSize)); |
162 | } |
9df7f429 |
163 | } |
9df7f429 |
164 | } |
165 | } |
166 | } |
167 | |
168 | //======================================================================= |
169 | //function : findBlock |
170 | //purpose : Find a block that the given allocation unit belongs to |
171 | //======================================================================= |
172 | NCollection_AccAllocator::Block* |
173 | NCollection_AccAllocator::findBlock(const Standard_Address theAddress, Key& theKey) |
174 | { |
175 | theKey = getKey(theAddress); |
176 | |
177 | Block* aBlock = myBlocks.ChangeSeek(theKey); |
178 | if (aBlock && aBlock->address <= theAddress) |
179 | { |
180 | return aBlock; |
181 | } |
182 | |
183 | theKey.Value--; |
184 | aBlock = myBlocks.ChangeSeek(theKey); |
185 | if (aBlock && |
186 | (Standard_Byte*)aBlock->address + (Standard_Size)myBlockSize > theAddress) |
187 | { |
188 | return aBlock; |
189 | } |
190 | |
191 | return 0L; |
192 | } |
193 | |
194 | //======================================================================= |
195 | //function : allocateNewBlock |
196 | //purpose : Allocate a new block and return a pointer to it |
197 | //======================================================================= |
198 | NCollection_AccAllocator::Block* |
199 | NCollection_AccAllocator::allocateNewBlock(const Standard_Size theSize) |
200 | { |
201 | Standard_Address anAddress = Standard::Allocate(theSize); |
202 | // we depend on the fact that Standard::Allocate always returns |
203 | // a pointer aligned to a 4 byte boundary |
7c47a3d6 |
204 | mypLastBlock = myBlocks.Bound(getKey(anAddress), |
205 | Block(anAddress, theSize, mypLastBlock)); |
0797d9d3 |
206 | #ifdef OCCT_DEBUG_FINDBLOCK |
9df7f429 |
207 | Key aKey; |
7c47a3d6 |
208 | Standard_ASSERT_VOID( |
209 | mypLastBlock == findBlock((Standard_Byte*)mypLastBlock->allocStart-1, aKey), |
210 | "improper work of NCollection_AccAllocator::findBlock"); |
9df7f429 |
211 | #endif |
212 | return mypLastBlock; |
213 | } |