0025261: NCollection, set of improvements
authorpdn <pdn@opencascade.com>
Thu, 2 Oct 2014 12:00:36 +0000 (16:00 +0400)
committerbugmaster <bugmaster@opencascade.com>
Thu, 2 Oct 2014 12:01:17 +0000 (16:01 +0400)
The following improvements were implemented:
* two additional allocators were introduced
  * Allocator which used WinHeap
  * Accumulating memory allocator
* Access to Allocators in lists are provided
* Access optimization in data map (seek and find functions returning reference or pointer to value in one shot)

Warning fixed

src/NCollection/FILES
src/NCollection/NCollection_AccAllocator.cxx [new file with mode: 0644]
src/NCollection/NCollection_AccAllocator.hxx [new file with mode: 0644]
src/NCollection/NCollection_BaseList.hxx
src/NCollection/NCollection_DataMap.hxx
src/NCollection/NCollection_WinHeapAllocator.cxx [new file with mode: 0644]
src/NCollection/NCollection_WinHeapAllocator.hxx [new file with mode: 0644]

index 38ee5c3..c9affa6 100755 (executable)
@@ -1,5 +1,7 @@
 NCollection_TypeDef.hxx
 
+NCollection_AccAllocator.hxx
+NCollection_AccAllocator.cxx
 NCollection_BaseAllocator.hxx
 NCollection_BaseAllocator.cxx
 NCollection_IncAllocator.hxx
@@ -9,6 +11,8 @@ NCollection_AlignedAllocator.cxx
 NCollection_HeapAllocator.hxx
 NCollection_HeapAllocator.cxx
 NCollection_StdAllocator.hxx
+NCollection_WinHeapAllocator.hxx
+NCollection_WinHeapAllocator.cxx
 
 NCollection_ListNode.hxx
 NCollection_BaseList.hxx
