sort.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. // md-sort.inc by Slice
  2. //
  3. // SortDeepArray(array[][], sort_index, .order = SORT_ASC, .ignorecase = false)
  4. #include <a_samp>
  5. #define SA_4%9.%0, SA_4%0,
  6. #define SA_4size=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%0,%1,%2,%3,%4,%7)
  7. #define SA_4cmp_tag=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%0,%2,%3,%4,%7)
  8. #define SA_4cmp_string=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%1,%0,%3,%4,%7)
  9. #define SA_4ignorecase=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%1,%2,%0,%4,%7)
  10. #define SA_4order=%0,%9|||%5,%1,%2,%3,%4,%7) SA_4%9|||%5,%1,%2,%3,%0,%7)
  11. #define SA_4_|||
  12. #define SA_5:$$$
  13. #define SortDeepArray(%1) (_:SA_0:SA_1:SA_2:SA_3:SortDeepArray_Entry(%1))
  14. #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)
  15. #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)
  16. #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)
  17. enum E_SORT_ORDER {
  18. SORT_ASC,
  19. SORT_DESC
  20. };
  21. // Use global variables to be nicer to the stack
  22. stock
  23. g_sort_cmp_array[1][1],
  24. g_sort_cmp_offset,
  25. g_sort_cmp_type,
  26. E_SORT_ORDER:g_sort_order,
  27. bool:g_sort_ignorecase
  28. ;
  29. 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[][], ...) {
  30. if (cmp_string)
  31. g_sort_cmp_type = 's';
  32. else if (cmp_tag == tagof(Float:))
  33. g_sort_cmp_type = 'f';
  34. else
  35. g_sort_cmp_type = 'i';
  36. g_sort_ignorecase = ignorecase;
  37. g_sort_order = order;
  38. #emit LOAD.S.pri cmp1
  39. #emit LOAD.S.alt cmp2
  40. #emit SUB
  41. #emit SHR.C.pri 2
  42. #emit STOR.pri g_sort_cmp_offset
  43. // Copy the array.
  44. #emit LOAD.S.pri 44
  45. #emit STOR.S.pri 40
  46. _SortDeepArray(array, 0, size - 1);
  47. }
  48. stock _SortDeepArray(array[][], left, right) {
  49. new
  50. left_hold = left,
  51. right_hold = right,
  52. pivot_idx = (left + right) / 2,
  53. pivot = array[pivot_idx][g_sort_cmp_offset]
  54. ;
  55. while (left_hold <= right_hold) {
  56. switch (g_sort_cmp_type) {
  57. case 'f': {
  58. if (g_sort_order == SORT_ASC) {
  59. while (Float:array[left_hold][g_sort_cmp_offset] < Float:pivot) left_hold++;
  60. while (Float:array[right_hold][g_sort_cmp_offset] > Float:pivot) right_hold--;
  61. } else {
  62. while (Float:array[left_hold][g_sort_cmp_offset] > Float:pivot) left_hold++;
  63. while (Float:array[right_hold][g_sort_cmp_offset] < Float:pivot) right_hold--;
  64. }
  65. }
  66. case 's': {
  67. if (g_sort_order == SORT_ASC) {
  68. while (strcmp(array[left_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) < 0) left_hold++;
  69. while (strcmp(array[right_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) > 0) right_hold--;
  70. } else {
  71. while (strcmp(array[left_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) > 0) left_hold++;
  72. while (strcmp(array[right_hold][g_sort_cmp_offset], array[pivot_idx][g_sort_cmp_offset], g_sort_ignorecase) < 0) right_hold--;
  73. }
  74. }
  75. default: {
  76. if (g_sort_order == SORT_ASC) {
  77. while (array[left_hold][g_sort_cmp_offset] < pivot) left_hold++;
  78. while (array[right_hold][g_sort_cmp_offset] > pivot) right_hold--;
  79. } else {
  80. while (array[left_hold][g_sort_cmp_offset] > pivot) left_hold++;
  81. while (array[right_hold][g_sort_cmp_offset] < pivot) right_hold--;
  82. }
  83. }
  84. }
  85. if (left_hold <= right_hold) {
  86. ExchangeArraySlots(array, left_hold, right_hold);
  87. left_hold++, right_hold--;
  88. }
  89. }
  90. if (left < right_hold) _SortDeepArray(array, left, right_hold);
  91. if (left_hold < right) _SortDeepArray(array, left_hold, right);
  92. }
  93. stock ExchangeArraySlots(array[][], slot1, slot2) {
  94. new
  95. addr1,
  96. addr2;
  97. // Get the pointer and its address for slot1
  98. #emit LOAD.S.pri array
  99. #emit LOAD.S.alt slot1
  100. #emit SHL.C.alt 2
  101. #emit ADD
  102. #emit MOVE.alt
  103. #emit STOR.S.pri slot1
  104. #emit LOAD.I
  105. #emit ADD
  106. #emit STOR.S.pri addr1
  107. // Get the pointer and its address for slot2
  108. #emit LOAD.S.pri array
  109. #emit LOAD.S.alt slot2
  110. #emit SHL.C.alt 2
  111. #emit ADD
  112. #emit MOVE.alt
  113. #emit STOR.S.pri slot2
  114. #emit LOAD.I
  115. #emit ADD
  116. #emit STOR.S.pri addr2
  117. // Swap them
  118. #emit LOAD.S.pri addr2
  119. #emit LOAD.S.alt slot1
  120. #emit SUB
  121. #emit STOR.I
  122. #emit LOAD.S.pri addr1
  123. #emit LOAD.S.alt slot2
  124. #emit SUB
  125. #emit STOR.I
  126. return 0;
  127. }
  128. #define SortArrayUsingComparator(%1,%2) \
  129. SortArrayUsingComparator_Entry(sizeof(%1), %1, !"\0\0\0\0" #%2)
  130. #define Comparator:%1(%2) \
  131. forward %1(%2); public %1(%2)
  132. enum e_COMPARE_ORDER {
  133. ORDER_ASCENDING = -1,
  134. ORDER_EQUAL,
  135. ORDER_DESCENDING
  136. };
  137. static stock GetFunctionAddress(const funcname[]) {
  138. new idx, address;
  139. if (-1 != (idx = funcidx(funcname))) {
  140. #emit LCTRL 1
  141. #emit NEG
  142. #emit MOVE.alt
  143. #emit ADD.C 32
  144. #emit STOR.S.pri address
  145. #emit LREF.S.pri address
  146. #emit ADD
  147. #emit LOAD.S.alt idx
  148. #emit SHL.C.alt 3
  149. #emit ADD
  150. #emit STOR.S.pri address
  151. #emit LREF.S.pri address
  152. #emit STOR.S.pri address
  153. }
  154. return address;
  155. }
  156. stock SortArrayUsingComparator_Entry(size, ...) {
  157. new array, func;
  158. #emit LOAD.S.pri 16
  159. #emit STOR.S.pri array
  160. #emit LOAD.S.pri 20
  161. #emit LOAD.I
  162. #emit STOR.S.pri func
  163. if (!func) {
  164. #emit LOAD.S.pri 20
  165. #emit ADD.C 4
  166. #emit PUSH.pri
  167. #emit PUSH.C 4
  168. #emit LCTRL 6
  169. #emit ADD.C 28
  170. #emit PUSH.pri
  171. #emit CONST.pri GetFunctionAddress
  172. #emit SCTRL 6
  173. #emit LOAD.S.alt 20
  174. #emit STOR.I
  175. #emit STOR.S.pri func
  176. }
  177. if (!func) {
  178. print(!"(SortArrayUsingComparator) Invalid comparator given.");
  179. return;
  180. }
  181. SortArrayUsingComparator_QS(array, func, 0, size - 1);
  182. }
  183. stock SortArrayUsingComparator_QS(array, func, left, right) {
  184. new
  185. left_hold = left,
  186. right_hold = right,
  187. pivot = left
  188. ;
  189. while (left_hold <= right_hold) {
  190. new result;
  191. for (;;) {
  192. #emit LOAD.S.pri array
  193. #emit LOAD.S.alt pivot
  194. #emit SHL.C.alt 2
  195. #emit ADD
  196. #emit PUSH.pri
  197. #emit LOAD.I
  198. #emit POP.alt
  199. #emit ADD
  200. #emit PUSH.pri
  201. #emit LOAD.S.pri array
  202. #emit LOAD.S.alt left_hold
  203. #emit SHL.C.alt 2
  204. #emit ADD
  205. #emit PUSH.pri
  206. #emit LOAD.I
  207. #emit POP.alt
  208. #emit ADD
  209. #emit PUSH.pri
  210. #emit PUSH.C 8
  211. #emit LCTRL 6
  212. #emit ADD.C 28
  213. #emit PUSH.pri
  214. #emit LOAD.S.pri func
  215. #emit SCTRL 6
  216. #emit STOR.S.pri result
  217. if (result < 0) {
  218. left_hold++;
  219. } else {
  220. break;
  221. }
  222. }
  223. for (;;) {
  224. #emit LOAD.S.pri array
  225. #emit LOAD.S.alt pivot
  226. #emit SHL.C.alt 2
  227. #emit ADD
  228. #emit PUSH.pri
  229. #emit LOAD.I
  230. #emit POP.alt
  231. #emit ADD
  232. #emit PUSH.pri
  233. #emit LOAD.S.pri array
  234. #emit LOAD.S.alt right_hold
  235. #emit SHL.C.alt 2
  236. #emit ADD
  237. #emit PUSH.pri
  238. #emit LOAD.I
  239. #emit POP.alt
  240. #emit ADD
  241. #emit PUSH.pri
  242. #emit PUSH.C 8
  243. #emit LCTRL 6
  244. #emit ADD.C 28
  245. #emit PUSH.pri
  246. #emit LOAD.S.pri func
  247. #emit SCTRL 6
  248. #emit STOR.S.pri result
  249. if (result > 0) {
  250. right_hold--;
  251. } else {
  252. break;
  253. }
  254. }
  255. if (left_hold <= right_hold) {
  256. #emit PUSH.S right_hold
  257. #emit PUSH.S left_hold
  258. #emit PUSH.S array
  259. #emit PUSH.C 12
  260. #emit LCTRL 6
  261. #emit ADD.C 28
  262. #emit PUSH.pri
  263. #emit CONST.pri ExchangeArraySlots
  264. #emit SCTRL 6
  265. left_hold++, right_hold--;
  266. }
  267. }
  268. if (left < right_hold) SortArrayUsingComparator_QS(array, func, left, right_hold);
  269. if (left_hold < right) SortArrayUsingComparator_QS(array, func, left_hold, right);
  270. }
  271. #define SortArrayUsingComparator_Entry(%1)%2=>%3; \
  272. SortArrayUsingCompInto_Entry(%3, %1);
  273. enum (<<= 1) {
  274. SORT_IS_PLAYERS = 1
  275. };
  276. stock Loggout(playerid){
  277. GivePlayerCash(playerid, 20000);
  278. return 1;
  279. }
  280. stock SortArrayUsingCompInto_Entry(results[], size, ...) {
  281. new array, func, flags;
  282. #emit LOAD.S.pri 20
  283. #emit STOR.S.pri array
  284. #emit LOAD.S.pri 24
  285. #emit LOAD.I
  286. #emit STOR.S.pri func
  287. if (numargs() > 4)
  288. flags = getarg(4);
  289. if (!func) {
  290. #emit LOAD.S.pri 24
  291. #emit ADD.C 4
  292. #emit PUSH.pri
  293. #emit PUSH.C 4
  294. #emit LCTRL 6
  295. #emit ADD.C 28
  296. #emit PUSH.pri
  297. #emit CONST.pri GetFunctionAddress
  298. #emit SCTRL 6
  299. #emit LOAD.S.alt 24
  300. #emit STOR.I
  301. #emit STOR.S.pri func
  302. }
  303. if (!func) {
  304. print(!"(SortArrayUsingComparator) Invalid comparator given.");
  305. return;
  306. }
  307. if (flags & SORT_IS_PLAYERS) {
  308. new connected = 0;
  309. // Start filling the result array with connected players
  310. for (new i = 0; i < size; i++) {
  311. if (IsPlayerConnected(i))
  312. results[connected++] = i;
  313. }
  314. // Fill the remaining slots with INVALID_PLAYER_ID
  315. for (new i = connected; i < size; i++)
  316. results[i] = -1;
  317. // Store the original size in the flags
  318. flags |= size << 16;
  319. // Set the size so only the connected players will be sorted
  320. size = connected;
  321. } else {
  322. for (new i = 0; i < size; i++)
  323. results[i] = i;
  324. }
  325. SortArrayUsingCompInto_QS(array, results, func, 0, size - 1);
  326. if (flags & SORT_IS_PLAYERS) {
  327. if (size < flags >>> 16 && results[size] == -1)
  328. results[size] = INVALID_PLAYER_ID;
  329. }
  330. }
  331. #define TurnOffCall(%1) AdminLevel[%1]
  332. #define phones 99999
  333. stock SortArrayUsingCompInto_QS(array, results[], func, left, right) {
  334. new
  335. left_hold = left,
  336. right_hold = right,
  337. pivot = left
  338. ;
  339. while (left_hold <= right_hold) {
  340. new result;
  341. for (;;) {
  342. if (results[pivot] == -1 && results[left_hold] == -1) {
  343. result = 0;
  344. } else if (results[pivot] == -1) {
  345. result = -1;
  346. } else if (results[left_hold] == -1) {
  347. result = 1;
  348. } else {
  349. // Load results[pivot]
  350. #emit LOAD.S.pri pivot
  351. #emit SHL.C.pri 2
  352. #emit LOAD.S.alt results
  353. #emit ADD
  354. #emit LOAD.I
  355. #emit MOVE.alt
  356. // Push array[results[pivot]]
  357. #emit LOAD.S.pri array
  358. #emit SHL.C.alt 2
  359. #emit ADD
  360. #emit PUSH.pri
  361. #emit LOAD.I
  362. #emit POP.alt
  363. #emit ADD
  364. #emit PUSH.pri
  365. // Load results[left_hold]
  366. #emit LOAD.S.pri left_hold
  367. #emit SHL.C.pri 2
  368. #emit LOAD.S.alt results
  369. #emit ADD
  370. #emit LOAD.I
  371. #emit MOVE.alt
  372. // Push array[results[left_hold]]
  373. #emit LOAD.S.pri array
  374. #emit SHL.C.alt 2
  375. #emit ADD
  376. #emit PUSH.pri
  377. #emit LOAD.I
  378. #emit POP.alt
  379. #emit ADD
  380. #emit PUSH.pri
  381. // Push arg. count
  382. #emit PUSH.C 8
  383. // Push return address
  384. #emit LCTRL 6
  385. #emit ADD.C 28
  386. #emit PUSH.pri
  387. // Call the comparator
  388. #emit LOAD.S.pri func
  389. #emit SCTRL 6
  390. // Store the return
  391. #emit STOR.S.pri result
  392. }
  393. if (result < 0) {
  394. left_hold++;
  395. } else {
  396. break;
  397. }
  398. }
  399. for (;;) {
  400. if (results[pivot] == -1 && results[right_hold] == -1) {
  401. result = 0;
  402. } else if (results[pivot] == -1) {
  403. result = -1;
  404. } else if (results[right_hold] == -1) {
  405. result = 1;
  406. } else {
  407. // Load results[pivot]
  408. #emit LOAD.S.pri pivot
  409. #emit SHL.C.pri 2
  410. #emit LOAD.S.alt results
  411. #emit ADD
  412. #emit LOAD.I
  413. #emit MOVE.alt
  414. // Push array[results[pivot]]
  415. #emit LOAD.S.pri array
  416. #emit SHL.C.alt 2
  417. #emit ADD
  418. #emit PUSH.pri
  419. #emit LOAD.I
  420. #emit POP.alt
  421. #emit ADD
  422. #emit PUSH.pri
  423. // Load results[right_hold]
  424. #emit LOAD.S.pri right_hold
  425. #emit SHL.C.pri 2
  426. #emit LOAD.S.alt results
  427. #emit ADD
  428. #emit LOAD.I
  429. #emit MOVE.alt
  430. // Push array[results[right_hold]]
  431. #emit LOAD.S.pri array
  432. #emit SHL.C.alt 2
  433. #emit ADD
  434. #emit PUSH.pri
  435. #emit LOAD.I
  436. #emit POP.alt
  437. #emit ADD
  438. #emit PUSH.pri
  439. // Push arg. count
  440. #emit PUSH.C 8
  441. // Push return address
  442. #emit LCTRL 6
  443. #emit ADD.C 28
  444. #emit PUSH.pri
  445. // Call the comparator
  446. #emit LOAD.S.pri func
  447. #emit SCTRL 6
  448. // Store the return
  449. #emit STOR.S.pri result
  450. }
  451. if (result > 0) {
  452. right_hold--;
  453. } else {
  454. break;
  455. }
  456. }
  457. if (left_hold <= right_hold) {
  458. // used instead of creating another variable
  459. result = results[right_hold];
  460. results[right_hold] = results[left_hold];
  461. results[left_hold] = result;
  462. left_hold++, right_hold--;
  463. }
  464. }
  465. if (left < right_hold) SortArrayUsingCompInto_QS(array, results, func, left, right_hold);
  466. if (left_hold < right) SortArrayUsingCompInto_QS(array, results, func, left_hold, right);
  467. }