# 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-2009 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 © 2008 Torus Knot Software Ltd
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Wed Nov 3 2010 19:24:52