diff --git a/src/NCollection/NCollection_AccAllocator.cxx b/src/NCollection/NCollection_AccAllocator.cxx
new file mode 100644 (file)
index 0000000..bb2e14e
--- /dev/null
@@ -0,0 +1,190 @@
+// Created on: 2013-11-12
+// Created by: Maxim YAKUNIN (myn)
+// Copyright (c) 2002-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <NCollection_AccAllocator.hxx>
+#include <Standard_OutOfMemory.hxx>
+#include <Standard_Assert.hxx>
+
+
+IMPLEMENT_STANDARD_HANDLE  (NCollection_AccAllocator, NCollection_BaseAllocator)
+IMPLEMENT_STANDARD_RTTIEXT (NCollection_AccAllocator, NCollection_BaseAllocator)
+
+//=======================================================================
+//function : NCollection_AccAllocator
+//purpose  : Constructor
+//=======================================================================
+NCollection_AccAllocator::NCollection_AccAllocator(const size_t theBlockSize)
+: myBlockSize(theBlockSize), mypLastBlock(0L)
+{
+  allocateNewBlock(myBlockSize);
+}
+
+//=======================================================================
+//function : ~NCollection_AccAllocator
+//purpose  : Destructor
+//=======================================================================
+NCollection_AccAllocator::~NCollection_AccAllocator()
+{
+  for (Block* aBlock = mypLastBlock; aBlock; aBlock = aBlock->prevBlock)
+  {
+    Standard::Free(aBlock->address);
+  }
+}
+
+//=======================================================================
+//function : Allocate
+//purpose  : Allocate a memory
+//=======================================================================
+void* NCollection_AccAllocator::Allocate(const size_t theSize)
+{
+  const AlignedSize aSize(theSize);
+  Block* aBlock;
+
+  if (aSize <= mypLastBlock->FreeSize())
+  {
+    aBlock = mypLastBlock;
+  }
+  else if (aSize > myBlockSize)
+  {
+    // If the requested size exceeds normal allocation size,
+    // allocate a separate block
+    aBlock = allocateNewBlock(aSize);
+  }
+  else
+  {
+    // Search for a block in the list with enough free space
+    Standard_Integer aBlocksRest = MaxLookupBlocks;
+    for (aBlock = mypLastBlock->prevBlock;
+         aBlock != 0L && --aBlocksRest;
+         aBlock = aBlock->prevBlock)
+    {
+      if (aSize <= aBlock->FreeSize())
+        break;
+    }
+    if (aBlock == 0L || !aBlocksRest)
+      // There is no available block with enough free space, create a new one
+      aBlock = allocateNewBlock(myBlockSize);
+  }
+
+  void* anAddress = aBlock->Allocate(aSize);
+#ifdef DEB_FINDBLOCK
+  Key aKey;
+  Standard_ASSERT_VOID(aBlock == findBlock(anAddress, aKey),
+                       "improper work of NCollection_AccAllocator::findBlock");
+#endif
+  return anAddress;
+}
+
+//=======================================================================
+//function : Free
+//purpose  : Free a previously allocated memory
+//=======================================================================
+void NCollection_AccAllocator::Free(void* theAddress)
+{
+  Key aKey;
+  Block* aBlock = findBlock(theAddress, aKey);
+
+#if !defined No_Exception && !defined No_Standard_ProgramError
+  if (aBlock == 0L || aBlock->allocCount == 0)
+  {
+    Standard_ProgramError::Raise("NCollection_AccAllocator::Free: \
+                                 Trying to free an invalid address");
+  }
+#endif
+
+  aBlock->Free();
+  if (aBlock->allocCount == 0)
+  {
+    Standard_Address anAddress = aBlock->address;
+
+    // Deallocate and remove the free block if there are more blocks
+    if (myBlocks.Size() > 1)
+    {
+      Standard::Free(anAddress);
+      Block** appBlock;
+      for (appBlock = &mypLastBlock;
+          *appBlock != 0L;
+           appBlock = &(*appBlock)->prevBlock)
+      {
+        if (*appBlock == aBlock)
+        {
+          *appBlock = aBlock->prevBlock;
+          break;
+        }
+      }
+      myBlocks.UnBind(aKey);
+    }
+    // If there are no more blocks, reallocate the block to the default size
+    else
+    {
+      anAddress = Standard::Reallocate(anAddress, myBlockSize);
+      if (anAddress)
+      {
+        aBlock->address = anAddress;
+      }
+      aBlock->allocStart = (Standard_Byte*)anAddress
+                          + (Standard_Size)myBlockSize;
+    }
+  }
+}
+
+//=======================================================================
+//function : findBlock
+//purpose  : Find a block that the given allocation unit belongs to
+//=======================================================================
+NCollection_AccAllocator::Block*
+NCollection_AccAllocator::findBlock(const Standard_Address theAddress, Key& theKey)
+{
+  theKey = getKey(theAddress);
+
+  Block* aBlock = myBlocks.ChangeSeek(theKey);
+  if (aBlock && aBlock->address <= theAddress)
+  {
+    return aBlock;
+  }
+
+  theKey.Value--;
+  aBlock = myBlocks.ChangeSeek(theKey);
+  if (aBlock &&
+    (Standard_Byte*)aBlock->address + (Standard_Size)myBlockSize > theAddress)
+  {
+    return aBlock;
+  }
+
+  return 0L;
+}
+
+//=======================================================================
+//function : allocateNewBlock
+//purpose  : Allocate a new block and return a pointer to it
+//=======================================================================
+NCollection_AccAllocator::Block*
+NCollection_AccAllocator::allocateNewBlock(const Standard_Size theSize)
+{
+  Standard_Address anAddress = Standard::Allocate(theSize);
+  // we depend on the fact that Standard::Allocate always returns
+  // a pointer aligned to a 4 byte boundary
+  Block aBlock = {anAddress,
+                  AlignedPtr((Standard_Byte*)anAddress + theSize),
+                  mypLastBlock,
+                  0};
+  mypLastBlock = myBlocks.Bound(getKey(anAddress), aBlock);
+#ifdef DEB_FINDBLOCK
+  Key aKey;
+  Standard_ASSERT_VOID(mypLastBlock == findBlock((Standard_Byte*)aBlock.allocStart-1, aKey),
+                       "improper work of NCollection_AccAllocator::findBlock");
+#endif
+  return mypLastBlock;
+}
diff --git a/src/NCollection/NCollection_AccAllocator.hxx b/src/NCollection/NCollection_AccAllocator.hxx
new file mode 100644 (file)
index 0000000..7e8dbf3
--- /dev/null
@@ -0,0 +1,173 @@
+// Created on: 2013-11-12
+// Created by: Maxim YAKUNIN (myn)
+// Copyright (c) 2002-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+
+#ifndef NCollection_AccAllocator_HeaderFile
+#define NCollection_AccAllocator_HeaderFile
+
+#include <NCollection_BaseAllocator.hxx>
+#include <NCollection_DataMap.hxx>
+
+//!
+//! Class  NCollection_AccAllocator  -  accumulating  memory  allocator.  This
+//! class  allocates  memory on request returning the pointer to the allocated
+//! space.  The  allocation  units  are  grouped  in blocks requested from the
+//! system  as  required.  This  memory  is  returned  to  the system when all
+//! allocations in a block are freed.
+//! 
+//! By comparison with  the standard new() and malloc()  calls, this method is
+//! faster and consumes very small additional memory to maintain the heap.
+//! 
+//! By comparison with NCollection_IncAllocator,  this class requires some more
+//! additional memory  and a little more time for allocation and deallocation.
+//! Memory overhead for NCollection_IncAllocator is 12 bytes per block;
+//! average memory overhead for NCollection_AccAllocator is 28 bytes per block.
+//! 
+//! All pointers  returned by Allocate() are aligned to 4 byte boundaries.
+//! To  define  the size  of  memory  blocks  requested  from the OS,  use the
+//! parameter of the constructor (measured in bytes).
+
+class NCollection_AccAllocator : public NCollection_BaseAllocator
+{
+// --------- PUBLIC CONSTANTS ---------
+public:
+  //! Alignment of all allocated objects: 4 bytes
+  static const Standard_Size    Align            = 4;
+
+  //! Default block size
+  static const Standard_Size    DefaultBlockSize = 24600;
+
+  //! Number of last blocks to check for free space
+  static const Standard_Integer MaxLookupBlocks  = 16;
+
+// ---------- PUBLIC METHODS ----------
+public:
+  //! Constructor
+  Standard_EXPORT NCollection_AccAllocator(const size_t
+                                           theBlockSize = DefaultBlockSize);
+
+  //! Destructor
+  Standard_EXPORT ~NCollection_AccAllocator();
+
+  //! Allocate memory with given size
+  Standard_EXPORT virtual void* Allocate  (const size_t theSize);
+
+  //! Free a previously allocated memory;
+  //! memory is returned to the OS when all allocations in some block are freed
+  Standard_EXPORT virtual void  Free      (void* theAddress);
+
+// --------- PROTECTED TYPES ---------
+protected:
+  //! Size value aligned to a 4 byte boundary
+  class AlignedSize
+  {
+    Standard_Size myValue;
+  public:
+    AlignedSize(){}
+    AlignedSize(const Standard_Size theValue)
+      : myValue((theValue + Align - 1) & ~(Align - 1)) {}
+    operator       Standard_Size()       {return myValue;}
+    operator const Standard_Size() const {return myValue;}
+  };
+
+  //! A pointer aligned to a 4 byte boundary
+  class AlignedPtr
+  {
+    Standard_Byte* myValue;
+  public:
+    AlignedPtr(){}
+    AlignedPtr(const Standard_Address theValue)
+      : myValue((Standard_Byte*)((Standard_Size)theValue & ~(Align - 1))) {}
+    operator Standard_Address       ()       {return myValue;}
+    operator Standard_Address const () const {return myValue;}
+    operator Standard_Byte*         ()       {return myValue;}
+    operator Standard_Byte*   const () const {return myValue;}
+    AlignedPtr operator -(const AlignedSize theValue) const
+      {return myValue - theValue;}
+    AlignedPtr operator +(const AlignedSize theValue) const
+      {return myValue + theValue;}
+    AlignedPtr operator -=(const AlignedSize theValue)
+      {return myValue -= theValue;}
+    AlignedPtr operator +=(const AlignedSize theValue)
+      {return myValue += theValue;}
+  };
+
+  //! A key for the map of blocks
+  struct Key {Standard_Size Value;};
+  //! AccAllocator hasher
+  class Hasher
+  {
+  public:
+    static Standard_Integer HashCode(const Key theKey, const Standard_Integer theUpper)
+    { return theKey.Value % theUpper + 1; }
+
+    static Standard_Boolean IsEqual(const Key theOne, const Key theTwo)
+    { return theOne.Value == theTwo.Value; }
+  };
+  
+  //! Descriptor of a block
+  struct Block
+  {
+    Standard_Address address;
+    AlignedPtr       allocStart;
+    Block*           prevBlock;
+    Standard_Integer allocCount;
+
+    Standard_Size FreeSize() const
+      {return (Standard_Byte*)allocStart - (Standard_Byte*)address;}
+
+    AlignedPtr Allocate(const AlignedSize theSize)
+      {allocCount++; return allocStart -= theSize;}
+
+    void Free()
+      {allocCount--;}
+  };
+
+// --------- PROTECTED METHODS ---------
+protected:
+  //! Calculate a key for the data map basing on the given address
+  inline Key getKey(const Standard_Address theAddress) const
+  {
+    Key aKey = {(Standard_Size)theAddress / myBlockSize};
+    return aKey;
+  }
+
+  //! Find a block that the given allocation unit belongs to
+  Standard_EXPORT Block* findBlock(const Standard_Address theAddress, Key& theKey);
+
+  //! Allocate a new block and return a pointer to it
+  Standard_EXPORT Block* allocateNewBlock(const Standard_Size theSize);
+
+// --------- PROHIBITED METHODS ---------
+private:
+  NCollection_AccAllocator (const NCollection_AccAllocator&);
+  NCollection_AccAllocator& operator = (const NCollection_AccAllocator&);
+
+// --------- PROTECTED DATA ---------
+protected:
+  AlignedSize myBlockSize;
+  Block*      mypLastBlock;
+  NCollection_DataMap<Key, Block, Hasher> myBlocks;
+
+// Declaration of CASCADE RTTI
+public:
+  DEFINE_STANDARD_RTTI (NCollection_AccAllocator)
+};
+
+// Definition of HANDLE object using Standard_DefineHandle.hxx
+DEFINE_STANDARD_HANDLE (NCollection_AccAllocator, NCollection_BaseAllocator)
+
+
+#endif
index 7ec0158..d1c698b 100644 (file)
@@ -114,6 +114,11 @@ public:
   Standard_Boolean IsEmpty (void) const
   { return (myFirst == NULL); }
 
