dynarr.inc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2000 by Florian Klaempfl
  4. member of the Free Pascal development team.
  5. This file implements the helper routines for dyn. Arrays in FPC
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************
  12. }
  13. type
  14. { don't add new fields, the size is used }
  15. { to calculate memory requirements }
  16. pdynarray = ^tdynarray;
  17. tdynarray = packed record
  18. refcount : ptrint;
  19. high : tdynarrayindex;
  20. end;
  21. pdynarraytypedata = ^tdynarraytypedata;
  22. tdynarraytypedata =
  23. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  24. packed
  25. {$else}
  26. {$ifdef powerpc64}
  27. { 3.0.0 does not align elType field on a 8-byte boundary,
  28. thus use packed also in this case }
  29. {$ifdef VER3_0_0}
  30. packed
  31. {$endif VER3_0_0}
  32. {$endif powerpc64}
  33. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  34. record
  35. {$if declared(TRttiDataCommon)}
  36. common: TRttiDataCommon;
  37. {$endif declared TRttiDataCommon}
  38. case TTypeKind of
  39. tkArray: (
  40. elSize : SizeUInt;
  41. {$ifdef VER3_0}
  42. elType2 : Pointer;
  43. {$else}
  44. elType2 : PPointer;
  45. {$endif}
  46. varType : Longint;
  47. {$ifdef VER3_0}
  48. elType : Pointer;
  49. {$else}
  50. elType : PPointer;
  51. {$endif}
  52. );
  53. { include for proper alignment }
  54. tkInt64: (
  55. dummy : Int64
  56. );
  57. end;
  58. procedure fpc_dynarray_rangecheck(p : pointer;i : tdynarrayindex);[Public,Alias:'FPC_DYNARRAY_RANGECHECK']; compilerproc;
  59. begin
  60. if not(assigned(p)) or (i<0) or (i>pdynarray(p-sizeof(tdynarray))^.high) then
  61. HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
  62. end;
  63. function fpc_dynarray_length(p : pointer) : tdynarrayindex;[Public,Alias:'FPC_DYNARRAY_LENGTH']; compilerproc;
  64. begin
  65. if assigned(p) then
  66. fpc_dynarray_length:=pdynarray(p-sizeof(tdynarray))^.high+1
  67. else
  68. fpc_dynarray_length:=0;
  69. end;
  70. function fpc_dynarray_high(p : pointer) : tdynarrayindex;[Public,Alias:'FPC_DYNARRAY_HIGH']; compilerproc;
  71. begin
  72. if assigned(p) then
  73. fpc_dynarray_high:=pdynarray(p-sizeof(tdynarray))^.high
  74. else
  75. fpc_dynarray_high:=-1;
  76. end;
  77. procedure fpc_dynarray_clear(var p : pointer;ti : pointer); [Public,Alias:'FPC_DYNARRAY_CLEAR']; compilerproc;
  78. var
  79. realp : pdynarray;
  80. begin
  81. if (P=Nil) then
  82. exit;
  83. realp:=pdynarray(p-sizeof(tdynarray));
  84. if realp^.refcount=0 then
  85. HandleErrorAddrFrameInd(204,get_pc_addr,get_frame);
  86. if (realp^.refcount>0) and declocked(realp^.refcount) then
  87. begin
  88. {$ifdef VER3_0}
  89. ti:=aligntoptr(ti+2+PByte(ti)[1]);
  90. {$else VER3_0}
  91. ti:=aligntoqword(ti+2+PByte(ti)[1]);
  92. {$endif VER3_0}
  93. if assigned(pdynarraytypedata(ti)^.elType) then
  94. int_finalizearray(p,pdynarraytypedata(ti)^.elType{$ifndef VER3_0}^{$endif},realp^.high+1);
  95. freemem(realp);
  96. end;
  97. p:=nil;
  98. end;
  99. { alias for internal use }
  100. Procedure fpc_dynarray_clear (var p : pointer;ti : pointer);[external name 'FPC_DYNARRAY_CLEAR'];
  101. procedure fpc_dynarray_incr_ref(p : pointer);[Public,Alias:'FPC_DYNARRAY_INCR_REF']; compilerproc;
  102. var
  103. realp : pdynarray;
  104. begin
  105. if p=nil then
  106. exit;
  107. realp:=pdynarray(p-sizeof(tdynarray));
  108. if realp^.refcount=0 then
  109. HandleErrorAddrFrameInd(204,get_pc_addr,get_frame)
  110. else if realp^.refcount>0 then
  111. inclocked(realp^.refcount);
  112. end;
  113. { provide local access to dynarr_decr_ref for dynarr_setlength }
  114. procedure fpc_dynarray_incr_ref(p : pointer); [external name 'FPC_DYNARRAY_INCR_REF'];
  115. procedure fpc_dynarray_assign(var dest: Pointer; src: Pointer; ti: pointer);[public,alias:'FPC_DYNARRAY_ASSIGN']; compilerproc;
  116. begin
  117. fpc_dynarray_incr_ref(src);
  118. fpc_dynarray_clear(dest,ti);
  119. Dest:=Src;
  120. end;
  121. procedure fpc_dynarray_assign(var dest: Pointer; src: Pointer; ti: pointer);[external name 'FPC_DYNARRAY_ASSIGN'];
  122. { provide local access to dynarr_setlength }
  123. procedure int_dynarray_setlength(var p : pointer;pti : pointer;
  124. dimcount : sizeint;dims : pdynarrayindex);[external name 'FPC_DYNARR_SETLENGTH'];
  125. procedure fpc_dynarray_setlength(var p : pointer;pti : pointer;
  126. dimcount : sizeint;dims : pdynarrayindex);[Public,Alias:'FPC_DYNARR_SETLENGTH']; compilerproc;
  127. var
  128. i : tdynarrayindex;
  129. movelen,
  130. size : sizeint;
  131. { contains the "fixed" pointers where the refcount }
  132. { and high are at positive offsets }
  133. realp,newp : pdynarray;
  134. ti : pointer;
  135. updatep: boolean;
  136. elesize : sizeint;
  137. eletype,eletypemngd : pointer;
  138. movsize : sizeint;
  139. begin
  140. { negative length is not allowed }
  141. if dims[0]<0 then
  142. HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
  143. { skip kind and name }
  144. {$ifdef VER3_0}
  145. ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
  146. {$else VER3_0}
  147. ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
  148. {$endif VER3_0}
  149. elesize:=pdynarraytypedata(ti)^.elSize;
  150. {$ifdef VER3_0}
  151. eletype:=pdynarraytypedata(ti)^.elType2;
  152. {$else}
  153. eletype:=pdynarraytypedata(ti)^.elType2^;
  154. {$endif}
  155. { only set if type needs finalization }
  156. {$ifdef VER3_0}
  157. eletypemngd:=pdynarraytypedata(ti)^.elType;
  158. {$else}
  159. if assigned(pdynarraytypedata(ti)^.elType) then
  160. eletypemngd:=pdynarraytypedata(ti)^.elType^
  161. else
  162. eletypemngd:=nil;
  163. {$endif}
  164. { determine new memory size }
  165. size:=elesize*dims[0]+sizeof(tdynarray);
  166. updatep := false;
  167. { not assigned yet? }
  168. if not(assigned(p)) then
  169. begin
  170. { do we have to allocate memory? }
  171. if dims[0] = 0 then
  172. exit;
  173. getmem(newp,size);
  174. fillchar(newp^,size,0);
  175. {$ifndef VER3_0}
  176. { call int_InitializeArray for management operators }
  177. if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject]) then
  178. int_InitializeArray(pointer(newp)+sizeof(tdynarray), eletype, dims[0]);
  179. {$endif VER3_0}
  180. updatep := true;
  181. end
  182. else
  183. begin
  184. { if the new dimension is 0, we've to release all data }
  185. if dims[0]=0 then
  186. begin
  187. fpc_dynarray_clear(p,pti);
  188. exit;
  189. end;
  190. realp:=pdynarray(p-sizeof(tdynarray));
  191. newp := realp;
  192. if realp^.refcount<>1 then
  193. begin
  194. updatep := true;
  195. { make an unique copy }
  196. getmem(newp,size);
  197. fillchar(newp^,sizeof(tdynarray),0);
  198. if realp^.high < dims[0] then
  199. movelen := realp^.high+1
  200. else
  201. movelen := dims[0];
  202. movsize := elesize*movelen;
  203. move(p^,(pointer(newp)+sizeof(tdynarray))^, movsize);
  204. if size-sizeof(tdynarray)>movsize then
  205. fillchar((pointer(newp)+sizeof(tdynarray)+movsize)^,size-sizeof(tdynarray)-movsize,0);
  206. { increment ref. count of managed members }
  207. if assigned(eletypemngd) then
  208. for i:= 0 to movelen-1 do
  209. int_addref(pointer(newp)+sizeof(tdynarray)+elesize*i,eletypemngd);
  210. { a declock(ref. count) isn't enough here }
  211. { it could be that the in MT environments }
  212. { in the mean time the refcount was }
  213. { decremented }
  214. { it is, because it doesn't really matter }
  215. { if the array is now removed }
  216. fpc_dynarray_clear(p,pti);
  217. end
  218. else if dims[0]<>realp^.high+1 then
  219. begin
  220. { range checking is quite difficult ... }
  221. { if size overflows then it is less than }
  222. { the values it was calculated from }
  223. if (size<sizeof(tdynarray)) or
  224. ((elesize>0) and (size<elesize)) then
  225. HandleErrorAddrFrameInd(201,get_pc_addr,get_frame);
  226. { resize? }
  227. { here, realp^.refcount has to be one, otherwise the previous }
  228. { if-statement would have been taken. Or is this also for MT }
  229. { code? (JM) }
  230. if realp^.refcount=1 then
  231. begin
  232. { shrink the array? }
  233. if dims[0]<realp^.high+1 then
  234. begin
  235. if assigned(eletypemngd) then
  236. int_finalizearray(pointer(realp)+sizeof(tdynarray)+
  237. elesize*dims[0],
  238. eletypemngd,realp^.high-dims[0]+1);
  239. reallocmem(realp,size);
  240. end
  241. else if dims[0]>realp^.high+1 then
  242. begin
  243. reallocmem(realp,size);
  244. fillchar((pointer(realp)+sizeof(tdynarray)+elesize*(realp^.high+1))^,
  245. (dims[0]-realp^.high-1)*elesize,0);
  246. {$ifndef VER3_0}
  247. { call int_InitializeArray for management operators }
  248. if assigned(eletypemngd) and (PTypeKind(eletype)^ in [tkRecord, tkObject]) then
  249. int_InitializeArray(pointer(realp)+sizeof(tdynarray)+elesize*(realp^.high+1),
  250. eletype, dims[0]-realp^.high-1);
  251. {$endif VER3_0}
  252. end;
  253. newp := realp;
  254. updatep := true;
  255. end;
  256. end;
  257. end;
  258. { handle nested arrays }
  259. if dimcount>1 then
  260. begin
  261. for i:=0 to dims[0]-1 do
  262. int_dynarray_setlength(pointer((pointer(newp)+sizeof(tdynarray)+i*elesize)^),
  263. eletype,dimcount-1,@dims[1]);
  264. end;
  265. if updatep then
  266. begin
  267. p:=pointer(newp)+sizeof(tdynarray);
  268. newp^.refcount:=1;
  269. newp^.high:=dims[0]-1;
  270. end;
  271. end;
  272. { provide local access to dynarr_copy }
  273. function int_dynarray_copy(psrc : pointer;ti : pointer;
  274. lowidx,count:tdynarrayindex) : fpc_stub_dynarray;[external name 'FPC_DYNARR_COPY'];
  275. function fpc_dynarray_copy(psrc : pointer;ti : pointer;
  276. lowidx,count:tdynarrayindex) : fpc_stub_dynarray;[Public,Alias:'FPC_DYNARR_COPY'];compilerproc;
  277. var
  278. realpsrc : pdynarray;
  279. i,size : sizeint;
  280. elesize : sizeint;
  281. eletype : pointer;
  282. begin
  283. fpc_dynarray_clear(pointer(result),ti);
  284. if psrc=nil then
  285. exit;
  286. {$ifndef FPC_DYNARRAYCOPY_FIXED}
  287. if (lowidx=-1) and (count=-1) then
  288. begin
  289. lowidx:=0;
  290. count:=high(tdynarrayindex);
  291. end;
  292. {$endif FPC_DYNARRAYCOPY_FIXED}
  293. realpsrc:=pdynarray(psrc-sizeof(tdynarray));
  294. if (lowidx<0) then
  295. begin
  296. { Decrease count if index is negative, this is different from how copy()
  297. works on strings. Checked against D7. }
  298. if count<=0 then
  299. exit; { may overflow when adding lowidx }
  300. count:=count+lowidx;
  301. lowidx:=0;
  302. end;
  303. if (count>realpsrc^.high-lowidx+1) then
  304. count:=realpsrc^.high-lowidx+1;
  305. if count<=0 then
  306. exit;
  307. { skip kind and name }
  308. {$ifdef VER3_0}
  309. ti:=aligntoptr(ti+2+PByte(ti)[1]);
  310. {$else VER3_0}
  311. ti:=aligntoqword(ti+2+PByte(ti)[1]);
  312. {$endif VER3_0}
  313. elesize:=pdynarraytypedata(ti)^.elSize;
  314. { only set if type needs finalization }
  315. {$ifdef VER3_0}
  316. eletype:=pdynarraytypedata(ti)^.elType;
  317. {$else}
  318. if assigned(pdynarraytypedata(ti)^.elType) then
  319. eletype:=pdynarraytypedata(ti)^.elType^
  320. else
  321. eletype:=nil;
  322. {$endif}
  323. { create new array }
  324. size:=elesize*count;
  325. getmem(pointer(result),size+sizeof(tdynarray));
  326. pdynarray(result)^.refcount:=1;
  327. pdynarray(result)^.high:=count-1;
  328. inc(pointer(result),sizeof(tdynarray));
  329. { copy data }
  330. move(pointer(psrc+elesize*lowidx)^,pointer(result)^,size);
  331. { increment ref. count of members? }
  332. if assigned(eletype) then
  333. for i:=0 to count-1 do
  334. int_addref(pointer(pointer(result)+elesize*i),eletype);
  335. end;
  336. {$ifndef VER3_0}
  337. procedure fpc_dynarray_delete(var p : pointer;source,count : SizeInt;pti : pointer);
  338. var
  339. newhigh,
  340. i : tdynarrayindex;
  341. size : sizeint;
  342. { contains the "fixed" pointers where the refcount }
  343. { and high are at positive offsets }
  344. realp,newp : pdynarray;
  345. ti : pointer;
  346. elesize : sizeint;
  347. eletype,eletypemngd : pointer;
  348. begin
  349. { if source > high then nothing to do }
  350. if not assigned(p) or
  351. (source>pdynarray(p-sizeof(tdynarray))^.high) or
  352. (count<=0) or
  353. (source<0) then
  354. exit;
  355. { cap count }
  356. if source+count-1>pdynarray(p-sizeof(tdynarray))^.high then
  357. count:=pdynarray(p-sizeof(tdynarray))^.high-source+1;
  358. { fast path: delete whole array }
  359. if (source=0) and (count=pdynarray(p-sizeof(tdynarray))^.high+1) then
  360. begin
  361. fpc_dynarray_clear(p,pti);
  362. exit;
  363. end;
  364. { skip kind and name }
  365. {$ifdef VER3_0}
  366. ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
  367. {$else VER3_0}
  368. ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
  369. {$endif VER3_0}
  370. elesize:=pdynarraytypedata(ti)^.elSize;
  371. eletype:=pdynarraytypedata(ti)^.elType2^;
  372. { only set if type needs finalization }
  373. if assigned(pdynarraytypedata(ti)^.elType) then
  374. eletypemngd:=pdynarraytypedata(ti)^.elType^
  375. else
  376. eletypemngd:=nil;
  377. realp:=pdynarray(p-sizeof(tdynarray));
  378. newp:=realp;
  379. { determine new memory size }
  380. newhigh:=realp^.high-count;
  381. size:=elesize*(newhigh+1)+sizeof(tdynarray);
  382. if realp^.refcount<>1 then
  383. begin
  384. { make an unique copy }
  385. getmem(newp,size);
  386. fillchar(newp^,sizeof(tdynarray),0);
  387. { copy the elements that we still need }
  388. if source>0 then
  389. move(p^,(pointer(newp)+sizeof(tdynarray))^,source*elesize);
  390. if source+count-1<realp^.high then
  391. move((p+(source+count)*elesize)^,(pointer(newp)+sizeof(tdynarray)+source*elesize)^,(realp^.high-(source+count)+1)*elesize);
  392. { increment ref. count of managed members }
  393. if assigned(eletypemngd) then
  394. for i:=0 to newhigh do
  395. int_addref(pointer(newp)+sizeof(tdynarray)+elesize*i,eletypemngd);
  396. { a declock(ref. count) isn't enough here }
  397. { it could be that the in MT environments }
  398. { in the mean time the refcount was }
  399. { decremented }
  400. { it is, because it doesn't really matter }
  401. { if the array is now removed }
  402. fpc_dynarray_clear(p,pti);
  403. end
  404. else
  405. begin
  406. { finalize the elements that will be removed }
  407. if assigned(eletypemngd) then
  408. begin
  409. for i:=source to source+count-1 do
  410. int_finalize(p+i*elesize,eletype);
  411. end;
  412. { close the gap by moving the trailing elements to the front }
  413. move((p+(source+count)*elesize)^,(p+source*elesize)^,(realp^.high-(source+count)+1)*elesize);
  414. { resize the array }
  415. reallocmem(realp,size);
  416. newp:=realp;
  417. end;
  418. p:=pointer(newp)+sizeof(tdynarray);
  419. newp^.refcount:=1;
  420. newp^.high:=newhigh;
  421. end;
  422. procedure fpc_dynarray_insert(var p : pointer;source : SizeInt;data : pointer;count : SizeInt;pti : pointer);compilerproc;
  423. var
  424. newhigh,
  425. i : tdynarrayindex;
  426. size : sizeint;
  427. realp,
  428. newp : pdynarray;
  429. ti : pointer;
  430. elesize : sizeint;
  431. eletype,eletypemngd : pointer;
  432. begin
  433. if not assigned(data) or
  434. (count=0) then
  435. exit;
  436. if assigned(p) then
  437. realp:=pdynarray(p-sizeof(tdynarray))
  438. else
  439. realp:=nil;
  440. newp:=realp;
  441. { cap insert index }
  442. if assigned(p) then
  443. begin
  444. if source<0 then
  445. source:=0
  446. else if source>realp^.high+1 then
  447. source:=realp^.high+1;
  448. end
  449. else
  450. source:=0;
  451. { skip kind and name }
  452. {$ifdef VER3_0}
  453. ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
  454. {$else VER3_0}
  455. ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
  456. {$endif VER3_0}
  457. elesize:=pdynarraytypedata(ti)^.elSize;
  458. eletype:=pdynarraytypedata(ti)^.elType2^;
  459. { only set if type needs initialization }
  460. if assigned(pdynarraytypedata(ti)^.elType) then
  461. eletypemngd:=pdynarraytypedata(ti)^.elType^
  462. else
  463. eletypemngd:=nil;
  464. { determine new memory size }
  465. if assigned(p) then
  466. newhigh:=realp^.high+count
  467. else
  468. newhigh:=count-1;
  469. size:=elesize*(newhigh+1)+sizeof(tdynarray);
  470. if assigned(p) then
  471. begin
  472. if realp^.refcount<>1 then
  473. begin
  474. { make an unique copy }
  475. getmem(newp,size);
  476. fillchar(newp^,sizeof(tdynarray),0);
  477. { copy leading elements }
  478. if source>0 then
  479. move(p^,(pointer(newp)+sizeof(tdynarray))^,source*elesize);
  480. { insert new elements }
  481. move(data^,(pointer(newp)+sizeof(tdynarray)+source*elesize)^,count*elesize);
  482. { copy trailing elements }
  483. if realp^.high-source+1>0 then
  484. move((p+source*elesize)^,(pointer(newp)+sizeof(tdynarray)+(source+count)*elesize)^,(realp^.high-source+1)*elesize);
  485. { increment ref. count of managed members }
  486. if assigned(eletypemngd) then
  487. for i:=0 to newhigh do
  488. int_addref(pointer(newp)+sizeof(tdynarray)+elesize*i,eletypemngd);
  489. { a declock(ref. count) isn't enough here }
  490. { it could be that the in MT environments }
  491. { in the mean time the refcount was }
  492. { decremented }
  493. { it is, because it doesn't really matter }
  494. { if the array is now removed }
  495. fpc_dynarray_clear(p,pti);
  496. end
  497. else
  498. begin
  499. { resize the array }
  500. reallocmem(realp,size);
  501. { p might no longer be correct }
  502. p:=pointer(realp)+sizeof(tdynarray);
  503. { move the trailing part after the inserted data }
  504. if source<=realp^.high then
  505. move((p+source*elesize)^,(p+(source+count)*elesize)^,(realp^.high-source+1)*elesize);
  506. { move the inserted data to the destination }
  507. move(data^,(p+source*elesize)^,count*elesize);
  508. { increase reference counts of inserted elements }
  509. if assigned(eletypemngd) then
  510. begin
  511. for i:=source to source+count-1 do
  512. int_addref(p+i*elesize,eletypemngd);
  513. end;
  514. newp:=realp;
  515. end;
  516. end
  517. else
  518. begin
  519. { allocate new array }
  520. getmem(newp,size);
  521. fillchar(newp^,sizeof(tdynarray),0);
  522. { insert data }
  523. move(data^,(pointer(newp)+sizeof(tdynarray))^,count*elesize);
  524. { increase reference counts of inserted elements }
  525. if assigned(eletypemngd) then
  526. begin
  527. for i:=0 to count-1 do
  528. int_addref(pointer(newp)+sizeof(tdynarray)+i*elesize,eletypemngd);
  529. end;
  530. end;
  531. p:=pointer(newp)+sizeof(tdynarray);
  532. newp^.refcount:=1;
  533. newp^.high:=newhigh;
  534. end;
  535. procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr:array of pointer); compilerproc;
  536. var
  537. i,
  538. offset,
  539. totallen : sizeint;
  540. newp,
  541. realp,
  542. srealp : pdynarray;
  543. ti : pointer;
  544. elesize : sizeint;
  545. eletypemngd : pointer;
  546. begin
  547. { sanity check }
  548. if length(sarr)=0 then
  549. exit;
  550. totallen:=0;
  551. for i:=0 to high(sarr) do
  552. if assigned(sarr[i]) then
  553. inc(totallen,pdynarray(sarr[i]-sizeof(tdynarray))^.high+1);
  554. if totallen=0 then
  555. begin
  556. fpc_dynarray_clear(dest,pti);
  557. exit;
  558. end;
  559. { skip kind and name }
  560. {$ifdef VER3_0}
  561. ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
  562. {$else VER3_0}
  563. ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
  564. {$endif VER3_0}
  565. elesize:=pdynarraytypedata(ti)^.elSize;
  566. { only set if type needs initialization }
  567. if assigned(pdynarraytypedata(ti)^.elType) then
  568. eletypemngd:=pdynarraytypedata(ti)^.elType^
  569. else
  570. eletypemngd:=nil;
  571. { copy the elements of each source array }
  572. offset:=0;
  573. { the idea to reuse the first array, re-allocate it and append the other entries is not possible as the first entry
  574. might be finalized later on by the caller however in case of a re-allocate, the entry itself might be gone }
  575. { allocate new array }
  576. getmem(newp,totallen*elesize+sizeof(tdynarray));
  577. for i:=0 to high(sarr) do
  578. if assigned(sarr[i]) then
  579. begin
  580. srealp:=pdynarray(sarr[i]-sizeof(tdynarray));
  581. if srealp^.high>=0 then
  582. begin
  583. move(sarr[i]^,(pointer(newp)+sizeof(tdynarray)+offset*elesize)^,(srealp^.high+1)*elesize);
  584. inc(offset,srealp^.high+1);
  585. end;
  586. end;
  587. { increase reference counts of all the elements }
  588. if assigned(eletypemngd) then
  589. begin
  590. for i:=0 to totallen-1 do
  591. int_addref(pointer(newp)+sizeof(tdynarray)+i*elesize,eletypemngd);
  592. end;
  593. { clear at the end, dest could be a reference to an array being used also as source }
  594. fpc_dynarray_clear(dest,pti);
  595. dest:=pointer(newp)+sizeof(tdynarray);
  596. newp^.refcount:=1;
  597. newp^.high:=totallen-1;
  598. end;
  599. procedure fpc_dynarray_concat(var dest : pointer; pti: pointer; const src1,src2 : pointer); compilerproc;
  600. var
  601. i,
  602. offset,
  603. totallen : sizeint;
  604. newp,
  605. realp,
  606. srealp : pdynarray;
  607. ti : pointer;
  608. elesize : sizeint;
  609. eletypemngd : pointer;
  610. begin
  611. totallen:=0;
  612. if assigned(src1) then
  613. inc(totallen,pdynarray(src1-sizeof(tdynarray))^.high+1);
  614. if assigned(src2) then
  615. inc(totallen,pdynarray(src2-sizeof(tdynarray))^.high+1);
  616. if totallen=0 then
  617. begin
  618. fpc_dynarray_clear(dest,pti);
  619. exit;
  620. end;
  621. { skip kind and name }
  622. {$ifdef VER3_0}
  623. ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
  624. {$else VER3_0}
  625. ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
  626. {$endif VER3_0}
  627. elesize:=pdynarraytypedata(ti)^.elSize;
  628. { only set if type needs initialization }
  629. if assigned(pdynarraytypedata(ti)^.elType) then
  630. eletypemngd:=pdynarraytypedata(ti)^.elType^
  631. else
  632. eletypemngd:=nil;
  633. { the idea to reuse the first array, re-allocate it and append the other entries is not possible as the first entry
  634. might be finalized later on by the caller however in case of a re-allocate, the entry itself might be gone }
  635. { allocate new array }
  636. getmem(newp,totallen*elesize+sizeof(tdynarray));
  637. { copy the elements of each source array }
  638. offset:=0;
  639. if assigned(src1) then
  640. begin
  641. srealp:=pdynarray(src1-sizeof(tdynarray));
  642. if srealp^.high>=0 then
  643. begin
  644. move(src1^,(pointer(newp)+sizeof(tdynarray)+offset*elesize)^,(srealp^.high+1)*elesize);
  645. inc(offset,srealp^.high+1);
  646. end;
  647. end;
  648. if assigned(src2) then
  649. begin
  650. srealp:=pdynarray(src2-sizeof(tdynarray));
  651. if srealp^.high>=0 then
  652. move(src2^,(pointer(newp)+sizeof(tdynarray)+offset*elesize)^,(srealp^.high+1)*elesize);
  653. end;
  654. { increase reference counts of all the elements }
  655. if assigned(eletypemngd) then
  656. begin
  657. for i:=0 to totallen-1 do
  658. int_addref(pointer(newp)+sizeof(tdynarray)+i*elesize,eletypemngd);
  659. end;
  660. { clear at the end, dest could be a reference to an array being also source }
  661. fpc_dynarray_clear(dest,pti);
  662. dest:=pointer(newp)+sizeof(tdynarray);
  663. newp^.refcount:=1;
  664. newp^.high:=totallen-1;
  665. end;
  666. {$endif VER3_0}
  667. procedure DynArraySetLength(var a: Pointer; typeInfo: Pointer; dimCnt: SizeInt; lengthVec: PSizeInt);
  668. external name 'FPC_DYNARR_SETLENGTH';
  669. function DynArraySize(a : pointer): tdynarrayindex;
  670. external name 'FPC_DYNARRAY_LENGTH';
  671. procedure DynArrayClear(var a: Pointer; typeInfo: Pointer);
  672. external name 'FPC_DYNARRAY_CLEAR';
  673. function DynArrayDim(typeInfo: Pointer): Integer;
  674. begin
  675. result:=0;
  676. while (typeInfo <> nil) and (pdynarraytypeinfo(typeInfo)^.kind = tkDynArray) do
  677. begin
  678. { skip kind and name }
  679. {$ifdef VER3_0}
  680. typeInfo:=aligntoptr(typeInfo+2+PByte(typeInfo)[1]);
  681. {$else VER3_0}
  682. typeInfo:=aligntoqword(typeInfo+2+PByte(typeInfo)[1]);
  683. {$endif VER3_0}
  684. { element type info}
  685. {$ifdef VER3_0}
  686. typeInfo:=pdynarraytypedata(typeInfo)^.elType2;
  687. {$else VER3_0}
  688. typeInfo:=pdynarraytypedata(typeInfo)^.elType2^;
  689. {$endif VER3_0}
  690. Inc(result);
  691. end;
  692. end;
  693. function DynArrayBounds(a: Pointer; typeInfo: Pointer): TBoundArray;
  694. var
  695. i,dim: sizeint;
  696. begin
  697. dim:=DynArrayDim(typeInfo);
  698. SetLength(result, dim);
  699. for i:=0 to pred(dim) do
  700. if a = nil then
  701. exit
  702. else
  703. begin
  704. result[i]:=DynArraySize(a)-1;
  705. a:=PPointerArray(a)^[0];
  706. end;
  707. end;
  708. function IsDynArrayRectangular(a: Pointer; typeInfo: Pointer): Boolean;
  709. var
  710. i,j: sizeint;
  711. dim,count: sizeint;
  712. begin
  713. dim:=DynArrayDim(typeInfo);
  714. for i:=1 to pred(dim) do
  715. begin
  716. count:=DynArraySize(PPointerArray(a)^[0]);
  717. for j:=1 to Pred(DynArraySize(a)) do
  718. if count<>DynArraySize(PPointerArray(a)^[j]) then
  719. exit(false);
  720. a:=PPointerArray(a)^[0];
  721. end;
  722. result:=true;
  723. end;
  724. function DynArrayIndex(a: Pointer; const indices: array of SizeInt; typeInfo: Pointer): Pointer;
  725. var
  726. i,h: sizeint;
  727. elsize: sizeuint;
  728. begin
  729. h:=High(indices);
  730. for i:=0 to h do
  731. begin
  732. if i<h then
  733. a := PPointerArray(a)^[indices[i]];
  734. { skip kind and name }
  735. {$ifdef VER3_0}
  736. typeInfo:=aligntoptr(Pointer(typeInfo)+2+PByte(typeInfo)[1]);
  737. {$else VER3_0}
  738. typeInfo:=aligntoqword(Pointer(typeInfo)+2+PByte(typeInfo)[1]);
  739. {$endif VER3_0}
  740. { store the last element size for the index calculation }
  741. elsize:=pdynarraytypedata(typeInfo)^.elSize;
  742. { element type info}
  743. {$ifdef VER3_0}
  744. typeInfo:=pdynarraytypedata(typeInfo)^.elType2;
  745. {$else VER3_0}
  746. typeInfo:=pdynarraytypedata(typeInfo)^.elType2^;
  747. {$endif VER3_0}
  748. if typeInfo=nil then
  749. exit(nil);
  750. end;
  751. { skip kind and name }
  752. {$ifdef VER3_0}
  753. typeInfo:=aligntoptr(Pointer(typeInfo)+2+PByte(typeInfo)[1]);
  754. {$else VER3_0}
  755. typeInfo:=aligntoqword(Pointer(typeInfo)+2+PByte(typeInfo)[1]);
  756. {$endif VER3_0}
  757. result:=@(PByte(a)[indices[h]*elsize]);
  758. end;
  759. { obsolete but needed for bootstrapping }
  760. procedure fpc_dynarray_decr_ref(var p : pointer;ti : pointer); [Public,Alias:'FPC_DYNARRAY_DECR_REF']; compilerproc;
  761. begin
  762. fpc_dynarray_clear(p,ti);
  763. end;