Re: [fpc-pascal] FPReport: Split text across two or more pages

2024-01-02 Thread Pique7 via fpc-pascal
On Tue, 2 Jan 2024 00:02:35 +0100 (CET)
Michael Van Canneyt via fpc-pascal  wrote:

>
>
> On Mon, 1 Jan 2024, Pique7 via fpc-pascal wrote:
>
> > Hello everyone,
> >
> > I have already asked this and related questions in the Lazarus Forum.
> >
> > I want to improve FPReport in order to use it for my project - if possible.
> > Some features are missing for this, e.g. automatic splitting of text across 
> > two or more pages.
> >
> > As far as I can judge, the current development status of FPReport does not 
> > really allow me to extend it without modifying the original classes.
>
> Why do you think so ?

Thanks for your reply. I am not sure whether I have defined the problem 
correctly from my point of view.
I have tried both FPReport and LazReport. LazReport is able to create page 
breaks within a band automatically (though not always correctly calculated). 
This is traceable by viewing the source code of LazReport. I haven't found 
anything similar in the source code of FPReport and thus considered to 
implement it myself. But I haven't found a straightforward solution.

>
> > What approach do you suggest? Would this be feasible/reasonable at all? I 
> > ask this because I am new to Lazarus and FPC. I come from Delphi 2007 ...
>
> If you ask me, it's perfectly doable without any changes.
>
> There is a demo that shows how to print a text by splitting it in lines, and
> simply printing a band per line. That will have the same effect as what you
> seem to need.  Basically, it means using a TStringList as a data source
> for a (sub)band instead of using it as the text of a single memo.

Unfortunately I couldn't find the demo program you mention. I know the fcl 
demos in "source\packages\fcl-report\demos". Admittedly I haven't examined 
every single unit yet. Most of the demo reports get the data from a 
TStringList. Is it this what is meant?

>
> What you may need to do is to split the text "correctly" over the lines of the
> TStringList, but that should be easily doable. All you need is a function to
> calculate the length of the text.
>
> I think this is perfectly doable without any changes to the original code.

Okay, probably you're right and I think I understand the basic idea but I still 
don't know how to transfer it to my case. I have a table with several columns 
containing multiline text. The data comes from a TDataSet descendent. If one 
the cells (Memo) content is to large to fit on the current page, the whole band 
should be split at the correct position and continued on the next page, e.g.:

[PAGE 1 - DATABAND 1 (bottom of page)]
COL 1-1  COL 2-1
COL 1-2  COL 2-2
COL 1-3  COL 2-3

[PAGE 2 - DATABAND 1 (continued)]
COL 1-4  COL 2-4
COL 1-5

I also have one report with one column containing richtext (RTF). I doubt that 
the TStringList solution will be helpful in this case.

So in a nutshell, I think I need a function like "Continue (data) band on the 
next page if remaining space is insufficient".
If you still think your suggested approach is suitable, please let me know. 
Maybe it is obvious, but at the moment it seems that I don't make any progress.

>
> Michael.
> ___
> fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] How to avoid Copy

2024-01-02 Thread Sven Barth via fpc-pascal

Am 01.01.2024 um 16:51 schrieb Wayne Sherman via fpc-pascal:

On Mon, Jan 1, 2024 at 6:14 AM Hairy Pixels wrote:

On Jan 1, 2024, at 3:50 PM, Michael Van Canneyt wrote:
You can't optimize that. As said, a generic is convenient but slow.

I don't know about that. Like was mentioned the enumerator needs to return a
pointer, preferable without ^ so it feels like a record and only use that in 
the for-in
scope. You can kind of do that yourself but it's cumbersome to maintain and
missing from the RTL (maybe for this reason).

Modern Pascal compilers already do this for certain types and pass by
reference parameters.  For example, AnsiString variables and variables
of type class are handled internally as pointers, but manipulated
opaquely without explicit pointer notation.  A record passed as a var
or constref parameter is internally a pointer, but does not require
the code writer to handle it explicitly as such.
That kind of concept only exists in Pascal for parameters, but not for 
variables or result values as would be needed for this.


Regards,
Sven___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] How to avoid Copy

2024-01-02 Thread Sven Barth via fpc-pascal

Am 31.12.2023 um 04:11 schrieb Amir--- via fpc-pascal:


On 12/30/23 00:20, Sven Barth via fpc-pascal wrote:
Amir via fpc-pascal  schrieb am Sa., 
30. Dez. 2023, 08:11:




On Dec 29, 2023 9:50 PM, Adriaan van Os  wrote:

Amir--- via fpc-pascal wrote:
> Hi all,
>
>  I have a List of record, where the record has a WideString
field.
>   I have some code like the following:
>
> function check(constref v: TMyRecord; data:
TListOfMyRecord): Boolean;
> var
>   r: TMyRecord;
>
> begin
>   Result := False;
>   for r in data do
> if r.State = v.State then
>   Exit(True);
> end;
>
> I call this method a lot and the CPU profiling shows a lot
of cpu time
> spent on "fpc_copy_proc" (which I assume is doing the deep
copy on
> records) from "TCustomListEnumerator.GetCurrent".
> I considered other alternatives like using enumerators but
they all need
> a to return a record (and hence copying the widestring field).
> I can think of two solutions to get rid of the wasting(!)
so much time
> on "fpc_copy_proc":
> 1) Changing the TMyRecord to TMyClass. But then I need to
Create and
> Free a "lot" of objects.
> 2) Update TListOfMyRecord to TListOfPointerToMyRecord. This
requires a
> "lot" of memory allocation/fragmentation.
>
> Is there a better solution?

Pass the data parameter by reference.

This means I need to have a ListOfMyRecord and a
ListOfConstRefMyRecord, right?


