7fd59977 |
1 | // File: NCollection_IncAllocator.cxx |
2 | // Created: 12.04.02 21:16:26 |
3 | // Author: Alexander GRIGORIEV |
4 | // Copyright: Open Cascade 2002 |
5 | |
6 | #include <NCollection_IncAllocator.hxx> |
7 | #include <Standard_OutOfMemory.hxx> |
8 | #include <stdio.h> |
9 | |
10 | IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator) |
11 | IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator) |
12 | |
13 | #define IMEM_SIZE(_size) ((((_size) - 1)/sizeof(aligned_t)) + 1) |
14 | #define IMEM_FREE(p_bl) ((unsigned int)(p_bl->p_end_block - p_bl->p_free_space)) |
15 | #define IMEM_ALIGN(_addr) (sizeof(aligned_t)* IMEM_SIZE((unsigned long)(_addr))) |
16 | |
17 | #define MaxLookup 16 |
18 | |
19 | //======================================================================= |
20 | //function : NCollection_IncAllocator() |
21 | //purpose : Constructor |
22 | //======================================================================= |
23 | |
24 | NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize) |
25 | { |
26 | #ifdef ALLOC_TRACK_USAGE |
27 | printf ("\n..NCollection_IncAllocator: Created (%x)\n",this); |
28 | #endif |
29 | const size_t aSize = IMEM_SIZE(sizeof(IBlock)) + |
30 | IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : 24600); |
31 | IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t)); |
32 | myFirstBlock = aBlock; |
33 | mySize = aSize; |
34 | if (aBlock == NULL) |
35 | Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory"); |
36 | aBlock -> p_free_space = (aligned_t *) IMEM_ALIGN (&aBlock[1]); |
37 | aBlock -> p_end_block = ((aligned_t *) aBlock) + aSize; |
38 | aBlock -> p_next = NULL; |
39 | } |
40 | |
41 | //======================================================================= |
42 | //function : ~NCollection_IncAllocator |
43 | //purpose : Destructor |
44 | //======================================================================= |
45 | |
46 | NCollection_IncAllocator::~NCollection_IncAllocator () |
47 | { |
48 | Clean(); |
49 | free (myFirstBlock); |
50 | } |
51 | |
52 | //======================================================================= |
53 | //function : Allocate |
54 | //purpose : allocate a memory |
55 | //remark : returns NULL if allocation fails |
56 | //======================================================================= |
57 | |
58 | void * NCollection_IncAllocator::Allocate (const size_t aSize) |
59 | { |
60 | aligned_t * aResult = NULL; |
61 | const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0; |
62 | |
63 | if (cSize > mySize) { |
64 | /* If the requested size exceeds normal allocation size, allocate |
65 | a separate block and place it as the head of the list */ |
66 | aResult = (aligned_t *) allocateNewBlock (cSize+1); |
67 | if (aResult) |
68 | myFirstBlock -> p_free_space = myFirstBlock -> p_end_block; |
69 | } else |
70 | if (cSize <= IMEM_FREE(myFirstBlock)) { |
71 | /* If the requested size fits into the free space in the 1st block */ |
72 | aResult = myFirstBlock -> allocateInBlock (cSize); |
73 | } else { |
74 | /* Search for a block in the list with enough free space */ |
75 | int aMaxLookup = MaxLookup; /* limit the number of blocks to query */ |
76 | IBlock * aCurrentBlock = myFirstBlock -> p_next; |
77 | while (aCurrentBlock && aMaxLookup--) { |
78 | if (cSize <= IMEM_FREE(aCurrentBlock)) { |
79 | aResult = aCurrentBlock -> allocateInBlock (cSize); |
80 | break; |
81 | } |
82 | aCurrentBlock = aCurrentBlock -> p_next; |
83 | } |
84 | if (aResult == NULL) { |
85 | /* There is no available block with enough free space. Create a new |
86 | one and place it in the head of the list */ |
87 | aResult = (aligned_t *) allocateNewBlock (mySize); |
88 | if (aResult) |
89 | myFirstBlock -> p_free_space = aResult + cSize; |
90 | } |
91 | } |
92 | return aResult; |
93 | } |
94 | |
95 | //======================================================================= |
96 | //function : Reallocate |
97 | //purpose : |
98 | //======================================================================= |
99 | |
100 | void * NCollection_IncAllocator::Reallocate (void * theAddress, |
101 | const size_t oldSize, |
102 | const size_t newSize) |
103 | { |
104 | // Check that the dummy parameters are OK |
105 | if (theAddress == NULL || oldSize == 0) |
106 | return Allocate (newSize); |
107 | const size_t cOldSize = IMEM_SIZE(oldSize); |
108 | const size_t cNewSize = newSize ? IMEM_SIZE(newSize) : 0; |
109 | aligned_t * anAddress = (aligned_t *) theAddress; |
110 | |
111 | // We check only the LAST allocation to do the real extension/contraction |
112 | if (anAddress + cOldSize == myFirstBlock -> p_free_space) { |
113 | myFirstBlock -> p_free_space = anAddress; |
114 | // If the new size fits into the memory block => OK |
115 | // This also includes any case of contraction |
116 | if (cNewSize <= IMEM_FREE(myFirstBlock)) { |
117 | myFirstBlock -> p_free_space += cNewSize; |
118 | return anAddress; |
119 | } |
120 | } |
121 | // In case of contraction of non-terminating allocation, do nothing |
122 | else if (cOldSize >= cNewSize) |
123 | return anAddress; |
124 | // Extension of non-terminated allocation if there is enough room in the |
125 | // current memory block |
126 | if (cNewSize <= IMEM_FREE(myFirstBlock)) { |
127 | aligned_t * aResult = myFirstBlock -> allocateInBlock (cNewSize); |
128 | if (aResult) |
129 | for (unsigned i = 0; i < cOldSize; i++) |
130 | aResult[i] = anAddress[i]; |
131 | return aResult; |
132 | } |
133 | |
134 | // This is either of the cases: |
135 | // - extension of non-terminating allocation, or |
136 | // - extension of terminating allocation when the new size is too big |
137 | // In both cases create a new memory block, allocate memory and copy there |
138 | // the reallocated memory. |
139 | aligned_t * aResult = (aligned_t *) allocateNewBlock (mySize); |
140 | if (aResult) { |
141 | myFirstBlock -> p_free_space = aResult + cNewSize; |
142 | for (unsigned i = 0; i < cOldSize; i++) |
143 | aResult[i] = anAddress[i]; |
144 | } |
145 | return aResult; |
146 | } |
147 | |
148 | //======================================================================= |
149 | //function : Free |
150 | //purpose : |
151 | //======================================================================= |
152 | |
153 | void NCollection_IncAllocator::Free (void *) |
154 | {} |
155 | |
156 | //======================================================================= |
157 | //function : Clean |
158 | //purpose : |
159 | //======================================================================= |
160 | |
161 | void NCollection_IncAllocator::Clean () |
162 | { |
163 | #ifdef ALLOC_TRACK_USAGE |
164 | printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n", |
165 | double(GetMemSize())/1024, this); |
166 | #endif |
167 | IBlock * aBlock = myFirstBlock; |
168 | if (aBlock) { |
169 | aBlock -> p_free_space = (aligned_t *) &aBlock[1]; |
170 | aBlock = aBlock -> p_next; |
171 | while (aBlock) { |
172 | IBlock * aNext = aBlock -> p_next; |
173 | free (aBlock); |
174 | aBlock = aNext; |
175 | } |
176 | myFirstBlock -> p_next = NULL; |
177 | } |
178 | } |
179 | |
180 | //======================================================================= |
181 | //function : Reset |
182 | //purpose : |
183 | //======================================================================= |
184 | |
185 | void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem) |
186 | { |
187 | if (doReleaseMem) |
188 | Clean(); |
189 | else { |
190 | Standard_Integer aBlockCount(0); |
191 | IBlock * aBlock = myFirstBlock; |
192 | while (aBlock) |
193 | if (aBlockCount++ < MaxLookup) { |
194 | aBlock -> p_free_space = (aligned_t *) &aBlock[1]; |
195 | if (aBlockCount < MaxLookup) |
196 | aBlock = aBlock -> p_next; |
197 | else { |
198 | IBlock * aNext = aBlock -> p_next; |
199 | aBlock -> p_next = NULL; |
200 | aBlock = aNext; |
201 | } |
202 | } else { |
203 | IBlock * aNext = aBlock -> p_next; |
204 | free (aBlock); |
205 | aBlock = aNext; |
206 | } |
207 | } |
208 | } |
209 | |
210 | //======================================================================= |
211 | //function : GetMemSize |
212 | //purpose : diagnostic utility |
213 | //======================================================================= |
214 | |
215 | size_t NCollection_IncAllocator::GetMemSize () const |
216 | { |
217 | size_t aResult = 0; |
218 | IBlock * aBlock = myFirstBlock; |
219 | while (aBlock) { |
220 | aResult += (aBlock -> p_end_block - (aligned_t *) aBlock); |
221 | aBlock = aBlock -> p_next; |
222 | } |
223 | return aResult * sizeof (aligned_t); |
224 | } |
225 | |
226 | //======================================================================= |
227 | //function : allocateNewBlock |
228 | //purpose : |
229 | //======================================================================= |
230 | |
231 | void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize) |
232 | { |
233 | aligned_t * aResult = 0L; |
234 | const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock)); |
235 | IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t)); |
236 | if (aBlock) { |
237 | aBlock -> p_end_block = ((aligned_t *)aBlock) + aSz; |
238 | aBlock -> p_next = myFirstBlock; |
239 | myFirstBlock = aBlock; |
240 | aResult = (aligned_t *) IMEM_ALIGN(&aBlock[1]); |
241 | } |
242 | else |
243 | Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory"); |
244 | return aResult; |
245 | } |