SRL Archive - Suggestions

Wrapper for FloodFillTPA


riwu

2012-11-13 04:36:40

Currently it is impossible to use FloodFillTPA in PS due to memory leak issue.

I'm trying to replicate FloodFillTPA to prevent memory leak (and hopefully it'll not be slowed down too much), but there isn't a procedure in PS for FillChar? Anyone know the source code for FillChar? Tried searching for it but all i get is explanation of usage and not the actual code. Or is it not actually needed in PS as the data is already initialized by SetLength?

Also does anyone know how FloodFillTPA works? Not really sure if i completely understood it…

A replacement for FillChar is all i need to get this working on scripts.

function FloodFillTPA2(const TPA : TPointArray) : T2DPointArray;
var
x,y,i,CurrentArray, LengthTPA,CurrentStack : integer;
TempBox : TBox;
PointsToFill : array of TBoolArray;
Lengths : TIntegerArray;
TempTPA : TPointArray;
Stack : TPointArray;
fx,fy : integer;
begin;
LengthTPA := High(TPA);
if LengthTPA < 1 then
begin;
if LengthTPA = 0 then
begin;
SetLength(Result,1);
SetLength(Result[0], 1);
Result[0][0] := TPA[0];
end else
SetLength(Result,0);
exit;
end;
TempBox := GetTPABounds(TPA);
SetLength(PointsToFill,TempBox.x2 - TempBox.x1+3); //W + 2, H + 2 so that we can check the borders
for i:=0 to High(PointsToFill) do
SetLength(PointsToFill[i], TempBox.y2 - TempBox.y1+3);

