4929ef173296c4debaa49679594ad45816966e80
[occt.git] / src / NCollection / NCollection_IncAllocator.cxx
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 }