+  // ******** Allocator
+  //! Returns attached allocator
+  const Handle(NCollection_BaseAllocator)& Allocator() const 
+  { return myAllocator; }
+
  protected:
   // --------- PROTECTED METHODS ----------
 
index f9040b3..a8cb2d6 100644 (file)
@@ -204,7 +204,9 @@ class NCollection_DataMap : public NCollection_BaseMap
     }
   }
 
-  //! Bind
+  //! Bind binds Item to Key in map. Returns Standard_True if Key was not
+  //! exist in the map. If the Key was already bound, the Item will be rebinded
+  //! and Standard_False will be returned.
   Standard_Boolean Bind (const TheKeyType& theKey, const TheItemType& theItem)
   {
     if (Resizable()) 
@@ -226,23 +228,36 @@ class NCollection_DataMap : public NCollection_BaseMap
     return Standard_True;
   }
 
-  //! IsBound
-  Standard_Boolean IsBound(const TheKeyType& K) const
+  //! Bound binds Item to Key in map. Returns modifiable Item 
+  TheItemType* Bound (const TheKeyType& theKey, const TheItemType& theItem)
   {
-    if (IsEmpty()) 
-      return Standard_False;
-    DataMapNode** data = (DataMapNode**) myData1;
-    DataMapNode* p = data[Hasher::HashCode(K,NbBuckets())];
-    while (p) 
+    if (Resizable()) 
+      ReSize(Extent());
+    DataMapNode** data = (DataMapNode**)myData1;
+    Standard_Integer k = Hasher::HashCode (theKey, NbBuckets());
+    DataMapNode* p = data[k];
+    while (p)
     {
-      if (Hasher::IsEqual(p->Key(),K)) 
-        return Standard_True;
-      p = (DataMapNode *) p->Next();
+      if (Hasher::IsEqual(p->Key(), theKey))
+      {
+        p->ChangeValue() = theItem;
+        return &p->ChangeValue();
+      }
+      p = (DataMapNode*)p->Next();
     }
-    return Standard_False;
+    data[k] = new (this->myAllocator) DataMapNode (theKey, theItem, data[k]);
+    Increment();
+    return &data[k]->ChangeValue();
   }
 
