1 // Created on: 2001-06-26
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <LDOM_MemManager.hxx>
17 #include <LDOMBasicString.hxx>
19 IMPLEMENT_STANDARD_HANDLE (LDOM_MemManager, MMgt_TShared)
20 IMPLEMENT_STANDARD_RTTIEXT (LDOM_MemManager, MMgt_TShared)
23 #define MINIMAL_ROOM 3
25 typedef unsigned char LDOM_HashValue; // allocating HASH_MASK integer
27 inline Standard_Integer convertBlockSize (const Standard_Integer aBlockSize)
29 return ((aBlockSize - 1) / sizeof(Standard_Integer)) + 1;
32 inline Standard_Boolean compareStrings (char * const str,
33 const char * theString,
34 const Standard_Integer theLength)
36 // ** This is a bit dangerous (can override the boundary of allocated memory)
37 // return (str[theLength] == '\0' &&
38 // memcmp (str, theString, theLength) == 0);
39 // ** This is a more stable (less performant) solution
40 if (memcmp (str, theString, theLength)) return Standard_False;
41 return (str[theLength] == '\0');
44 //=======================================================================
45 //function : MemBlock::MemBlock
47 //=======================================================================
49 inline LDOM_MemManager::MemBlock::MemBlock (const Standard_Integer aSize,
50 LDOM_MemManager::MemBlock * aFirst)
51 : mySize (aSize), myNext (aFirst)
53 myFreeSpace = myBlock = new Standard_Integer [aSize];
54 myEndBlock = myBlock + aSize;
57 //=======================================================================
58 //function : MemBlock::Allocate
60 //=======================================================================
62 inline void * LDOM_MemManager::MemBlock::Allocate (const Standard_Integer aSize)
64 void * aResult = NULL;
65 if (aSize <= myEndBlock - myFreeSpace) {
66 aResult = myFreeSpace;
72 //=======================================================================
73 //function : MemBlock::AllocateAndCheck
75 //=======================================================================
77 void * LDOM_MemManager::MemBlock::AllocateAndCheck
78 (const Standard_Integer aSize,
79 const LDOM_MemManager::MemBlock *& aFirstWithoutRoom)
81 void * aResult = NULL;
82 Standard_Integer aRoom = (Standard_Integer)(myEndBlock - myFreeSpace);
84 aResult = myFreeSpace;
87 if (aRoom < MINIMAL_ROOM) {
88 if (aFirstWithoutRoom == NULL) aFirstWithoutRoom = this;
90 aFirstWithoutRoom = NULL;
94 //=======================================================================
95 //function : ~MemBlock
96 //purpose : Destructor
97 //=======================================================================
99 LDOM_MemManager::MemBlock::~MemBlock ()
105 //=======================================================================
106 //function : HashTable
107 //purpose : Constructor
108 //=======================================================================
110 LDOM_MemManager::HashTable::HashTable (/* const Standard_Integer aMask, */
111 LDOM_MemManager& aMemManager)
112 : myManager (aMemManager)
114 Standard_Integer m, nKeys = HASH_MASK + 1;
116 Standard_Integer m = aMask;
117 Standard_Integer nKeys = 1;
124 myTable = (TableItem *) myManager.Allocate (sizeof(TableItem) * nKeys);
125 for (m = 0; m < nKeys; m += 2) {
126 myTable[m].str = NULL;
127 myTable[m].next = NULL;
128 myTable[m+1].str = NULL;
129 myTable[m+1].next = NULL;
133 //=======================================================================
135 //purpose : CRC-16 hash function
136 //=======================================================================
138 Standard_Integer LDOM_MemManager::HashTable::Hash (const char * aString,
139 const Standard_Integer aLen)
141 static const unsigned int wCRC16a[16] =
143 0000000, 0140301, 0140601, 0000500,
144 0141401, 0001700, 0001200, 0141101,
145 0143001, 0003300, 0003600, 0143501,
146 0002400, 0142701, 0142201, 0002100,
149 static const unsigned int wCRC16b[16] =
151 0000000, 0146001, 0154001, 0012000,
152 0170001, 0036000, 0024000, 0162001,
153 0120001, 0066000, 0074000, 0132001,
154 0050000, 0116001, 0104001, 0043000,
157 unsigned int aCRC = 0;
158 const unsigned char * aPtr = (const unsigned char *) aString;
159 for (Standard_Integer i = aLen; i > 0; i--) {
160 const unsigned int bTmp = aCRC ^ (const unsigned int) (* aPtr++);
161 aCRC = ((aCRC >> 8) ^ wCRC16a[bTmp & 0x0F]) ^ wCRC16b[(bTmp >> 4) & 0x0F];
163 return Standard_Integer (aCRC & HASH_MASK /* myMask */);
166 //=======================================================================
167 //function : AddString
168 //purpose : Add or find a string in the hash table
169 //=======================================================================
171 const char * LDOM_MemManager::HashTable::AddString
172 (const char * theString,
173 const Standard_Integer theLen,
174 Standard_Integer& theHashIndex)
176 const char * aResult = NULL;
177 if (theString == NULL) return NULL;
178 Standard_Integer aHashIndex = Hash (theString, theLen);
179 TableItem * aNode = &myTable[aHashIndex];
180 if (aNode -> str == NULL) {
181 LDOM_HashValue * anAlloc = (LDOM_HashValue *)
182 myManager.Allocate (theLen + 1 + sizeof(LDOM_HashValue));
183 anAlloc[0] = LDOM_HashValue (aHashIndex);
184 aNode -> str = (char *) &anAlloc[1];
185 memcpy (aNode -> str, theString, theLen);
186 aNode -> str [theLen] = '\0';
187 aResult = aNode -> str;
189 if (compareStrings (aNode -> str, theString, theLen))
190 aResult = aNode -> str;
192 while (aNode -> next) {
193 aNode = aNode -> next;
194 if (compareStrings (aNode -> str, theString, theLen)) {
195 aResult = aNode -> str;
199 if (aResult == NULL) {
200 // Attention!!! We can make this allocation in a separate pool
201 // improving performance
202 aNode -> next = (TableItem *) myManager.Allocate (sizeof(TableItem));
203 aNode = aNode -> next;
204 LDOM_HashValue * anAlloc = (LDOM_HashValue *)
205 myManager.Allocate (theLen + 1 + sizeof(LDOM_HashValue));
206 anAlloc[0] = LDOM_HashValue (aHashIndex);
207 aNode -> str = (char *) &anAlloc[1];
208 memcpy (aNode -> str, theString, theLen);
209 aNode -> str [theLen] = '\0';
210 aResult = aNode -> str;
211 aNode -> next = NULL;
214 theHashIndex = aHashIndex;
218 //=======================================================================
219 //function : LDOM_MemManager
220 //purpose : Constructor
221 //=======================================================================
223 LDOM_MemManager::LDOM_MemManager (const Standard_Integer aBlockSize)
224 : myRootElement (NULL),
226 myFirstWithoutRoom (NULL),
227 myBlockSize (convertBlockSize(aBlockSize)),
228 myHashTable (NULL) {}
230 //=======================================================================
231 //function : ~LDOM_MemManager
232 //purpose : Destructor
233 //=======================================================================
235 LDOM_MemManager::~LDOM_MemManager ()
238 Standard_Integer aSomme = 0, aCount = 0;
239 MemBlock * aBlock = myFirstBlock;
240 //FILE * out = fopen ("/tmp/dump","w");
243 aSomme += aBlock -> mySize;
244 // for (const Standard_Integer * aPtr = aBlock -> myBlock;
245 // aPtr < aBlock -> myEndBlock; ) {
246 // const char * aStr = (const char *) aPtr;
247 // Standard_Integer aLen = strlen (aStr) + 1;
248 // if (aLen > 1) fprintf (out, "%s\n", aStr);
249 // aPtr += convertBlockSize (aLen);
251 aBlock = aBlock -> Next();
254 cout << ".. Destroying " << aCount << " LDOM memory allocations: "
255 << aSomme / 256 << " kB" << endl;
263 //=======================================================================
264 //function : Allocate
266 //=======================================================================
268 void * LDOM_MemManager::Allocate (const Standard_Integer theSize)
270 void * aResult = NULL;
271 Standard_Integer aSize = convertBlockSize (theSize);
273 if (aSize >= myBlockSize) {
274 myFirstBlock = new MemBlock (aSize, myFirstBlock);
275 aResult = myFirstBlock -> Allocate (aSize);
277 MemBlock * aBlock = myFirstBlock;
278 if (aBlock == NULL) {
279 myFirstBlock = new MemBlock (myBlockSize, myFirstBlock);
280 return myFirstBlock -> Allocate (aSize);
282 aResult = aBlock -> Allocate (aSize);
285 aBlock = aBlock -> Next();
286 const MemBlock * aFirstWithoutRoom = NULL;
287 while (aBlock != myFirstWithoutRoom) {
288 aResult = aBlock -> AllocateAndCheck (aSize, aFirstWithoutRoom);
290 aBlock = aBlock -> Next();
292 myFirstWithoutRoom = (MemBlock *&)aFirstWithoutRoom;
293 if (aResult == NULL) {
294 myFirstBlock = new MemBlock (myBlockSize, myFirstBlock);
295 aResult = myFirstBlock -> Allocate (aSize);
301 //=======================================================================
302 //function : HashedAllocate
303 //purpose : Memory allocation with access via hash table. No new allocation
304 // if already present
305 //=======================================================================
307 const char * LDOM_MemManager::HashedAllocate (const char * theString,
308 const Standard_Integer theLen,
309 Standard_Integer& theHash)
311 if (myHashTable == NULL) myHashTable = new HashTable (* this);
312 return myHashTable -> AddString (theString, theLen, theHash);
315 //=======================================================================
316 //function : HashedAllocate
317 //purpose : Memory allocation with access via hash table. No new allocation
318 // if already present
319 //=======================================================================
321 void LDOM_MemManager::HashedAllocate (const char * aString,
322 const Standard_Integer theLen,
323 LDOMBasicString& theResult)
325 theResult.myType = LDOMBasicString::LDOM_AsciiHashed;
326 Standard_Integer aDummy;
327 const char * aHashedString = HashedAllocate (aString, theLen, aDummy);
328 if (aHashedString != NULL)
329 theResult.myVal.ptr = (void *) aHashedString;
332 //=======================================================================
333 //function : CompareStrings
335 //=======================================================================
337 Standard_Boolean LDOM_MemManager::CompareStrings
338 (const char * theString,
339 const Standard_Integer theHashValue,
340 const char * theHashedStr)
342 if (((LDOM_HashValue *)theHashedStr)[-1] == LDOM_HashValue(theHashValue))
343 if (!strcmp (theString, theHashedStr))
344 return Standard_True;
345 return Standard_False;