NCollection_TypeDef.hxx
+NCollection_AccAllocator.hxx
+NCollection_AccAllocator.cxx
NCollection_BaseAllocator.hxx
NCollection_BaseAllocator.cxx
NCollection_IncAllocator.hxx
NCollection_HeapAllocator.hxx
NCollection_HeapAllocator.cxx
NCollection_StdAllocator.hxx
+NCollection_WinHeapAllocator.hxx
+NCollection_WinHeapAllocator.cxx
NCollection_ListNode.hxx
NCollection_BaseList.hxx
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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
Standard_Boolean IsEmpty (void) const
{ return (myFirst == NULL); }
+ // ******** Allocator
+ //! Returns attached allocator
+ const Handle(NCollection_BaseAllocator)& Allocator() const
+ { return myAllocator; }
+
protected:
// --------- PROTECTED METHODS ----------
}
}
- //! 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())
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())
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 ()
//! 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
--- /dev/null
+// 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
+ }
+}
--- /dev/null
+// 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