OgreRadixSort.h

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright (c) 2000-2012 Torus Knot Software Ltd
00008 
00009 Permission is hereby granted, free of charge, to any person obtaining a copy
00010 of this software and associated documentation files (the "Software"), to deal
00011 in the Software without restriction, including without limitation the rights
00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00013 copies of the Software, and to permit persons to whom the Software is
00014 furnished to do so, subject to the following conditions:
00015 
00016 The above copyright notice and this permission notice shall be included in
00017 all copies or substantial portions of the Software.
00018 
00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00025 THE SOFTWARE.
00026 -----------------------------------------------------------------------------
00027 */
00028 #ifndef __RadixSort_H__
00029 #define __RadixSort_H__
00030 
00031 #include "OgrePrerequisites.h"
00032 
00033 namespace Ogre {
00034 
00087     template <class TContainer, class TContainerValueType, typename TCompValueType>
00088     class RadixSort
00089     {
00090     public:
00091         typedef typename TContainer::iterator ContainerIter;
00092     protected:
00095         int mCounters[4][256];
00097         int mOffsets[256];
00099         int mSortSize;
00101         int mNumPasses;
00102 
00103         struct SortEntry
00104         {
00105             TCompValueType key;
00106             ContainerIter iter;
00107             SortEntry() {}
00108             SortEntry(TCompValueType k, ContainerIter it)
00109                 : key(k), iter(it) {}
00110 
00111         };
00113         typedef std::vector<SortEntry, STLAllocator<SortEntry, GeneralAllocPolicy> > SortVector; 
00114         SortVector mSortArea1;
00115         SortVector mSortArea2;
00116         SortVector* mSrc;
00117         SortVector* mDest;
00118         TContainer mTmpContainer; // initial copy
00119 
00120 
00121         void sortPass(int byteIndex)
00122         {
00123             // Calculate offsets
00124             // Basically this just leaves gaps for duplicate entries to fill
00125             mOffsets[0] = 0;
00126             for (int i = 1; i < 256; ++i)
00127             {
00128                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
00129             }
00130 
00131             // Sort pass
00132             for (int i = 0; i < mSortSize; ++i)
00133             {
00134                 unsigned char byteVal = getByte(byteIndex, (*mSrc)[i].key);
00135                 (*mDest)[mOffsets[byteVal]++] = (*mSrc)[i];
00136             }
00137 
00138         }
00139         template <typename T>
00140         void finalPass(int byteIndex, T val)
00141         {
00142             // default is to do normal pass
00143             sortPass(byteIndex);
00144         }
00145         
00146         // special case signed int
00147         void finalPass(int byteIndex, int val)
00148         {
00149             int numNeg = 0;
00150             // all negative values are in entries 128+ in most significant byte
00151             for (int i = 128; i < 256; ++i)
00152             {
00153                 numNeg += mCounters[byteIndex][i];
00154             }
00155             // Calculate offsets - positive ones start at the number of negatives
00156             // do positive numbers
00157             mOffsets[0] = numNeg;
00158             for (int i = 1; i < 128; ++i)
00159             {
00160                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
00161             }
00162             // Do negative numbers (must start at zero)
00163             // No need to invert ordering, already correct (-1 is highest number)
00164             mOffsets[128] = 0;
00165             for (int i = 129; i < 256; ++i)
00166             {
00167                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
00168             }
00169 
00170             // Sort pass
00171             for (int i = 0; i < mSortSize; ++i)
00172             {
00173                 unsigned char byteVal = getByte(byteIndex, (*mSrc)[i].key);
00174                 (*mDest)[mOffsets[byteVal]++] = (*mSrc)[i];
00175             }
00176         }
00177         
00178 
00179         // special case float
00180         void finalPass(int byteIndex, float val)
00181         {
00182             // floats need to be special cased since negative numbers will come
00183             // after positives (high bit = sign) and will be in reverse order
00184             // (no ones-complement of the +ve value)
00185             int numNeg = 0;
00186             // all negative values are in entries 128+ in most significant byte
00187             for (int i = 128; i < 256; ++i)
00188             {
00189                 numNeg += mCounters[byteIndex][i];
00190             }
00191             // Calculate offsets - positive ones start at the number of negatives
00192             // do positive numbers normally
00193             mOffsets[0] = numNeg;
00194             for (int i = 1; i < 128; ++i)
00195             {
00196                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
00197             }
00198             // Do negative numbers (must start at zero)
00199             // Also need to invert ordering
00200             // In order to preserve the stability of the sort (essential since
00201             // we rely on previous bytes already being sorted) we have to count
00202             // backwards in our offsets from 
00203             mOffsets[255] = mCounters[byteIndex][255];
00204             for (int i = 254; i > 127; --i)
00205             {
00206                 mOffsets[i] = mOffsets[i+1] + mCounters[byteIndex][i];
00207             }
00208 
00209             // Sort pass
00210             for (int i = 0; i < mSortSize; ++i)
00211             {
00212                 unsigned char byteVal = getByte(byteIndex, (*mSrc)[i].key);
00213                 if (byteVal > 127)
00214                 {
00215                     // -ve; pre-decrement since offsets set to count
00216                     (*mDest)[--mOffsets[byteVal]] = (*mSrc)[i];
00217                 }
00218                 else
00219                 {
00220                     // +ve
00221                     (*mDest)[mOffsets[byteVal]++] = (*mSrc)[i];
00222                 }
00223             }
00224         }
00225 
00226         inline unsigned char getByte(int byteIndex, TCompValueType val)
00227         {
00228 #if OGRE_ENDIAN == OGRE_ENDIAN_LITTLE
00229             return ((unsigned char*)(&val))[byteIndex];
00230 #else
00231             return ((unsigned char*)(&val))[mNumPasses - byteIndex - 1];
00232 #endif
00233         }
00234 
00235     public:
00236 
00237         RadixSort() {}
00238         ~RadixSort() {}
00239 
00245         template <class TFunction>
00246         void sort(TContainer& container, TFunction func)
00247         {
00248             if (container.empty())
00249                 return;
00250 
00251             // Set up the sort areas
00252             mSortSize = static_cast<int>(container.size());
00253             mSortArea1.resize(container.size());
00254             mSortArea2.resize(container.size());
00255 
00256             // Copy data now (we need constant iterators for sorting)
00257             mTmpContainer = container;
00258 
00259             mNumPasses = sizeof(TCompValueType);
00260 
00261             // Counter pass
00262             // Initialise the counts
00263             int p;
00264             for (p = 0; p < mNumPasses; ++p)
00265                 memset(mCounters[p], 0, sizeof(int) * 256);
00266 
00267             // Perform alpha pass to count
00268             ContainerIter i = mTmpContainer.begin();
00269             TCompValueType prevValue = func.operator()(*i); 
00270             bool needsSorting = false;
00271             for (int u = 0; i != mTmpContainer.end(); ++i, ++u)
00272             {
00273                 // get sort value
00274                 TCompValueType val = func.operator()(*i);
00275                 // cheap check to see if needs sorting (temporal coherence)
00276                 if (!needsSorting && val < prevValue)
00277                     needsSorting = true;
00278 
00279                 // Create a sort entry
00280                 mSortArea1[u].key = val;
00281                 mSortArea1[u].iter = i;
00282 
00283                 // increase counters
00284                 for (p = 0; p < mNumPasses; ++p)
00285                 {
00286                     unsigned char byteVal = getByte(p, val);
00287                     mCounters[p][byteVal]++;
00288                 }
00289 
00290                 prevValue = val;
00291 
00292             }
00293 
00294             // early exit if already sorted
00295             if (!needsSorting)
00296                 return;
00297 
00298 
00299             // Sort passes
00300             mSrc = &mSortArea1;
00301             mDest = &mSortArea2;
00302 
00303             for (p = 0; p < mNumPasses - 1; ++p)
00304             {
00305                 sortPass(p);
00306                 // flip src/dst
00307                 SortVector* tmp = mSrc;
00308                 mSrc = mDest;
00309                 mDest = tmp;
00310             }
00311             // Final pass may differ, make polymorphic
00312             finalPass(p, prevValue);
00313 
00314             // Copy everything back
00315             int c = 0;
00316             for (i = container.begin(); 
00317                 i != container.end(); ++i, ++c)
00318             {
00319                 *i = *((*mDest)[c].iter);
00320             }
00321         }
00322 
00323     };
00324 
00328 }
00329 #endif
00330 

Copyright © 2012 Torus Knot Software Ltd
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Fri May 25 23:36:25 2012