-  //! UnBind
+  //! IsBound
+  Standard_Boolean IsBound(const TheKeyType& K) const
+  {
+    DataMapNode* p;
+    return lookup(K, p);
+  }
+
+  //! UnBind removes Item Key pair from map
   Standard_Boolean UnBind(const TheKeyType& K)
   {
     if (IsEmpty()) 
@@ -270,61 +285,59 @@ class NCollection_DataMap : public NCollection_BaseMap
     return Standard_False;
   }
 
-  //! Find
+  //! Seek returns pointer to Item by Key. Returns
+  //! NULL is Key was not bound.
+  const TheItemType* Seek(const TheKeyType& theKey) const
+  {
+    DataMapNode* p = 0;
+    if (!lookup(theKey, p))
+      return 0L;
+    return &p->Value();
+  }
+
+  //! Find returns the Item for Key. Raises if Key was not bound
   const TheItemType& Find(const TheKeyType& theKey) const
   {
-    Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_DataMap::Find");
-    DataMapNode* p = (DataMapNode*) myData1[Hasher::HashCode(theKey,NbBuckets())];
-    while (p) 
-    {
-      if (Hasher::IsEqual(p->Key(),theKey)) 
-        return p->Value();
-      p = (DataMapNode*) p->Next();
-    }
-    Standard_NoSuchObject::Raise("NCollection_DataMap::Find");
-    return p->Value(); // This for compiler
+    DataMapNode* p = 0;
+    if (!lookup(theKey, p))
+      Standard_NoSuchObject::Raise("NCollection_DataMap::Find");
+    return p->Value();
   }
 
