md-sort.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. // md-sort.inc by Slice
  2. //
  3. // SortDeepArray(array[][], sort_index, .order = SORT_ASC, .ignorecase = false)
  4. #if defined _INC_md_sort
  5. #endinput
  6. #endif
  7. #define _INC_md_sort
  8. #include <a_samp>
  9. #define SA_4%9.%0, SA_4%0,
  10. #define SA_4size=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%0,%1,%2,%3,%4,%7)
  11. #define SA_4cmp_tag=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%0,%2,%3,%4,%7)
  12. #define SA_4cmp_string=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%1,%0,%3,%4,%7)
  13. #define SA_4ignorecase=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%1,%2,%0,%4,%7)
  14. #define SA_4order=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%1,%2,%3,%0,%7)
  15. #define SA_4_|||
  16. #define SA_5:$$$
  17. #define SortDeepArray(%1) (_:SA_0:SA_1:SA_2:SA_3:SortDeepArray_Entry(%1))
  18. #define SA_0:SA_1:SA_2:SA_3:SortDeepArray_Entry(%1,%2,%3) SA_2:SA_3:SortDeepArray_Entry(%1[0][%2], _:%1[0][(%2) - (%2)], SA_4%3,_|||sizeof(%1),_,bool:SA_5:$$$false,_,_,g_sort_cmp_array,_:%1)
  19. #define SA_1:SA_2:SA_3:SortDeepArray_Entry(%1,%2) SA_2:SA_3:SortDeepArray_Entry(%1[0][%2], _:%1[0][(%2) - (%2)], sizeof(%1), _, _, _, _, g_sort_cmp_array, _:%1)
  20. #define SA_2:SA_3:SortDeepArray_Entry(%3[0][%4string%5:%6],%7,%8$$$false%9) SortDeepArray_Entry(%3[0][%6], _:%3[0][(%6) - (%6)], %8$$$true%9)
  21. enum E_SORT_ORDER {
  22. SORT_ASC,
  23. SORT_DESC
  24. };
  25. // Use global variables to be nicer to the stack
  26. stock
  27. g_sort_stack[256],
  28. g_sort_cmp_array[1][1],
  29. g_sort_cmp_offset,
  30. g_sort_cmp_type,
  31. E_SORT_ORDER:g_sort_order,
  32. bool:g_sort_ignorecase
  33. ;
  34. #if !defined FLOAT_TAG
  35. stock const
  36. Float:FLOAT_TAG_;
  37. #define FLOAT_TAG (tagof (FLOAT_TAG_))
  38. #endif
  39. stock SortDeepArray_Entry(&{Float, String, string, _}:cmp1, &_:cmp2, size, cmp_tag = tagof(cmp1), bool:cmp_string = false, bool:ignorecase = false, E_SORT_ORDER:order = SORT_ASC, array[][], ...) {
  40. if (cmp_string)
  41. g_sort_cmp_type = 's';
  42. else if (cmp_tag == FLOAT_TAG)
  43. g_sort_cmp_type = 'f';
  44. else
  45. g_sort_cmp_type = 'i';
  46. g_sort_ignorecase = ignorecase;
  47. g_sort_order = order;
  48. #emit LOAD.S.pri cmp1
  49. #emit LOAD.S.alt cmp2
  50. #emit SUB
  51. #emit SHR.C.pri 2
  52. #emit STOR.pri g_sort_cmp_offset
  53. // Copy the array.
  54. #emit LOAD.S.pri 44
  55. #emit STOR.S.pri 40
  56. _SortDeepArray(array, 0, size - 1);
  57. }
  58. stock _SortDeepArray(array[][], left, right) {
  59. new
  60. sp;
  61. _SortDeepArray_recurse:
  62. new
  63. left_hold = left,
  64. right_hold = right,
  65. pivot_idx = (left + right) / 2,
  66. pivot = array[pivot_idx][g_sort_cmp_offset]
  67. ;
  68. if (g_sort_cmp_type == 'f' && Float:pivot != Float:pivot) {
  69. // Pivot is NaN, put everything else before it - NaN ALWAYS goes at the
  70. // end of the array, regardless of sort order.
  71. left_hold = right;
  72. right_hold = right - 1;
  73. ExchangeArraySlots(array, pivot_idx, right);
  74. } else while (left_hold <= right_hold) {
  75. switch (g_sort_cmp_type) {
  76. case 'f': {
  77. if (g_sort_order == SORT_ASC) {
  78. while (Float:pivot > Float:array[left_hold][g_sort_cmp_offset]) left_hold++;
  79. while (Float:pivot < Float:array[right_hold][g_sort_cmp_offset]) right_hold--;
  80. } else {
  81. while (Float:array[left_hold][g_sort_cmp_offset] > Float:pivot) left_hold++;
  82. while (Float:array[right_hold][g_sort_cmp_offset] < Float:pivot) right_hold--;
  83. }
  84. }
  85. case 's': {
  86. if (g_sort_order == SORT_ASC) {
  87. while (strcmp(array[left_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) < 0) left_hold++;
  88. while (strcmp(array[right_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) > 0) right_hold--;
  89. } else {
  90. while (strcmp(array[left_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) > 0) left_hold++;
  91. while (strcmp(array[right_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) < 0) right_hold--;
  92. }
  93. }
  94. default: {
  95. if (g_sort_order == SORT_ASC) {
  96. while (array[left_hold][g_sort_cmp_offset] < pivot) left_hold++;
  97. while (array[right_hold][g_sort_cmp_offset] > pivot) right_hold--;
  98. } else {
  99. while (array[left_hold][g_sort_cmp_offset] > pivot) left_hold++;
  100. while (array[right_hold][g_sort_cmp_offset] < pivot) right_hold--;
  101. }
  102. }
  103. }
  104. if (left_hold <= right_hold) {
  105. ExchangeArraySlots(array, left_hold, right_hold);
  106. left_hold++, right_hold--;
  107. }
  108. }
  109. if (left_hold < right) {
  110. g_sort_stack[sp++] = left_hold;
  111. g_sort_stack[sp++] = right;
  112. }
  113. if (left < right_hold){
  114. right = right_hold;
  115. goto _SortDeepArray_recurse;
  116. }
  117. if (sp) {
  118. right = g_sort_stack[--sp];
  119. left = g_sort_stack[--sp];
  120. goto _SortDeepArray_recurse;
  121. }
  122. }
  123. stock ExchangeArraySlots(array[][], slot1, slot2) {
  124. new
  125. addr1,
  126. addr2;
  127. // Get the pointer and its address for slot1
  128. #emit LOAD.S.pri array
  129. #emit LOAD.S.alt slot1
  130. #emit SHL.C.alt 2
  131. #emit ADD
  132. #emit MOVE.alt
  133. #emit STOR.S.pri slot1
  134. #emit LOAD.I
  135. #emit ADD
  136. #emit STOR.S.pri addr1
  137. // Get the pointer and its address for slot2
  138. #emit LOAD.S.pri array
  139. #emit LOAD.S.alt slot2
  140. #emit SHL.C.alt 2
  141. #emit ADD
  142. #emit MOVE.alt
  143. #emit STOR.S.pri slot2
  144. #emit LOAD.I
  145. #emit ADD
  146. #emit STOR.S.pri addr2
  147. // Swap them
  148. #emit LOAD.S.pri addr2
  149. #emit LOAD.S.alt slot1
  150. #emit SUB
  151. #emit STOR.I
  152. #emit LOAD.S.pri addr1
  153. #emit LOAD.S.alt slot2
  154. #emit SUB
  155. #emit STOR.I
  156. return 0;
  157. }
  158. #define ShuffleDeepArray(%0) ShuffleDeepArray_Entry(_:%0, sizeof(%0), sizeof (%0[]))
  159. stock ShuffleDeepArray_Entry(...) {
  160. assert(numargs() == 3);
  161. new
  162. i,
  163. base,
  164. size = getarg(1),
  165. target;
  166. #emit LOAD.S.alt 12
  167. #emit STOR.S.alt base
  168. #emit LOAD.S.pri size
  169. #emit SHL.C.pri 2
  170. #emit ADD
  171. #emit STOR.S.pri i
  172. while (i != base) {
  173. i -= 4;
  174. target = (random(size) << 2) + base;
  175. // Get the first slot.
  176. #emit LREF.S.pri i
  177. #emit LOAD.S.alt i
  178. #emit ADD
  179. #emit PUSH.pri
  180. // Get any other slot.
  181. #emit LREF.S.pri target
  182. #emit LOAD.S.alt target
  183. #emit ADD
  184. // Save one.
  185. #emit LOAD.S.alt i
  186. #emit SUB
  187. #emit SREF.S.pri i
  188. // Save the other
  189. #emit POP.pri
  190. #emit LOAD.S.alt target
  191. #emit SUB
  192. #emit SREF.S.pri target
  193. }
  194. }
  195. #define ResetDeepArray(%0) ResetDeepArray_Entry(_:%0, sizeof(%0), sizeof (%0[]))
  196. stock ResetDeepArray_Entry(...) {
  197. // Put all the slots back how they should be originally.
  198. assert(numargs() == 3);
  199. new
  200. i,
  201. base,
  202. size = getarg(1),
  203. target;
  204. #emit LOAD.S.alt 12
  205. #emit STOR.S.alt i
  206. #emit LOAD.S.pri size
  207. #emit SHL.C.pri 2
  208. #emit ADD
  209. #emit STOR.S.pri base
  210. #emit STOR.S.pri target
  211. size = getarg(2) << 2;
  212. while (i != base) {
  213. #emit LOAD.S.alt i
  214. #emit LOAD.S.pri target
  215. #emit SUB
  216. #emit STOR.I
  217. i += 4;
  218. target += size;
  219. }
  220. }
  221. #define SortArrayUsingComparator(%1,%2) \
  222. SortArrayUsingComparator_Entry(sizeof(%1), %1, !"\0\0\0\0" #%2)
  223. #define Comparator:%1(%2) \
  224. forward %1(%2); public %1(%2)
  225. enum e_COMPARE_ORDER {
  226. ORDER_ASCENDING = -1,
  227. ORDER_EQUAL,
  228. ORDER_DESCENDING
  229. };
  230. static stock GetFunctionAddress(const funcname[]) {
  231. new idx, address;
  232. if (-1 != (idx = funcidx(funcname))) {
  233. #emit LCTRL 1
  234. #emit NEG
  235. #emit MOVE.alt
  236. #emit ADD.C 32
  237. #emit STOR.S.pri address
  238. #emit LREF.S.pri address
  239. #emit ADD
  240. #emit LOAD.S.alt idx
  241. #emit SHL.C.alt 3
  242. #emit ADD
  243. #emit STOR.S.pri address
  244. #emit LREF.S.pri address
  245. #emit STOR.S.pri address
  246. }
  247. return address;
  248. }
  249. stock SortArrayUsingComparator_Entry(size, ...) {
  250. new array, func;
  251. #emit LOAD.S.pri 16
  252. #emit STOR.S.pri array
  253. #emit LOAD.S.pri 20
  254. #emit LOAD.I
  255. #emit STOR.S.pri func
  256. if (!func) {
  257. #emit LOAD.S.pri 20
  258. #emit ADD.C 4
  259. #emit PUSH.pri
  260. #emit PUSH.C 4
  261. #emit LCTRL 6
  262. #emit ADD.C 36
  263. #emit LCTRL 8
  264. #emit PUSH.pri
  265. #emit CONST.pri GetFunctionAddress
  266. #emit SCTRL 6
  267. #emit LOAD.S.alt 20
  268. #emit STOR.I
  269. #emit STOR.S.pri func
  270. }
  271. if (!func) {
  272. print(!"(SortArrayUsingComparator) Invalid comparator given.");
  273. return;
  274. }
  275. SortArrayUsingComparator_QS(array, func, 0, size - 1);
  276. }
  277. stock SortArrayUsingComparator_QS(array, func, left, right) {
  278. new
  279. sp;
  280. _SortDeepArray_recurse:
  281. new
  282. left_hold = left,
  283. right_hold = right,
  284. pivot = left
  285. ;
  286. while (left_hold <= right_hold) {
  287. new result;
  288. for (;;) {
  289. #emit LOAD.S.pri array
  290. #emit LOAD.S.alt pivot
  291. #emit SHL.C.alt 2
  292. #emit ADD
  293. #emit PUSH.pri
  294. #emit LOAD.I
  295. #emit POP.alt
  296. #emit ADD
  297. #emit PUSH.pri
  298. #emit LOAD.S.pri array
  299. #emit LOAD.S.alt left_hold
  300. #emit SHL.C.alt 2
  301. #emit ADD
  302. #emit PUSH.pri
  303. #emit LOAD.I
  304. #emit POP.alt
  305. #emit ADD
  306. #emit PUSH.pri
  307. #emit PUSH.C 8
  308. #emit LCTRL 6
  309. #emit ADD.C 36
  310. #emit LCTRL 8
  311. #emit PUSH.pri
  312. #emit LOAD.S.pri func
  313. #emit SCTRL 6
  314. #emit STOR.S.pri result
  315. if (result < 0) {
  316. left_hold++;
  317. } else {
  318. break;
  319. }
  320. }
  321. for (;;) {
  322. #emit LOAD.S.pri array
  323. #emit LOAD.S.alt pivot
  324. #emit SHL.C.alt 2
  325. #emit ADD
  326. #emit PUSH.pri
  327. #emit LOAD.I
  328. #emit POP.alt
  329. #emit ADD
  330. #emit PUSH.pri
  331. #emit LOAD.S.pri array
  332. #emit LOAD.S.alt right_hold
  333. #emit SHL.C.alt 2
  334. #emit ADD
  335. #emit PUSH.pri
  336. #emit LOAD.I
  337. #emit POP.alt
  338. #emit ADD
  339. #emit PUSH.pri
  340. #emit PUSH.C 8
  341. #emit LCTRL 6
  342. #emit ADD.C 36
  343. #emit LCTRL 8
  344. #emit PUSH.pri
  345. #emit LOAD.S.pri func
  346. #emit SCTRL 6
  347. #emit STOR.S.pri result
  348. if (result > 0) {
  349. right_hold--;
  350. } else {
  351. break;
  352. }
  353. }
  354. if (left_hold <= right_hold) {
  355. #emit PUSH.S right_hold
  356. #emit PUSH.S left_hold
  357. #emit PUSH.S array
  358. #emit PUSH.C 12
  359. #emit LCTRL 6
  360. #emit ADD.C 36
  361. #emit LCTRL 8
  362. #emit PUSH.pri
  363. #emit CONST.pri ExchangeArraySlots
  364. #emit SCTRL 6
  365. left_hold++, right_hold--;
  366. }
  367. }
  368. if (left_hold < right) {
  369. g_sort_stack[sp++] = left_hold;
  370. g_sort_stack[sp++] = right;
  371. }
  372. if (left < right_hold){
  373. right = right_hold;
  374. goto _SortDeepArray_recurse;
  375. }
  376. if (sp) {
  377. right = g_sort_stack[--sp];
  378. left = g_sort_stack[--sp];
  379. goto _SortDeepArray_recurse;
  380. }
  381. }
  382. #define SortArrayUsingComparator_Entry(%1)%2=>%3; \
  383. SortArrayUsingCompInto_Entry(%3, %1);
  384. enum (<<= 1) {
  385. SORT_IS_PLAYERS = 1
  386. };
  387. stock SortArrayUsingCompInto_Entry(results[], size, ...) {
  388. new array, func, flags;
  389. #emit LOAD.S.pri 20
  390. #emit STOR.S.pri array
  391. #emit LOAD.S.pri 24
  392. #emit LOAD.I
  393. #emit STOR.S.pri func
  394. if (numargs() > 4)
  395. flags = getarg(4);
  396. if (!func) {
  397. #emit LOAD.S.pri 24
  398. #emit ADD.C 4
  399. #emit PUSH.pri
  400. #emit PUSH.C 4
  401. #emit LCTRL 6
  402. #emit ADD.C 36
  403. #emit LCTRL 8
  404. #emit PUSH.pri
  405. #emit CONST.pri GetFunctionAddress
  406. #emit SCTRL 6
  407. #emit LOAD.S.alt 24
  408. #emit STOR.I
  409. #emit STOR.S.pri func
  410. }
  411. if (!func) {
  412. print(!"(SortArrayUsingComparator) Invalid comparator given.");
  413. return;
  414. }
  415. if (flags & SORT_IS_PLAYERS) {
  416. new connected = 0;
  417. // Start filling the result array with connected players
  418. for (new i = 0; i < size; i++) {
  419. if (IsPlayerConnected(i))
  420. results[connected++] = i;
  421. }
  422. // Fill the remaining slots with INVALID_PLAYER_ID
  423. for (new i = connected; i < size; i++)
  424. results[i] = -1;
  425. // Store the original size in the flags
  426. flags |= size << 16;
  427. // Set the size so only the connected players will be sorted
  428. size = connected;
  429. } else {
  430. for (new i = 0; i < size; i++)
  431. results[i] = i;
  432. }
  433. SortArrayUsingCompInto_QS(array, results, func, 0, size - 1);
  434. if (flags & SORT_IS_PLAYERS) {
  435. if (size < flags >>> 16 && results[size] == -1)
  436. results[size] = INVALID_PLAYER_ID;
  437. }
  438. }
  439. stock SortArrayUsingCompInto_QS(array, results[], func, left, right) {
  440. new
  441. sp;
  442. _SortDeepArray_recurse:
  443. new
  444. left_hold = left,
  445. right_hold = right,
  446. pivot = left
  447. ;
  448. while (left_hold <= right_hold) {
  449. new result;
  450. for (;;) {
  451. if (results[pivot] == -1 && results[left_hold] == -1) {
  452. result = 0;
  453. } else if (results[pivot] == -1) {
  454. result = -1;
  455. } else if (results[left_hold] == -1) {
  456. result = 1;
  457. } else {
  458. // Load results[pivot]
  459. #emit LOAD.S.pri pivot
  460. #emit SHL.C.pri 2
  461. #emit LOAD.S.alt results
  462. #emit ADD
  463. #emit LOAD.I
  464. #emit MOVE.alt
  465. // Push array[results[pivot]]
  466. #emit LOAD.S.pri array
  467. #emit SHL.C.alt 2
  468. #emit ADD
  469. #emit PUSH.pri
  470. #emit LOAD.I
  471. #emit POP.alt
  472. #emit ADD
  473. #emit PUSH.pri
  474. // Load results[left_hold]
  475. #emit LOAD.S.pri left_hold
  476. #emit SHL.C.pri 2
  477. #emit LOAD.S.alt results
  478. #emit ADD
  479. #emit LOAD.I
  480. #emit MOVE.alt
  481. // Push array[results[left_hold]]
  482. #emit LOAD.S.pri array
  483. #emit SHL.C.alt 2
  484. #emit ADD
  485. #emit PUSH.pri
  486. #emit LOAD.I
  487. #emit POP.alt
  488. #emit ADD
  489. #emit PUSH.pri
  490. // Push arg. count
  491. #emit PUSH.C 8
  492. // Push return address
  493. #emit LCTRL 6
  494. #emit ADD.C 36
  495. #emit LCTRL 8
  496. #emit PUSH.pri
  497. // Call the comparator
  498. #emit LOAD.S.pri func
  499. #emit SCTRL 6
  500. // Store the return
  501. #emit STOR.S.pri result
  502. }
  503. if (result < 0) {
  504. left_hold++;
  505. } else {
  506. break;
  507. }
  508. }
  509. for (;;) {
  510. if (results[pivot] == -1 && results[right_hold] == -1) {
  511. result = 0;
  512. } else if (results[pivot] == -1) {
  513. result = -1;
  514. } else if (results[right_hold] == -1) {
  515. result = 1;
  516. } else {
  517. // Load results[pivot]
  518. #emit LOAD.S.pri pivot
  519. #emit SHL.C.pri 2
  520. #emit LOAD.S.alt results
  521. #emit ADD
  522. #emit LOAD.I
  523. #emit MOVE.alt
  524. // Push array[results[pivot]]
  525. #emit LOAD.S.pri array
  526. #emit SHL.C.alt 2
  527. #emit ADD
  528. #emit PUSH.pri
  529. #emit LOAD.I
  530. #emit POP.alt
  531. #emit ADD
  532. #emit PUSH.pri
  533. // Load results[right_hold]
  534. #emit LOAD.S.pri right_hold
  535. #emit SHL.C.pri 2
  536. #emit LOAD.S.alt results
  537. #emit ADD
  538. #emit LOAD.I
  539. #emit MOVE.alt
  540. // Push array[results[right_hold]]
  541. #emit LOAD.S.pri array
  542. #emit SHL.C.alt 2
  543. #emit ADD
  544. #emit PUSH.pri
  545. #emit LOAD.I
  546. #emit POP.alt
  547. #emit ADD
  548. #emit PUSH.pri
  549. // Push arg. count
  550. #emit PUSH.C 8
  551. // Push return address
  552. #emit LCTRL 6
  553. #emit ADD.C 36
  554. #emit LCTRL 8
  555. #emit PUSH.pri
  556. // Call the comparator
  557. #emit LOAD.S.pri func
  558. #emit SCTRL 6
  559. // Store the return
  560. #emit STOR.S.pri result
  561. }
  562. if (result > 0) {
  563. right_hold--;
  564. } else {
  565. break;
  566. }
  567. }
  568. if (left_hold <= right_hold) {
  569. // used instead of creating another variable
  570. result = results[right_hold];
  571. results[right_hold] = results[left_hold];
  572. results[left_hold] = result;
  573. left_hold++, right_hold--;
  574. }
  575. }
  576. if (left_hold < right) {
  577. g_sort_stack[sp++] = left_hold;
  578. g_sort_stack[sp++] = right;
  579. }
  580. if (left < right_hold){
  581. right = right_hold;
  582. goto _SortDeepArray_recurse;
  583. }
  584. if (sp) {
  585. right = g_sort_stack[--sp];
  586. left = g_sort_stack[--sp];
  587. goto _SortDeepArray_recurse;
  588. }
  589. }