# 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-2005 The OGRE Team
    00008 Also see acknowledgements in Readme.html
    00009
    00010 This program is free software; you can redistribute it and/or modify it under
    00011 the terms of the GNU Lesser General Public License as published by the Free Software
    00012 Foundation; either version 2 of the License, or (at your option) any later
    00013 version.
    00014
    00015 This program is distributed in the hope that it will be useful, but WITHOUT
    00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
    00018
    00019 You should have received a copy of the GNU Lesser General Public License along with
    00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
    00022 http://www.gnu.org/copyleft/lesser.txt.
    00023 -----------------------------------------------------------------------------
    00024 */
    00025 #ifndef __RadixSort_H__
    00026 #define __RadixSort_H__
    00027
    00028 #include "OgrePrerequisites.h"
    00029
    00030 namespace Ogre {
    00031
    00078     template <class TContainer, class TContainerValueType, typename TCompValueType>
    00079     class RadixSort
    00080     {
    00081     public:
    00082         typedef typename TContainer::iterator ContainerIter;
    00083     protected:
    00086         int mCounters[4][256];
    00088         int mOffsets[256];
    00090         int mSortSize;
    00092         int mNumPasses;
    00093
    00094         struct SortEntry
    00095         {
    00096             TCompValueType key;
    00097             ContainerIter iter;
    00098             SortEntry() {}
    00099             SortEntry(TCompValueType k, ContainerIter it)
    00100                 : key(k), iter(it) {}
    00101
    00102         };
    00104         std::vector<SortEntry> mSortArea1;
    00105         std::vector<SortEntry> mSortArea2;
    00106         std::vector<SortEntry>* mSrc;
    00107         std::vector<SortEntry>* mDest;
    00108         TContainer mTmpContainer; // initial copy
    00109
    00110
    00111         void sortPass(int byteIndex)
    00112         {
    00113             // Calculate offsets
    00114             // Basically this just leaves gaps for duplicate entries to fill
    00115             mOffsets[0] = 0;
    00116             for (int i = 1; i < 256; ++i)
    00117             {
    00118                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
    00119             }
    00120
    00121             // Sort pass
    00122             for (int i = 0; i < mSortSize; ++i)
    00123             {
    00124                 unsigned char byteVal = getByte(byteIndex, (*mSrc)[i].key);
    00125                 (*mDest)[mOffsets[byteVal]++] = (*mSrc)[i];
    00126             }
    00127
    00128         }
    00129         template <typename T>
    00130         void finalPass(int byteIndex, T val)
    00131         {
    00132             // default is to do normal pass
    00133             sortPass(byteIndex);
    00134         }
    00135
    00136         // special case signed int
    00137         void finalPass(int byteIndex, int val)
    00138         {
    00139             int numNeg = 0;
    00140             // all negative values are in entries 128+ in most significant byte
    00141             for (int i = 128; i < 256; ++i)
    00142             {
    00143                 numNeg += mCounters[byteIndex][i];
    00144             }
    00145             // Calculate offsets - positive ones start at the number of negatives
    00146             // do positive numbers
    00147             mOffsets[0] = numNeg;
    00148             for (int i = 1; i < 128; ++i)
    00149             {
    00150                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
    00151             }
    00152             // Do negative numbers (must start at zero)
    00153             // No need to invert ordering, already correct (-1 is highest number)
    00154             mOffsets[128] = 0;
    00155             for (int i = 129; i < 256; ++i)
    00156             {
    00157                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
    00158             }
    00159
    00160             // Sort pass
    00161             for (int i = 0; i < mSortSize; ++i)
    00162             {
    00163                 unsigned char byteVal = getByte(byteIndex, (*mSrc)[i].key);
    00164                 (*mDest)[mOffsets[byteVal]++] = (*mSrc)[i];
    00165             }
    00166         }
    00167
    00168
    00169         // special case float
    00170         void finalPass(int byteIndex, float val)
    00171         {
    00172             // floats need to be special cased since negative numbers will come
    00173             // after positives (high bit = sign) and will be in reverse order
    00174             // (no ones-complement of the +ve value)
    00175             int numNeg = 0;
    00176             // all negative values are in entries 128+ in most significant byte
    00177             for (int i = 128; i < 256; ++i)
    00178             {
    00179                 numNeg += mCounters[byteIndex][i];
    00180             }
    00181             // Calculate offsets - positive ones start at the number of negatives
    00182             // do positive numbers normally
    00183             mOffsets[0] = numNeg;
    00184             for (int i = 1; i < 128; ++i)
    00185             {
    00186                 mOffsets[i] = mOffsets[i-1] + mCounters[byteIndex][i-1];
    00187             }
    00188             // Do negative numbers (must start at zero)
    00189             // Also need to invert ordering
    00190             // In order to preserve the stability of the sort (essential since
    00191             // we rely on previous bytes already being sorted) we have to count
    00192             // backwards in our offsets from
    00193             mOffsets[255] = mCounters[byteIndex][255];
    00194             for (int i = 254; i > 127; --i)
    00195             {
    00196                 mOffsets[i] = mOffsets[i+1] + mCounters[byteIndex][i];
    00197             }
    00198
    00199             // Sort pass
    00200             for (int i = 0; i < mSortSize; ++i)
    00201             {
    00202                 unsigned char byteVal = getByte(byteIndex, (*mSrc)[i].key);
    00203                 if (byteVal > 127)
    00204                 {
    00205                     // -ve; pre-decrement since offsets set to count
    00206                     (*mDest)[--mOffsets[byteVal]] = (*mSrc)[i];
    00207                 }
    00208                 else
    00209                 {
    00210                     // +ve
    00211                     (*mDest)[mOffsets[byteVal]++] = (*mSrc)[i];
    00212                 }
    00213             }
    00214         }
    00215
    00216         inline unsigned char getByte(int byteIndex, TCompValueType val)
    00217         {
    00218 #if OGRE_ENDIAN == OGRE_ENDIAN_LITTLE
    00219             return ((unsigned char*)(&val))[byteIndex];
    00220 #else
    00221             return ((unsigned char*)(&val))[mNumPasses - byteIndex - 1];
    00222 #endif
    00223         }
    00224
    00225     public:
    00226
    00227         RadixSort() {}
    00228         ~RadixSort() {}
    00229
    00235         template <class TFunction>
    00236         void sort(TContainer& container, TFunction func)
    00237         {
    00238             if (container.empty())
    00239                 return;
    00240
    00241             // Set up the sort areas
    00242             mSortSize = static_cast<int>(container.size());
    00243             mSortArea1.resize(container.size());
    00244             mSortArea2.resize(container.size());
    00245
    00246             // Copy data now (we need constant iterators for sorting)
    00247             mTmpContainer = container;
    00248
    00249             mNumPasses = sizeof(TCompValueType);
    00250
    00251             // Counter pass
    00252             // Initialise the counts
    00253             int p;
    00254             for (p = 0; p < mNumPasses; ++p)
    00255                 memset(mCounters[p], 0, sizeof(int) * 256);
    00256
    00257             // Perform alpha pass to count
    00258             ContainerIter i = mTmpContainer.begin();
    00259             TCompValueType prevValue = func.operator()(*i);
    00260             bool needsSorting = false;
    00261             for (int u = 0; i != mTmpContainer.end(); ++i, ++u)
    00262             {
    00263                 // get sort value
    00264                 TCompValueType val = func.operator()(*i);
    00265                 // cheap check to see if needs sorting (temporal coherence)
    00266                 if (!needsSorting && val < prevValue)
    00267                     needsSorting = true;
    00268
    00269                 // Create a sort entry
    00270                 mSortArea1[u].key = val;
    00271                 mSortArea1[u].iter = i;
    00272
    00273                 // increase counters
    00274                 for (p = 0; p < mNumPasses; ++p)
    00275                 {
    00276                     unsigned char byteVal = getByte(p, val);
    00277                     mCounters[p][byteVal]++;
    00278                 }
    00279
    00280                 prevValue = val;
    00281
    00282             }
    00283
    00284             // early exit if already sorted
    00285             if (!needsSorting)
    00286                 return;
    00287
    00288
    00289             // Sort passes
    00290             mSrc = &mSortArea1;
    00291             mDest = &mSortArea2;
    00292
    00293             for (p = 0; p < mNumPasses - 1; ++p)
    00294             {
    00295                 sortPass(p);
    00296                 // flip src/dst
    00297                 std::vector<SortEntry>* tmp = mSrc;
    00298                 mSrc = mDest;
    00299                 mDest = tmp;
    00300             }
    00301             // Final pass may differ, make polymorphic
    00302             finalPass(p, prevValue);
    00303
    00304             // Copy everything back
    00305             int c = 0;
    00306             for (i = container.begin();
    00307                 i != container.end(); ++i, ++c)
    00308             {
    00309                 *i = *((*mDest)[c].iter);
    00310             }
    00311         }
    00312
    00313     };
    00314
    00315
    00316 }
    00317 #endif
    00318

Copyright © 2000-2005 by The OGRE Team
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Sun Sep 17 15:39:11 2006