-  //! Find value for key with copying.
+  //! Find Item for key with copying.
   //! @return true if key was found
   Standard_Boolean Find (const TheKeyType& theKey,
                          TheItemType&      theValue) const
   {
-    if (IsEmpty())
-    {
+    DataMapNode* p = 0;
+    if (!lookup(theKey, p))
       return Standard_False;
-    }
 
-    for (DataMapNode* aNodeIter = (DataMapNode* )myData1[Hasher::HashCode (theKey, NbBuckets())];
-         aNodeIter != NULL;
-         aNodeIter = (DataMapNode* )aNodeIter->Next())
-    {
-      if (Hasher::IsEqual (aNodeIter->Key(), theKey))
-      {
-        theValue = aNodeIter->Value();
-        return Standard_True;
-      }
-    }
-    return Standard_False;
+    theValue = p->Value();
+    return Standard_True;
   }
 
   //! operator ()
   const TheItemType& operator() (const TheKeyType& theKey) const
   { return Find(theKey); }
 
-  //! ChangeFind
+  //! ChangeSeek returns modifiable pointer to Item by Key. Returns
+  //! NULL is Key was not bound.
+  TheItemType* ChangeSeek(const TheKeyType& theKey)
+  {
+    DataMapNode* p = 0;
+    if (!lookup(theKey, p))
+      return 0L;
+    return &p->ChangeValue();
+  }
+
+  //! ChangeFind returns mofifiable Item by Key. Raises if Key was not bound
   TheItemType& ChangeFind (const TheKeyType& theKey)
   {
-    Standard_NoSuchObject_Raise_if (IsEmpty(), "NCollection_DataMap::Find");
-    DataMapNode*  p = (DataMapNode*) myData1[Hasher::HashCode(theKey,NbBuckets())];
-    while (p) 
-    {
-      if (Hasher::IsEqual(p->Key(),theKey)) 
-        return p->ChangeValue();
-      p = (DataMapNode*) p->Next();
-    }
-    Standard_NoSuchObject::Raise("NCollection_DataMap::Find");
-    return p->ChangeValue(); // This for compiler
+    DataMapNode* p = 0;
+    if (!lookup(theKey, p))
+      Standard_NoSuchObject::Raise("NCollection_DataMap::Find");
+    return p->ChangeValue();
   }
 
   //! operator ()
