mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-11 10:26:05 +02:00
+ support for <dyn. array>+<dyn. array>, resolves #30463
git-svn-id: trunk@38406 -
This commit is contained in:
parent
f0042a4719
commit
c230f81719
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -15873,6 +15873,7 @@ tests/webtbs/tw3041.pp svneol=native#text/plain
|
|||||||
tests/webtbs/tw30431.pp svneol=native#text/plain
|
tests/webtbs/tw30431.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw30443.pp svneol=native#text/plain
|
tests/webtbs/tw30443.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw3045.pp svneol=native#text/plain
|
tests/webtbs/tw3045.pp svneol=native#text/plain
|
||||||
|
tests/webtbs/tw30463.pp svneol=native#text/pascal
|
||||||
tests/webtbs/tw3048.pp svneol=native#text/plain
|
tests/webtbs/tw3048.pp svneol=native#text/plain
|
||||||
tests/webtbs/tw30498.pp svneol=native#text/pascal
|
tests/webtbs/tw30498.pp svneol=native#text/pascal
|
||||||
tests/webtbs/tw30522.pp svneol=native#text/plain
|
tests/webtbs/tw30522.pp svneol=native#text/plain
|
||||||
|
@ -499,6 +499,13 @@ implementation
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ <dyn. array> + <dyn. array> is handled by the compiler }
|
||||||
|
if (treetyp=addn) and (is_dynamic_array(ld) or is_dynamic_array(rd)) then
|
||||||
|
begin
|
||||||
|
allowed:=false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
allowed:=true;
|
allowed:=true;
|
||||||
end;
|
end;
|
||||||
objectdef :
|
objectdef :
|
||||||
|
@ -56,6 +56,7 @@ interface
|
|||||||
{ parts explicitely in the code generator (JM) }
|
{ parts explicitely in the code generator (JM) }
|
||||||
function first_addstring: tnode; virtual;
|
function first_addstring: tnode; virtual;
|
||||||
function first_addset: tnode; virtual;
|
function first_addset: tnode; virtual;
|
||||||
|
function first_adddynarray : tnode; virtual;
|
||||||
{ only implements "muln" nodes, the rest always has to be done in }
|
{ only implements "muln" nodes, the rest always has to be done in }
|
||||||
{ the code generator for performance reasons (JM) }
|
{ the code generator for performance reasons (JM) }
|
||||||
function first_add64bitint: tnode; virtual;
|
function first_add64bitint: tnode; virtual;
|
||||||
@ -1236,12 +1237,12 @@ implementation
|
|||||||
|
|
||||||
{ convert array constructors to sets, because there is no other operator
|
{ convert array constructors to sets, because there is no other operator
|
||||||
possible for array constructors }
|
possible for array constructors }
|
||||||
if is_array_constructor(left.resultdef) then
|
if not(is_dynamic_array(right.resultdef)) and is_array_constructor(left.resultdef) then
|
||||||
begin
|
begin
|
||||||
arrayconstructor_to_set(left);
|
arrayconstructor_to_set(left);
|
||||||
typecheckpass(left);
|
typecheckpass(left);
|
||||||
end;
|
end;
|
||||||
if is_array_constructor(right.resultdef) then
|
if not(is_dynamic_array(left.resultdef)) and is_array_constructor(right.resultdef) then
|
||||||
begin
|
begin
|
||||||
arrayconstructor_to_set(right);
|
arrayconstructor_to_set(right);
|
||||||
typecheckpass(right);
|
typecheckpass(right);
|
||||||
@ -2120,7 +2121,16 @@ implementation
|
|||||||
inserttypeconv_explicit(right,left.resultdef)
|
inserttypeconv_explicit(right,left.resultdef)
|
||||||
end
|
end
|
||||||
|
|
||||||
{ support dynamicarray=nil,dynamicarray<>nil }
|
{ <dyn. array>+<dyn. array> ? }
|
||||||
|
else if (nodetype=addn) and (is_dynamic_array(ld) or is_dynamic_array(rd)) then
|
||||||
|
begin
|
||||||
|
if not(is_dynamic_array(ld)) then
|
||||||
|
inserttypeconv(left,rd);
|
||||||
|
if not(is_dynamic_array(rd)) then
|
||||||
|
inserttypeconv(right,ld);
|
||||||
|
end
|
||||||
|
|
||||||
|
{ support dynamicarray=nil,dynamicarray<>nil }
|
||||||
else if (is_dynamic_array(ld) and (rt=niln)) or
|
else if (is_dynamic_array(ld) and (rt=niln)) or
|
||||||
(is_dynamic_array(rd) and (lt=niln)) or
|
(is_dynamic_array(rd) and (lt=niln)) or
|
||||||
(is_dynamic_array(ld) and is_dynamic_array(rd)) then
|
(is_dynamic_array(ld) and is_dynamic_array(rd)) then
|
||||||
@ -2729,6 +2739,104 @@ implementation
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function taddnode.first_adddynarray : tnode;
|
||||||
|
var
|
||||||
|
p: tnode;
|
||||||
|
newstatement : tstatementnode;
|
||||||
|
tempnode (*,tempnode2*) : ttempcreatenode;
|
||||||
|
cmpfuncname: string;
|
||||||
|
para: tcallparanode;
|
||||||
|
begin
|
||||||
|
result:=nil;
|
||||||
|
{ when we get here, we are sure that both the left and the right }
|
||||||
|
{ node are both strings of the same stringtype (JM) }
|
||||||
|
case nodetype of
|
||||||
|
addn:
|
||||||
|
begin
|
||||||
|
if (left.nodetype=arrayconstructorn) and (tarrayconstructornode(left).isempty) then
|
||||||
|
begin
|
||||||
|
result:=right;
|
||||||
|
left.free;
|
||||||
|
left:=nil;
|
||||||
|
right:=nil;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if (right.nodetype=arrayconstructorn) and (tarrayconstructornode(right).isempty) then
|
||||||
|
begin
|
||||||
|
result:=left;
|
||||||
|
left:=nil;
|
||||||
|
right.free;
|
||||||
|
right:=nil;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
{ create the call to the concat routine both strings as arguments }
|
||||||
|
if assigned(aktassignmentnode) and
|
||||||
|
(aktassignmentnode.right=self) and
|
||||||
|
(aktassignmentnode.left.resultdef=resultdef) and
|
||||||
|
valid_for_var(aktassignmentnode.left,false) then
|
||||||
|
begin
|
||||||
|
para:=ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(right,voidcodepointertype),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(left,voidcodepointertype),
|
||||||
|
ccallparanode.create(
|
||||||
|
caddrnode.create_internal(crttinode.create(tstoreddef(resultdef),initrtti,rdt_normal)),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(aktassignmentnode.left.getcopy,voidcodepointertype),nil)
|
||||||
|
)));
|
||||||
|
result:=ccallnode.createintern(
|
||||||
|
'fpc_dynarray_concat',
|
||||||
|
para
|
||||||
|
);
|
||||||
|
include(aktassignmentnode.flags,nf_assign_done_in_right);
|
||||||
|
firstpass(result);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
result:=internalstatements(newstatement);
|
||||||
|
tempnode:=ctempcreatenode.create(resultdef,resultdef.size,tt_persistent,true);
|
||||||
|
addstatement(newstatement,tempnode);
|
||||||
|
{ initialize the temp, since it will be passed to a
|
||||||
|
var-parameter (and finalization, which is performed by the
|
||||||
|
ttempcreate node and which takes care of the initialization
|
||||||
|
on native targets, is a noop on managed VM targets) }
|
||||||
|
if (target_info.system in systems_managed_vm) and
|
||||||
|
is_managed_type(resultdef) then
|
||||||
|
addstatement(newstatement,cinlinenode.create(in_setlength_x,
|
||||||
|
false,
|
||||||
|
ccallparanode.create(genintconstnode(0),
|
||||||
|
ccallparanode.create(ctemprefnode.create(tempnode),nil))));
|
||||||
|
para:=ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(right,voidcodepointertype),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(left,voidcodepointertype),
|
||||||
|
ccallparanode.create(
|
||||||
|
caddrnode.create_internal(crttinode.create(tstoreddef(resultdef),initrtti,rdt_normal)),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(ctemprefnode.create(tempnode),voidcodepointertype),nil)
|
||||||
|
)));
|
||||||
|
addstatement(
|
||||||
|
newstatement,
|
||||||
|
ccallnode.createintern(
|
||||||
|
'fpc_dynarray_concat',
|
||||||
|
para
|
||||||
|
)
|
||||||
|
);
|
||||||
|
addstatement(newstatement,ctempdeletenode.create_normal_temp(tempnode));
|
||||||
|
addstatement(newstatement,ctemprefnode.create(tempnode));
|
||||||
|
end;
|
||||||
|
{ we reused the arguments }
|
||||||
|
left := nil;
|
||||||
|
right := nil;
|
||||||
|
end;
|
||||||
|
unequaln,equaln:
|
||||||
|
{ nothing to do }
|
||||||
|
;
|
||||||
|
else
|
||||||
|
Internalerror(2018030301);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function taddnode.use_generic_mul32to64: boolean;
|
function taddnode.use_generic_mul32to64: boolean;
|
||||||
begin
|
begin
|
||||||
@ -3218,6 +3326,15 @@ implementation
|
|||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Can we optimize multiple dyn. array additions into a single call?
|
||||||
|
This need to be done on a complete tree to detect the multiple
|
||||||
|
add nodes and is therefor done before the subtrees are processed }
|
||||||
|
if canbemultidynarrayadd(self) then
|
||||||
|
begin
|
||||||
|
result:=genmultidynarrayadd(self);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
{ typical set tests like (s*[const. set])<>/=[] can be converted into an or'ed chain of in tests
|
{ typical set tests like (s*[const. set])<>/=[] can be converted into an or'ed chain of in tests
|
||||||
for var sets if const. set contains only a few elements }
|
for var sets if const. set contains only a few elements }
|
||||||
if (cs_opt_level1 in current_settings.optimizerswitches) and (nodetype in [unequaln,equaln]) and (left.resultdef.typ=setdef) and not(is_smallset(left.resultdef)) then
|
if (cs_opt_level1 in current_settings.optimizerswitches) and (nodetype in [unequaln,equaln]) and (left.resultdef.typ=setdef) and not(is_smallset(left.resultdef)) then
|
||||||
@ -3581,6 +3698,11 @@ implementation
|
|||||||
end
|
end
|
||||||
{$endif SUPPORT_MMX}
|
{$endif SUPPORT_MMX}
|
||||||
|
|
||||||
|
else if is_dynamic_array(ld) or is_dynamic_array(rd) then
|
||||||
|
begin
|
||||||
|
result:=first_adddynarray;
|
||||||
|
exit;
|
||||||
|
end
|
||||||
{ the general solution is to convert to 32 bit int }
|
{ the general solution is to convert to 32 bit int }
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
@ -121,6 +121,7 @@ interface
|
|||||||
function docompare(p: tnode): boolean; override;
|
function docompare(p: tnode): boolean; override;
|
||||||
procedure force_type(def:tdef);
|
procedure force_type(def:tdef);
|
||||||
procedure insert_typeconvs;
|
procedure insert_typeconvs;
|
||||||
|
function isempty : boolean;
|
||||||
end;
|
end;
|
||||||
tarrayconstructornodeclass = class of tarrayconstructornode;
|
tarrayconstructornodeclass = class of tarrayconstructornode;
|
||||||
|
|
||||||
@ -1016,6 +1017,12 @@ implementation
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function tarrayconstructornode.isempty:boolean;
|
||||||
|
begin
|
||||||
|
result:=not(assigned(left)) and not(assigned(right));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function tarrayconstructornode.pass_typecheck:tnode;
|
function tarrayconstructornode.pass_typecheck:tnode;
|
||||||
var
|
var
|
||||||
hdef : tdef;
|
hdef : tdef;
|
||||||
|
@ -76,6 +76,8 @@ function canbeaddsstringcsstringoptnode(p: taddnode): boolean;
|
|||||||
function genaddsstringcsstringoptnode(p: taddnode): tnode;
|
function genaddsstringcsstringoptnode(p: taddnode): tnode;
|
||||||
function canbemultistringadd(p: taddnode): boolean;
|
function canbemultistringadd(p: taddnode): boolean;
|
||||||
function genmultistringadd(p: taddnode): tnode;
|
function genmultistringadd(p: taddnode): tnode;
|
||||||
|
function canbemultidynarrayadd(p: taddnode): boolean;
|
||||||
|
function genmultidynarrayadd(p: taddnode): tnode;
|
||||||
|
|
||||||
|
|
||||||
function is_addsstringoptnode(p: tnode): boolean;
|
function is_addsstringoptnode(p: tnode): boolean;
|
||||||
@ -406,6 +408,97 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function canbemultidynarrayadd(p: taddnode): boolean;
|
||||||
|
var
|
||||||
|
hp : tnode;
|
||||||
|
i : longint;
|
||||||
|
begin
|
||||||
|
result:=false;
|
||||||
|
if not(is_dynamic_array(p.resultdef)) then
|
||||||
|
exit;
|
||||||
|
i:=0;
|
||||||
|
hp:=p;
|
||||||
|
while assigned(hp) and (hp.nodetype=addn) do
|
||||||
|
begin
|
||||||
|
inc(i);
|
||||||
|
hp:=taddnode(hp).left;
|
||||||
|
end;
|
||||||
|
result:=(i>1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function genmultidynarrayadd(p: taddnode): tnode;
|
||||||
|
var
|
||||||
|
hp,sn : tnode;
|
||||||
|
arrp : tarrayconstructornode;
|
||||||
|
newstatement : tstatementnode;
|
||||||
|
tempnode : ttempcreatenode;
|
||||||
|
para : tcallparanode;
|
||||||
|
begin
|
||||||
|
arrp:=nil;
|
||||||
|
hp:=p;
|
||||||
|
while assigned(hp) and (hp.nodetype=addn) do
|
||||||
|
begin
|
||||||
|
sn:=ctypeconvnode.create_internal(taddnode(hp).right.getcopy,voidpointertype);
|
||||||
|
arrp:=carrayconstructornode.create(sn,arrp);
|
||||||
|
hp:=taddnode(hp).left;
|
||||||
|
end;
|
||||||
|
sn:=ctypeconvnode.create_internal(hp.getcopy,voidpointertype);
|
||||||
|
arrp:=carrayconstructornode.create(sn,arrp);
|
||||||
|
arrp.allow_array_constructor:=true;
|
||||||
|
if assigned(aktassignmentnode) and
|
||||||
|
(aktassignmentnode.right=p) and
|
||||||
|
(aktassignmentnode.left.resultdef=p.resultdef) and
|
||||||
|
valid_for_var(aktassignmentnode.left,false) then
|
||||||
|
begin
|
||||||
|
para:=ccallparanode.create(
|
||||||
|
arrp,
|
||||||
|
ccallparanode.create(
|
||||||
|
caddrnode.create_internal(crttinode.create(tstoreddef(p.resultdef),initrtti,rdt_normal)),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(aktassignmentnode.left.getcopy,voidpointertype),nil)
|
||||||
|
));
|
||||||
|
result:=ccallnode.createintern(
|
||||||
|
'fpc_dynarray_concat_multi',
|
||||||
|
para
|
||||||
|
);
|
||||||
|
include(aktassignmentnode.flags,nf_assign_done_in_right);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
result:=internalstatements(newstatement);
|
||||||
|
tempnode:=ctempcreatenode.create(p.resultdef,p.resultdef.size,tt_persistent ,true);
|
||||||
|
addstatement(newstatement,tempnode);
|
||||||
|
{ initialize the temp, since it will be passed to a
|
||||||
|
var-parameter (and finalization, which is performed by the
|
||||||
|
ttempcreate node and which takes care of the initialization
|
||||||
|
on native targets, is a noop on managed VM targets) }
|
||||||
|
if (target_info.system in systems_managed_vm) and
|
||||||
|
is_managed_type(p.resultdef) then
|
||||||
|
addstatement(newstatement,cinlinenode.create(in_setlength_x,
|
||||||
|
false,
|
||||||
|
ccallparanode.create(genintconstnode(0),
|
||||||
|
ccallparanode.create(ctemprefnode.create(tempnode),nil))));
|
||||||
|
para:=ccallparanode.create(
|
||||||
|
arrp,
|
||||||
|
ccallparanode.create(
|
||||||
|
caddrnode.create_internal(crttinode.create(tstoreddef(p.resultdef),initrtti,rdt_normal)),
|
||||||
|
ccallparanode.create(
|
||||||
|
ctypeconvnode.create_internal(ctemprefnode.create(tempnode),voidpointertype),nil)
|
||||||
|
));
|
||||||
|
addstatement(
|
||||||
|
newstatement,
|
||||||
|
ccallnode.createintern(
|
||||||
|
'fpc_dynarray_concat_multi',
|
||||||
|
para
|
||||||
|
)
|
||||||
|
);
|
||||||
|
addstatement(newstatement,ctempdeletenode.create_normal_temp(tempnode));
|
||||||
|
addstatement(newstatement,ctemprefnode.create(tempnode));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
caddsstringcharoptnode := taddsstringcharoptnode;
|
caddsstringcharoptnode := taddsstringcharoptnode;
|
||||||
caddsstringcsstringoptnode := taddsstringcsstringoptnode;
|
caddsstringcsstringoptnode := taddsstringcsstringoptnode;
|
||||||
|
@ -81,6 +81,7 @@ procedure fpc_dynarray_assign(var dest : pointer; src : pointer; ti: pointer); c
|
|||||||
procedure fpc_dynarray_delete(var p : pointer;source,count : SizeInt;pti : pointer);compilerproc;
|
procedure fpc_dynarray_delete(var p : pointer;source,count : SizeInt;pti : pointer);compilerproc;
|
||||||
procedure fpc_dynarray_insert(var p : pointer;source : SizeInt;data : pointer;count : SizeInt;pti : pointer);compilerproc;
|
procedure fpc_dynarray_insert(var p : pointer;source : SizeInt;data : pointer;count : SizeInt;pti : pointer);compilerproc;
|
||||||
procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr:array of pointer); compilerproc;
|
procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr:array of pointer); compilerproc;
|
||||||
|
procedure fpc_dynarray_concat(var dest : pointer; pti: pointer; const src1,src2 : pointer); compilerproc;
|
||||||
{$endif VER3_0}
|
{$endif VER3_0}
|
||||||
{$endif FPC_HAS_FEATURE_DYNARRAYS}
|
{$endif FPC_HAS_FEATURE_DYNARRAYS}
|
||||||
|
|
||||||
|
@ -401,11 +401,7 @@ procedure fpc_dynarray_delete(var p : pointer;source,count : SizeInt;pti : point
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
{ skip kind and name }
|
{ skip kind and name }
|
||||||
{$ifdef VER3_0}
|
|
||||||
ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
|
|
||||||
{$else VER3_0}
|
|
||||||
ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
|
ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
|
||||||
{$endif VER3_0}
|
|
||||||
|
|
||||||
elesize:=pdynarraytypedata(ti)^.elSize;
|
elesize:=pdynarraytypedata(ti)^.elSize;
|
||||||
eletype:=pdynarraytypedata(ti)^.elType2^;
|
eletype:=pdynarraytypedata(ti)^.elType2^;
|
||||||
@ -468,6 +464,7 @@ procedure fpc_dynarray_delete(var p : pointer;source,count : SizeInt;pti : point
|
|||||||
newp^.high:=newhigh;
|
newp^.high:=newhigh;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure fpc_dynarray_insert(var p : pointer;source : SizeInt;data : pointer;count : SizeInt;pti : pointer);compilerproc;
|
procedure fpc_dynarray_insert(var p : pointer;source : SizeInt;data : pointer;count : SizeInt;pti : pointer);compilerproc;
|
||||||
var
|
var
|
||||||
newhigh,
|
newhigh,
|
||||||
@ -501,11 +498,7 @@ procedure fpc_dynarray_insert(var p : pointer;source : SizeInt;data : pointer;co
|
|||||||
source:=0;
|
source:=0;
|
||||||
|
|
||||||
{ skip kind and name }
|
{ skip kind and name }
|
||||||
{$ifdef VER3_0}
|
|
||||||
ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
|
|
||||||
{$else VER3_0}
|
|
||||||
ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
|
ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
|
||||||
{$endif VER3_0}
|
|
||||||
|
|
||||||
elesize:=pdynarraytypedata(ti)^.elSize;
|
elesize:=pdynarraytypedata(ti)^.elSize;
|
||||||
eletype:=pdynarraytypedata(ti)^.elType2^;
|
eletype:=pdynarraytypedata(ti)^.elType2^;
|
||||||
@ -600,6 +593,7 @@ procedure fpc_dynarray_insert(var p : pointer;source : SizeInt;data : pointer;co
|
|||||||
newp^.high:=newhigh;
|
newp^.high:=newhigh;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr:array of pointer); compilerproc;
|
procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr:array of pointer); compilerproc;
|
||||||
var
|
var
|
||||||
i,
|
i,
|
||||||
@ -610,11 +604,8 @@ procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr
|
|||||||
srealp : pdynarray;
|
srealp : pdynarray;
|
||||||
ti : pointer;
|
ti : pointer;
|
||||||
elesize : sizeint;
|
elesize : sizeint;
|
||||||
{eletype,}eletypemngd : pointer;
|
eletypemngd : pointer;
|
||||||
begin
|
begin
|
||||||
{ the destination is overwritten in each case, so clear it }
|
|
||||||
fpc_dynarray_clear(dest,pti);
|
|
||||||
|
|
||||||
{ sanity check }
|
{ sanity check }
|
||||||
if length(sarr)=0 then
|
if length(sarr)=0 then
|
||||||
exit;
|
exit;
|
||||||
@ -622,35 +613,33 @@ procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr
|
|||||||
totallen:=0;
|
totallen:=0;
|
||||||
for i:=0 to high(sarr) do
|
for i:=0 to high(sarr) do
|
||||||
if assigned(sarr[i]) then
|
if assigned(sarr[i]) then
|
||||||
begin
|
inc(totallen,pdynarray(sarr[i]-sizeof(tdynarray))^.high+1);
|
||||||
srealp:=pdynarray(sarr[i]-sizeof(tdynarray));
|
|
||||||
inc(totallen,srealp^.high+1);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if totallen=0 then
|
if totallen=0 then
|
||||||
exit;
|
begin
|
||||||
|
fpc_dynarray_clear(dest,pti);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
{ skip kind and name }
|
{ skip kind and name }
|
||||||
{$ifdef VER3_0}
|
|
||||||
ti:=aligntoptr(Pointer(pti)+2+PByte(pti)[1]);
|
|
||||||
{$else VER3_0}
|
|
||||||
ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
|
ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
|
||||||
{$endif VER3_0}
|
|
||||||
|
|
||||||
elesize:=pdynarraytypedata(ti)^.elSize;
|
elesize:=pdynarraytypedata(ti)^.elSize;
|
||||||
//eletype:=pdynarraytypedata(ti)^.elType2^;
|
|
||||||
{ only set if type needs initialization }
|
{ only set if type needs initialization }
|
||||||
if assigned(pdynarraytypedata(ti)^.elType) then
|
if assigned(pdynarraytypedata(ti)^.elType) then
|
||||||
eletypemngd:=pdynarraytypedata(ti)^.elType^
|
eletypemngd:=pdynarraytypedata(ti)^.elType^
|
||||||
else
|
else
|
||||||
eletypemngd:=nil;
|
eletypemngd:=nil;
|
||||||
|
|
||||||
{ allocate new array }
|
|
||||||
getmem(newp,totallen*elesize+sizeof(tdynarray));
|
|
||||||
fillchar(newp^,sizeof(tdynarray),0);
|
|
||||||
|
|
||||||
{ copy the elements of each source array }
|
{ copy the elements of each source array }
|
||||||
offset:=0;
|
offset:=0;
|
||||||
|
|
||||||
|
{ the idea to reuse the first array, re-allocate it and append the other entries is not possible as the first entry
|
||||||
|
might be finalized later on by the caller however in case of a re-allocate, the entry itself might be gone }
|
||||||
|
{ allocate new array }
|
||||||
|
getmem(newp,totallen*elesize+sizeof(tdynarray));
|
||||||
|
|
||||||
for i:=0 to high(sarr) do
|
for i:=0 to high(sarr) do
|
||||||
if assigned(sarr[i]) then
|
if assigned(sarr[i]) then
|
||||||
begin
|
begin
|
||||||
@ -661,6 +650,79 @@ procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr
|
|||||||
inc(offset,srealp^.high+1);
|
inc(offset,srealp^.high+1);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
{ increase reference counts of all the elements }
|
||||||
|
if assigned(eletypemngd) then
|
||||||
|
begin
|
||||||
|
for i:=0 to totallen-1 do
|
||||||
|
int_addref(pointer(newp)+sizeof(tdynarray)+i*elesize,eletypemngd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ clear at the end, dest could be a reference to an array being used also as source }
|
||||||
|
fpc_dynarray_clear(dest,pti);
|
||||||
|
dest:=pointer(newp)+sizeof(tdynarray);
|
||||||
|
newp^.refcount:=1;
|
||||||
|
newp^.high:=totallen-1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure fpc_dynarray_concat(var dest : pointer; pti: pointer; const src1,src2 : pointer); compilerproc;
|
||||||
|
var
|
||||||
|
i,
|
||||||
|
offset,
|
||||||
|
totallen : sizeint;
|
||||||
|
newp,
|
||||||
|
realp,
|
||||||
|
srealp : pdynarray;
|
||||||
|
ti : pointer;
|
||||||
|
elesize : sizeint;
|
||||||
|
eletypemngd : pointer;
|
||||||
|
begin
|
||||||
|
totallen:=0;
|
||||||
|
if assigned(src1) then
|
||||||
|
inc(totallen,pdynarray(src1-sizeof(tdynarray))^.high+1);
|
||||||
|
if assigned(src2) then
|
||||||
|
inc(totallen,pdynarray(src2-sizeof(tdynarray))^.high+1);
|
||||||
|
|
||||||
|
if totallen=0 then
|
||||||
|
begin
|
||||||
|
fpc_dynarray_clear(dest,pti);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ skip kind and name }
|
||||||
|
ti:=aligntoqword(Pointer(pti)+2+PByte(pti)[1]);
|
||||||
|
|
||||||
|
elesize:=pdynarraytypedata(ti)^.elSize;
|
||||||
|
|
||||||
|
{ only set if type needs initialization }
|
||||||
|
if assigned(pdynarraytypedata(ti)^.elType) then
|
||||||
|
eletypemngd:=pdynarraytypedata(ti)^.elType^
|
||||||
|
else
|
||||||
|
eletypemngd:=nil;
|
||||||
|
|
||||||
|
{ the idea to reuse the first array, re-allocate it and append the other entries is not possible as the first entry
|
||||||
|
might be finalized later on by the caller however in case of a re-allocate, the entry itself might be gone }
|
||||||
|
{ allocate new array }
|
||||||
|
getmem(newp,totallen*elesize+sizeof(tdynarray));
|
||||||
|
|
||||||
|
{ copy the elements of each source array }
|
||||||
|
offset:=0;
|
||||||
|
if assigned(src1) then
|
||||||
|
begin
|
||||||
|
srealp:=pdynarray(src1-sizeof(tdynarray));
|
||||||
|
if srealp^.high>=0 then
|
||||||
|
begin
|
||||||
|
move(src1^,(pointer(newp)+sizeof(tdynarray)+offset*elesize)^,(srealp^.high+1)*elesize);
|
||||||
|
inc(offset,srealp^.high+1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if assigned(src2) then
|
||||||
|
begin
|
||||||
|
srealp:=pdynarray(src2-sizeof(tdynarray));
|
||||||
|
if srealp^.high>=0 then
|
||||||
|
move(src2^,(pointer(newp)+sizeof(tdynarray)+offset*elesize)^,(srealp^.high+1)*elesize);
|
||||||
|
end;
|
||||||
|
|
||||||
{ increase reference counts of all the elements }
|
{ increase reference counts of all the elements }
|
||||||
if assigned(eletypemngd) then
|
if assigned(eletypemngd) then
|
||||||
@ -669,6 +731,8 @@ procedure fpc_dynarray_concat_multi(var dest : pointer; pti: pointer; const sarr
|
|||||||
int_addref(pointer(newp)+sizeof(tdynarray)+i*elesize,eletypemngd);
|
int_addref(pointer(newp)+sizeof(tdynarray)+i*elesize,eletypemngd);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ clear at the end, dest could be a reference to an array being also source }
|
||||||
|
fpc_dynarray_clear(dest,pti);
|
||||||
dest:=pointer(newp)+sizeof(tdynarray);
|
dest:=pointer(newp)+sizeof(tdynarray);
|
||||||
newp^.refcount:=1;
|
newp^.refcount:=1;
|
||||||
newp^.high:=totallen-1;
|
newp^.high:=totallen-1;
|
||||||
|
46
tests/webtbs/tw30463.pp
Normal file
46
tests/webtbs/tw30463.pp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{$mode objfpc}
|
||||||
|
procedure p1;
|
||||||
|
var
|
||||||
|
A: array of Integer;
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
A := [];
|
||||||
|
A := A + A;
|
||||||
|
A := Concat(A,[123456789]);
|
||||||
|
A := A + [6];
|
||||||
|
A := A + A;
|
||||||
|
|
||||||
|
if A[0]<>123456789 then
|
||||||
|
Halt(1);
|
||||||
|
if A[High(A)]<>6 then
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure p2;
|
||||||
|
var
|
||||||
|
A, B, C: array of Integer;
|
||||||
|
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
A := [];
|
||||||
|
A := A + A + A;
|
||||||
|
A := Concat(A,[123456789],[8]);
|
||||||
|
A := A + [6] + A;
|
||||||
|
A := A + A + A;
|
||||||
|
B:=copy(A);
|
||||||
|
C:=B+A;
|
||||||
|
|
||||||
|
if C[0]<>123456789 then
|
||||||
|
Halt(1);
|
||||||
|
if C[High(C)]<>8 then
|
||||||
|
Halt(1);
|
||||||
|
if C[High(C)-1]<>123456789 then
|
||||||
|
Halt(1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
// p1;
|
||||||
|
p2;
|
||||||
|
writeln('ok');
|
||||||
|
end.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user