fy := TempBox.y2 - TempBox.y1+3;
fx := TempBox.x2 - TempBox.x1+2;
for i := 0 to fx do
FillChar(PointsToFill[i][0],fy,0);
x := TempBox.x1 - 1;
y := TempBox.y1 - 1;
CurrentArray := -1;
SetLength(Stack , LengthTPA + 1);
SetLength(Lengths , LengthTPA + 1);
SetLength(TempTPA , LengthTPA + 1);
for I := 0 to LengthTPA do
begin;
TempTPA[I].x := TPA[I].x - x;
TempTPA[I].y := TPA[I].y - y;
end;
for I := 0 to LengthTPA do
PointsToFill[TempTPA[I].x][TempTPA[I].y] := True;
for I := 0 to LengthTPA do
if PointsToFill[TempTPA[I].x][TempTPA[I].y] then
begin;
PointsToFill[TempTPA[i].x][TempTPA[i].y] := false;
inc(CurrentArray);
SetLength(Result,CurrentArray + 1);
SetLength(Result[CurrentArray],LengthTPA - I + 1);
Lengths[CurrentArray] := 0;
CurrentStack := 0;
Stack[0].x := TempTPA[I].x;
Stack[0].y := TempTPA[I].y;
While CurrentStack > -1 do
begin;
fx := stack[CurrentStack].x;
fy := stack[CurrentStack].y;
dec(CurrentStack);
Result[CurrentArray][Lengths[CurrentArray]].x := fx + x;
Result[CurrentArray][Lengths[CurrentArray]].y := fy + y;
inc(Lengths[CurrentArray]);
if PointsToFill[fx+1][fy] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy;PointsToFill[fx+1][fy] := false;
end;
if PointsToFill[fx][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx;Stack[Currentstack].y := fy+1;PointsToFill[fx][fy+1] := false;
end;
if PointsToFill[fx-1][fy] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy;PointsToFill[fx-1][fy] := false;
end;
if PointsToFill[fx][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx;Stack[Currentstack].y := fy-1;PointsToFill[fx][fy-1] := false;
end;
if PointsToFill[fx+1][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy+1;PointsToFill[fx+1][fy+1] := false;
end;
if PointsToFill[fx-1][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy-1;PointsToFill[fx-1][fy-1] := false;
end;
if PointsToFill[fx-1][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy+1;PointsToFill[fx-1][fy+1] := false;
end;
if PointsToFill[fx+1][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy-1;PointsToFill[fx+1][fy-1] := false;
end;
end;
SetLength(Result[CurrentArray],Lengths[CurrentArray]);
end;
SetLength(Stack,0);
SetLength(TempTPA,0);
SetLength(Lengths,0);
end;

nokkasiili

2012-11-13 04:57:52

for y  := -1 to 1 do
for x := -1 to 1 do
if PointsToFill[fx+x][fy+y] then
use something like this to replace that block of ifs

riwu

2012-11-13 05:08:19

From: nokkasiili
for y  := -1 to 1 do
for x := -1 to 1 do
if PointsToFill[fx+x][fy+y] then
use something like this to replace that block of ifs

The actual code is like that; i believe the lack of uniformity/pattern in the fx fy 'pairing' make using a loop impossible.

It could possibly be simplified with a customized T2DIntegerArray though, but no point editing something that has already been done.

nokkasiili

2012-11-13 05:11:22

From: riwu
The actual code is like that; i believe the lack of uniformity/pattern in both the fx fy pairing and variables to be inc would make using a loop like the above impossible.


You can skip 0,0.
Is there any reason why you cant use := in loop instead of fillchar

masterBB

2012-11-13 05:29:50

FillChar(PointsToFill[0],fy,0);

is

SetLength(PointsToFill, fy);
(source)

Also I can help you with this. Shall I explain you how to create a wrapper yourself or do you want to know how floodfillTPA works?

riwu

2012-11-13 05:44:49

From: masterBB
FillChar(PointsToFill[0],fy,0);

is

SetLength(PointsToFill, fy);
(source)

Also I can help you with this. Shall I explain you how to create a wrapper yourself or do you want to know how floodfillTPA works?

So i can just take out the FillChar since i already have
for i:=0 to High(PointsToFill) do
SetLength(PointsToFill[i], TempBox.y2 - TempBox.y1+3);

If i copy the function into my script wouldn't that already prevent leak since you told me that only function results passed from Simba would cause leaks?
If it were to be implemented into Simba guess it'll just need something like this?

procedure FloodFillTPAWrap(const TPA: TPointArray; out ATPA: T2DPointArray);
begin
ATPA:= FloodFillTPA(TPA);
end;


And yes, would be good if you can explain how FloodFillTPA works :)

masterBB

2012-11-13 08:44:10

I will explain the internal workings of FloodFill as soon as I am home. For now I will post which files you have to edit.

https://github.com/MerlijnWajer/Simba/blob/master/Units/MMLAddon/PSInc/Wrappers/tpa.inc

Add your function in the following form:

procedure ps_FloodFillTPAWrap(const TPA : TPointArray; var Res : T2DPointArray); extdecl;begin  Res := FloodFillTPA(TPA);end;

https://github.com/MerlijnWajer/Simba/blob/master/Units/MMLAddon/PSInc/psexportedmethods.inc

Add it here too:


AddFunction(@ps_FloodFillTPAWrap,'procedure FloodFillTPAWrap(const TPA : TPointArray; var Res : T2DPointArray);');

You can also add it too lape, but since lape doesn't leak it doesn't seem nes. to me.

riwu

2012-11-13 09:04:24

So i'll have to edit the Simba source code and then compile my own version of Simba…? I don't really understand how Simba works, where are all these TPA functions stored in? There's only libsmart, sps dll in the Plugins folder?

masterBB

2012-11-13 10:13:40

I am just done with my exam, I will head home in 20 minutes, 100 minutes of travel, 60 for cooking and eating. So uhm, in about three hours I will have time to explain it better.

All the simba functions are stored in the folder units/MMLCore . Note that the TPA functions are stored in tpa.pas.

However to add the functions to pascalscript you will have to export them in MMLAddon. In my previous post I showed you where to do that. Note that Ps is pascalscript and lp is Lape.

Olly

2012-11-13 11:01:05

From: masterBB
I will head home 100 minutes of travel,


Totally off topic but ouch :p

KingKong

2012-11-13 20:01:07

I dont see why you need to use wrappers at all nor why everyone thinks why its hard to get rid of memory leaks. All you need to do is setlength(tpa/atpa/arraytype, 0) and all memory leaks are gone. The memory leak occurs because the reference count is not decremented when the variable goes out of scope(why its not decremented, ask the simba devs, its the way the functions are implemented)


program new;
var
tpa: TPointarray;
i: Integer;
atpa: T2dpointarray;
begin
setlength(tpa, 1000);
writeln(length(tpa));
for i := 0 to 999 do
begin
tpa[i].x := i;
tpa[i].y := i;
end;
for i:= 0 to 5000 do
begin
//atpa := TPAtoATPA(tpa, 2);
atpa := floodfilltpa(tpa);
setlength(atpa, 0); //comment this line and you have memory leak
end;
end.

riwu

2012-11-13 22:42:41

From: KingKong
I dont see why you need to use wrappers at all nor why everyone thinks why its hard to get rid of memory leaks. All you need to do is setlength(tpa/atpa/arraytype, 0) and all memory leaks are gone. The memory leak occurs because the reference count is not decremented when the variable goes out of scope(why its not decremented, ask the simba devs, its the way the functions are implemented)

Thanks! That works!
tempATPA:= FloodFillTPA(TPA);
ATPA:= tempATPA;
SetLength(tempATPA, 0);
Is that the right way to do it?
The 3MB/call problem is gone now, but there is still some super minor few MB/hr leak in my WF script. I used wrapper for all tpa functions, and freed dtm/bitmaps properly. Any idea what it could be?

KingKong

2012-11-14 01:23:34

From: riwu
Thanks! That works!
tempATPA:= FloodFillTPA(TPA);
ATPA:= tempATPA;
SetLength(tempATPA, 0);
Is that the right way to do it?
The 3MB/call problem is gone now, but there is still some super minor few MB/hr leak in my WF script. I used wrapper for all tpa functions, and freed dtm/bitmaps properly. Any idea what it could be?


without looking at the script i can't tell you where the problem could be, but make sure you call setlength on all array types that are the result of another function.

masterBB

2012-11-14 09:46:24

The working of FloodFillTPA

On request, I will explain in short how FloodFillTPA works, both in code and function. I include the source of this function at the bottom, as well as a few stuff I used to display it better. I suggest holding the code of the function next to this walk through.

function FloodFillTPA2(const TPA : TPointArray) : T2DPointArray;

So the TPA we will give to this function as the parameter is:
[INDENT]const TPA: TPointArray[/INDENT]

If you wonder how the TPA looks within simba:
[{X = 10, Y = 0}, {X = 11, Y = 0}, {X = 12, Y = 0}, {X = 1, Y = 1}, {X = 9, Y = 1}, {X = 10, Y = 1}, {X = 11, Y = 1}, {X = 12, Y = 1}, {X = 1, Y = 2}, {X = 2, Y = 2}, {X = 3, Y = 2}, {X = 8, Y = 2}, {X = 9, Y = 2}, {X = 10, Y = 2}, {X = 11, Y = 2}, {X = 12, Y = 2}, {X = 2, Y = 3}, {X = 3, Y = 3}, {X = 7, Y = 3}, {X = 8, Y = 3}, {X = 2, Y = 4}, {X = 3, Y = 4}, {X = 7, Y = 4}, {X = 15, Y = 4}, {X = 16, Y = 4}, {X = 17, Y = 4}, {X = 2, Y = 5}, {X = 7, Y = 5}, {X = 14, Y = 5}, {X = 15, Y = 5}, {X = 16, Y = 5}, {X = 17, Y = 5}, {X = 2, Y = 6}, {X = 13, Y = 6}, {X = 14, Y = 6}, {X = 15, Y = 6}, {X = 16, Y = 6}, {X = 17, Y = 6}, {X = 18, Y = 6}, {X = 8, Y = 7}, {X = 12, Y = 7}, {X = 13, Y = 7}, {X = 14, Y = 7}, {X = 15, Y = 7}, {X = 16, Y = 7}, {X = 17, Y = 7}, {X = 18, Y = 7}, {X = 6, Y = 8}, {X = 7, Y = 8}, {X = 8, Y = 8}, {X = 12, Y = 8}, {X = 13, Y = 8}, {X = 14, Y = 8}, {X = 15, Y = 8}, {X = 16, Y = 8}, {X = 17, Y = 8}, {X = 18, Y = 8}, {X = 3, Y = 9}, {X = 4, Y = 9}, {X = 5, Y = 9}, {X = 6, Y = 9}, {X = 7, Y = 9}, {X = 12, Y = 9}, {X = 13, Y = 9}, {X = 14, Y = 9}, {X = 15, Y = 9}, {X = 16, Y = 9}, {X = 17, Y = 9}, {X = 2, Y = 10}, {X = 3, Y = 10}, {X = 4, Y = 10}, {X = 5, Y = 10}, {X = 6, Y = 10}, {X = 13, Y = 10}, {X = 14, Y = 10}, {X = 15, Y = 10}, {X = 4, Y = 11}, {X = 5, Y = 11}, {X = 6, Y = 11}, {X = 11, Y = 13}, {X = 12, Y = 13}, {X = 13, Y = 13}, {X = 14, Y = 13}, {X = 15, Y = 13}, {X = 4, Y = 14}, {X = 5, Y = 14}, {X = 6, Y = 14}, {X = 7, Y = 14}, {X = 8, Y = 14}, {X = 9, Y = 14}, {X = 10, Y = 14}, {X = 13, Y = 14}, {X = 14, Y = 14}, {X = 15, Y = 14}, {X = 16, Y = 14}, {X = 3, Y = 15}, {X = 4, Y = 15}, {X = 5, Y = 15}, {X = 6, Y = 15}, {X = 7, Y = 15}, {X = 8, Y = 15}, {X = 9, Y = 15}, {X = 10, Y = 15}, {X = 14, Y = 15}, {X = 15, Y = 15}, {X = 16, Y = 15}, {X = 17, Y = 15}, {X = 2, Y = 16}, {X = 3, Y = 16}, {X = 4, Y = 16}, {X = 5, Y = 16}, {X = 6, Y = 16}, {X = 7, Y = 16}, {X = 8, Y = 16}, {X = 9, Y = 16}, {X = 10, Y = 16}, {X = 14, Y = 16}, {X = 15, Y = 16}, {X = 16, Y = 16}, {X = 17, Y = 16}, {X = 2, Y = 17}, {X = 3, Y = 17}, {X = 4, Y = 17}, {X = 5, Y = 17}, {X = 6, Y = 17}, {X = 7, Y = 17}, {X = 8, Y = 17}, {X = 9, Y = 17}, {X = 10, Y = 17}, {X = 15, Y = 17}, {X = 16, Y = 17}, {X = 17, Y = 17}, {X = 1, Y = 18}, {X = 2, Y = 18}, {X = 3, Y = 18}, {X = 4, Y = 18}, {X = 5, Y = 18}, {X = 6, Y = 18}, {X = 7, Y = 18}, {X = 8, Y = 18}, {X = 9, Y = 18}, {X = 15, Y = 18}, {X = 16, Y = 18}, {X = 3, Y = 19}, {X = 4, Y = 19}, {X = 5, Y = 19}]

The next thing we will do is create a 2D Array of Boolean, where we will set all the points that needs to be filled to true. That are all the points from the above TPA.

[INDENT]var PointsToFill: Array of Array of Boolean[/INDENT]

The big pro is that if you want to know if a point needs to be filled is that you can easily check it up by going to the right row and column and check if it is true or false. In the original TPA you would have to loop through each point. Also note how much easier it is to set one element in the 2DBooleanArray to false compare to removing one point of the TPA.

One might note the comment stating that the width and height of this Array are 2 bigger then required. This is done because while looping we can just check these points, see that they are false and skip them. Instead of having an if/else structure searching for the borders. You will see this later on, when we are really floodfilling stuff. So the actual PointsToFill Array looks like this:

[INDENT]var PointsToFill: Array of Array of Boolean[/INDENT]

Well we are done with preparing. Let's start to flood fill!

for I := 0 to LengthTPA do
[INDENT]if PointsToFill[TempTPA.x][TempTPA.y] then[/INDENT]


We will loop through every point in the original array and looks if it is true in the PointsToFill variable. In the first run of this loop it will always be true because we just set it to true in PointsToFill earlier.

Stack[0].x := TempTPA.x;
Stack[0].y := TempTPA.y;


We add the first point to the stack. The Stack is the array of points we will loop through while filling. In this example we will fill the Stack five times. One for every object we found. The stack is added to the result as one of the arrays.

While CurrentStack > -1 do

CurrenStack is an integer used to indicate which are checked and which not. Stack[currentStack] is the point we will be checking the surroundings of.

if PointsToFill[fx+1][fy] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy;PointsToFill[fx+1][fy] := false;
end;
if PointsToFill[fx][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx;Stack[Currentstack].y := fy+1;PointsToFill[fx][fy+1] := false;
end;
if PointsToFill[fx-1][fy] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy;PointsToFill[fx-1][fy] := false;
end;
if PointsToFill[fx][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx;Stack[Currentstack].y := fy-1;PointsToFill[fx][fy-1] := false;
end;
if PointsToFill[fx+1][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy+1;PointsToFill[fx+1][fy+1] := false;
end;
if PointsToFill[fx-1][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy-1;PointsToFill[fx-1][fy-1] := false;
end;
if PointsToFill[fx-1][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy+1;PointsToFill[fx-1][fy+1] := false;
end;
if PointsToFill[fx+1][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy-1;PointsToFill[fx+1][fy-1] := false;
end;

Actually checks the surroundings of the point it currently is checking out. Note that it checks in all the eight directions. It will add the found points to the Stack if it is True within PointsToFill(Green in my images).

[INDENT]Step by step looping though the stack.[/INDENT]

function FloodFillTPA2(const TPA : TPointArray) : T2DPointArray;
var
x,y,i,CurrentArray, LengthTPA,CurrentStack : integer;
TempBox : TBox;
PointsToFill : array of TBoolArray;
Lengths : TIntegerArray;
TempTPA : TPointArray;
Stack : TPointArray;
fx,fy : integer;
begin;
LengthTPA := High(TPA);
if LengthTPA < 1 then
begin;
if LengthTPA = 0 then
begin;
SetLength(Result,1);
SetLength(Result[0], 1);
Result[0][0] := TPA[0];
end else
SetLength(Result,0);
exit;
end;
TempBox := GetTPABounds(TPA);
SetLength(PointsToFill,TempBox.x2 - TempBox.x1+3); //W + 2, H + 2 so that we can check the borders
for i:=0 to High(PointsToFill) do
SetLength(PointsToFill[i], TempBox.y2 - TempBox.y1+3);

fy := TempBox.y2 - TempBox.y1+3;
fx := TempBox.x2 - TempBox.x1+2;
for i := 0 to fx do
FillChar(PointsToFill[i][0],fy,0);
x := TempBox.x1 - 1;
y := TempBox.y1 - 1;
CurrentArray := -1;
SetLength(Stack , LengthTPA + 1);
SetLength(Lengths , LengthTPA + 1);
SetLength(TempTPA , LengthTPA + 1);
for I := 0 to LengthTPA do
begin;
TempTPA[I].x := TPA[I].x - x;
TempTPA[I].y := TPA[I].y - y;
end;
for I := 0 to LengthTPA do
PointsToFill[TempTPA[I].x][TempTPA[I].y] := True;
for I := 0 to LengthTPA do
if PointsToFill[TempTPA[I].x][TempTPA[I].y] then
begin;
PointsToFill[TempTPA[i].x][TempTPA[i].y] := false;
inc(CurrentArray);
SetLength(Result,CurrentArray + 1);
SetLength(Result[CurrentArray],LengthTPA - I + 1);
Lengths[CurrentArray] := 0;
CurrentStack := 0;
Stack[0].x := TempTPA[I].x;
Stack[0].y := TempTPA[I].y;
While CurrentStack > -1 do
begin;
fx := stack[CurrentStack].x;
fy := stack[CurrentStack].y;
dec(CurrentStack);
Result[CurrentArray][Lengths[CurrentArray]].x := fx + x;
Result[CurrentArray][Lengths[CurrentArray]].y := fy + y;
inc(Lengths[CurrentArray]);
if PointsToFill[fx+1][fy] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy;PointsToFill[fx+1][fy] := false;
end;
if PointsToFill[fx][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx;Stack[Currentstack].y := fy+1;PointsToFill[fx][fy+1] := false;
end;
if PointsToFill[fx-1][fy] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy;PointsToFill[fx-1][fy] := false;
end;
if PointsToFill[fx][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx;Stack[Currentstack].y := fy-1;PointsToFill[fx][fy-1] := false;
end;
if PointsToFill[fx+1][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy+1;PointsToFill[fx+1][fy+1] := false;
end;
if PointsToFill[fx-1][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy-1;PointsToFill[fx-1][fy-1] := false;
end;
if PointsToFill[fx-1][fy+1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx-1;Stack[Currentstack].y := fy+1;PointsToFill[fx-1][fy+1] := false;
end;
if PointsToFill[fx+1][fy-1] then
begin
inc(CurrentStack);Stack[CurrentStack].x := fx+1;Stack[Currentstack].y := fy-1;PointsToFill[fx+1][fy-1] := false;
end;
end;
SetLength(Result[CurrentArray],Lengths[CurrentArray]);
end;
SetLength(Stack,0);
SetLength(TempTPA,0);
SetLength(Lengths,0);
end;

From: KingKong
(why its not decremented, ask the simba devs, its the way the functions are implemented)


How about it is pascalscript not simba which is doing that… -_- So how about asking the pascalscript devs. Nielsie created LAPE, which doesn't got that problem.

J J

2012-11-14 10:17:00

In addition to MasterBB's helpful post, here is a topic where I posted some Flood fill snippets.
http://villavu.com/forum/showthread.php?t=87769

riwu

2012-11-15 00:37:59

From: masterBB
The working of FloodFillTPA

Thanks for the wonderful explanation! Very innovative to convert the TPA to T2DBool.

Am i right to say that FloodFillTPA is basically SplitTPA(TPA, 1), but much faster due to it dealing with T2DBool rather than TPA?

Why don't the function give the option of expanding search region of each stack by checking further (fx-2, fx-3 etc), hence giving it the same flexibility of SplitTPA?

Also why
fx := TempBox.x2 - TempBox.x1+2;
It makes sense to add 3 like what it did earlier on, 1 to account for the intrinsic nature of subtraction (there are (100-1)+1 elements from 1 to 100), and 2 to add 1 to each side.

EDIT: understand it now, 1 less than length since it's used for the loop (which starts from 0) to FillChar.

What are you trying to show in the attachment though? :confused:

Regarding the PS leak, does it mean that ALL functions passed from Simba, even simpler ones like GetColor, CountColor, IntToBox, ToStr, DTM/BitmapFromString, (insert endless list here) would leak?! That would really cause some serious leaks across all scripts?

Markus

2012-11-15 06:43:37

Only functions which return an array of a record, which in practice are only a couple of (A)TPA functions.
And yea it does cause some trouble, code 8 anyone?

riwu

2012-11-15 08:48:15

From: Markus
Only functions which return an array of a record, which in practice are only a couple of (A)TPA functions.
And yea it does cause some trouble, code 8 anyone?

Oh that makes things simpler then. I set up the RAYMONDPOWNS and added every single wrapper functions, seems like all leaks are gone now :)