IceRevisitedRadix.cpp 21 KB

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