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