y_jaggedarray_impl.inc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  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. #define Jagged_ResizeOne(%0,%1) _Jagged_ResizeOne(_Jagged(%0),%1)
  175. /*-------------------------------------------------------------------------*//**
  176. * <param name="array">The array we want to resize a slot in.</param>
  177. * <param name="size1">The number of slots in the array.</param>
  178. * <param name="size2">The ORIGINAL size of every slot.</param>
  179. * <param name="">Multiple {slot, size} tuples.</param>
  180. * <remarks>
  181. * Resize multiple array slots, maintining all of their data.
  182. * </remarks>
  183. *//*------------------------------------------------------------------------**/
  184. stock bool:_Jagged_Resize(array[][], size1, size2, ...)
  185. {
  186. new
  187. num = numargs();
  188. // Now, as you can imagine, this requires some tricky low-level code, but
  189. // that is all in other functions now.
  190. for (new i = 3; i != num; ++i)
  191. {
  192. P:7("_Jagged_Resize: loop %d %d %d", i, getarg(i, 0), getarg(i, 1));
  193. if (!_Jagged_ResizeOne(array, size1, size2, getarg(i, 0), getarg(i, 1)))
  194. return false;
  195. }
  196. return true;
  197. }
  198. #define Jagged_Resize(%0,%1) _Jagged_Resize(_Jagged(%0),%1)
  199. #define _ALS_Jagged_Resize
  200. /*-------------------------------------------------------------------------*//**
  201. * <param name="array">The array we want to resize a slot in.</param>
  202. * <param name="size1">The number of slots in the array.</param>
  203. * <param name="size2">The ORIGINAL size of every slot.</param>
  204. * <param name="">New sizes for every slot.</param>
  205. * <remarks>
  206. * Resize multilpe array slots, maintining all of their data.
  207. * </remarks>
  208. *//*------------------------------------------------------------------------**/
  209. stock bool:_Jagged_ResizeAll(array[][], size1, size2, ...)
  210. {
  211. new
  212. num = min(numargs() - 3, size1);
  213. // Now, as you can imagine, this requires some tricky low-level code, but
  214. // that is all in other functions now.
  215. for (new i = 3, j = 0; j != num; ++i, ++j)
  216. {
  217. P:7("_Jagged_Resize: loop %d %d %d", i, j, getarg(i));
  218. _Jagged_ResizeOne(array, size1, size2, j, getarg(i));
  219. }
  220. }
  221. #define Jagged_ResizeAll(%0,%1) _Jagged_ResizeAll(_Jagged(%0),%1)
  222. #define _ALS_Jagged_ResizeAll
  223. /*-------------------------------------------------------------------------*//**
  224. * <param name="array">The array we want to resize a slot in.</param>
  225. * <param name="size1">The number of slots in the array.</param>
  226. * <param name="size2">The ORIGINAL size of every slot.</param>
  227. * <param name="slot">The slot to resize.</param>
  228. * <param name="newSize">The new size of the slot.</param>
  229. * <remarks>
  230. * The "slot" variable is usually used to hold the NEXT slot - we barely need
  231. * the number of the current slot once we have its address. "Resize" copies
  232. * data to keep as much of the original data as possible. This just moves the
  233. * boundaries.
  234. * </remarks>
  235. *//*------------------------------------------------------------------------**/
  236. stock bool:Jagged_MoveOne(array[][], size1, size2, slot, newSize)
  237. {
  238. if (newSize < 0)
  239. {
  240. return false;
  241. }
  242. // SLOT GETS INCREMENTED VERY FAST!
  243. if (0 < ++slot < size1)
  244. {
  245. // Get the slot's current size and address.
  246. newSize *= 4;
  247. new
  248. newEnd = _Jagged_Address(array, slot - 1) + newSize,
  249. arrayEnd = _Jagged_End(array, size1, size2);
  250. if (newEnd > arrayEnd)
  251. {
  252. P:1("Insufficient space to grow jagged array.");
  253. return false;
  254. }
  255. new
  256. slotEnd = _Jagged_Address(array, slot),
  257. shift = newEnd - slotEnd;
  258. P:5("Jagged_MoveOne: Mov slot %d from %d to %d", slot - 1, _Jagged_SizeOf(array, size1, size2, slot - 1), newSize);
  259. if (shift != 0)
  260. {
  261. // Shift all the subsequent slots.
  262. size2 = size2 * size1 * 4;
  263. while (slot < size1)
  264. {
  265. Jagged_MovePtr(array, size2 + (size1 - slot) * 4, slot, shift);
  266. ++slot;
  267. }
  268. }
  269. // Do nothing if they're the same.
  270. return true;
  271. }
  272. P:C(else if (slot == size1) printf("Cannot alter the last slot in an array."););
  273. return false;
  274. }
  275. /*-------------------------------------------------------------------------*//**
  276. * <param name="array">The array we want to resize a slot in.</param>
  277. * <param name="size1">The number of slots in the array.</param>
  278. * <param name="size2">The ORIGINAL size of every slot.</param>
  279. * <param name="">Multiple {slot, size} tuples.</param>
  280. * <remarks>
  281. * "Resize" copies data to keep as much of the original data as possible. This
  282. * just moves the boundaries.
  283. * </remarks>
  284. *//*------------------------------------------------------------------------**/
  285. stock bool:_Jagged_Move(array[][], size1, size2, ...)
  286. {
  287. new
  288. num = numargs();
  289. // Now, as you can imagine, this requires some tricky low-level code, but
  290. // that is all in other functions now.
  291. for (new i = 3; i != num; ++i)
  292. {
  293. P:7("_Jagged_Move: loop %d %d %d", i, getarg(i, 0), getarg(i, 1));
  294. Jagged_MoveOne(array, size1, size2, getarg(i, 0), getarg(i, 1));
  295. }
  296. }
  297. #define Jagged_Move(%0,%1) _Jagged_Move(_Jagged(%0),%1)
  298. #define _ALS_Jagged_Move
  299. /*-------------------------------------------------------------------------*//**
  300. * <param name="array">The array we want to resize a slot in.</param>
  301. * <param name="size1">The number of slots in the array.</param>
  302. * <param name="size2">The ORIGINAL size of every slot.</param>
  303. * <remarks>
  304. * Changes all pointers except the first one to point at the very end of the
  305. * array. I.e. makes <c>sizeof (array[0]) == sizeof (array) * sizeof
  306. * (array[])</c>
  307. * and <c>sizeof (array[n &gt; 0]) == 0</c>.
  308. * </remarks>
  309. *//*------------------------------------------------------------------------**/
  310. stock _Jagged_Empty(array[][], size1, size2)
  311. {
  312. // The size of the main storage area, including the header.
  313. size2 = (size1 + size1 * size2) * cellbytes;
  314. while (--size1)
  315. {
  316. #emit LOAD.S.pri array
  317. #emit ADD.C 4
  318. #emit MOVE.alt
  319. #emit LOAD.S.pri size2
  320. #emit ADD.C 0xFFFFFFFC // -4
  321. #emit STOR.I
  322. #emit STOR.S.pri size2
  323. #emit STOR.S.alt array
  324. }
  325. }
  326. #define Jagged_Empty(%0) _Jagged_Empty(_Jagged(%0))
  327. #define _ALS_Jagged_Empty
  328. /*-------------------------------------------------------------------------*//**
  329. * <param name="array">The array we want to resize a slot in.</param>
  330. * <param name="slot">The slot we want to resize.</param>
  331. * <param name="newSize">The new size of the slot.</param>
  332. * <remarks>
  333. * This purely moves the next pointer in the array. It does nothing at all
  334. * with any data stored in the array, or any other pointers. This means many
  335. * bad things can happen when it is used incorrectly. Just one example is
  336. * that extending a slot over the next few slots will mean those later slots
  337. * will now point in to the middle of the current slot's data. This is best
  338. * used in conjunction with Jagged_Empty, so that the array is an almost blank
  339. * slate before dangerous messing.
  340. * </remarks>
  341. *//*------------------------------------------------------------------------**/
  342. stock Jagged_UnsafeResizeOne(array[][], slot, newSize)
  343. {
  344. // Get a pointer to the next slot.
  345. #emit LOAD.S.alt array
  346. #emit LOAD.S.pri slot
  347. #emit INC.I
  348. #emit IDXADDR
  349. #emit PUSH.pri
  350. // Get the offset to this array's current start point.
  351. #emit LOAD.S.pri slot
  352. #emit LIDX
  353. // Get the offset to the new end.
  354. #emit LOAD.S.alt newSize
  355. #emit XCHG
  356. #emit IDXADDR
  357. // Subtract 4 to make it the offset for the next slot, save it to the
  358. // pointer we pushed earlier.
  359. #emit ADD.C 0xFFFFFFFC
  360. #emit SREF.S.pri 0xFFFFFFFC
  361. // End.
  362. #emit POP.pri
  363. #emit RETN
  364. __COMPILER_NAKED
  365. }
  366. //#define Jagged_UnsafeResizeOne(%0,%1) _Jagged_UnsafeResizeOne(_Jagged(%0),%1)
  367. //#define _ALS_Jagged_UnsafeResizeOne
  368. /*-------------------------------------------------------------------------*//**
  369. * <param name="array">The array we want to resize a slot in.</param>
  370. * <param name="size1">The number of slots in the array.</param>
  371. * <param name="size2">The ORIGINAL size of every slot.</param>
  372. * <param name="">New sizes for every slot.</param>
  373. * <remarks>
  374. * "Resize" copies data to keep as much of the original data as possible. This
  375. * just moves the boundaries.
  376. * </remarks>
  377. *//*------------------------------------------------------------------------**/
  378. stock bool:_Jagged_MoveAll(array[][], size1, size2, ...)
  379. {
  380. new
  381. num = min(numargs() - 3, size1);
  382. // Now, as you can imagine, this requires some tricky low-level code, but
  383. // that is all in other functions now.
  384. for (new i = 3, j = 0; j != num; ++i, ++j)
  385. {
  386. P:7("_Jagged_Move: loop %d %d %d", i, j, getarg(i));
  387. Jagged_MoveOne(array, size1, size2, j, getarg(i));
  388. }
  389. }
  390. #define Jagged_MoveAll(%0,%1) _Jagged_MoveAll(_Jagged(%0),%1)
  391. #define _ALS_Jagged_MoveAll
  392. /*-------------------------------------------------------------------------*//**
  393. * <param name="array">The array we want to get the size of a slot in.</param>
  394. * <param name="size1">The number of slots in the array.</param>
  395. * <param name="size2">The ORIGINAL size of every slot.</param>
  396. * <param name="slot">The slot to get the size of.</param>
  397. * <returns>
  398. * The current size of this slot. This is NOT a compile-time operation.
  399. * </returns>
  400. * <remarks>
  401. * Returns the data in BYTES NOT CELLS.
  402. * </remarks>
  403. *//*------------------------------------------------------------------------**/
  404. stock _Jagged_SizeOf(array[][], size1, size2, slot)
  405. {
  406. if (0 <= slot < size1)
  407. {
  408. new
  409. start = _Jagged_Address(array, slot);
  410. if (++slot == size1)
  411. {
  412. // Figure out the end address of the array.
  413. return _Jagged_End(array, size1, size2) - start;
  414. }
  415. else
  416. {
  417. return _Jagged_Address(array, slot) - start;
  418. }
  419. }
  420. return -1;
  421. }
  422. #define Jagged_SizeOf(%0,%1) _Jagged_SizeOf(_Jagged(%0),%1)
  423. #define _ALS_Jagged_SizeOf
  424. #define jaggedsizeof(%0[%1]) (_Jagged_SizeOf(_Jagged(%0),%1)>>2)
  425. /*-------------------------------------------------------------------------*//**
  426. * <param name="array">The array we want to get the address of a slot in.</param>
  427. * <param name="size1">The number of slots in the array.</param>
  428. * <param name="size2">The ORIGINAL size of every slot.</param>
  429. * <param name="slot">The slot to get the address of.</param>
  430. * <returns>
  431. * The absolute address of this slot.
  432. * </returns>
  433. *//*------------------------------------------------------------------------**/
  434. #if _DEBUG == 0
  435. static
  436. #endif
  437. stock _Jagged_Address(array[][], slot)
  438. {
  439. // Get the slot pointer.
  440. #emit LOAD.S.alt array
  441. #emit LOAD.S.pri slot
  442. #emit IDXADDR
  443. #emit MOVE.alt
  444. #emit LOAD.I
  445. #emit ADD
  446. #emit RETN
  447. __COMPILER_NAKED
  448. }
  449. /*-------------------------------------------------------------------------*//**
  450. * <param name="array">The array we want to get the end of.</param>
  451. * <param name="size1">The number of slots in the array.</param>
  452. * <param name="size2">The ORIGINAL size of every slot.</param>
  453. * <returns>
  454. * The absolute address of the end of this array.
  455. * </returns>
  456. *//*------------------------------------------------------------------------**/
  457. #if _DEBUG == 0
  458. static
  459. #endif
  460. stock _Jagged_End(array[][], size1, size2)
  461. {
  462. #emit LOAD.S.alt size2
  463. #emit INC.alt
  464. #emit LOAD.S.pri size1
  465. #emit UMUL
  466. #emit LOAD.S.alt array
  467. #emit IDXADDR
  468. #emit RETN
  469. __COMPILER_NAKED
  470. }
  471. stock _Jagged_PrintHeader(array[][], size1, size2)
  472. {
  473. #pragma unused size2
  474. for (new ptr, slot = 0; slot != size1; ++slot)
  475. {
  476. // Get the slot pointer.
  477. #emit LOAD.S.alt array
  478. #emit LOAD.S.pri slot
  479. #emit LIDX
  480. #emit PUSH.pri
  481. // Get the relative offset.
  482. #emit LOAD.S.pri slot
  483. #emit LOAD.S.alt size1
  484. #emit SUB.alt
  485. #emit SHL.C.pri 2
  486. // Adjust the output to absolute.
  487. #emit POP.alt
  488. #emit SUB.alt
  489. // #emit LOAD.S.alt array
  490. // #emit ADD
  491. #emit STOR.S.pri ptr
  492. printf("Array header: %d = %d", slot, ptr);
  493. }
  494. }
  495. #define Jagged_PrintHeader(%0) _Jagged_PrintHeader(_Jagged(%0))
  496. #define _ALS_Jagged_PrintHeader