@@ -351,6 +364,26 @@ class NCollection_DataMap : public NCollection_BaseMap
   //! Size
   Standard_Integer Size(void) const
   { return Extent(); }
+
+  
+ protected:
+  // ---------- PROTECTED METHODS ----------
+  //! Lookup for particular key in map. Returns true if key is found and
+  //! thepNode points to binded node. Returns false if key is not found,
+  //! thehNode value is this case is not usable.
+  Standard_Boolean lookup(const TheKeyType& theKey,DataMapNode*& thepNode) const
+  {
+    if (IsEmpty())
+      return Standard_False; // Not found
+    for (thepNode = (DataMapNode*)myData1[Hasher::HashCode(theKey, NbBuckets())];
+         thepNode; thepNode = (DataMapNode*)thepNode->Next())
+    {
+      if (Hasher::IsEqual(thepNode->Key(), theKey)) 
+        return Standard_True;
+    }
+    return Standard_False; // Not found
+  }
+
 };
 
 #endif
diff --git a/src/NCollection/NCollection_WinHeapAllocator.cxx b/src/NCollection/NCollection_WinHeapAllocator.cxx
new file mode 100644 (file)
index 0000000..dde35c3
--- /dev/null
@@ -0,0 +1,87 @@
+// File:      NCollection_WinHeapAllocator.cxx
+// Created:   22.07.11
+// Author:    Kirill GAVRILOV
+// Copyright: Open Cascade 2011
+
+#include <NCollection_WinHeapAllocator.hxx>
+#include <Standard_OutOfMemory.hxx>
+
+#if(defined(_WIN32) || defined(__WIN32__))
+  #include <windows.h>
+#endif
+
+IMPLEMENT_STANDARD_HANDLE (NCollection_WinHeapAllocator,
+                           NCollection_BaseAllocator)
+IMPLEMENT_STANDARD_RTTIEXT(NCollection_WinHeapAllocator,
+                           NCollection_BaseAllocator)
+
+//=======================================================================
+//function : NCollection_WinHeapAllocator
+//purpose  : Main constructor
+//=======================================================================
+NCollection_WinHeapAllocator::NCollection_WinHeapAllocator
+                                        (const size_t theInitSizeBytes)
+: NCollection_BaseAllocator(),
+#if(defined(_WIN32) || defined(__WIN32__))
+  myHeapH (HeapCreate (0, theInitSizeBytes, 0)),
+#endif
+  myToZeroMemory (Standard_False)
+{
+#if(defined(_WIN32) || defined(__WIN32__))
+  // activate LHF to improve small size allocations
+  ULONG aHeapInfo = 2;
+  HeapSetInformation (myHeapH, HeapCompatibilityInformation,
+                      &aHeapInfo, sizeof(aHeapInfo));
+#endif
+}
+
+//=======================================================================
+//function : ~NCollection_WinHeapAllocator
+//purpose  : Destructor
+//=======================================================================
+NCollection_WinHeapAllocator::~NCollection_WinHeapAllocator()
+{
+#if(defined(_WIN32) || defined(__WIN32__))
+  HeapDestroy (myHeapH);
+#endif
+}
+
+
+//=======================================================================
+//function : Allocate
+//purpose  :
+//=======================================================================
+void* NCollection_WinHeapAllocator::Allocate (const Standard_Size theSize)
+{
+  // the size is rounded up to word size.
+  const Standard_Size aRoundSize = (theSize + 3) & ~0x3;
+#if(defined(_WIN32) || defined(__WIN32__))
+  void* aResult = HeapAlloc (myHeapH, myToZeroMemory ? HEAP_ZERO_MEMORY : 0,
+                             aRoundSize);
+#else
+  void* aResult = malloc (aRoundSize);
+#endif
+  if (aResult == NULL)
+  {
+    char aBuf[128];
+    Sprintf (aBuf, "Failed to allocate "PRIuPTR" bytes in local dynamic heap", theSize);
+    Standard_OutOfMemory::Raise (aBuf);
+  }
+  return aResult;
+}
+
+//=======================================================================
+//function : Free
+//purpose  :
+//=======================================================================
+void NCollection_WinHeapAllocator::Free (void* theAddress)
+{
+  if (theAddress != NULL)
+  {
+  #if(defined(_WIN32) || defined(__WIN32__))
+    HeapFree (myHeapH, 0, theAddress);
+  #else
+    free (theAddress);
+  #endif
+  }
+}
diff --git a/src/NCollection/NCollection_WinHeapAllocator.hxx b/src/NCollection/NCollection_WinHeapAllocator.hxx
new file mode 100644 (file)
index 0000000..698a7d9
--- /dev/null
@@ -0,0 +1,58 @@
+// File:      NCollection_WinHeapAllocator.hxx
+// Created:   22.07.11
+// Author:    Kirill GAVRILOV
+// Copyright: Open Cascade 2011
+
+#ifndef NCollection_WinHeapAllocator_HeaderFile
+#define NCollection_WinHeapAllocator_HeaderFile
+
+#include <NCollection_BaseAllocator.hxx>
+
+//! This memory allocator creates dedicated heap for allocations.
+//! This technics available only on Windows platform
+//! (no alternative on Unix systems).
+//! It may be used to take control over memory fragmentation
+//! because on destruction ALL allocated memory will be released
+//! to the system.
+//!
+//! This allocator can also be created per each working thread
+//! hovewer it real multi-threading performance is dubious.
+//!
+//! Notice that this also means that existing pointers will be broken
+//! and you shoould control that allocator is alive along all objects
+//! allocated with him.
+class NCollection_WinHeapAllocator : public NCollection_BaseAllocator
+{
+public:
+
+  //! Main constructor
+  Standard_EXPORT NCollection_WinHeapAllocator (const size_t theInitSizeBytes = 0x80000);
+
+  //! Destructor
+  Standard_EXPORT virtual ~NCollection_WinHeapAllocator();
+
+  //! Allocate memory
+  Standard_EXPORT virtual void* Allocate (const Standard_Size theSize);
+
+  //! Release memory
+  Standard_EXPORT virtual void  Free (void* theAddress);
+
+  // Declaration of CASCADE RTTI
+  DEFINE_STANDARD_RTTI(NCollection_WinHeapAllocator)
+
+private:
+  //! Copy constructor - prohibited
+  NCollection_WinHeapAllocator (const NCollection_WinHeapAllocator& );
+
+private:
+#if(defined(_WIN32) || defined(__WIN32__))
+  void* myHeapH;
+#endif
+  Standard_Boolean myToZeroMemory;
+
+};
+
+// Definition of HANDLE object using Standard_DefineHandle.hxx
+DEFINE_STANDARD_HANDLE (NCollection_WinHeapAllocator, NCollection_BaseAllocator)
+
+#endif //NCollection_WinHeapAllocator_HeaderFile