impl.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. Legal:
  3. Version: MPL 1.1
  4. The contents of this file are subject to the Mozilla Public License Version
  5. 1.1 the "License"; you may not use this file except in compliance with
  6. the License. You may obtain a copy of the License at
  7. http://www.mozilla.org/MPL/
  8. Software distributed under the License is distributed on an "AS IS" basis,
  9. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  10. for the specific language governing rights and limitations under the
  11. License.
  12. The Original Code is the YSI framework.
  13. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  14. Portions created by the Initial Developer are Copyright C 2011
  15. the Initial Developer. All Rights Reserved.
  16. Contributors:
  17. Y_Less
  18. koolk
  19. JoeBullet/Google63
  20. g_aSlice/Slice
  21. Misiur
  22. samphunter
  23. tianmeta
  24. maddinat0r
  25. spacemud
  26. Crayder
  27. Dayvison
  28. Ahmad45123
  29. Zeex
  30. irinel1996
  31. Yiin-
  32. Chaprnks
  33. Konstantinos
  34. Masterchen09
  35. Southclaws
  36. PatchwerkQWER
  37. m0k1
  38. paulommu
  39. udan111
  40. Thanks:
  41. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  42. ZeeX - Very productive conversations.
  43. koolk - IsPlayerinAreaEx code.
  44. TheAlpha - Danish translation.
  45. breadfish - German translation.
  46. Fireburn - Dutch translation.
  47. yom - French translation.
  48. 50p - Polish translation.
  49. Zamaroht - Spanish translation.
  50. Los - Portuguese translation.
  51. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes for
  52. me to strive to better.
  53. Pixels^ - Running XScripters where the idea was born.
  54. Matite - Pestering me to release it and using it.
  55. Very special thanks to:
  56. Thiadmer - PAWN, whose limits continue to amaze me!
  57. Kye/Kalcor - SA:MP.
  58. SA:MP Team past, present and future - SA:MP.
  59. Optional plugins:
  60. Gamer_Z - GPS.
  61. Incognito - Streamer.
  62. Me - sscanf2, fixes2, Whirlpool.
  63. */
  64. // Helper macro so people don't need to enter all the sizes all the time.
  65. #define _Jagged(%0) (%0),sizeof(%0),sizeof(%0[])
  66. #define _Jagged_Sum:(%0,%1) _Jagged_Sum:(%0+%1)
  67. // Ceiling division so that all slots will be at least big enough. Otherwise
  68. //
  69. // Jagged:X[3]<12, 1 1>
  70. //
  71. // Would result in "[3][4]", which doesn't have 14 slots total.
  72. #define Jagged:%0[%1]<%2>; %0[%1][_:_Jagged_Sum:(%2,%1,-1) / (%1)];Jagged_ResizeAll(%0,%2);
  73. static stock Jagged_MovePtr(array[][], maxSize, slot, shift)
  74. {
  75. new
  76. tmp0,
  77. tmp1,
  78. ptr;
  79. // Get the slot pointer.
  80. #emit LOAD.S.alt array
  81. #emit LOAD.S.pri slot
  82. #emit IDXADDR
  83. #emit STOR.S.pri tmp0
  84. //#emit MOVE.alt
  85. #emit LOAD.I
  86. #emit STOR.S.pri ptr
  87. //printf("Jagged_MovePtr: Moving %d by %d to %d (mod %d)", ptr, shift, ptr + shift, maxSize);
  88. ptr += shift;
  89. // I have to do it this way to avoid a bug with "if" statements and "#emit".
  90. ptr = (ptr > maxSize) ? maxSize : ptr;
  91. #emit LOAD.S.alt array
  92. #emit LOAD.S.pri slot
  93. #emit IDXADDR
  94. #emit STOR.S.pri tmp1
  95. #emit STOR.S.pri shift
  96. #emit LOAD.S.pri ptr
  97. #emit SREF.S.pri shift
  98. //printf("%d %d %d %d", tmp0, tmp1, shift, ptr);
  99. #if _DEBUG >= 7
  100. printf("Jagged_MovePtr: Header:");
  101. _Jagged_PrintHeader(array, 4, 0);
  102. #endif
  103. }
  104. /*-------------------------------------------------------------------------*//**
  105. * <param name="array">The array we want to resize a slot in.</param>
  106. * <param name="size1">The number of slots in the array.</param>
  107. * <param name="size2">The ORIGINAL size of every slot.</param>
  108. * <param name="slot">The slot to resize.</param>
  109. * <param name="newSize">The new size of the slot.</param>
  110. * <remarks>
  111. * Resize an array slot, maintining all of its data. The "slot" variable is
  112. * usually used to hold the NEXT slot - we barely need the number of the
  113. * current slot once we have its address.
  114. * </remarks>
  115. *//*------------------------------------------------------------------------**/
  116. stock bool:Jagged_ResizeOne(array[][], size1, size2, slot, newSize)
  117. {
  118. if (newSize < 0)
  119. {
  120. return false;
  121. }
  122. // SLOT GETS INCREMENTED VERY FAST!
  123. if (0 < ++slot < size1)
  124. {
  125. // Get the slot's current size and address.
  126. newSize *= 4;
  127. new
  128. newEnd = _Jagged_Address(array, slot - 1) + newSize,
  129. arrayEnd = _Jagged_End(array, size1, size2);
  130. if (newEnd > arrayEnd)
  131. {
  132. P:1("Insufficient space to grow jagged array.");
  133. return false;
  134. }
  135. new
  136. slotEnd = _Jagged_Address(array, slot),
  137. //oldSize = slotEnd - slotStart,
  138. shift = newEnd - slotEnd; //newSize - oldSize;
  139. P:5("Jagged_ResizeOne: Resizing slot %d from %d to %d", slot - 1, _Jagged_SizeOf(array, size1, size2, slot - 1), newSize);
  140. if (shift != 0)
  141. {
  142. new
  143. remain = arrayEnd - newEnd;
  144. // Grow the slot. This has to be done largely in assembly to remove
  145. // the "BOUNDS" OpCodes that would otherwise be inserted. Actually,
  146. // we can't have "BOUNDS" here because there's no way for the
  147. // compiler to know the array's size in advance. This works even
  148. // when "shift" is negative.
  149. memcpy(array[slot][shift / 4], array[slot], 0, remain, remain / 4);
  150. // Now shift all the subsequent slots.
  151. size2 = size2 * size1 * 4;
  152. while (slot < size1)
  153. {
  154. Jagged_MovePtr(array, size2 + (size1 - slot) * 4, slot, shift);
  155. ++slot;
  156. }
  157. if (shift > 0)
  158. {
  159. // Blank the remainder of the slot we are growing.
  160. rawMemset(slotEnd, 0, shift);
  161. }
  162. else
  163. {
  164. // Blank the end of the array.
  165. rawMemset(arrayEnd + shift, 0, -shift);
  166. }
  167. }
  168. // Do nothing if they're the same.
  169. return true;
  170. }
  171. P:C(else if (slot == size1) printf("Cannot alter the last slot in an array."););
  172. return false;
  173. }
  174. /*-------------------------------------------------------------------------*//**
  175. * <param name="array">The array we want to resize a slot in.</param>
  176. * <param name="size1">The number of slots in the array.</param>
  177. * <param name="size2">The ORIGINAL size of every slot.</param>
  178. * <param name="">Multiple {slot, size} tuples.</param>
  179. * <remarks>
  180. * Resize multiple array slots, maintining all of their data.
  181. * </remarks>
  182. *//*------------------------------------------------------------------------**/
  183. stock bool:_Jagged_Resize(array[][], size1, size2, ...)
  184. {
  185. new
  186. num = numargs();
  187. // Now, as you can imagine, this requires some tricky low-level code, but
  188. // that is all in other functions now.
  189. for (new i = 3; i != num; ++i)
  190. {
  191. P:7("_Jagged_Resize: loop %d %d %d", i, getarg(i, 0), getarg(i, 1));
  192. Jagged_ResizeOne(array, size1, size2, getarg(i, 0), getarg(i, 1));
  193. }
  194. }
  195. #define Jagged_Resize(%0,%1) _Jagged_Resize(_Jagged(%0),%1)
  196. #define _ALS_Jagged_Resize
  197. /*-------------------------------------------------------------------------*//**
  198. * <param name="array">The array we want to resize a slot in.</param>
  199. * <param name="size1">The number of slots in the array.</param>
  200. * <param name="size2">The ORIGINAL size of every slot.</param>
  201. * <param name="">New sizes for every slot.</param>
  202. * <remarks>
  203. * Resize multilpe array slots, maintining all of their data.
  204. * </remarks>
  205. *//*------------------------------------------------------------------------**/
  206. stock bool:_Jagged_ResizeAll(array[][], size1, size2, ...)
  207. {
  208. new
  209. num = min(numargs() - 3, size1);
  210. // Now, as you can imagine, this requires some tricky low-level code, but
  211. // that is all in other functions now.
  212. for (new i = 3, j = 0; j != num; ++i, ++j)
  213. {
  214. P:7("_Jagged_Resize: loop %d %d %d", i, j, getarg(i));
  215. Jagged_ResizeOne(array, size1, size2, j, getarg(i));
  216. }
  217. }
  218. #define Jagged_ResizeAll(%0,%1) _Jagged_ResizeAll(_Jagged(%0),%1)
  219. #define _ALS_Jagged_ResizeAll
  220. /*-------------------------------------------------------------------------*//**
  221. * <param name="array">The array we want to resize a slot in.</param>
  222. * <param name="size1">The number of slots in the array.</param>
  223. * <param name="size2">The ORIGINAL size of every slot.</param>
  224. * <param name="slot">The slot to resize.</param>
  225. * <param name="newSize">The new size of the slot.</param>
  226. * <remarks>
  227. * The "slot" variable is usually used to hold the NEXT slot - we barely need
  228. * the number of the current slot once we have its address. "Resize" copies
  229. * data to keep as much of the original data as possible. This just moves the
  230. * boundaries.
  231. * </remarks>
  232. *//*------------------------------------------------------------------------**/
  233. stock bool:Jagged_MoveOne(array[][], size1, size2, slot, newSize)
  234. {
  235. if (newSize < 0)
  236. {
  237. return false;
  238. }
  239. // SLOT GETS INCREMENTED VERY FAST!
  240. if (0 < ++slot < size1)
  241. {
  242. // Get the slot's current size and address.
  243. newSize *= 4;
  244. new
  245. newEnd = _Jagged_Address(array, slot - 1) + newSize,
  246. arrayEnd = _Jagged_End(array, size1, size2);
  247. if (newEnd > arrayEnd)
  248. {
  249. P:1("Insufficient space to grow jagged array.");
  250. return false;
  251. }
  252. new
  253. slotEnd = _Jagged_Address(array, slot),
  254. shift = newEnd - slotEnd;
  255. P:5("Jagged_MoveOne: Mov slot %d from %d to %d", slot - 1, _Jagged_SizeOf(array, size1, size2, slot - 1), newSize);
  256. if (shift != 0)
  257. {
  258. // Shift all the subsequent slots.
  259. size2 = size2 * size1 * 4;
  260. while (slot < size1)
  261. {
  262. Jagged_MovePtr(array, size2 + (size1 - slot) * 4, slot, shift);
  263. ++slot;
  264. }
  265. }
  266. // Do nothing if they're the same.
  267. return true;
  268. }
  269. P:C(else if (slot == size1) printf("Cannot alter the last slot in an array."););
  270. return false;
  271. }
  272. /*-------------------------------------------------------------------------*//**
  273. * <param name="array">The array we want to resize a slot in.</param>
  274. * <param name="size1">The number of slots in the array.</param>
  275. * <param name="size2">The ORIGINAL size of every slot.</param>
  276. * <param name="">Multiple {slot, size} tuples.</param>
  277. * <remarks>
  278. * "Resize" copies data to keep as much of the original data as possible. This
  279. * just moves the boundaries.
  280. * </remarks>
  281. *//*------------------------------------------------------------------------**/
  282. stock bool:_Jagged_Move(array[][], size1, size2, ...)
  283. {
  284. new
  285. num = numargs();
  286. // Now, as you can imagine, this requires some tricky low-level code, but
  287. // that is all in other functions now.
  288. for (new i = 3; i != num; ++i)
  289. {
  290. P:7("_Jagged_Move: loop %d %d %d", i, getarg(i, 0), getarg(i, 1));
  291. Jagged_MoveOne(array, size1, size2, getarg(i, 0), getarg(i, 1));
  292. }
  293. }
  294. #define Jagged_Move(%0,%1) _Jagged_Move(_Jagged(%0),%1)
  295. #define _ALS_Jagged_Move
  296. /*-------------------------------------------------------------------------*//**
  297. * <param name="array">The array we want to resize a slot in.</param>
  298. * <param name="size1">The number of slots in the array.</param>
  299. * <param name="size2">The ORIGINAL size of every slot.</param>
  300. * <param name="">New sizes for every slot.</param>
  301. * <remarks>
  302. * "Resize" copies data to keep as much of the original data as possible. This
  303. * just moves the boundaries.
  304. * </remarks>
  305. *//*------------------------------------------------------------------------**/
  306. stock bool:_Jagged_MoveAll(array[][], size1, size2, ...)
  307. {
  308. new
  309. num = min(numargs() - 3, size1);
  310. // Now, as you can imagine, this requires some tricky low-level code, but
  311. // that is all in other functions now.
  312. for (new i = 3, j = 0; j != num; ++i, ++j)
  313. {
  314. P:7("_Jagged_Move: loop %d %d %d", i, j, getarg(i));
  315. Jagged_MoveOne(array, size1, size2, j, getarg(i));
  316. }
  317. }
  318. #define Jagged_MoveAll(%0,%1) _Jagged_MoveAll(_Jagged(%0),%1)
  319. #define _ALS_Jagged_MoveAll
  320. /*-------------------------------------------------------------------------*//**
  321. * <param name="array">The array we want to get the size of a slot in.</param>
  322. * <param name="size1">The number of slots in the array.</param>
  323. * <param name="size2">The ORIGINAL size of every slot.</param>
  324. * <param name="slot">The slot to get the size of.</param>
  325. * <returns>
  326. * The current size of this slot. This is NOT a compile-time operation.
  327. * </returns>
  328. * <remarks>
  329. * Returns the data in BYTES NOT CELLS.
  330. * </remarks>
  331. *//*------------------------------------------------------------------------**/
  332. stock _Jagged_SizeOf(array[][], size1, size2, slot)
  333. {
  334. if (0 <= slot < size1)
  335. {
  336. new
  337. start = _Jagged_Address(array, slot);
  338. if (++slot == size1)
  339. {
  340. // Figure out the end address of the array.
  341. return _Jagged_End(array, size1, size2) - start;
  342. }
  343. else
  344. {
  345. return _Jagged_Address(array, slot) - start;
  346. }
  347. }
  348. return -1;
  349. }
  350. #define Jagged_SizeOf(%0,%1) _Jagged_SizeOf(_Jagged(%0),%1)
  351. #define _ALS_Jagged_SizeOf
  352. #define jaggedsizeof(%0[%1]) (_Jagged_SizeOf(_Jagged(%0),%1)>>2)
  353. /*-------------------------------------------------------------------------*//**
  354. * <param name="array">The array we want to get the address of a slot in.</param>
  355. * <param name="size1">The number of slots in the array.</param>
  356. * <param name="size2">The ORIGINAL size of every slot.</param>
  357. * <param name="slot">The slot to get the address of.</param>
  358. * <returns>
  359. * The absolute address of this slot.
  360. * </returns>
  361. *//*------------------------------------------------------------------------**/
  362. #if _DEBUG == 0
  363. static
  364. #endif
  365. stock _Jagged_Address(array[][], slot)
  366. {
  367. // Get the slot pointer.
  368. #emit LOAD.S.alt array
  369. #emit LOAD.S.pri slot
  370. #emit IDXADDR
  371. #emit MOVE.alt
  372. #emit LOAD.I
  373. #emit ADD
  374. #emit RETN
  375. return 0;
  376. }
  377. /*-------------------------------------------------------------------------*//**
  378. * <param name="array">The array we want to get the end of.</param>
  379. * <param name="size1">The number of slots in the array.</param>
  380. * <param name="size2">The ORIGINAL size of every slot.</param>
  381. * <returns>
  382. * The absolute address of the end of this array.
  383. * </returns>
  384. *//*------------------------------------------------------------------------**/
  385. #if _DEBUG == 0
  386. static
  387. #endif
  388. stock _Jagged_End(array[][], size1, size2)
  389. {
  390. #emit LOAD.S.alt size2
  391. #emit INC.alt
  392. #emit LOAD.S.pri size1
  393. #emit UMUL
  394. #emit LOAD.S.alt array
  395. #emit IDXADDR
  396. #emit RETN
  397. return 0;
  398. }
  399. stock _Jagged_PrintHeader(array[][], size1, size2)
  400. {
  401. #pragma unused size2
  402. for (new ptr, slot = 0; slot != size1; ++slot)
  403. {
  404. // Get the slot pointer.
  405. #emit LOAD.S.alt array
  406. #emit LOAD.S.pri slot
  407. #emit LIDX
  408. #emit PUSH.pri
  409. // Get the relative offset.
  410. #emit LOAD.S.pri slot
  411. #emit LOAD.S.alt size1
  412. #emit SUB.alt
  413. #emit SHL.C.pri 2
  414. // Adjust the output to absolute.
  415. #emit POP.alt
  416. #emit SUB.alt
  417. // #emit LOAD.S.alt array
  418. // #emit ADD
  419. #emit STOR.S.pri ptr
  420. printf("Array header: %d = %d", slot, ptr);
  421. }
  422. }
  423. #define Jagged_PrintHeader(%0) _Jagged_PrintHeader(_Jagged(%0))
  424. #define _ALS_Jagged_PrintHeader