No, that's not a thing.

You simply need to declare your "data" parameter as "constref" or 
"const" as well, just like your "v" parameter.

Have a look at this piece of code (The complete code is attached):
type
  TMyRecord = record
    Str: AnsiString;
    Index: Integer;

  end;
  PMyRecord = ^TMyRecord;

  TMyList = specialize TList;
  TMyPtrList = specialize TList;

function Check1(const MyList: TMyList): Integer;
var
   data: TMyRecord;

begin
  Result := 0;
  for data in MyList do
    if data.Index mod 100 = 0 then
  Inc(Result);

end;

function Check2(MyList: TMyList): Integer;
var
   data: TMyRecord;

begin
  Result := 0;
  for data in MyList do
    if data.Index mod 100 = 0 then
  Inc(Result);

end;

function Check3(MyPtrList: TMyPtrList): Integer;
var
   data: PMyRecord;

begin
  Result := 0;
  for data in MyPtrList do
    if data^.Index mod 100 = 0 then
  Inc(Result);

end;


I compiled the code with `fpc -O3 -Sd -gv -g -gl ` and ran `valgrind` 
on it (the output is attached). It does not look like there is a big 
difference between the Check1 and Check2 but Check3 is about 20 times 
faster than the other two.


For a class type there isn't much difference between being passed as 
"const" or not. It's mainly records and managed types this affects.


I believe the issue could be resolved if we make 
"TCustomListWithPointers.GetPtrEnumerator" a public method. Then, one 
can implement the following function:


function Check4(MyList: TMyList): Integer;

  it := MyList.GetPreEnumerator;
  while it.MoveNext do
  begin
    if it.Current^.Index mod 100 = 0 then
 
  end;


You simply need to inherit from the list class so that you can make the 
function public. And with a little trick you can also use it inside a 
for-in-loop:


=== code begin ===

program tlistitr;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}

uses
  Generics.Collections;

type
  TRec = record
    a, b, c: Int64;
    constructor Create(aArg1, aArg2, aArg3: Int64);
  end;

  { this way the GetPtrEnumerator function is available; you could also 
use a class helper }

  TMyList = class(specialize TList)
  public
    function GetPtrEnumerator: specialize TEnumerator;
  end;

constructor TRec.Create(aArg1, aArg2, aArg3: Int64);
begin
  a := aArg1;
  b := aArg2;
  c := aArg3;
end;

function TMyList.GetPtrEnumerator: specialize TEnumerator;
begin
  Result := inherited GetPtrEnumerator();
end;

{ with this you can simply do "for PtrTypeVar in List.GetPtrEnumerator do",
  though this *might* not work in mode Delphi... }
operator Enumerator(aEnum: specialize TEnumerator): 
specialize TEnumerator;

begin
  Result := aEnum;
end;

var
  l: TMyList;
  r: TRec;
  p: TMyList.PT;
begin
  l := TMyList.Create;
  l.Add(TRec.Create(1, 2, 3));
  l.Add(TRec.Create(9, 8, 7));
  for p in l.GetPtrEnumerator do begin
    Writeln(p^.a, ' ', p^.b, ' ', p^.c);
  end;
end.

=== code end ===

Regards,
Sven___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] How to avoid Copy

2024-01-02 Thread Amir--- via fpc-pascal
Yeap! That is actually what I posted here (Feature Request) 
.


 You simply need to inherit from the list class so that you can make 
the function public. And with a little trick you can also use it 
inside a for-in-loop:


=== code begin ===

program tlistitr;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}

uses
  Generics.Collections;

type
  TRec = record
    a, b, c: Int64;
    constructor Create(aArg1, aArg2, aArg3: Int64);
  end;

  { this way the GetPtrEnumerator function is available; you could 
also use a class helper }

  TMyList = class(specialize TList)
  public
    function GetPtrEnumerator: specialize TEnumerator;
  end;

constructor TRec.Create(aArg1, aArg2, aArg3: Int64);
begin
  a := aArg1;
  b := aArg2;
  c := aArg3;
end;

function TMyList.GetPtrEnumerator: specialize TEnumerator;
begin
  Result := inherited GetPtrEnumerator();
end;

{ with this you can simply do "for PtrTypeVar in List.GetPtrEnumerator 
do",

  though this *might* not work in mode Delphi... }
operator Enumerator(aEnum: specialize TEnumerator): 
specialize TEnumerator;

begin
  Result := aEnum;
end;

var
  l: TMyList;
  r: TRec;
  p: TMyList.PT;
begin
  l := TMyList.Create;
  l.Add(TRec.Create(1, 2, 3));
  l.Add(TRec.Create(9, 8, 7));
  for p in l.GetPtrEnumerator do begin
    Writeln(p^.a, ' ', p^.b, ' ', p^.c);
  end;
end.

=== code end ===

Regards,
Sven

___
fpc-pascal maillist  -fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] How to avoid Copy

2024-01-02 Thread Sven Barth via fpc-pascal
Amir--- via fpc-pascal  schrieb am Mi., 3.
Jan. 2024, 07:53:

> Yeap! That is actually what I posted here (Feature Request)
> .
>

My example allows you to access it right now with the existing FPC release.

Regards,
Sven

>
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal


Re: [fpc-pascal] How to avoid Copy

2024-01-02 Thread Amir--- via fpc-pascal

Thanks!

On 1/2/24 22:59, Sven Barth via fpc-pascal wrote:
Amir--- via fpc-pascal  schrieb am 
Mi., 3. Jan. 2024, 07:53:


Yeap! That is actually what I posted here (Feature Request)
.


My example allows you to access it right now with the existing FPC 
release.


Regards,
Sven


___
fpc-pascal maillist  -fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
___
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal