IceRevisitedRadix.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /**
  3. * Contains source code from the article "Radix Sort Revisited".
  4. * \file IceRevisitedRadix.cpp
  5. * \author Pierre Terdiman
  6. * \date April, 4, 2000
  7. */
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  10. /**
  11. * Revisited Radix Sort.
  12. * This is my new radix routine:
  13. * - it uses indices and doesn't recopy the values anymore, hence wasting less ram
  14. * - it creates all the histograms in one run instead of four
  15. * - it sorts words faster than dwords and bytes faster than words
  16. * - it correctly sorts negative floating-point values by patching the offsets
  17. * - it automatically takes advantage of temporal coherence
  18. * - multiple keys support is a side effect of temporal coherence
  19. * - it may be worth recoding in asm... (mainly to use FCOMI, FCMOV, etc) [it's probably memory-bound anyway]
  20. *
  21. * History:
  22. * - 08.15.98: very first version
  23. * - 04.04.00: recoded for the radix article
  24. * - 12.xx.00: code lifting
  25. * - 09.18.01: faster CHECK_PASS_VALIDITY thanks to Mark D. Shattuck (who provided other tips, not included here)
  26. * - 10.11.01: added local ram support
  27. * - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting......
  28. * - 01.02.02: - "mIndices" renamed => "mRanks". That's a rank sorter after all.
  29. * - ranks are not "reset" anymore, but implicit on first calls
  30. * - 07.05.02: - offsets rewritten with one less indirection.
  31. * - 11.03.02: - "bool" replaced with RadixHint enum
  32. *
  33. * \class RadixSort
  34. * \author Pierre Terdiman
  35. * \version 1.4
  36. * \date August, 15, 1998
  37. */
  38. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. /*
  40. To do:
  41. - add an offset parameter between two input values (avoid some data recopy sometimes)
  42. - unroll ? asm ?
  43. - 11 bits trick & 3 passes as Michael did
  44. - prefetch stuff the day I have a P3
  45. - make a version with 16-bits indices ?
  46. */
  47. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  48. // Precompiled Header
  49. #include "Stdafx.h"
  50. using namespace IceCore;
  51. #define INVALIDATE_RANKS mCurrentSize|=0x80000000
  52. #define VALIDATE_RANKS mCurrentSize&=0x7fffffff
  53. #define CURRENT_SIZE (mCurrentSize&0x7fffffff)
  54. #define INVALID_RANKS (mCurrentSize&0x80000000)
  55. #define CHECK_RESIZE(n) \
  56. if(n!=mPreviousSize) \
  57. { \
  58. if(n>mCurrentSize) Resize(n); \
  59. else ResetRanks(); \
  60. mPreviousSize = n; \
  61. }
  62. #define CREATE_HISTOGRAMS(type, buffer) \
  63. /* Clear counters/histograms */ \
  64. ZeroMemory(mHistogram, 256*4*sizeof(udword)); \
  65. \
  66. /* Prepare to count */ \
  67. ubyte* p = (ubyte*)input; \
  68. ubyte* pe = &p[nb*4]; \
  69. udword* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \
  70. udword* h1= &mHistogram[256]; /* Histogram for second pass */ \
  71. udword* h2= &mHistogram[512]; /* Histogram for third pass */ \
  72. udword* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \
  73. \
  74. bool AlreadySorted = true; /* Optimism... */ \
  75. \
  76. if(INVALID_RANKS) \
  77. { \
  78. /* Prepare for temporal coherence */ \
  79. type* Running = (type*)buffer; \
  80. type PrevVal = *Running; \
  81. \
  82. while(p!=pe) \
  83. { \
  84. /* Read input buffer in previous sorted order */ \
  85. type Val = *Running++; \
  86. /* Check whether already sorted or not */ \
  87. if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \
  88. /* Update for next iteration */ \
  89. PrevVal = Val; \
  90. \
  91. /* Create histograms */ \
  92. h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
  93. } \
  94. \
  95. /* If all input values are already sorted, we just have to return and leave the */ \
  96. /* previous list unchanged. That way the routine may take advantage of temporal */ \
  97. /* coherence, for example when used to sort transparent faces. */ \
  98. if(AlreadySorted) \
  99. { \
  100. mNbHits++; \
  101. for(udword i=0;i<nb;i++) mRanks[i] = i; \
  102. return *this; \
  103. } \
  104. } \
  105. else \
  106. { \
  107. /* Prepare for temporal coherence */ \
  108. udword* Indices = mRanks; \
  109. type PrevVal = (type)buffer[*Indices]; \
  110. \
  111. while(p!=pe) \
  112. { \
  113. /* Read input buffer in previous sorted order */ \
  114. type Val = (type)buffer[*Indices++]; \
  115. /* Check whether already sorted or not */ \
  116. if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \
  117. /* Update for next iteration */ \
  118. PrevVal = Val; \
  119. \
  120. /* Create histograms */ \
  121. h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
  122. } \
  123. \
  124. /* If all input values are already sorted, we just have to return and leave the */ \
  125. /* previous list unchanged. That way the routine may take advantage of temporal */ \
  126. /* coherence, for example when used to sort transparent faces. */ \
  127. if(AlreadySorted) { mNbHits++; return *this; } \
  128. } \
  129. \
  130. /* Else there has been an early out and we must finish computing the histograms */ \
  131. while(p!=pe) \
  132. { \
  133. /* Create histograms without the previous overhead */ \
  134. h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
  135. }
  136. #define CHECK_PASS_VALIDITY(pass) \
  137. /* Shortcut to current counters */ \
  138. udword* CurCount = &mHistogram[pass<<8]; \
  139. \
  140. /* Reset flag. The sorting pass is supposed to be performed. (default) */ \
  141. bool PerformPass = true; \
  142. \
  143. /* Check pass validity */ \
  144. \
  145. /* If all values have the same byte, sorting is useless. */ \
  146. /* It may happen when sorting bytes or words instead of dwords. */ \
  147. /* This routine actually sorts words faster than dwords, and bytes */ \
  148. /* faster than words. Standard running time (O(4*n))is reduced to O(2*n) */ \
  149. /* for words and O(n) for bytes. Running time for floats depends on actual values... */ \
  150. \
  151. /* Get first byte */ \
  152. ubyte UniqueVal = *(((ubyte*)input)+pass); \
  153. \
  154. /* Check that byte's counter */ \
  155. if(CurCount[UniqueVal]==nb) PerformPass=false;
  156. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  157. /**
  158. * Constructor.
  159. */
  160. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  161. RadixSort::RadixSort() : mCurrentSize(0), mRanks(null), mRanks2(null), mTotalCalls(0), mNbHits(0)
  162. {
  163. #ifndef RADIX_LOCAL_RAM
  164. // Allocate input-independent ram
  165. mHistogram = new udword[256*4];
  166. mOffset = new udword[256];
  167. #endif
  168. // Initialize indices
  169. INVALIDATE_RANKS;
  170. }
  171. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  172. /**
  173. * Destructor.
  174. */
  175. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  176. RadixSort::~RadixSort()
  177. {
  178. // Release everything
  179. #ifndef RADIX_LOCAL_RAM
  180. DELETEARRAY(mOffset);
  181. DELETEARRAY(mHistogram);
  182. #endif
  183. DELETEARRAY(mRanks2);
  184. DELETEARRAY(mRanks);
  185. }
  186. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  187. /**
  188. * Resizes the inner lists.
  189. * \param nb [in] new size (number of dwords)
  190. * \return true if success
  191. */
  192. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  193. bool RadixSort::Resize(udword nb)
  194. {
  195. // Free previously used ram
  196. DELETEARRAY(mRanks2);
  197. DELETEARRAY(mRanks);
  198. // Get some fresh one
  199. mRanks = new udword[nb]; CHECKALLOC(mRanks);
  200. mRanks2 = new udword[nb]; CHECKALLOC(mRanks2);
  201. return true;
  202. }
  203. inline_ void RadixSort::CheckResize(udword nb)
  204. {
  205. udword CurSize = CURRENT_SIZE;
  206. if(nb!=CurSize)
  207. {
  208. if(nb>CurSize) Resize(nb);
  209. mCurrentSize = nb;
  210. INVALIDATE_RANKS;
  211. }
  212. }
  213. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  214. /**
  215. * Main sort routine.
  216. * This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.
  217. * \param input [in] a list of integer values to sort
  218. * \param nb [in] number of values to sort, must be < 2^31
  219. * \param hint [in] RADIX_SIGNED to handle negative values, RADIX_UNSIGNED if you know your input buffer only contains positive values
  220. * \return Self-Reference
  221. */
  222. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  223. RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint)
  224. {
  225. // Checkings
  226. if(!input || !nb || nb&0x80000000) return *this;
  227. // Stats
  228. mTotalCalls++;
  229. // Resize lists if needed
  230. CheckResize(nb);
  231. #ifdef RADIX_LOCAL_RAM
  232. // Allocate histograms & offsets on the stack
  233. udword mHistogram[256*4];
  234. // udword mOffset[256];
  235. udword* mLink[256];
  236. #endif
  237. // Create histograms (counters). Counters for all passes are created in one run.
  238. // Pros: read input buffer once instead of four times
  239. // Cons: mHistogram is 4Kb instead of 1Kb
  240. // We must take care of signed/unsigned values for temporal coherence.... I just
  241. // have 2 code paths even if just a single opcode changes. Self-modifying code, someone?
  242. if(hint==RADIX_UNSIGNED) { CREATE_HISTOGRAMS(udword, input); }
  243. else { CREATE_HISTOGRAMS(sdword, input); }
  244. // Compute #negative values involved if needed
  245. udword NbNegativeValues = 0;
  246. if(hint==RADIX_SIGNED)
  247. {
  248. // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
  249. // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
  250. // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
  251. udword* h3= &mHistogram[768];
  252. for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
  253. }
  254. // Radix sort, j is the pass number (0=LSB, 3=MSB)
  255. for(udword j=0;j<4;j++)
  256. {
  257. CHECK_PASS_VALIDITY(j);
  258. // Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is
  259. // not a problem, numbers are correctly sorted anyway.
  260. if(PerformPass)
  261. {
  262. // Should we care about negative values?
  263. if(j!=3 || hint==RADIX_UNSIGNED)
  264. {
  265. // Here we deal with positive values only
  266. // Create offsets
  267. // mOffset[0] = 0;
  268. // for(udword i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
  269. mLink[0] = mRanks2;
  270. for(udword i=1;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
  271. }
  272. else
  273. {
  274. // This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place.
  275. // Create biased offsets, in order for negative numbers to be sorted as well
  276. // mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
  277. mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
  278. // for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
  279. for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
  280. // Fixing the wrong place for negative values
  281. // mOffset[128] = 0;
  282. mLink[128] = mRanks2;
  283. // for(i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
  284. for(udword i=129;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
  285. }
  286. // Perform Radix Sort
  287. ubyte* InputBytes = (ubyte*)input;
  288. InputBytes += j;
  289. if(INVALID_RANKS)
  290. {
  291. // for(udword i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
  292. for(udword i=0;i<nb;i++) *mLink[InputBytes[i<<2]]++ = i;
  293. VALIDATE_RANKS;
  294. }
  295. else
  296. {
  297. udword* Indices = mRanks;
  298. udword* IndicesEnd = &mRanks[nb];
  299. while(Indices!=IndicesEnd)
  300. {
  301. udword id = *Indices++;
  302. // mRanks2[mOffset[InputBytes[id<<2]]++] = id;
  303. *mLink[InputBytes[id<<2]]++ = id;
  304. }
  305. }
  306. // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
  307. udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
  308. }
  309. }
  310. return *this;
  311. }
  312. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  313. /**
  314. * Main sort routine.
  315. * This one is for floating-point values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.
  316. * \param input [in] a list of floating-point values to sort
  317. * \param nb [in] number of values to sort, must be < 2^31
  318. * \return Self-Reference
  319. * \warning only sorts IEEE floating-point values
  320. */
  321. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  322. RadixSort& RadixSort::Sort(const float* input2, udword nb)
  323. {
  324. // Checkings
  325. if(!input2 || !nb || nb&0x80000000) return *this;
  326. // Stats
  327. mTotalCalls++;
  328. udword* input = (udword*)input2;
  329. // Resize lists if needed
  330. CheckResize(nb);
  331. #ifdef RADIX_LOCAL_RAM
  332. // Allocate histograms & offsets on the stack
  333. udword mHistogram[256*4];
  334. // udword mOffset[256];
  335. udword* mLink[256];
  336. #endif
  337. // Create histograms (counters). Counters for all passes are created in one run.
  338. // Pros: read input buffer once instead of four times
  339. // Cons: mHistogram is 4Kb instead of 1Kb
  340. // Floating-point values are always supposed to be signed values, so there's only one code path there.
  341. // Please note the floating point comparison needed for temporal coherence! Although the resulting asm code
  342. // is dreadful, this is surprisingly not such a performance hit - well, I suppose that's a big one on first
  343. // generation Pentiums....We can't make comparison on integer representations because, as Chris said, it just
  344. // wouldn't work with mixed positive/negative values....
  345. { CREATE_HISTOGRAMS(float, input2); }
  346. // Compute #negative values involved if needed
  347. udword NbNegativeValues = 0;
  348. // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
  349. // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
  350. // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
  351. udword* h3= &mHistogram[768];
  352. for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
  353. // Radix sort, j is the pass number (0=LSB, 3=MSB)
  354. for(udword j=0;j<4;j++)
  355. {
  356. // Should we care about negative values?
  357. if(j!=3)
  358. {
  359. // Here we deal with positive values only
  360. CHECK_PASS_VALIDITY(j);
  361. if(PerformPass)
  362. {
  363. // Create offsets
  364. // mOffset[0] = 0;
  365. mLink[0] = mRanks2;
  366. // for(udword i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
  367. for(udword i=1;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1];
  368. // Perform Radix Sort
  369. ubyte* InputBytes = (ubyte*)input;
  370. InputBytes += j;
  371. if(INVALID_RANKS)
  372. {
  373. // for(i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
  374. for(udword i=0;i<nb;i++) *mLink[InputBytes[i<<2]]++ = i;
  375. VALIDATE_RANKS;
  376. }
  377. else
  378. {
  379. udword* Indices = mRanks;
  380. udword* IndicesEnd = &mRanks[nb];
  381. while(Indices!=IndicesEnd)
  382. {
  383. udword id = *Indices++;
  384. // mRanks2[mOffset[InputBytes[id<<2]]++] = id;
  385. *mLink[InputBytes[id<<2]]++ = id;
  386. }
  387. }
  388. // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
  389. udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
  390. }
  391. }
  392. else
  393. {
  394. // This is a special case to correctly handle negative values
  395. CHECK_PASS_VALIDITY(j);
  396. if(PerformPass)
  397. {
  398. // Create biased offsets, in order for negative numbers to be sorted as well
  399. // mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
  400. mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
  401. // for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
  402. for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
  403. // We must reverse the sorting order for negative numbers!
  404. // mOffset[255] = 0;
  405. mLink[255] = mRanks2;
  406. // for(i=0;i<127;i++) mOffset[254-i] = mOffset[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
  407. for(udword i=0;i<127;i++) mLink[254-i] = mLink[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
  408. // for(i=128;i<256;i++) mOffset[i] += CurCount[i]; // Fixing the wrong place for negative values
  409. for(udword i=128;i<256;i++) mLink[i] += CurCount[i]; // Fixing the wrong place for negative values
  410. // Perform Radix Sort
  411. if(INVALID_RANKS)
  412. {
  413. for(udword i=0;i<nb;i++)
  414. {
  415. udword Radix = input[i]>>24; // Radix byte, same as above. AND is useless here (udword).
  416. // ### cmp to be killed. Not good. Later.
  417. // if(Radix<128) mRanks2[mOffset[Radix]++] = i; // Number is positive, same as above
  418. // else mRanks2[--mOffset[Radix]] = i; // Number is negative, flip the sorting order
  419. if(Radix<128) *mLink[Radix]++ = i; // Number is positive, same as above
  420. else *(--mLink[Radix]) = i; // Number is negative, flip the sorting order
  421. }
  422. VALIDATE_RANKS;
  423. }
  424. else
  425. {
  426. for(udword i=0;i<nb;i++)
  427. {
  428. udword Radix = input[mRanks[i]]>>24; // Radix byte, same as above. AND is useless here (udword).
  429. // ### cmp to be killed. Not good. Later.
  430. // if(Radix<128) mRanks2[mOffset[Radix]++] = mRanks[i]; // Number is positive, same as above
  431. // else mRanks2[--mOffset[Radix]] = mRanks[i]; // Number is negative, flip the sorting order
  432. if(Radix<128) *mLink[Radix]++ = mRanks[i]; // Number is positive, same as above
  433. else *(--mLink[Radix]) = mRanks[i]; // Number is negative, flip the sorting order
  434. }
  435. }
  436. // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
  437. udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
  438. }
  439. else
  440. {
  441. // The pass is useless, yet we still have to reverse the order of current list if all values are negative.
  442. if(UniqueVal>=128)
  443. {
  444. if(INVALID_RANKS)
  445. {
  446. // ###Possible?
  447. for(udword i=0;i<nb;i++) mRanks2[i] = nb-i-1;
  448. VALIDATE_RANKS;
  449. }
  450. else
  451. {
  452. for(udword i=0;i<nb;i++) mRanks2[i] = mRanks[nb-i-1];
  453. }
  454. // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
  455. udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
  456. }
  457. }
  458. }
  459. }
  460. return *this;
  461. }
  462. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. /**
  464. * Gets the ram used.
  465. * \return memory used in bytes
  466. */
  467. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  468. udword RadixSort::GetUsedRam() const
  469. {
  470. udword UsedRam = sizeof(RadixSort);
  471. #ifndef RADIX_LOCAL_RAM
  472. UsedRam += 256*4*sizeof(udword); // Histograms
  473. UsedRam += 256*sizeof(udword); // Offsets
  474. #endif
  475. UsedRam += 2*CURRENT_SIZE*sizeof(udword); // 2 lists of indices
  476. return UsedRam;
  477. }