FBX SDK Reference Guide: kcontainerallocators.h Source File
00001 #ifndef FBXFILESDK_COMPONENTS_KBASELIB_KLIB_KCONTAINERALLOCATORS_H
00002 #define FBXFILESDK_COMPONENTS_KBASELIB_KLIB_KCONTAINERALLOCATORS_H
00003 
00004 /**************************************************************************************
00005 
00006  Copyright © 2001 - 2008 Autodesk, Inc. and/or its licensors.
00007  All Rights Reserved.
00008 
00009  The coded instructions, statements, computer programs, and/or related material 
00010  (collectively the "Data") in these files contain unpublished information 
00011  proprietary to Autodesk, Inc. and/or its licensors, which is protected by 
00012  Canada and United States of America federal copyright law and by international 
00013  treaties. 
00014  
00015  The Data may not be disclosed or distributed to third parties, in whole or in
00016  part, without the prior written consent of Autodesk, Inc. ("Autodesk").
00017 
00018  THE DATA IS PROVIDED "AS IS" AND WITHOUT WARRANTY.
00019  ALL WARRANTIES ARE EXPRESSLY EXCLUDED AND DISCLAIMED. AUTODESK MAKES NO
00020  WARRANTY OF ANY KIND WITH RESPECT TO THE DATA, EXPRESS, IMPLIED OR ARISING
00021  BY CUSTOM OR TRADE USAGE, AND DISCLAIMS ANY IMPLIED WARRANTIES OF TITLE, 
00022  NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE OR USE. 
00023  WITHOUT LIMITING THE FOREGOING, AUTODESK DOES NOT WARRANT THAT THE OPERATION
00024  OF THE DATA WILL BE UNINTERRUPTED OR ERROR FREE. 
00025  
00026  IN NO EVENT SHALL AUTODESK, ITS AFFILIATES, PARENT COMPANIES, LICENSORS
00027  OR SUPPLIERS ("AUTODESK GROUP") BE LIABLE FOR ANY LOSSES, DAMAGES OR EXPENSES
00028  OF ANY KIND (INCLUDING WITHOUT LIMITATION PUNITIVE OR MULTIPLE DAMAGES OR OTHER
00029  SPECIAL, DIRECT, INDIRECT, EXEMPLARY, INCIDENTAL, LOSS OF PROFITS, REVENUE
00030  OR DATA, COST OF COVER OR CONSEQUENTIAL LOSSES OR DAMAGES OF ANY KIND),
00031  HOWEVER CAUSED, AND REGARDLESS OF THE THEORY OF LIABILITY, WHETHER DERIVED
00032  FROM CONTRACT, TORT (INCLUDING, BUT NOT LIMITED TO, NEGLIGENCE), OR OTHERWISE,
00033  ARISING OUT OF OR RELATING TO THE DATA OR ITS USE OR ANY OTHER PERFORMANCE,
00034  WHETHER OR NOT AUTODESK HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS
00035  OR DAMAGE. 
00036 
00037 **************************************************************************************/
00038 
00039 #include <fbxfilesdk/components/kbaselib/kbaselib_h.h>
00040 
00041 #include <fbxfilesdk/components/kbaselib/klib/kdebug.h>
00042 
00043 #include <stdlib.h>
00044 
00045 #include <fbxfilesdk/fbxfilesdk_nsbegin.h>
00046 
00047 /*
00048 
00049 An allocator class for use as a template parameter to one of the
00050 container class (KMap, KSet2, KDynamicArray...) must implement these
00051 methods:
00052 
00053     Constructor(size_t pRecordSize)
00054         The class constructor. The parameter pRecordSize is the
00055         size of one record held by the container. This is not
00056         necessarily the same size as of the value type, since the
00057         container may wrap the value into a private class.
00058 
00059     void* AllocateRecords(size_t pRecordCount)
00060         Returns a pointer to a uninitialized continuous block of memory
00061         able to hold pRecordCount * pRecordSize  bytes. pRecordSize was
00062         defined in the Constructor description, above.
00063 
00064     void FreeMemory(void* pRecord)
00065         Frees a block of memory returned by AllocateRecords.
00066 
00067     void Reserve(size_t pRecordCount)
00068         This tells the allocator that we are about to call AllocateRecords
00069         one or many times to allocate pRecordCount records.
00070         This gives the allocator a chance to do whatever it deems necessary
00071         to optimize subsequent allocations, for example, by preallocating a
00072         sufficiently large pool of memory.
00073 
00074     size_t GetRecordSize() const
00075         Returns the size of each record allocated.
00076 
00077     operator=()
00078         The allocator must have appropriate copy semantics; does not need to
00079         copy its allocated blocks, but it should adjust its record size.
00080 */
00081 
00082 
00083 class KFBX_DLL KBaseAllocator
00084 {
00085 public:
00086     KBaseAllocator(size_t const pRecordSize)
00087         : mRecordSize(pRecordSize)
00088     {
00089     }
00090 
00091     void Reserve(size_t const pRecordCount)
00092     {
00093     }
00094 
00095     void* AllocateRecords(size_t const pRecordCount = 1)
00096     {
00097         return malloc(pRecordCount * mRecordSize);
00098     }
00099 
00100     void FreeMemory(void* pRecord)
00101     {
00102         free(pRecord);
00103     }
00104 
00105     size_t GetRecordSize() const
00106     {
00107         return mRecordSize;
00108     }
00109 
00110     // Use default copy / assignment
00111 
00112 private:
00113     size_t mRecordSize;
00114 };
00115 
00116 /*
00117 This allocator only frees the allocated memory when it is deleted.
00118 This is a good allocator for building dictionaries, where we only
00119 add things to a container, but never remove them.
00120 */
00121 class KHungryAllocator
00122 {
00123 public:
00124     KHungryAllocator(size_t pRecordSize)
00125         : mRecordSize(pRecordSize)
00126         , mData(NULL)
00127         , mRecordPoolSize(0)
00128     {
00129     }
00130 
00131     KHungryAllocator(const KHungryAllocator& pOther)
00132         : mRecordSize(pOther.mRecordSize)
00133         , mData(0)
00134         , mRecordPoolSize(pOther.mRecordPoolSize)
00135     {
00136     }
00137 
00138     ~KHungryAllocator()
00139     {
00140         MemoryBlock* lCurrent = mData;
00141         MemoryBlock* lNext = lCurrent ? lCurrent->mNextBlock : 0;
00142         while (lCurrent)
00143         {
00144             delete lCurrent;
00145             lCurrent = lNext;
00146             lNext = lCurrent ? lCurrent->mNextBlock : 0;
00147         }
00148     }
00149 
00150     void Reserve(size_t const pRecordCount)
00151     {
00152         MemoryBlock* lMem = new MemoryBlock(pRecordCount * mRecordSize);
00153         lMem->mNextBlock = mData;
00154         mData = lMem;
00155         mRecordPoolSize += pRecordCount;
00156     }
00157 
00158     void* AllocateRecords(size_t const pRecordCount = 1)
00159     {
00160         MemoryBlock* lBlock = mData;
00161         void* lRecord = NULL;
00162 
00163         while ((lBlock != NULL) &&
00164             ((lRecord = lBlock->GetChunk(pRecordCount * mRecordSize)) == NULL))
00165         {
00166             lBlock = lBlock->mNextBlock;
00167         }
00168 
00169         if (lRecord == NULL)
00170         {
00171             size_t lNumRecordToAllocate = mRecordPoolSize / 8 == 0 ? 2 : mRecordPoolSize / 8;
00172             if (lNumRecordToAllocate < pRecordCount)
00173             {
00174                 lNumRecordToAllocate = pRecordCount;
00175             }
00176             Reserve(lNumRecordToAllocate);
00177             lRecord = AllocateRecords(pRecordCount);
00178         }
00179 
00180         return lRecord;
00181     }
00182 
00183     void FreeMemory(void* pRecord)
00184     {
00185     }
00186 
00187     size_t GetRecordSize() const
00188     {
00189         return mRecordSize;
00190     }
00191 
00192     KHungryAllocator& operator=(const KHungryAllocator& pOther)
00193     {
00194         if( this != &pOther )
00195         {
00196             // The next call to AllocateRecords() may skip over currently reserved
00197             // records if the size changes drastically, but otherwise GetChunk()
00198             // is size-oblivious.
00199             if( mRecordSize < pOther.mRecordSize )
00200             {
00201                 mRecordPoolSize = 0;
00202             }
00203 
00204             mRecordSize = pOther.mRecordSize;
00205         }
00206 
00207         return(*this);
00208     }
00209 
00210 private:
00211     class MemoryBlock
00212     {
00213     public:
00214         MemoryBlock(size_t pSize)
00215             : mNextBlock(NULL)
00216             , mData(NULL)
00217             , mFreeData(NULL)
00218             , mEnd(NULL)
00219         {
00220             mData = malloc(pSize);
00221             mFreeData = mData;
00222             mEnd = reinterpret_cast<char*>(mData) + pSize;
00223         };
00224 
00225         ~MemoryBlock()
00226         {
00227             free(mData);
00228         }
00229 
00230         void* GetChunk(size_t const pSize)
00231         {
00232             if (reinterpret_cast<char*>(mFreeData) + pSize < mEnd)
00233             {
00234                 void* lChunk = mFreeData;
00235                 mFreeData = reinterpret_cast<char*>(mFreeData) + pSize;
00236                 return lChunk;
00237             }
00238 
00239             return NULL;
00240         }
00241 
00242         MemoryBlock* mNextBlock;
00243         void* mData;
00244         void* mFreeData;
00245         void* mEnd;
00246     };
00247 
00248     size_t mRecordSize;
00249     MemoryBlock* mData;
00250     size_t mRecordPoolSize;
00251 };
00252 
00253 
00254 
00255 #include <fbxfilesdk/fbxfilesdk_nsend.h>
00256 
00257 #endif // FBXFILESDK_COMPONENTS_KBASELIB_KLIB_KCONTAINERALLOCATORS_H
00258